feat(eslint): Enable for non react files
This commit is contained in:
parent
b1b3807e9b
commit
969f5d67ab
272
.eslintrc.js
272
.eslintrc.js
|
@ -23,9 +23,157 @@ module.exports = {
|
||||||
'sourceType': 'module'
|
'sourceType': 'module'
|
||||||
},
|
},
|
||||||
'plugins': [
|
'plugins': [
|
||||||
'flowtype'
|
'flowtype',
|
||||||
|
|
||||||
|
// ESLint's rule no-duplicate-imports does not understand Flow's import
|
||||||
|
// type. Fortunately, eslint-plugin-import understands Flow's import
|
||||||
|
// type.
|
||||||
|
'import'
|
||||||
],
|
],
|
||||||
'rules': {
|
'rules': {
|
||||||
|
// Possible Errors group
|
||||||
|
'no-cond-assign': 2,
|
||||||
|
'no-console': 0,
|
||||||
|
'no-constant-condition': 2,
|
||||||
|
'no-control-regex': 2,
|
||||||
|
'no-debugger': 2,
|
||||||
|
'no-dupe-args': 2,
|
||||||
|
'no-dupe-keys': 2,
|
||||||
|
'no-duplicate-case': 2,
|
||||||
|
'no-empty': 2,
|
||||||
|
'no-empty-character-class': 2,
|
||||||
|
'no-ex-assign': 2,
|
||||||
|
'no-extra-boolean-cast': 2,
|
||||||
|
'no-extra-parens': [
|
||||||
|
'error',
|
||||||
|
'all',
|
||||||
|
{ 'nestedBinaryExpressions': false }
|
||||||
|
],
|
||||||
|
'no-extra-semi': 2,
|
||||||
|
'no-func-assign': 2,
|
||||||
|
'no-inner-declarations': 2,
|
||||||
|
'no-invalid-regexp': 2,
|
||||||
|
'no-irregular-whitespace': 2,
|
||||||
|
'no-negated-in-lhs': 2,
|
||||||
|
'no-obj-calls': 2,
|
||||||
|
'no-prototype-builtins': 0,
|
||||||
|
'no-regex-spaces': 2,
|
||||||
|
'no-sparse-arrays': 2,
|
||||||
|
'no-unexpected-multiline': 2,
|
||||||
|
'no-unreachable': 2,
|
||||||
|
'no-unsafe-finally': 2,
|
||||||
|
'use-isnan': 2,
|
||||||
|
'valid-typeof': 2,
|
||||||
|
|
||||||
|
// Best Practices group
|
||||||
|
'accessor-pairs': 0,
|
||||||
|
'array-callback-return': 2,
|
||||||
|
'block-scoped-var': 0,
|
||||||
|
'complexity': 0,
|
||||||
|
'consistent-return': 0,
|
||||||
|
'curly': 2,
|
||||||
|
'default-case': 0,
|
||||||
|
'dot-location': [ 'error', 'property' ],
|
||||||
|
'dot-notation': 2,
|
||||||
|
'eqeqeq': 2,
|
||||||
|
'guard-for-in': 2,
|
||||||
|
'no-alert': 2,
|
||||||
|
'no-caller': 2,
|
||||||
|
'no-case-declarations': 2,
|
||||||
|
'no-div-regex': 0,
|
||||||
|
'no-else-return': 2,
|
||||||
|
'no-empty-function': 2,
|
||||||
|
'no-empty-pattern': 2,
|
||||||
|
'no-eq-null': 2,
|
||||||
|
'no-eval': 2,
|
||||||
|
'no-extend-native': 2,
|
||||||
|
'no-extra-bind': 2,
|
||||||
|
'no-extra-label': 2,
|
||||||
|
'no-fallthrough': 2,
|
||||||
|
'no-floating-decimal': 2,
|
||||||
|
'no-implicit-coercion': 2,
|
||||||
|
'no-implicit-globals': 2,
|
||||||
|
'no-implied-eval': 2,
|
||||||
|
'no-invalid-this': 2,
|
||||||
|
'no-iterator': 2,
|
||||||
|
'no-labels': 2,
|
||||||
|
'no-lone-blocks': 2,
|
||||||
|
'no-loop-func': 2,
|
||||||
|
'no-magic-numbers': 0,
|
||||||
|
'no-multi-spaces': 2,
|
||||||
|
'no-multi-str': 2,
|
||||||
|
'no-native-reassign': 2,
|
||||||
|
'no-new': 2,
|
||||||
|
'no-new-func': 2,
|
||||||
|
'no-new-wrappers': 2,
|
||||||
|
'no-octal': 2,
|
||||||
|
'no-octal-escape': 2,
|
||||||
|
'no-param-reassign': 2,
|
||||||
|
'no-proto': 2,
|
||||||
|
'no-redeclare': 2,
|
||||||
|
'no-return-assign': 2,
|
||||||
|
'no-script-url': 2,
|
||||||
|
'no-self-assign': 2,
|
||||||
|
'no-self-compare': 2,
|
||||||
|
'no-sequences': 2,
|
||||||
|
'no-throw-literal': 2,
|
||||||
|
'no-unmodified-loop-condition': 2,
|
||||||
|
'no-unused-expressions': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
'allowShortCircuit': true,
|
||||||
|
'allowTernary': true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'no-unused-labels': 2,
|
||||||
|
'no-useless-call': 2,
|
||||||
|
'no-useless-concat': 2,
|
||||||
|
'no-useless-escape': 2,
|
||||||
|
'no-void': 2,
|
||||||
|
'no-warning-comments': 0,
|
||||||
|
'no-with': 2,
|
||||||
|
'radix': 2,
|
||||||
|
'vars-on-top': 2,
|
||||||
|
'wrap-iife': [ 'error', 'inside' ],
|
||||||
|
'yoda': 2,
|
||||||
|
|
||||||
|
// Strict Mode group
|
||||||
|
'strict': 2,
|
||||||
|
|
||||||
|
// Variables group
|
||||||
|
'init-declarations': 0,
|
||||||
|
'no-catch-shadow': 2,
|
||||||
|
'no-delete-var': 2,
|
||||||
|
'no-label-var': 2,
|
||||||
|
'no-restricted-globals': 0,
|
||||||
|
'no-shadow': 2,
|
||||||
|
'no-shadow-restricted-names': 2,
|
||||||
|
'no-undef': 2,
|
||||||
|
'no-undef-init': 2,
|
||||||
|
'no-undefined': 0,
|
||||||
|
'no-unused-vars': 2,
|
||||||
|
'no-use-before-define': [ 'error', { 'functions': false } ],
|
||||||
|
|
||||||
|
// Stylistic issues group
|
||||||
|
'array-bracket-spacing': [
|
||||||
|
'error',
|
||||||
|
'always',
|
||||||
|
{ 'objectsInArrays': true }
|
||||||
|
],
|
||||||
|
'block-spacing': [ 'error', 'always' ],
|
||||||
|
'brace-style': 2,
|
||||||
|
'camelcase': 2,
|
||||||
|
'comma-dangle': 2,
|
||||||
|
'comma-spacing': 2,
|
||||||
|
'comma-style': 2,
|
||||||
|
'computed-property-spacing': 2,
|
||||||
|
'consistent-this': [ 'error', 'self' ],
|
||||||
|
'eol-last': 2,
|
||||||
|
'func-names': 0,
|
||||||
|
'func-style': 0,
|
||||||
|
'id-blacklist': 0,
|
||||||
|
'id-length': 0,
|
||||||
|
'id-match': 0,
|
||||||
'indent': [
|
'indent': [
|
||||||
'error',
|
'error',
|
||||||
4,
|
4,
|
||||||
|
@ -43,19 +191,121 @@ module.exports = {
|
||||||
'SwitchCase': 0
|
'SwitchCase': 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'new-cap': [
|
'key-spacing': 2,
|
||||||
|
'keyword-spacing': 2,
|
||||||
|
'linebreak-style': [ 'error', 'unix' ],
|
||||||
|
'lines-around-comment': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
'capIsNew': false // Behave like JSHint's newcap.
|
'allowBlockStart': true,
|
||||||
|
'allowObjectStart': true,
|
||||||
|
'beforeBlockComment': true,
|
||||||
|
'beforeLineComment': true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
// While it is considered a best practice to avoid using methods on
|
'max-depth': 2,
|
||||||
// console in JavaScript that is designed to be executed in the browser
|
'max-len': [ 'error', 80 ],
|
||||||
// and ESLint includes the rule among its set of recommended rules, (1)
|
'max-lines': 0,
|
||||||
// the general practice is to strip such calls before pushing to
|
'max-nested-callbacks': 2,
|
||||||
// production and (2) we prefer to utilize console in lib-jitsi-meet
|
'max-params': 2,
|
||||||
// (and jitsi-meet).
|
'max-statements': 0,
|
||||||
'no-console': 'off',
|
'max-statements-per-line': 2,
|
||||||
'semi': 'error'
|
'multiline-ternary': 0,
|
||||||
|
'new-cap': 2,
|
||||||
|
'new-parens': 2,
|
||||||
|
'newline-after-var': 2,
|
||||||
|
'newline-before-return': 2,
|
||||||
|
'newline-per-chained-call': 2,
|
||||||
|
'no-array-constructor': 2,
|
||||||
|
'no-bitwise': 2,
|
||||||
|
'no-continue': 2,
|
||||||
|
'no-inline-comments': 0,
|
||||||
|
'no-lonely-if': 2,
|
||||||
|
'no-mixed-operators': 2,
|
||||||
|
'no-mixed-spaces-and-tabs': 2,
|
||||||
|
'no-multiple-empty-lines': 2,
|
||||||
|
'no-negated-condition': 2,
|
||||||
|
'no-nested-ternary': 0,
|
||||||
|
'no-new-object': 2,
|
||||||
|
'no-plusplus': 0,
|
||||||
|
'no-restricted-syntax': 0,
|
||||||
|
'no-spaced-func': 2,
|
||||||
|
'no-tabs': 2,
|
||||||
|
'no-ternary': 0,
|
||||||
|
'no-trailing-spaces': 2,
|
||||||
|
'no-underscore-dangle': 0,
|
||||||
|
'no-unneeded-ternary': 2,
|
||||||
|
'no-whitespace-before-property': 2,
|
||||||
|
'object-curly-newline': 0,
|
||||||
|
'object-curly-spacing': [ 'error', 'always' ],
|
||||||
|
'object-property-newline': 2,
|
||||||
|
'one-var': 0,
|
||||||
|
'one-var-declaration-per-line': 0,
|
||||||
|
'operator-assignment': 0,
|
||||||
|
'operator-linebreak': [ 'error', 'before' ],
|
||||||
|
'padded-blocks': 0,
|
||||||
|
'quote-props': 0,
|
||||||
|
'quotes': [ 'error', 'single' ],
|
||||||
|
'require-jsdoc': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
'require': {
|
||||||
|
'ClassDeclaration': true,
|
||||||
|
'FunctionDeclaration': true,
|
||||||
|
'MethodDefinition': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'semi': [ 'error', 'always' ],
|
||||||
|
'semi-spacing': 2,
|
||||||
|
'sort-vars': 2,
|
||||||
|
'space-before-blocks': 2,
|
||||||
|
'space-before-function-paren': [ 'error', 'never' ],
|
||||||
|
'space-in-parens': [ 'error', 'never' ],
|
||||||
|
'space-infix-ops': 2,
|
||||||
|
'space-unary-ops': 2,
|
||||||
|
'spaced-comment': 2,
|
||||||
|
'unicode-bom': 0,
|
||||||
|
'wrap-regex': 0,
|
||||||
|
|
||||||
|
// ES6 group rules
|
||||||
|
'arrow-body-style': [
|
||||||
|
'error',
|
||||||
|
'as-needed',
|
||||||
|
{ requireReturnForObjectLiteral: true }
|
||||||
|
],
|
||||||
|
'arrow-parens': [ 'error', 'as-needed' ],
|
||||||
|
'arrow-spacing': 2,
|
||||||
|
'constructor-super': 2,
|
||||||
|
'generator-star-spacing': 2,
|
||||||
|
'no-class-assign': 2,
|
||||||
|
'no-confusing-arrow': 2,
|
||||||
|
'no-const-assign': 2,
|
||||||
|
'no-dupe-class-members': 2,
|
||||||
|
'no-new-symbol': 2,
|
||||||
|
'no-restricted-imports': 0,
|
||||||
|
'no-this-before-super': 2,
|
||||||
|
'no-useless-computed-key': 2,
|
||||||
|
'no-useless-constructor': 2,
|
||||||
|
'no-useless-rename': 2,
|
||||||
|
'no-var': 2,
|
||||||
|
'object-shorthand': [
|
||||||
|
'error',
|
||||||
|
'always',
|
||||||
|
{ 'avoidQuotes': true }
|
||||||
|
],
|
||||||
|
'prefer-arrow-callback': [ 'error', { 'allowNamedFunctions': true } ],
|
||||||
|
'prefer-const': 2,
|
||||||
|
'prefer-reflect': 0,
|
||||||
|
'prefer-rest-params': 2,
|
||||||
|
'prefer-spread': 2,
|
||||||
|
'prefer-template': 2,
|
||||||
|
'require-yield': 2,
|
||||||
|
'rest-spread-spacing': 2,
|
||||||
|
'sort-imports': 0,
|
||||||
|
'template-curly-spacing': 2,
|
||||||
|
'yield-star-spacing': 2,
|
||||||
|
|
||||||
|
'import/no-duplicates': 2
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
/**
|
/**
|
||||||
* Notifies interested parties that hangup procedure will start.
|
* Notifies interested parties that hangup procedure will start.
|
||||||
*/
|
*/
|
||||||
export const BEFORE_HANGUP = "conference.before_hangup";
|
export const BEFORE_HANGUP = 'conference.before_hangup';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies interested parties that desktop sharing enable/disable state is
|
* Notifies interested parties that desktop sharing enable/disable state is
|
||||||
* changed.
|
* changed.
|
||||||
*/
|
*/
|
||||||
export const DESKTOP_SHARING_ENABLED_CHANGED
|
export const DESKTOP_SHARING_ENABLED_CHANGED
|
||||||
= "conference.desktop_sharing_enabled_changed";
|
= 'conference.desktop_sharing_enabled_changed';
|
||||||
|
|
65
analytics.js
65
analytics.js
|
@ -1,38 +1,45 @@
|
||||||
/* global ga */
|
/* global ga */
|
||||||
/* eslint-disable indent */
|
/* eslint-disable indent */
|
||||||
|
|
||||||
(function (ctx) {
|
(function(ctx) {
|
||||||
function Analytics() {
|
|
||||||
/* eslint-disable semi */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Google Analytics
|
*
|
||||||
*/
|
*/
|
||||||
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
function Analytics() {
|
||||||
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
/* eslint-disable */
|
||||||
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
|
||||||
ga('create', 'UA-319188-14', 'jit.si');
|
|
||||||
ga('send', 'pageview');
|
|
||||||
|
|
||||||
/* eslint-enable semi */
|
/**
|
||||||
}
|
* Google Analytics
|
||||||
|
*/
|
||||||
|
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
|
||||||
|
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
|
||||||
|
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
|
||||||
|
ga('create', 'UA-319188-14', 'jit.si');
|
||||||
|
ga('send', 'pageview');
|
||||||
|
|
||||||
Analytics.prototype.sendEvent = function (action, data) {
|
/* eslint-enable */
|
||||||
// empty label if missing value for it and add the value,
|
}
|
||||||
// the value should be integer or null
|
|
||||||
var value = data.value;
|
|
||||||
value = value? Math.round(parseFloat(value)) : null;
|
|
||||||
var label = data.label || "";
|
|
||||||
|
|
||||||
ga('send', 'event', 'jit.si',
|
Analytics.prototype.sendEvent = function(action, data) {
|
||||||
action + '.' + data.browserName, label, value);
|
// empty label if missing value for it and add the value,
|
||||||
};
|
// the value should be integer or null
|
||||||
|
let value = data.value;
|
||||||
|
|
||||||
if (typeof ctx.JitsiMeetJS === "undefined")
|
value = value ? Math.round(parseFloat(value)) : null;
|
||||||
ctx.JitsiMeetJS = {};
|
const label = data.label || '';
|
||||||
if (typeof ctx.JitsiMeetJS.app === "undefined")
|
|
||||||
ctx.JitsiMeetJS.app = {};
|
ga('send', 'event', 'jit.si',
|
||||||
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === "undefined")
|
`${action}.${data.browserName}`, label, value);
|
||||||
ctx.JitsiMeetJS.app.analyticsHandlers = [];
|
};
|
||||||
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
|
|
||||||
}(window));
|
if (typeof ctx.JitsiMeetJS === 'undefined') {
|
||||||
|
ctx.JitsiMeetJS = {};
|
||||||
|
}
|
||||||
|
if (typeof ctx.JitsiMeetJS.app === 'undefined') {
|
||||||
|
ctx.JitsiMeetJS.app = {};
|
||||||
|
}
|
||||||
|
if (typeof ctx.JitsiMeetJS.app.analyticsHandlers === 'undefined') {
|
||||||
|
ctx.JitsiMeetJS.app.analyticsHandlers = [];
|
||||||
|
}
|
||||||
|
ctx.JitsiMeetJS.app.analyticsHandlers.push(Analytics);
|
||||||
|
})(window);
|
||||||
|
|
698
conference.js
698
conference.js
File diff suppressed because it is too large
Load Diff
105
config.js
105
config.js
|
@ -1,12 +1,13 @@
|
||||||
|
/* eslint-disable no-unused-vars, no-var */
|
||||||
var config = { // eslint-disable-line no-unused-vars
|
var config = { // eslint-disable-line no-unused-vars
|
||||||
// Configuration
|
// Configuration
|
||||||
//
|
//
|
||||||
|
|
||||||
// Alternative location for the configuration.
|
// Alternative location for the configuration.
|
||||||
//configLocation: './config.json',
|
// configLocation: './config.json',
|
||||||
|
|
||||||
// Custom function which given the URL path should return a room name.
|
// Custom function which given the URL path should return a room name.
|
||||||
//getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
|
// getroomnode: function (path) { return 'someprefixpossiblybasedonpath'; },
|
||||||
|
|
||||||
|
|
||||||
// Connection
|
// Connection
|
||||||
|
@ -17,22 +18,22 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
domain: 'jitsi-meet.example.com',
|
domain: 'jitsi-meet.example.com',
|
||||||
|
|
||||||
// XMPP MUC domain. FIXME: use XEP-0030 to discover it.
|
// XMPP MUC domain. FIXME: use XEP-0030 to discover it.
|
||||||
muc: 'conference.jitsi-meet.example.com',
|
muc: 'conference.jitsi-meet.example.com'
|
||||||
|
|
||||||
// When using authentication, domain for guest users.
|
// When using authentication, domain for guest users.
|
||||||
//anonymousdomain: 'guest.example.com',
|
// anonymousdomain: 'guest.example.com',
|
||||||
|
|
||||||
// Domain for authenticated users. Defaults to <domain>.
|
// Domain for authenticated users. Defaults to <domain>.
|
||||||
//authdomain: 'jitsi-meet.example.com',
|
// authdomain: 'jitsi-meet.example.com',
|
||||||
|
|
||||||
// Jirecon recording component domain.
|
// Jirecon recording component domain.
|
||||||
//jirecon: 'jirecon.jitsi-meet.example.com',
|
// jirecon: 'jirecon.jitsi-meet.example.com',
|
||||||
|
|
||||||
// Call control component (Jigasi).
|
// Call control component (Jigasi).
|
||||||
//call_control: 'callcontrol.jitsi-meet.example.com',
|
// call_control: 'callcontrol.jitsi-meet.example.com',
|
||||||
|
|
||||||
// Focus component domain. Defaults to focus.<domain>.
|
// Focus component domain. Defaults to focus.<domain>.
|
||||||
//focus: 'focus.jitsi-meet.example.com',
|
// focus: 'focus.jitsi-meet.example.com',
|
||||||
},
|
},
|
||||||
|
|
||||||
// BOSH URL. FIXME: use XEP-0156 to discover it.
|
// BOSH URL. FIXME: use XEP-0156 to discover it.
|
||||||
|
@ -42,7 +43,7 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
clientNode: 'http://jitsi.org/jitsimeet',
|
clientNode: 'http://jitsi.org/jitsimeet',
|
||||||
|
|
||||||
// The real JID of focus participant - can be overridden here
|
// The real JID of focus participant - can be overridden here
|
||||||
//focusUserJid: 'focus@auth.jitsi-meet.example.com',
|
// focusUserJid: 'focus@auth.jitsi-meet.example.com',
|
||||||
|
|
||||||
|
|
||||||
// Testing / experimental features.
|
// Testing / experimental features.
|
||||||
|
@ -51,18 +52,19 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
testing: {
|
testing: {
|
||||||
// Enables experimental simulcast support on Firefox.
|
// Enables experimental simulcast support on Firefox.
|
||||||
enableFirefoxSimulcast: false,
|
enableFirefoxSimulcast: false,
|
||||||
|
|
||||||
// P2P test mode disables automatic switching to P2P when there are 2
|
// P2P test mode disables automatic switching to P2P when there are 2
|
||||||
// participants in the conference.
|
// participants in the conference.
|
||||||
p2pTestMode: false,
|
p2pTestMode: false
|
||||||
},
|
},
|
||||||
|
|
||||||
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
// Disables ICE/UDP by filtering out local and remote UDP candidates in
|
||||||
// signalling.
|
// signalling.
|
||||||
//webrtcIceUdpDisable: false,
|
// webrtcIceUdpDisable: false,
|
||||||
|
|
||||||
// Disables ICE/TCP by filtering out local and remote TCP candidates in
|
// Disables ICE/TCP by filtering out local and remote TCP candidates in
|
||||||
// signalling.
|
// signalling.
|
||||||
//webrtcIceTcpDisable: false,
|
// webrtcIceTcpDisable: false,
|
||||||
|
|
||||||
|
|
||||||
// Media
|
// Media
|
||||||
|
@ -71,52 +73,52 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
// Audio
|
// Audio
|
||||||
|
|
||||||
// Disable measuring of audio levels.
|
// Disable measuring of audio levels.
|
||||||
//disableAudioLevels: false,
|
// disableAudioLevels: false,
|
||||||
|
|
||||||
// Start the conference in audio only mode (no video is being received nor
|
// Start the conference in audio only mode (no video is being received nor
|
||||||
// sent).
|
// sent).
|
||||||
//startAudioOnly: false,
|
// startAudioOnly: false,
|
||||||
|
|
||||||
// Every participant after the Nth will start audio muted.
|
// Every participant after the Nth will start audio muted.
|
||||||
//startAudioMuted: 10,
|
// startAudioMuted: 10,
|
||||||
|
|
||||||
// Start calls with audio muted. Unlike the option above, this one is only
|
// Start calls with audio muted. Unlike the option above, this one is only
|
||||||
// applied locally. FIXME: having these 2 options is confusing.
|
// applied locally. FIXME: having these 2 options is confusing.
|
||||||
//startWithAudioMuted: false,
|
// startWithAudioMuted: false,
|
||||||
|
|
||||||
// Video
|
// Video
|
||||||
|
|
||||||
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
// Sets the preferred resolution (height) for local video. Defaults to 720.
|
||||||
//resolution: 720,
|
// resolution: 720,
|
||||||
|
|
||||||
// Enable / disable simulcast support.
|
// Enable / disable simulcast support.
|
||||||
//disableSimulcast: false,
|
// disableSimulcast: false,
|
||||||
|
|
||||||
// Suspend sending video if bandwidth estimation is too low. This may cause
|
// Suspend sending video if bandwidth estimation is too low. This may cause
|
||||||
// problems with audio playback. Disabled until these are fixed.
|
// problems with audio playback. Disabled until these are fixed.
|
||||||
disableSuspendVideo: true,
|
disableSuspendVideo: true,
|
||||||
|
|
||||||
// Every participant after the Nth will start video muted.
|
// Every participant after the Nth will start video muted.
|
||||||
//startVideoMuted: 10,
|
// startVideoMuted: 10,
|
||||||
|
|
||||||
// Start calls with video muted. Unlike the option above, this one is only
|
// Start calls with video muted. Unlike the option above, this one is only
|
||||||
// applied locally. FIXME: having these 2 options is confusing.
|
// applied locally. FIXME: having these 2 options is confusing.
|
||||||
//startWithVideoMuted: false,
|
// startWithVideoMuted: false,
|
||||||
|
|
||||||
// If set to true, prefer to use the H.264 video codec (if supported).
|
// If set to true, prefer to use the H.264 video codec (if supported).
|
||||||
// Note that it's not recommended to do this because simulcast is not
|
// Note that it's not recommended to do this because simulcast is not
|
||||||
// supported when using H.264. For 1-to-1 calls this setting is enabled by
|
// supported when using H.264. For 1-to-1 calls this setting is enabled by
|
||||||
// default and can be toggled in the p2p section.
|
// default and can be toggled in the p2p section.
|
||||||
//preferH264: true,
|
// preferH264: true,
|
||||||
|
|
||||||
// If set to true, disable H.264 video codec by stripping it out of the
|
// If set to true, disable H.264 video codec by stripping it out of the
|
||||||
// SDP.
|
// SDP.
|
||||||
//disableH264: false,
|
// disableH264: false,
|
||||||
|
|
||||||
// Desktop sharing
|
// Desktop sharing
|
||||||
|
|
||||||
// Enable / disable desktop sharing
|
// Enable / disable desktop sharing
|
||||||
//disableDesktopSharing: false,
|
// disableDesktopSharing: false,
|
||||||
|
|
||||||
// The ID of the jidesha extension for Chrome.
|
// The ID of the jidesha extension for Chrome.
|
||||||
desktopSharingChromeExtId: null,
|
desktopSharingChromeExtId: null,
|
||||||
|
@ -126,7 +128,7 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
// The media sources to use when using screen sharing with the Chrome
|
// The media sources to use when using screen sharing with the Chrome
|
||||||
// extension.
|
// extension.
|
||||||
desktopSharingChromeSources: ['screen', 'window', 'tab'],
|
desktopSharingChromeSources: [ 'screen', 'window', 'tab' ],
|
||||||
|
|
||||||
// Required version of Chrome extension
|
// Required version of Chrome extension
|
||||||
desktopSharingChromeMinExtVersion: '0.1',
|
desktopSharingChromeMinExtVersion: '0.1',
|
||||||
|
@ -149,15 +151,15 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
desktopSharingFirefoxExtensionURL: null,
|
desktopSharingFirefoxExtensionURL: null,
|
||||||
|
|
||||||
// Try to start calls with screen-sharing instead of camera video.
|
// Try to start calls with screen-sharing instead of camera video.
|
||||||
//startScreenSharing: false,
|
// startScreenSharing: false,
|
||||||
|
|
||||||
// Recording
|
// Recording
|
||||||
|
|
||||||
// Whether to enable recording or not.
|
// Whether to enable recording or not.
|
||||||
//enableRecording: false,
|
// enableRecording: false,
|
||||||
|
|
||||||
// Type for recording: one of jibri or jirecon.
|
// Type for recording: one of jibri or jirecon.
|
||||||
//recordingType: 'jibri',
|
// recordingType: 'jibri',
|
||||||
|
|
||||||
// Misc
|
// Misc
|
||||||
|
|
||||||
|
@ -165,29 +167,29 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
channelLastN: -1,
|
channelLastN: -1,
|
||||||
|
|
||||||
// Disables or enables RTX (RFC 4588) (defaults to false).
|
// Disables or enables RTX (RFC 4588) (defaults to false).
|
||||||
//disableRtx: false,
|
// disableRtx: false,
|
||||||
|
|
||||||
// Use XEP-0215 to fetch STUN and TURN servers.
|
// Use XEP-0215 to fetch STUN and TURN servers.
|
||||||
//useStunTurn: true,
|
// useStunTurn: true,
|
||||||
|
|
||||||
// Enable IPv6 support.
|
// Enable IPv6 support.
|
||||||
//useIPv6: true,
|
// useIPv6: true,
|
||||||
|
|
||||||
// Enables / disables a data communication channel with the Videobridge.
|
// Enables / disables a data communication channel with the Videobridge.
|
||||||
// Values can be 'datachannel', 'websocket', true (treat it as
|
// Values can be 'datachannel', 'websocket', true (treat it as
|
||||||
// 'datachannel'), undefined (treat it as 'datachannel') and false (don't
|
// 'datachannel'), undefined (treat it as 'datachannel') and false (don't
|
||||||
// open any channel).
|
// open any channel).
|
||||||
//openBridgeChannel: true,
|
// openBridgeChannel: true,
|
||||||
|
|
||||||
|
|
||||||
// UI
|
// UI
|
||||||
//
|
//
|
||||||
|
|
||||||
// Use display name as XMPP nickname.
|
// Use display name as XMPP nickname.
|
||||||
//useNicks: false,
|
// useNicks: false,
|
||||||
|
|
||||||
// Require users to always specify a display name.
|
// Require users to always specify a display name.
|
||||||
//requireDisplayName: true,
|
// requireDisplayName: true,
|
||||||
|
|
||||||
// Whether to use a welcome page or not. In case it's false a random room
|
// Whether to use a welcome page or not. In case it's false a random room
|
||||||
// will be joined when no room is specified.
|
// will be joined when no room is specified.
|
||||||
|
@ -195,17 +197,19 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
// Enabling the close page will ignore the welcome page redirection when
|
// Enabling the close page will ignore the welcome page redirection when
|
||||||
// a call is hangup.
|
// a call is hangup.
|
||||||
//enableClosePage: false,
|
// enableClosePage: false,
|
||||||
|
|
||||||
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
|
// Disable hiding of remote thumbnails when in a 1-on-1 conference call.
|
||||||
//disable1On1Mode: false,
|
// disable1On1Mode: false,
|
||||||
|
|
||||||
|
|
||||||
|
// The minumum value a video's height (or width, whichever is smaller) needs
|
||||||
// The minimum value a video's height (or width, whichever is smaller) needs
|
// The minimum value a video's height (or width, whichever is smaller) needs
|
||||||
// to be in order to be considered high-definition.
|
// to be in order to be considered high-definition.
|
||||||
minHDHeight: 540,
|
minHDHeight: 540,
|
||||||
|
|
||||||
// Default language for the user interface.
|
// Default language for the user interface.
|
||||||
//defaultLanguage: 'en',
|
// defaultLanguage: 'en',
|
||||||
|
|
||||||
// If true all users without a token will be considered guests and all users
|
// If true all users without a token will be considered guests and all users
|
||||||
// with token will be considered non-guests. Only guests will be allowed to
|
// with token will be considered non-guests. Only guests will be allowed to
|
||||||
|
@ -214,19 +218,19 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
// Message to show the users. Example: 'The service will be down for
|
// Message to show the users. Example: 'The service will be down for
|
||||||
// maintenance at 01:00 AM GMT,
|
// maintenance at 01:00 AM GMT,
|
||||||
//noticeMessage: '',
|
// noticeMessage: '',
|
||||||
|
|
||||||
|
|
||||||
// Stats
|
// Stats
|
||||||
//
|
//
|
||||||
|
|
||||||
// Whether to enable stats collection or not.
|
// Whether to enable stats collection or not.
|
||||||
//disableStats: false,
|
// disableStats: false,
|
||||||
|
|
||||||
// To enable sending statistics to callstats.io you must provide the
|
// To enable sending statistics to callstats.io you must provide the
|
||||||
// Application ID and Secret.
|
// Application ID and Secret.
|
||||||
//callStatsID: '',
|
// callStatsID: '',
|
||||||
//callStatsSecret: '',
|
// callStatsSecret: '',
|
||||||
|
|
||||||
|
|
||||||
// Privacy
|
// Privacy
|
||||||
|
@ -235,7 +239,7 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
// If third party requests are disabled, no other server will be contacted.
|
// If third party requests are disabled, no other server will be contacted.
|
||||||
// This means avatars will be locally generated and callstats integration
|
// This means avatars will be locally generated and callstats integration
|
||||||
// will not function.
|
// will not function.
|
||||||
//disableThirdPartyRequests: false,
|
// disableThirdPartyRequests: false,
|
||||||
|
|
||||||
|
|
||||||
// Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
|
// Peer-To-Peer mode: used (if enabled) when there are just 2 participants.
|
||||||
|
@ -251,13 +255,13 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
|
||||||
// Use XEP-0215 to fetch STUN and TURN servers.
|
// Use XEP-0215 to fetch STUN and TURN servers.
|
||||||
//useStunTurn: true,
|
// useStunTurn: true,
|
||||||
|
|
||||||
// The STUN servers that will be used in the peer to peer connections
|
// The STUN servers that will be used in the peer to peer connections
|
||||||
stunServers: [
|
stunServers: [
|
||||||
{ urls: "stun:stun.l.google.com:19302" },
|
{ urls: 'stun:stun.l.google.com:19302' },
|
||||||
{ urls: "stun:stun1.l.google.com:19302" },
|
{ urls: 'stun:stun1.l.google.com:19302' },
|
||||||
{ urls: "stun:stun2.l.google.com:19302" }
|
{ urls: 'stun:stun2.l.google.com:19302' }
|
||||||
],
|
],
|
||||||
|
|
||||||
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
|
// If set to true, it will prefer to use H.264 for P2P calls (if H.264
|
||||||
|
@ -266,11 +270,11 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
|
|
||||||
// If set to true, disable H.264 video codec by stripping it out of the
|
// If set to true, disable H.264 video codec by stripping it out of the
|
||||||
// SDP.
|
// SDP.
|
||||||
//disableH264: false,
|
// disableH264: false,
|
||||||
|
|
||||||
// How long we're going to wait, before going back to P2P after the 3rd
|
// How long we're going to wait, before going back to P2P after the 3rd
|
||||||
// participant has left the conference (to filter out page reload).
|
// participant has left the conference (to filter out page reload).
|
||||||
//backToP2PDelay: 5
|
// backToP2PDelay: 5
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
@ -279,8 +283,9 @@ var config = { // eslint-disable-line no-unused-vars
|
||||||
//
|
//
|
||||||
|
|
||||||
deploymentInfo: {
|
deploymentInfo: {
|
||||||
//shard: "shard1",
|
// shard: "shard1",
|
||||||
//region: "europe",
|
// region: "europe",
|
||||||
//userRegion: "asia"
|
// userRegion: "asia"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
/* eslint-enable no-unused-vars, no-var */
|
||||||
|
|
|
@ -13,7 +13,7 @@ import {
|
||||||
JitsiConnectionEvents
|
JitsiConnectionEvents
|
||||||
} from './react/features/base/lib-jitsi-meet';
|
} from './react/features/base/lib-jitsi-meet';
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if we have data to use attach instead of connect. If we have the data
|
* Checks if we have data to use attach instead of connect. If we have the data
|
||||||
|
@ -27,26 +27,31 @@ const logger = require("jitsi-meet-logger").getLogger(__filename);
|
||||||
* @param {string} [roomName] the name of the conference.
|
* @param {string} [roomName] the name of the conference.
|
||||||
*/
|
*/
|
||||||
function checkForAttachParametersAndConnect(id, password, connection) {
|
function checkForAttachParametersAndConnect(id, password, connection) {
|
||||||
if(window.XMPPAttachInfo){
|
if (window.XMPPAttachInfo) {
|
||||||
APP.connect.status = "connecting";
|
APP.connect.status = 'connecting';
|
||||||
|
|
||||||
// When connection optimization is not deployed or enabled the default
|
// When connection optimization is not deployed or enabled the default
|
||||||
// value will be window.XMPPAttachInfo.status = "error"
|
// value will be window.XMPPAttachInfo.status = "error"
|
||||||
// If the connection optimization is deployed and enabled and there is
|
// If the connection optimization is deployed and enabled and there is
|
||||||
// a failure the value will be window.XMPPAttachInfo.status = "error"
|
// a failure the value will be window.XMPPAttachInfo.status = "error"
|
||||||
if(window.XMPPAttachInfo.status === "error") {
|
if (window.XMPPAttachInfo.status === 'error') {
|
||||||
connection.connect({id, password});
|
connection.connect({ id,
|
||||||
|
password });
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var attachOptions = window.XMPPAttachInfo.data;
|
const attachOptions = window.XMPPAttachInfo.data;
|
||||||
if(attachOptions) {
|
|
||||||
|
if (attachOptions) {
|
||||||
connection.attach(attachOptions);
|
connection.attach(attachOptions);
|
||||||
delete window.XMPPAttachInfo.data;
|
delete window.XMPPAttachInfo.data;
|
||||||
} else {
|
} else {
|
||||||
connection.connect({id, password});
|
connection.connect({ id,
|
||||||
|
password });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
APP.connect.status = "ready";
|
APP.connect.status = 'ready';
|
||||||
APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
|
APP.connect.handler = checkForAttachParametersAndConnect.bind(null,
|
||||||
id, password, connection);
|
id, password, connection);
|
||||||
}
|
}
|
||||||
|
@ -64,15 +69,15 @@ function connect(id, password, roomName) {
|
||||||
const connectionConfig = Object.assign({}, config);
|
const connectionConfig = Object.assign({}, config);
|
||||||
const { issuer, jwt } = APP.store.getState()['features/base/jwt'];
|
const { issuer, jwt } = APP.store.getState()['features/base/jwt'];
|
||||||
|
|
||||||
connectionConfig.bosh += '?room=' + roomName;
|
connectionConfig.bosh += `?room=${roomName}`;
|
||||||
|
|
||||||
let connection
|
const connection
|
||||||
= new JitsiMeetJS.JitsiConnection(
|
= new JitsiMeetJS.JitsiConnection(
|
||||||
null,
|
null,
|
||||||
jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
|
jwt && issuer && issuer !== 'anonymous' ? jwt : undefined,
|
||||||
connectionConfig);
|
connectionConfig);
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
connection.addEventListener(
|
connection.addEventListener(
|
||||||
JitsiConnectionEvents.CONNECTION_ESTABLISHED,
|
JitsiConnectionEvents.CONNECTION_ESTABLISHED,
|
||||||
handleConnectionEstablished);
|
handleConnectionEstablished);
|
||||||
|
@ -83,6 +88,9 @@ function connect(id, password, roomName) {
|
||||||
JitsiConnectionEvents.CONNECTION_FAILED,
|
JitsiConnectionEvents.CONNECTION_FAILED,
|
||||||
connectionFailedHandler);
|
connectionFailedHandler);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function connectionFailedHandler(error, message, credentials) {
|
function connectionFailedHandler(error, message, credentials) {
|
||||||
APP.store.dispatch(
|
APP.store.dispatch(
|
||||||
connectionFailed(connection, error, message, credentials));
|
connectionFailed(connection, error, message, credentials));
|
||||||
|
@ -94,6 +102,9 @@ function connect(id, password, roomName) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function unsubscribe() {
|
function unsubscribe() {
|
||||||
connection.removeEventListener(
|
connection.removeEventListener(
|
||||||
JitsiConnectionEvents.CONNECTION_ESTABLISHED,
|
JitsiConnectionEvents.CONNECTION_ESTABLISHED,
|
||||||
|
@ -103,15 +114,21 @@ function connect(id, password, roomName) {
|
||||||
handleConnectionFailed);
|
handleConnectionFailed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function handleConnectionEstablished() {
|
function handleConnectionEstablished() {
|
||||||
APP.store.dispatch(connectionEstablished(connection));
|
APP.store.dispatch(connectionEstablished(connection));
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
resolve(connection);
|
resolve(connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function handleConnectionFailed(err) {
|
function handleConnectionFailed(err) {
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
logger.error("CONNECTION FAILED:", err);
|
logger.error('CONNECTION FAILED:', err);
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,17 +149,17 @@ function connect(id, password, roomName) {
|
||||||
*
|
*
|
||||||
* @returns {Promise<JitsiConnection>}
|
* @returns {Promise<JitsiConnection>}
|
||||||
*/
|
*/
|
||||||
export function openConnection({id, password, retry, roomName}) {
|
export function openConnection({ id, password, retry, roomName }) {
|
||||||
let usernameOverride
|
const usernameOverride
|
||||||
= jitsiLocalStorage.getItem("xmpp_username_override");
|
= jitsiLocalStorage.getItem('xmpp_username_override');
|
||||||
let passwordOverride
|
const passwordOverride
|
||||||
= jitsiLocalStorage.getItem("xmpp_password_override");
|
= jitsiLocalStorage.getItem('xmpp_password_override');
|
||||||
|
|
||||||
if (usernameOverride && usernameOverride.length > 0) {
|
if (usernameOverride && usernameOverride.length > 0) {
|
||||||
id = usernameOverride;
|
id = usernameOverride; // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
if (passwordOverride && passwordOverride.length > 0) {
|
if (passwordOverride && passwordOverride.length > 0) {
|
||||||
password = passwordOverride;
|
password = passwordOverride; // eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
|
|
||||||
return connect(id, password, roomName).catch(err => {
|
return connect(id, password, roomName).catch(err => {
|
||||||
|
|
|
@ -72,9 +72,9 @@
|
||||||
+ "font-size: medium;"
|
+ "font-size: medium;"
|
||||||
+ "font-weight: 400;"
|
+ "font-weight: 400;"
|
||||||
+ "transform: translate(-50%, -50%)'>"
|
+ "transform: translate(-50%, -50%)'>"
|
||||||
+ "Uh oh! We couldn't fully download everything we needed :(" // jshint ignore:line
|
+ "Uh oh! We couldn't fully download everything we needed :("
|
||||||
+ "<br/> "
|
+ "<br/> "
|
||||||
+ "We will try again shortly. In the mean time, check for problems with your Internet connection!" // jshint ignore:line
|
+ "We will try again shortly. In the mean time, check for problems with your Internet connection!"
|
||||||
+ "<br/><br/> "
|
+ "<br/><br/> "
|
||||||
+ "<div id='moreInfo' style='"
|
+ "<div id='moreInfo' style='"
|
||||||
+ "display: none;'>" + "Missing " + fileRef
|
+ "display: none;'>" + "Missing " + fileRef
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
var interfaceConfig = { // eslint-disable-line no-unused-vars
|
/* eslint-disable no-unused-vars, no-var, max-len */
|
||||||
|
var interfaceConfig = {
|
||||||
// TO FIX: this needs to be handled from SASS variables. There are some
|
// TO FIX: this needs to be handled from SASS variables. There are some
|
||||||
// methods allowing to use variables both in css and js.
|
// methods allowing to use variables both in css and js.
|
||||||
DEFAULT_BACKGROUND: '#474747',
|
DEFAULT_BACKGROUND: '#474747',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In case the desktop sharing is disabled through the config the button
|
* In case the desktop sharing is disabled through the config the button
|
||||||
* will not be hidden, but displayed as disabled with this text us as
|
* will not be hidden, but displayed as disabled with this text us as
|
||||||
|
@ -10,45 +12,53 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||||
DESKTOP_SHARING_BUTTON_DISABLED_TOOLTIP: null,
|
DESKTOP_SHARING_BUTTON_DISABLED_TOOLTIP: null,
|
||||||
INITIAL_TOOLBAR_TIMEOUT: 20000,
|
INITIAL_TOOLBAR_TIMEOUT: 20000,
|
||||||
TOOLBAR_TIMEOUT: 4000,
|
TOOLBAR_TIMEOUT: 4000,
|
||||||
DEFAULT_REMOTE_DISPLAY_NAME: "Fellow Jitster",
|
DEFAULT_REMOTE_DISPLAY_NAME: 'Fellow Jitster',
|
||||||
DEFAULT_LOCAL_DISPLAY_NAME: "me",
|
DEFAULT_LOCAL_DISPLAY_NAME: 'me',
|
||||||
SHOW_JITSI_WATERMARK: true,
|
SHOW_JITSI_WATERMARK: true,
|
||||||
JITSI_WATERMARK_LINK: "https://jitsi.org",
|
JITSI_WATERMARK_LINK: 'https://jitsi.org',
|
||||||
|
|
||||||
// if watermark is disabled by default, it can be shown only for guests
|
// if watermark is disabled by default, it can be shown only for guests
|
||||||
SHOW_WATERMARK_FOR_GUESTS: true,
|
SHOW_WATERMARK_FOR_GUESTS: true,
|
||||||
SHOW_BRAND_WATERMARK: false,
|
SHOW_BRAND_WATERMARK: false,
|
||||||
BRAND_WATERMARK_LINK: "",
|
BRAND_WATERMARK_LINK: '',
|
||||||
SHOW_POWERED_BY: false,
|
SHOW_POWERED_BY: false,
|
||||||
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
GENERATE_ROOMNAMES_ON_WELCOME_PAGE: true,
|
||||||
APP_NAME: "Jitsi Meet",
|
APP_NAME: 'Jitsi Meet',
|
||||||
LANG_DETECTION: false, // Allow i18n to detect the system language
|
LANG_DETECTION: false, // Allow i18n to detect the system language
|
||||||
INVITATION_POWERED_BY: true,
|
INVITATION_POWERED_BY: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If we should show authentication block in profile
|
* If we should show authentication block in profile
|
||||||
*/
|
*/
|
||||||
AUTHENTICATION_ENABLE: true,
|
AUTHENTICATION_ENABLE: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* the toolbar buttons line is intentionally left in one line, to be able
|
* the toolbar buttons line is intentionally left in one line, to be able
|
||||||
* to easily override values or remove them using regex
|
* to easily override values or remove them using regex
|
||||||
*/
|
*/
|
||||||
TOOLBAR_BUTTONS: [
|
TOOLBAR_BUTTONS: [
|
||||||
//main toolbar
|
|
||||||
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup', // jshint ignore:line
|
// main toolbar
|
||||||
//extended toolbar
|
'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup',
|
||||||
'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip'], // jshint ignore:line
|
|
||||||
|
// extended toolbar
|
||||||
|
'profile', 'contacts', 'info', 'chat', 'recording', 'etherpad', 'sharedvideo', 'settings', 'raisehand', 'videoquality', 'filmstrip' ],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Toolbar Buttons
|
* Main Toolbar Buttons
|
||||||
* All of them should be in TOOLBAR_BUTTONS
|
* All of them should be in TOOLBAR_BUTTONS
|
||||||
*/
|
*/
|
||||||
MAIN_TOOLBAR_BUTTONS: ['microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup'], // jshint ignore:line
|
MAIN_TOOLBAR_BUTTONS: [ 'microphone', 'camera', 'desktop', 'invite', 'fullscreen', 'fodeviceselection', 'hangup' ],
|
||||||
SETTINGS_SECTIONS: ['language', 'devices', 'moderator'],
|
SETTINGS_SECTIONS: [ 'language', 'devices', 'moderator' ],
|
||||||
INVITE_OPTIONS: ['invite', 'dialout', 'addtocall'],
|
INVITE_OPTIONS: [ 'invite', 'dialout', 'addtocall' ],
|
||||||
|
|
||||||
// Determines how the video would fit the screen. 'both' would fit the whole
|
// Determines how the video would fit the screen. 'both' would fit the whole
|
||||||
// screen, 'height' would fit the original video height to the height of the
|
// screen, 'height' would fit the original video height to the height of the
|
||||||
// screen, 'width' would fit the original video width to the width of the
|
// screen, 'width' would fit the original video width to the width of the
|
||||||
// screen respecting ratio.
|
// screen respecting ratio.
|
||||||
VIDEO_LAYOUT_FIT: 'both',
|
VIDEO_LAYOUT_FIT: 'both',
|
||||||
SHOW_CONTACTLIST_AVATARS: true,
|
SHOW_CONTACTLIST_AVATARS: true,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether to only show the filmstrip (and hide the toolbar).
|
* Whether to only show the filmstrip (and hide the toolbar).
|
||||||
*/
|
*/
|
||||||
|
@ -59,11 +69,12 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||||
*/
|
*/
|
||||||
VERTICAL_FILMSTRIP: true,
|
VERTICAL_FILMSTRIP: true,
|
||||||
|
|
||||||
//A html text to be shown to guests on the close page, false disables it
|
// A html text to be shown to guests on the close page, false disables it
|
||||||
CLOSE_PAGE_GUEST_HINT: false,
|
CLOSE_PAGE_GUEST_HINT: false,
|
||||||
RANDOM_AVATAR_URL_PREFIX: false,
|
RANDOM_AVATAR_URL_PREFIX: false,
|
||||||
RANDOM_AVATAR_URL_SUFFIX: false,
|
RANDOM_AVATAR_URL_SUFFIX: false,
|
||||||
FILM_STRIP_MAX_HEIGHT: 120,
|
FILM_STRIP_MAX_HEIGHT: 120,
|
||||||
|
|
||||||
// Enables feedback star animation.
|
// Enables feedback star animation.
|
||||||
ENABLE_FEEDBACK_ANIMATION: false,
|
ENABLE_FEEDBACK_ANIMATION: false,
|
||||||
DISABLE_FOCUS_INDICATOR: false,
|
DISABLE_FOCUS_INDICATOR: false,
|
||||||
|
@ -76,13 +87,13 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
DISABLE_RINGING: false,
|
DISABLE_RINGING: false,
|
||||||
AUDIO_LEVEL_PRIMARY_COLOR: "rgba(255,255,255,0.4)",
|
AUDIO_LEVEL_PRIMARY_COLOR: 'rgba(255,255,255,0.4)',
|
||||||
AUDIO_LEVEL_SECONDARY_COLOR: "rgba(255,255,255,0.2)",
|
AUDIO_LEVEL_SECONDARY_COLOR: 'rgba(255,255,255,0.2)',
|
||||||
POLICY_LOGO: null,
|
POLICY_LOGO: null,
|
||||||
LOCAL_THUMBNAIL_RATIO: 16/9, //16:9
|
LOCAL_THUMBNAIL_RATIO: 16 / 9, // 16:9
|
||||||
REMOTE_THUMBNAIL_RATIO: 1, //1:1
|
REMOTE_THUMBNAIL_RATIO: 1, // 1:1
|
||||||
// Documentation reference for the live streaming feature.
|
// Documentation reference for the live streaming feature.
|
||||||
LIVE_STREAMING_HELP_LINK: "https://jitsi.org/live",
|
LIVE_STREAMING_HELP_LINK: 'https://jitsi.org/live',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the mobile app Jitsi Meet is to be promoted to participants
|
* Whether the mobile app Jitsi Meet is to be promoted to participants
|
||||||
|
@ -131,3 +142,4 @@ var interfaceConfig = { // eslint-disable-line no-unused-vars
|
||||||
*/
|
*/
|
||||||
// ADD_PEOPLE_APP_NAME: ""
|
// ADD_PEOPLE_APP_NAME: ""
|
||||||
};
|
};
|
||||||
|
/* eslint-enable no-unused-vars, no-var, max-len */
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
|
/* eslint-disable no-unused-vars, no-var */
|
||||||
// Logging configuration
|
// Logging configuration
|
||||||
var loggingConfig = { // eslint-disable-line no-unused-vars
|
var loggingConfig = {
|
||||||
//default log level for the app and lib-jitsi-meet
|
// default log level for the app and lib-jitsi-meet
|
||||||
defaultLogLevel: 'trace',
|
defaultLogLevel: 'trace',
|
||||||
|
|
||||||
// Option to disable LogCollector (which stores the logs on CallStats)
|
// Option to disable LogCollector (which stores the logs on CallStats)
|
||||||
//disableLogCollector: true,
|
// disableLogCollector: true,
|
||||||
|
|
||||||
// Logging level adjustments for verbose modules:
|
// Logging level adjustments for verbose modules:
|
||||||
'modules/xmpp/strophe.util.js': 'log',
|
'modules/xmpp/strophe.util.js': 'log',
|
||||||
'modules/statistics/CallStats.js': 'info'
|
'modules/statistics/CallStats.js': 'info'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* eslint-enable no-unused-vars, no-var */
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import UIEvents from '../service/UI/UIEvents';
|
import UIEvents from '../service/UI/UIEvents';
|
||||||
import VideoLayout from './UI/videolayout/VideoLayout';
|
import VideoLayout from './UI/videolayout/VideoLayout';
|
||||||
|
@ -23,7 +23,7 @@ import VideoLayout from './UI/videolayout/VideoLayout';
|
||||||
* {State} for the local state at the time of this writing) of a {FollowMe}
|
* {State} for the local state at the time of this writing) of a {FollowMe}
|
||||||
* (instance) between participants.
|
* (instance) between participants.
|
||||||
*/
|
*/
|
||||||
const _COMMAND = "follow-me";
|
const _COMMAND = 'follow-me';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The timeout after which a follow-me command that has been received will be
|
* The timeout after which a follow-me command that has been received will be
|
||||||
|
@ -50,34 +50,61 @@ class State {
|
||||||
* the property, the old value of the property before the change, and the
|
* the property, the old value of the property before the change, and the
|
||||||
* new value of the property after the change.
|
* new value of the property after the change.
|
||||||
*/
|
*/
|
||||||
constructor (propertyChangeCallback) {
|
constructor(propertyChangeCallback) {
|
||||||
this._propertyChangeCallback = propertyChangeCallback;
|
this._propertyChangeCallback = propertyChangeCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
get filmstripVisible () { return this._filmstripVisible; }
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get filmstripVisible() {
|
||||||
|
return this._filmstripVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
set filmstripVisible(b) {
|
||||||
|
const oldValue = this._filmstripVisible;
|
||||||
|
|
||||||
set filmstripVisible (b) {
|
|
||||||
var oldValue = this._filmstripVisible;
|
|
||||||
if (oldValue !== b) {
|
if (oldValue !== b) {
|
||||||
this._filmstripVisible = b;
|
this._filmstripVisible = b;
|
||||||
this._firePropertyChange('filmstripVisible', oldValue, b);
|
this._firePropertyChange('filmstripVisible', oldValue, b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get nextOnStage() { return this._nextOnStage; }
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get nextOnStage() {
|
||||||
|
return this._nextOnStage;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
set nextOnStage(id) {
|
set nextOnStage(id) {
|
||||||
var oldValue = this._nextOnStage;
|
const oldValue = this._nextOnStage;
|
||||||
|
|
||||||
if (oldValue !== id) {
|
if (oldValue !== id) {
|
||||||
this._nextOnStage = id;
|
this._nextOnStage = id;
|
||||||
this._firePropertyChange('nextOnStage', oldValue, id);
|
this._firePropertyChange('nextOnStage', oldValue, id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get sharedDocumentVisible () { return this._sharedDocumentVisible; }
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get sharedDocumentVisible() {
|
||||||
|
return this._sharedDocumentVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
set sharedDocumentVisible(b) {
|
||||||
|
const oldValue = this._sharedDocumentVisible;
|
||||||
|
|
||||||
set sharedDocumentVisible (b) {
|
|
||||||
var oldValue = this._sharedDocumentVisible;
|
|
||||||
if (oldValue !== b) {
|
if (oldValue !== b) {
|
||||||
this._sharedDocumentVisible = b;
|
this._sharedDocumentVisible = b;
|
||||||
this._firePropertyChange('sharedDocumentVisible', oldValue, b);
|
this._firePropertyChange('sharedDocumentVisible', oldValue, b);
|
||||||
|
@ -93,10 +120,12 @@ class State {
|
||||||
* @param oldValue the value of {property} before the change
|
* @param oldValue the value of {property} before the change
|
||||||
* @param newValue the value of {property} after the change
|
* @param newValue the value of {property} after the change
|
||||||
*/
|
*/
|
||||||
_firePropertyChange (property, oldValue, newValue) {
|
_firePropertyChange(property, oldValue, newValue) {
|
||||||
var propertyChangeCallback = this._propertyChangeCallback;
|
const propertyChangeCallback = this._propertyChangeCallback;
|
||||||
if (propertyChangeCallback)
|
|
||||||
|
if (propertyChangeCallback) {
|
||||||
propertyChangeCallback(property, oldValue, newValue);
|
propertyChangeCallback(property, oldValue, newValue);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +147,7 @@ class FollowMe {
|
||||||
* destination (model/state) to receive from the remote moderator if the
|
* destination (model/state) to receive from the remote moderator if the
|
||||||
* local participant is not the moderator
|
* local participant is not the moderator
|
||||||
*/
|
*/
|
||||||
constructor (conference, UI) {
|
constructor(conference, UI) {
|
||||||
this._conference = conference;
|
this._conference = conference;
|
||||||
this._UI = UI;
|
this._UI = UI;
|
||||||
this.nextOnStageTimer = 0;
|
this.nextOnStageTimer = 0;
|
||||||
|
@ -150,9 +179,10 @@ class FollowMe {
|
||||||
this._nextOnStage(pinnedId, Boolean(pinnedId));
|
this._nextOnStage(pinnedId, Boolean(pinnedId));
|
||||||
|
|
||||||
// check whether shared document is enabled/initialized
|
// check whether shared document is enabled/initialized
|
||||||
if(this._UI.getSharedDocumentManager())
|
if (this._UI.getSharedDocumentManager()) {
|
||||||
this._sharedDocumentToggled
|
this._sharedDocumentToggled
|
||||||
.bind(this, this._UI.getSharedDocumentManager().isVisible());
|
.bind(this, this._UI.getSharedDocumentManager().isVisible());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -162,20 +192,21 @@ class FollowMe {
|
||||||
* the states of interest.
|
* the states of interest.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_addFollowMeListeners () {
|
_addFollowMeListeners() {
|
||||||
this.filmstripEventHandler = this._filmstripToggled.bind(this);
|
this.filmstripEventHandler = this._filmstripToggled.bind(this);
|
||||||
this._UI.addListener(UIEvents.TOGGLED_FILMSTRIP,
|
this._UI.addListener(UIEvents.TOGGLED_FILMSTRIP,
|
||||||
this.filmstripEventHandler);
|
this.filmstripEventHandler);
|
||||||
|
|
||||||
var self = this;
|
const self = this;
|
||||||
this.pinnedEndpointEventHandler = function (videoId, isPinned) {
|
|
||||||
|
this.pinnedEndpointEventHandler = function(videoId, isPinned) {
|
||||||
self._nextOnStage(videoId, isPinned);
|
self._nextOnStage(videoId, isPinned);
|
||||||
};
|
};
|
||||||
this._UI.addListener(UIEvents.PINNED_ENDPOINT,
|
this._UI.addListener(UIEvents.PINNED_ENDPOINT,
|
||||||
this.pinnedEndpointEventHandler);
|
this.pinnedEndpointEventHandler);
|
||||||
|
|
||||||
this.sharedDocEventHandler = this._sharedDocumentToggled.bind(this);
|
this.sharedDocEventHandler = this._sharedDocumentToggled.bind(this);
|
||||||
this._UI.addListener( UIEvents.TOGGLED_SHARED_DOCUMENT,
|
this._UI.addListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
|
||||||
this.sharedDocEventHandler);
|
this.sharedDocEventHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +214,7 @@ class FollowMe {
|
||||||
* Removes all follow me listeners.
|
* Removes all follow me listeners.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_removeFollowMeListeners () {
|
_removeFollowMeListeners() {
|
||||||
this._UI.removeListener(UIEvents.TOGGLED_FILMSTRIP,
|
this._UI.removeListener(UIEvents.TOGGLED_FILMSTRIP,
|
||||||
this.filmstripEventHandler);
|
this.filmstripEventHandler);
|
||||||
this._UI.removeListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
|
this._UI.removeListener(UIEvents.TOGGLED_SHARED_DOCUMENT,
|
||||||
|
@ -198,13 +229,13 @@ class FollowMe {
|
||||||
* @param enable {true} to enable the follow me functionality, {false} -
|
* @param enable {true} to enable the follow me functionality, {false} -
|
||||||
* to disable it
|
* to disable it
|
||||||
*/
|
*/
|
||||||
enableFollowMe (enable) {
|
enableFollowMe(enable) {
|
||||||
if (enable) {
|
if (enable) {
|
||||||
this._setFollowMeInitialState();
|
this._setFollowMeInitialState();
|
||||||
this._addFollowMeListeners();
|
this._addFollowMeListeners();
|
||||||
}
|
} else {
|
||||||
else
|
|
||||||
this._removeFollowMeListeners();
|
this._removeFollowMeListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -214,7 +245,7 @@ class FollowMe {
|
||||||
* @param filmstripVisible {Boolean} {true} if the filmstrip was shown (as a
|
* @param filmstripVisible {Boolean} {true} if the filmstrip was shown (as a
|
||||||
* result of the toggle) or {false} if the filmstrip was hidden
|
* result of the toggle) or {false} if the filmstrip was hidden
|
||||||
*/
|
*/
|
||||||
_filmstripToggled (filmstripVisible) {
|
_filmstripToggled(filmstripVisible) {
|
||||||
this._local.filmstripVisible = filmstripVisible;
|
this._local.filmstripVisible = filmstripVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,7 +256,7 @@ class FollowMe {
|
||||||
* @param sharedDocumentVisible {Boolean} {true} if the shared document was
|
* @param sharedDocumentVisible {Boolean} {true} if the shared document was
|
||||||
* shown (as a result of the toggle) or {false} if it was hidden
|
* shown (as a result of the toggle) or {false} if it was hidden
|
||||||
*/
|
*/
|
||||||
_sharedDocumentToggled (sharedDocumentVisible) {
|
_sharedDocumentToggled(sharedDocumentVisible) {
|
||||||
this._local.sharedDocumentVisible = sharedDocumentVisible;
|
this._local.sharedDocumentVisible = sharedDocumentVisible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,13 +268,16 @@ class FollowMe {
|
||||||
* unpinned
|
* unpinned
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_nextOnStage (videoId, isPinned) {
|
_nextOnStage(videoId, isPinned) {
|
||||||
if (!this._conference.isModerator)
|
if (!this._conference.isModerator) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var nextOnStage = null;
|
let nextOnStage = null;
|
||||||
if(isPinned)
|
|
||||||
|
if (isPinned) {
|
||||||
nextOnStage = videoId;
|
nextOnStage = videoId;
|
||||||
|
}
|
||||||
|
|
||||||
this._local.nextOnStage = nextOnStage;
|
this._local.nextOnStage = nextOnStage;
|
||||||
}
|
}
|
||||||
|
@ -251,24 +285,25 @@ class FollowMe {
|
||||||
/**
|
/**
|
||||||
* Sends the follow-me command, when a local property change occurs.
|
* Sends the follow-me command, when a local property change occurs.
|
||||||
*
|
*
|
||||||
* @param property the property name
|
|
||||||
* @param oldValue the old value
|
|
||||||
* @param newValue the new value
|
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
_localPropertyChange() { // eslint-disable-next-line no-unused-vars
|
||||||
_localPropertyChange (property, oldValue, newValue) {
|
|
||||||
// Only a moderator is allowed to send commands.
|
// Only a moderator is allowed to send commands.
|
||||||
const conference = this._conference;
|
const conference = this._conference;
|
||||||
if (!conference.isModerator)
|
|
||||||
|
if (!conference.isModerator) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const commands = conference.commands;
|
const commands = conference.commands;
|
||||||
|
|
||||||
// XXX The "Follow Me" command represents a snapshot of all states
|
// XXX The "Follow Me" command represents a snapshot of all states
|
||||||
// which are to be followed so don't forget to removeCommand before
|
// which are to be followed so don't forget to removeCommand before
|
||||||
// sendCommand!
|
// sendCommand!
|
||||||
|
|
||||||
commands.removeCommand(_COMMAND);
|
commands.removeCommand(_COMMAND);
|
||||||
const local = this._local;
|
const local = this._local;
|
||||||
|
|
||||||
commands.sendCommandOnce(
|
commands.sendCommandOnce(
|
||||||
_COMMAND,
|
_COMMAND,
|
||||||
{
|
{
|
||||||
|
@ -289,22 +324,24 @@ class FollowMe {
|
||||||
* notable idiosyncrasy of the Command(s) API to be mindful of here is that
|
* notable idiosyncrasy of the Command(s) API to be mindful of here is that
|
||||||
* the command may be issued by the local participant.
|
* the command may be issued by the local participant.
|
||||||
*/
|
*/
|
||||||
_onFollowMeCommand ({ attributes }, id) {
|
_onFollowMeCommand({ attributes }, id) {
|
||||||
// We require to know who issued the command because (1) only a
|
// We require to know who issued the command because (1) only a
|
||||||
// moderator is allowed to send commands and (2) a command MUST be
|
// moderator is allowed to send commands and (2) a command MUST be
|
||||||
// issued by a defined commander.
|
// issued by a defined commander.
|
||||||
if (typeof id === 'undefined')
|
if (typeof id === 'undefined') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// The Command(s) API will send us our own commands and we don't want
|
// The Command(s) API will send us our own commands and we don't want
|
||||||
// to act upon them.
|
// to act upon them.
|
||||||
if (this._conference.isLocalId(id))
|
if (this._conference.isLocalId(id)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this._conference.isParticipantModerator(id)) {
|
||||||
|
logger.warn('Received follow-me command '
|
||||||
|
+ 'not from moderator');
|
||||||
|
|
||||||
if (!this._conference.isParticipantModerator(id))
|
|
||||||
{
|
|
||||||
logger.warn('Received follow-me command ' +
|
|
||||||
'not from moderator');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -328,14 +365,16 @@ class FollowMe {
|
||||||
// attributes, at least) at the time of this writing so take into
|
// attributes, at least) at the time of this writing so take into
|
||||||
// account that what originated as a Boolean may be a String on
|
// account that what originated as a Boolean may be a String on
|
||||||
// receipt.
|
// receipt.
|
||||||
filmstripVisible = (filmstripVisible == 'true');
|
// eslint-disable-next-line eqeqeq, no-param-reassign
|
||||||
|
filmstripVisible = filmstripVisible == 'true';
|
||||||
|
|
||||||
// FIXME The UI (module) very likely doesn't (want to) expose its
|
// FIXME The UI (module) very likely doesn't (want to) expose its
|
||||||
// eventEmitter as a public field. I'm not sure at the time of this
|
// eventEmitter as a public field. I'm not sure at the time of this
|
||||||
// writing whether calling UI.toggleFilmstrip() is acceptable (from
|
// writing whether calling UI.toggleFilmstrip() is acceptable (from
|
||||||
// a design standpoint) either.
|
// a design standpoint) either.
|
||||||
if (filmstripVisible !== this._UI.isFilmstripVisible())
|
if (filmstripVisible !== this._UI.isFilmstripVisible()) {
|
||||||
this._UI.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
this._UI.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,22 +386,24 @@ class FollowMe {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_onNextOnStage(id) {
|
_onNextOnStage(id) {
|
||||||
var clickId = null;
|
let clickId = null;
|
||||||
var pin;
|
let pin;
|
||||||
|
|
||||||
// if there is an id which is not pinned we schedule it for pin only the
|
// if there is an id which is not pinned we schedule it for pin only the
|
||||||
// first time
|
// first time
|
||||||
if(typeof id !== 'undefined' && !VideoLayout.isPinned(id)) {
|
|
||||||
|
if (typeof id !== 'undefined' && !VideoLayout.isPinned(id)) {
|
||||||
clickId = id;
|
clickId = id;
|
||||||
pin = true;
|
pin = true;
|
||||||
}
|
} else if (typeof id === 'undefined' && VideoLayout.getPinnedId()) {
|
||||||
// if there is no id, but we have a pinned one, let's unpin
|
// if there is no id, but we have a pinned one, let's unpin
|
||||||
else if (typeof id == 'undefined' && VideoLayout.getPinnedId()) {
|
|
||||||
clickId = VideoLayout.getPinnedId();
|
clickId = VideoLayout.getPinnedId();
|
||||||
pin = false;
|
pin = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clickId)
|
if (clickId) {
|
||||||
this._pinVideoThumbnailById(clickId, pin);
|
this._pinVideoThumbnailById(clickId, pin);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -378,11 +419,13 @@ class FollowMe {
|
||||||
// attributes, at least) at the time of this writing so take into
|
// attributes, at least) at the time of this writing so take into
|
||||||
// account that what originated as a Boolean may be a String on
|
// account that what originated as a Boolean may be a String on
|
||||||
// receipt.
|
// receipt.
|
||||||
sharedDocumentVisible = (sharedDocumentVisible == 'true');
|
// eslint-disable-next-line eqeqeq, no-param-reassign
|
||||||
|
sharedDocumentVisible = sharedDocumentVisible == 'true';
|
||||||
|
|
||||||
if (sharedDocumentVisible
|
if (sharedDocumentVisible
|
||||||
!== this._UI.getSharedDocumentManager().isVisible())
|
!== this._UI.getSharedDocumentManager().isVisible()) {
|
||||||
this._UI.getSharedDocumentManager().toggleEtherpad();
|
this._UI.getSharedDocumentManager().toggleEtherpad();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,27 +437,31 @@ class FollowMe {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_pinVideoThumbnailById(clickId, pin) {
|
_pinVideoThumbnailById(clickId, pin) {
|
||||||
var self = this;
|
const self = this;
|
||||||
var smallVideo = VideoLayout.getSmallVideo(clickId);
|
const smallVideo = VideoLayout.getSmallVideo(clickId);
|
||||||
|
|
||||||
// If the SmallVideo for the given clickId exists we proceed with the
|
// If the SmallVideo for the given clickId exists we proceed with the
|
||||||
// pin/unpin.
|
// pin/unpin.
|
||||||
if (smallVideo) {
|
if (smallVideo) {
|
||||||
this.nextOnStageTimer = 0;
|
this.nextOnStageTimer = 0;
|
||||||
clearTimeout(this.nextOnStageTimout);
|
clearTimeout(this.nextOnStageTimout);
|
||||||
|
/* eslint-disable no-mixed-operators */
|
||||||
if (pin && !VideoLayout.isPinned(clickId)
|
if (pin && !VideoLayout.isPinned(clickId)
|
||||||
|| !pin && VideoLayout.isPinned(clickId))
|
|| !pin && VideoLayout.isPinned(clickId)) {
|
||||||
|
/* eslint-disable no-mixed-operators */
|
||||||
VideoLayout.handleVideoThumbClicked(clickId);
|
VideoLayout.handleVideoThumbClicked(clickId);
|
||||||
}
|
}
|
||||||
// If there's no SmallVideo object for the given id, lets wait and see
|
} else {
|
||||||
// if it's going to be created in the next 30sec.
|
// If there's no SmallVideo object for the given id, lets wait and
|
||||||
else {
|
// see if it's going to be created in the next 30sec.
|
||||||
this.nextOnStageTimout = setTimeout(function () {
|
this.nextOnStageTimout = setTimeout(function() {
|
||||||
if (self.nextOnStageTimer > _FOLLOW_ME_RECEIVED_TIMEOUT) {
|
if (self.nextOnStageTimer > _FOLLOW_ME_RECEIVED_TIMEOUT) {
|
||||||
self.nextOnStageTimer = 0;
|
self.nextOnStageTimer = 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-invalid-this
|
||||||
this.nextOnStageTimer++;
|
this.nextOnStageTimer++;
|
||||||
self._pinVideoThumbnailById(clickId, pin);
|
self._pinVideoThumbnailById(clickId, pin);
|
||||||
}, 1000);
|
}, 1000);
|
||||||
|
|
433
modules/UI/UI.js
433
modules/UI/UI.js
|
@ -1,24 +1,24 @@
|
||||||
/* global APP, $, config, interfaceConfig */
|
/* global APP, $, config, interfaceConfig */
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
var UI = {};
|
const UI = {};
|
||||||
|
|
||||||
import Chat from "./side_pannels/chat/Chat";
|
import Chat from './side_pannels/chat/Chat';
|
||||||
import SidePanels from "./side_pannels/SidePanels";
|
import SidePanels from './side_pannels/SidePanels';
|
||||||
import Avatar from "./avatar/Avatar";
|
import Avatar from './avatar/Avatar';
|
||||||
import SideContainerToggler from "./side_pannels/SideContainerToggler";
|
import SideContainerToggler from './side_pannels/SideContainerToggler';
|
||||||
import messageHandler from "./util/MessageHandler";
|
import messageHandler from './util/MessageHandler';
|
||||||
import UIUtil from "./util/UIUtil";
|
import UIUtil from './util/UIUtil';
|
||||||
import UIEvents from "../../service/UI/UIEvents";
|
import UIEvents from '../../service/UI/UIEvents';
|
||||||
import EtherpadManager from './etherpad/Etherpad';
|
import EtherpadManager from './etherpad/Etherpad';
|
||||||
import SharedVideoManager from './shared_video/SharedVideo';
|
import SharedVideoManager from './shared_video/SharedVideo';
|
||||||
import Recording from "./recording/Recording";
|
import Recording from './recording/Recording';
|
||||||
|
|
||||||
import VideoLayout from "./videolayout/VideoLayout";
|
import VideoLayout from './videolayout/VideoLayout';
|
||||||
import Filmstrip from "./videolayout/Filmstrip";
|
import Filmstrip from './videolayout/Filmstrip';
|
||||||
import SettingsMenu from "./side_pannels/settings/SettingsMenu";
|
import SettingsMenu from './side_pannels/settings/SettingsMenu';
|
||||||
import Profile from "./side_pannels/profile/Profile";
|
import Profile from './side_pannels/profile/Profile';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
openDeviceSelectionDialog
|
openDeviceSelectionDialog
|
||||||
|
@ -43,11 +43,13 @@ import {
|
||||||
showToolbox
|
showToolbox
|
||||||
} from '../../react/features/toolbox';
|
} from '../../react/features/toolbox';
|
||||||
|
|
||||||
var EventEmitter = require("events");
|
const EventEmitter = require('events');
|
||||||
UI.messageHandler = messageHandler;
|
|
||||||
import FollowMe from "../FollowMe";
|
UI.messageHandler = messageHandler;
|
||||||
|
import FollowMe from '../FollowMe';
|
||||||
|
|
||||||
|
const eventEmitter = new EventEmitter();
|
||||||
|
|
||||||
var eventEmitter = new EventEmitter();
|
|
||||||
UI.eventEmitter = eventEmitter;
|
UI.eventEmitter = eventEmitter;
|
||||||
|
|
||||||
let etherpadManager;
|
let etherpadManager;
|
||||||
|
@ -62,38 +64,82 @@ const JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP = {
|
||||||
|
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.camera[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
|
.camera[JitsiTrackErrors.UNSUPPORTED_RESOLUTION]
|
||||||
= "dialog.cameraUnsupportedResolutionError";
|
= 'dialog.cameraUnsupportedResolutionError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.GENERAL]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.GENERAL]
|
||||||
= "dialog.cameraUnknownError";
|
= 'dialog.cameraUnknownError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.PERMISSION_DENIED]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.PERMISSION_DENIED]
|
||||||
= "dialog.cameraPermissionDeniedError";
|
= 'dialog.cameraPermissionDeniedError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.NOT_FOUND]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.NOT_FOUND]
|
||||||
= "dialog.cameraNotFoundError";
|
= 'dialog.cameraNotFoundError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.CONSTRAINT_FAILED]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[JitsiTrackErrors.CONSTRAINT_FAILED]
|
||||||
= "dialog.cameraConstraintFailedError";
|
= 'dialog.cameraConstraintFailedError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.camera[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
.camera[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
||||||
= "dialog.cameraNotSendingData";
|
= 'dialog.cameraNotSendingData';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.GENERAL]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.GENERAL]
|
||||||
= "dialog.micUnknownError";
|
= 'dialog.micUnknownError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.microphone[JitsiTrackErrors.PERMISSION_DENIED]
|
.microphone[JitsiTrackErrors.PERMISSION_DENIED]
|
||||||
= "dialog.micPermissionDeniedError";
|
= 'dialog.micPermissionDeniedError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.NOT_FOUND]
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.microphone[JitsiTrackErrors.NOT_FOUND]
|
||||||
= "dialog.micNotFoundError";
|
= 'dialog.micNotFoundError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.microphone[JitsiTrackErrors.CONSTRAINT_FAILED]
|
.microphone[JitsiTrackErrors.CONSTRAINT_FAILED]
|
||||||
= "dialog.micConstraintFailedError";
|
= 'dialog.micConstraintFailedError';
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.microphone[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
.microphone[JitsiTrackErrors.NO_DATA_FROM_SOURCE]
|
||||||
= "dialog.micNotSendingData";
|
= 'dialog.micNotSendingData';
|
||||||
|
|
||||||
|
const UIListeners = new Map([
|
||||||
|
[
|
||||||
|
UIEvents.ETHERPAD_CLICKED,
|
||||||
|
() => etherpadManager && etherpadManager.toggleEtherpad()
|
||||||
|
], [
|
||||||
|
UIEvents.SHARED_VIDEO_CLICKED,
|
||||||
|
() => sharedVideoManager && sharedVideoManager.toggleSharedVideo()
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_FULLSCREEN,
|
||||||
|
() => UI.toggleFullScreen()
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_CHAT,
|
||||||
|
() => UI.toggleChat()
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_SETTINGS,
|
||||||
|
() => {
|
||||||
|
// Opening of device selection is special-cased as it is a dialog
|
||||||
|
// opened through a button in settings and not directly displayed in
|
||||||
|
// settings itself. As it is not useful to only have a settings menu
|
||||||
|
// with a button to open a dialog, open the dialog directly instead.
|
||||||
|
if (interfaceConfig.SETTINGS_SECTIONS.length === 1
|
||||||
|
&& UIUtil.isSettingEnabled('devices')) {
|
||||||
|
APP.store.dispatch(openDeviceSelectionDialog());
|
||||||
|
} else {
|
||||||
|
UI.toggleSidePanel('settings_container');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_CONTACT_LIST,
|
||||||
|
() => UI.toggleContactList()
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_PROFILE,
|
||||||
|
() => {
|
||||||
|
UI.toggleSidePanel('profile_container');
|
||||||
|
}
|
||||||
|
], [
|
||||||
|
UIEvents.TOGGLE_FILMSTRIP,
|
||||||
|
() => UI.handleToggleFilmstrip()
|
||||||
|
], [
|
||||||
|
UIEvents.FOLLOW_ME_ENABLED,
|
||||||
|
enabled => followMeHandler && followMeHandler.enableFollowMe(enabled)
|
||||||
|
]
|
||||||
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the application in and out of full screen mode
|
* Toggles the application in and out of full screen mode
|
||||||
* (a.k.a. presentation mode in Chrome).
|
* (a.k.a. presentation mode in Chrome).
|
||||||
*/
|
*/
|
||||||
UI.toggleFullScreen = function() {
|
UI.toggleFullScreen = function() {
|
||||||
(UIUtil.isFullScreen())
|
UIUtil.isFullScreen()
|
||||||
? UIUtil.exitFullScreen()
|
? UIUtil.exitFullScreen()
|
||||||
: UIUtil.enterFullScreen();
|
: UIUtil.enterFullScreen();
|
||||||
};
|
};
|
||||||
|
@ -101,7 +147,7 @@ UI.toggleFullScreen = function() {
|
||||||
/**
|
/**
|
||||||
* Notify user that server has shut down.
|
* Notify user that server has shut down.
|
||||||
*/
|
*/
|
||||||
UI.notifyGracefulShutdown = function () {
|
UI.notifyGracefulShutdown = function() {
|
||||||
messageHandler.openMessageDialog(
|
messageHandler.openMessageDialog(
|
||||||
'dialog.serviceUnavailable',
|
'dialog.serviceUnavailable',
|
||||||
'dialog.gracefulShutdown'
|
'dialog.gracefulShutdown'
|
||||||
|
@ -111,31 +157,33 @@ UI.notifyGracefulShutdown = function () {
|
||||||
/**
|
/**
|
||||||
* Notify user that reservation error happened.
|
* Notify user that reservation error happened.
|
||||||
*/
|
*/
|
||||||
UI.notifyReservationError = function (code, msg) {
|
UI.notifyReservationError = function(code, msg) {
|
||||||
var message = APP.translation.generateTranslationHTML(
|
const message = APP.translation.generateTranslationHTML(
|
||||||
"dialog.reservationErrorMsg", {code: code, msg: msg});
|
'dialog.reservationErrorMsg', { code,
|
||||||
|
msg });
|
||||||
|
|
||||||
messageHandler.openDialog(
|
messageHandler.openDialog(
|
||||||
"dialog.reservationError", message, true, {}, () => false);
|
'dialog.reservationError', message, true, {}, () => false);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify user that he has been kicked from the server.
|
* Notify user that he has been kicked from the server.
|
||||||
*/
|
*/
|
||||||
UI.notifyKicked = function () {
|
UI.notifyKicked = function() {
|
||||||
messageHandler.openMessageDialog(
|
messageHandler.openMessageDialog(
|
||||||
"dialog.sessTerminated",
|
'dialog.sessTerminated',
|
||||||
"dialog.kickMessage");
|
'dialog.kickMessage');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify user that conference was destroyed.
|
* Notify user that conference was destroyed.
|
||||||
* @param reason {string} the reason text
|
* @param reason {string} the reason text
|
||||||
*/
|
*/
|
||||||
UI.notifyConferenceDestroyed = function (reason) {
|
UI.notifyConferenceDestroyed = function(reason) {
|
||||||
//FIXME: use Session Terminated from translation, but
|
// FIXME: use Session Terminated from translation, but
|
||||||
// 'reason' text comes from XMPP packet and is not translated
|
// 'reason' text comes from XMPP packet and is not translated
|
||||||
messageHandler.openDialog(
|
messageHandler.openDialog(
|
||||||
"dialog.sessTerminated", reason, true, {}, () => false);
|
'dialog.sessTerminated', reason, true, {}, () => false);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,7 +191,7 @@ UI.notifyConferenceDestroyed = function (reason) {
|
||||||
* @param err the Error
|
* @param err the Error
|
||||||
* @param msg
|
* @param msg
|
||||||
*/
|
*/
|
||||||
UI.showChatError = function (err, msg) {
|
UI.showChatError = function(err, msg) {
|
||||||
if (interfaceConfig.filmStripOnly) {
|
if (interfaceConfig.filmStripOnly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -155,12 +203,12 @@ UI.showChatError = function (err, msg) {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
* @param {string} displayName new nickname
|
* @param {string} displayName new nickname
|
||||||
*/
|
*/
|
||||||
UI.changeDisplayName = function (id, displayName) {
|
UI.changeDisplayName = function(id, displayName) {
|
||||||
VideoLayout.onDisplayNameChanged(id, displayName);
|
VideoLayout.onDisplayNameChanged(id, displayName);
|
||||||
|
|
||||||
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
|
if (APP.conference.isLocalId(id) || id === 'localVideoContainer') {
|
||||||
Profile.changeDisplayName(displayName);
|
Profile.changeDisplayName(displayName);
|
||||||
Chat.setChatConversationMode(!!displayName);
|
Chat.setChatConversationMode(Boolean(displayName));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -171,7 +219,7 @@ UI.changeDisplayName = function (id, displayName) {
|
||||||
* currently in the interrupted state or <tt>false</tt> if the connection
|
* currently in the interrupted state or <tt>false</tt> if the connection
|
||||||
* is fine.
|
* is fine.
|
||||||
*/
|
*/
|
||||||
UI.showLocalConnectionInterrupted = function (isInterrupted) {
|
UI.showLocalConnectionInterrupted = function(isInterrupted) {
|
||||||
VideoLayout.showLocalConnectionInterrupted(isInterrupted);
|
VideoLayout.showLocalConnectionInterrupted(isInterrupted);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -198,7 +246,7 @@ UI.setLocalRaisedHandStatus
|
||||||
/**
|
/**
|
||||||
* Initialize conference UI.
|
* Initialize conference UI.
|
||||||
*/
|
*/
|
||||||
UI.initConference = function () {
|
UI.initConference = function() {
|
||||||
const { dispatch, getState } = APP.store;
|
const { dispatch, getState } = APP.store;
|
||||||
const { avatarID, email, id, name } = getLocalParticipant(getState);
|
const { avatarID, email, id, name } = getLocalParticipant(getState);
|
||||||
|
|
||||||
|
@ -208,7 +256,7 @@ UI.initConference = function () {
|
||||||
|
|
||||||
UI.showToolbar();
|
UI.showToolbar();
|
||||||
|
|
||||||
let displayName = config.displayJids ? id : name;
|
const displayName = config.displayJids ? id : name;
|
||||||
|
|
||||||
if (displayName) {
|
if (displayName) {
|
||||||
UI.changeDisplayName('localVideoContainer', displayName);
|
UI.changeDisplayName('localVideoContainer', displayName);
|
||||||
|
@ -230,7 +278,7 @@ UI.initConference = function () {
|
||||||
followMeHandler = new FollowMe(APP.conference, UI);
|
followMeHandler = new FollowMe(APP.conference, UI);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.mucJoined = function () {
|
UI.mucJoined = function() {
|
||||||
VideoLayout.mucJoined();
|
VideoLayout.mucJoined();
|
||||||
|
|
||||||
// Update local video now that a conference is joined a user ID should be
|
// Update local video now that a conference is joined a user ID should be
|
||||||
|
@ -240,7 +288,7 @@ UI.mucJoined = function () {
|
||||||
APP.conference.getLocalDisplayName());
|
APP.conference.getLocalDisplayName());
|
||||||
};
|
};
|
||||||
|
|
||||||
/***
|
/** *
|
||||||
* Handler for toggling filmstrip
|
* Handler for toggling filmstrip
|
||||||
*/
|
*/
|
||||||
UI.handleToggleFilmstrip = () => UI.toggleFilmstrip();
|
UI.handleToggleFilmstrip = () => UI.toggleFilmstrip();
|
||||||
|
@ -249,7 +297,7 @@ UI.handleToggleFilmstrip = () => UI.toggleFilmstrip();
|
||||||
* Returns the shared document manager object.
|
* Returns the shared document manager object.
|
||||||
* @return {EtherpadManager} the shared document manager object
|
* @return {EtherpadManager} the shared document manager object
|
||||||
*/
|
*/
|
||||||
UI.getSharedVideoManager = function () {
|
UI.getSharedVideoManager = function() {
|
||||||
return sharedVideoManager;
|
return sharedVideoManager;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -259,11 +307,11 @@ UI.getSharedVideoManager = function () {
|
||||||
* @returns {boolean} true if the UI is ready and the conference should be
|
* @returns {boolean} true if the UI is ready and the conference should be
|
||||||
* established, false - otherwise (for example in the case of welcome page)
|
* established, false - otherwise (for example in the case of welcome page)
|
||||||
*/
|
*/
|
||||||
UI.start = function () {
|
UI.start = function() {
|
||||||
document.title = interfaceConfig.APP_NAME;
|
document.title = interfaceConfig.APP_NAME;
|
||||||
|
|
||||||
// Set the defaults for prompt dialogs.
|
// Set the defaults for prompt dialogs.
|
||||||
$.prompt.setDefaults({persistent: false});
|
$.prompt.setDefaults({ persistent: false });
|
||||||
|
|
||||||
|
|
||||||
SideContainerToggler.init(eventEmitter);
|
SideContainerToggler.init(eventEmitter);
|
||||||
|
@ -276,22 +324,24 @@ UI.start = function () {
|
||||||
VideoLayout.resizeVideoArea(true, true);
|
VideoLayout.resizeVideoArea(true, true);
|
||||||
|
|
||||||
sharedVideoManager = new SharedVideoManager(eventEmitter);
|
sharedVideoManager = new SharedVideoManager(eventEmitter);
|
||||||
|
// eslint-disable-next-line no-negated-condition
|
||||||
if (!interfaceConfig.filmStripOnly) {
|
if (!interfaceConfig.filmStripOnly) {
|
||||||
// Initialise the recording module.
|
// Initialise the recording module.
|
||||||
if (config.enableRecording) {
|
if (config.enableRecording) {
|
||||||
Recording.init(eventEmitter, config.recordingType);
|
Recording.init(eventEmitter, config.recordingType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize side panels
|
// Initialize side panels
|
||||||
SidePanels.init(eventEmitter);
|
SidePanels.init(eventEmitter);
|
||||||
} else {
|
} else {
|
||||||
$("body").addClass("filmstrip-only");
|
$('body').addClass('filmstrip-only');
|
||||||
UI.showToolbar();
|
UI.showToolbar();
|
||||||
Filmstrip.setFilmstripOnly();
|
Filmstrip.setFilmstripOnly();
|
||||||
APP.store.dispatch(setNotificationsEnabled(false));
|
APP.store.dispatch(setNotificationsEnabled(false));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
||||||
$("body").addClass("vertical-filmstrip");
|
$('body').addClass('vertical-filmstrip');
|
||||||
}
|
}
|
||||||
|
|
||||||
document.title = interfaceConfig.APP_NAME;
|
document.title = interfaceConfig.APP_NAME;
|
||||||
|
@ -322,6 +372,9 @@ UI.unregisterListeners
|
||||||
* Setup some DOM event listeners.
|
* Setup some DOM event listeners.
|
||||||
*/
|
*/
|
||||||
UI.bindEvents = () => {
|
UI.bindEvents = () => {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function onResize() {
|
function onResize() {
|
||||||
SideContainerToggler.resize();
|
SideContainerToggler.resize();
|
||||||
VideoLayout.resizeVideoArea();
|
VideoLayout.resizeVideoArea();
|
||||||
|
@ -364,7 +417,7 @@ UI.addLocalStream = track => {
|
||||||
VideoLayout.changeLocalVideo(track);
|
VideoLayout.changeLocalVideo(track);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
logger.error("Unknown stream type: " + track.getType());
|
logger.error(`Unknown stream type: ${track.getType()}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -413,17 +466,18 @@ UI.getSharedDocumentManager = () => etherpadManager;
|
||||||
* Show user on UI.
|
* Show user on UI.
|
||||||
* @param {JitsiParticipant} user
|
* @param {JitsiParticipant} user
|
||||||
*/
|
*/
|
||||||
UI.addUser = function (user) {
|
UI.addUser = function(user) {
|
||||||
var id = user.getId();
|
const id = user.getId();
|
||||||
var displayName = user.getDisplayName();
|
const displayName = user.getDisplayName();
|
||||||
|
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
displayName,'notify.somebody', 'connected', 'notify.connected'
|
displayName, 'notify.somebody', 'connected', 'notify.connected'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!config.startAudioMuted ||
|
if (!config.startAudioMuted
|
||||||
config.startAudioMuted > APP.conference.membersCount)
|
|| config.startAudioMuted > APP.conference.membersCount) {
|
||||||
UIUtil.playSoundNotification('userJoined');
|
UIUtil.playSoundNotification('userJoined');
|
||||||
|
}
|
||||||
|
|
||||||
// Add Peer's container
|
// Add Peer's container
|
||||||
VideoLayout.addParticipantContainer(user);
|
VideoLayout.addParticipantContainer(user);
|
||||||
|
@ -432,8 +486,9 @@ UI.addUser = function (user) {
|
||||||
UI.setUserEmail(id);
|
UI.setUserEmail(id);
|
||||||
|
|
||||||
// set initial display name
|
// set initial display name
|
||||||
if(displayName)
|
if (displayName) {
|
||||||
UI.changeDisplayName(id, displayName);
|
UI.changeDisplayName(id, displayName);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -441,9 +496,9 @@ UI.addUser = function (user) {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
* @param {string} displayName user nickname
|
* @param {string} displayName user nickname
|
||||||
*/
|
*/
|
||||||
UI.removeUser = function (id, displayName) {
|
UI.removeUser = function(id, displayName) {
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
displayName,'notify.somebody', 'disconnected', 'notify.disconnected'
|
displayName, 'notify.somebody', 'disconnected', 'notify.disconnected'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!config.startAudioMuted
|
if (!config.startAudioMuted
|
||||||
|
@ -476,9 +531,10 @@ UI.updateLocalRole = isModerator => {
|
||||||
SettingsMenu.showFollowMeOptions(isModerator);
|
SettingsMenu.showFollowMeOptions(isModerator);
|
||||||
|
|
||||||
if (isModerator) {
|
if (isModerator) {
|
||||||
if (!interfaceConfig.DISABLE_FOCUS_INDICATOR)
|
if (!interfaceConfig.DISABLE_FOCUS_INDICATOR) {
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
null, "notify.me", 'connected', "notify.moderator");
|
null, 'notify.me', 'connected', 'notify.moderator');
|
||||||
|
}
|
||||||
|
|
||||||
Recording.checkAutoRecord();
|
Recording.checkAutoRecord();
|
||||||
}
|
}
|
||||||
|
@ -498,7 +554,8 @@ UI.updateUserRole = user => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var displayName = user.getDisplayName();
|
const displayName = user.getDisplayName();
|
||||||
|
|
||||||
if (displayName) {
|
if (displayName) {
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
displayName, 'notify.somebody',
|
displayName, 'notify.somebody',
|
||||||
|
@ -524,9 +581,10 @@ UI.updateUserStatus = (user, status) => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let displayName = user.getDisplayName();
|
const displayName = user.getDisplayName();
|
||||||
|
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
displayName, '', 'connected', "dialOut.statusMessage",
|
displayName, '', 'connected', 'dialOut.statusMessage',
|
||||||
{
|
{
|
||||||
status: UIUtil.escapeHtml(status)
|
status: UIUtil.escapeHtml(status)
|
||||||
});
|
});
|
||||||
|
@ -540,9 +598,9 @@ UI.toggleSmileys = () => Chat.toggleSmileys();
|
||||||
/**
|
/**
|
||||||
* Toggles filmstrip.
|
* Toggles filmstrip.
|
||||||
*/
|
*/
|
||||||
UI.toggleFilmstrip = function () {
|
UI.toggleFilmstrip = function() {
|
||||||
var self = Filmstrip;
|
// eslint-disable-next-line prefer-rest-params
|
||||||
self.toggleFilmstrip.apply(self, arguments);
|
Filmstrip.toggleFilmstrip(...arguments);
|
||||||
VideoLayout.resizeVideoArea(true, false);
|
VideoLayout.resizeVideoArea(true, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -555,12 +613,12 @@ UI.isFilmstripVisible = () => Filmstrip.isFilmstripVisible();
|
||||||
/**
|
/**
|
||||||
* Toggles chat panel.
|
* Toggles chat panel.
|
||||||
*/
|
*/
|
||||||
UI.toggleChat = () => UI.toggleSidePanel("chat_container");
|
UI.toggleChat = () => UI.toggleSidePanel('chat_container');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles contact list panel.
|
* Toggles contact list panel.
|
||||||
*/
|
*/
|
||||||
UI.toggleContactList = () => UI.toggleSidePanel("contacts_container");
|
UI.toggleContactList = () => UI.toggleSidePanel('contacts_container');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggles the given side panel.
|
* Toggles the given side panel.
|
||||||
|
@ -573,7 +631,7 @@ UI.toggleSidePanel = sidePanelId => SideContainerToggler.toggle(sidePanelId);
|
||||||
/**
|
/**
|
||||||
* Handle new user display name.
|
* Handle new user display name.
|
||||||
*/
|
*/
|
||||||
UI.inputDisplayNameHandler = function (newDisplayName) {
|
UI.inputDisplayNameHandler = function(newDisplayName) {
|
||||||
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newDisplayName);
|
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newDisplayName);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -588,7 +646,8 @@ UI.inputDisplayNameHandler = function (newDisplayName) {
|
||||||
* @param {number} timeout - The time to show the popup
|
* @param {number} timeout - The time to show the popup
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
UI.showCustomToolbarPopup = function (buttonName, popupID, show, timeout) {
|
// eslint-disable-next-line max-params
|
||||||
|
UI.showCustomToolbarPopup = function(buttonName, popupID, show, timeout) {
|
||||||
const action = show
|
const action = show
|
||||||
? setButtonPopupTimeout(buttonName, popupID, timeout)
|
? setButtonPopupTimeout(buttonName, popupID, timeout)
|
||||||
: clearButtonPopup(buttonName);
|
: clearButtonPopup(buttonName);
|
||||||
|
@ -601,7 +660,7 @@ UI.showCustomToolbarPopup = function (buttonName, popupID, show, timeout) {
|
||||||
* @param jid the jid for the remote video
|
* @param jid the jid for the remote video
|
||||||
* @returns the video type video or screen.
|
* @returns the video type video or screen.
|
||||||
*/
|
*/
|
||||||
UI.getRemoteVideoType = function (jid) {
|
UI.getRemoteVideoType = function(jid) {
|
||||||
return VideoLayout.getRemoteVideoType(jid);
|
return VideoLayout.getRemoteVideoType(jid);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -609,17 +668,19 @@ UI.getRemoteVideoType = function (jid) {
|
||||||
UI.showLoginPopup = function(callback) {
|
UI.showLoginPopup = function(callback) {
|
||||||
logger.log('password is required');
|
logger.log('password is required');
|
||||||
|
|
||||||
let message = (
|
const message
|
||||||
`<input name="username" type="text"
|
= `<input name="username" type="text"
|
||||||
placeholder="user@domain.net"
|
placeholder="user@domain.net"
|
||||||
class="input-control" autofocus>
|
class="input-control" autofocus>
|
||||||
<input name="password" type="password"
|
<input name="password" type="password"
|
||||||
data-i18n="[placeholder]dialog.userPassword"
|
data-i18n="[placeholder]dialog.userPassword"
|
||||||
class="input-control"
|
class="input-control"
|
||||||
placeholder="user password">`
|
placeholder="user password">`
|
||||||
);
|
|
||||||
|
|
||||||
let submitFunction = (e, v, m, f) => {
|
;
|
||||||
|
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
|
const submitFunction = (e, v, m, f) => {
|
||||||
if (v) {
|
if (v) {
|
||||||
if (f.username && f.password) {
|
if (f.username && f.password) {
|
||||||
callback(f.username, f.password);
|
callback(f.username, f.password);
|
||||||
|
@ -628,7 +689,7 @@ UI.showLoginPopup = function(callback) {
|
||||||
};
|
};
|
||||||
|
|
||||||
messageHandler.openTwoButtonDialog({
|
messageHandler.openTwoButtonDialog({
|
||||||
titleKey : "dialog.passwordRequired",
|
titleKey: 'dialog.passwordRequired',
|
||||||
msgString: message,
|
msgString: message,
|
||||||
leftButtonKey: 'dialog.Ok',
|
leftButtonKey: 'dialog.Ok',
|
||||||
submitFunction,
|
submitFunction,
|
||||||
|
@ -636,14 +697,15 @@ UI.showLoginPopup = function(callback) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.askForNickname = function () {
|
UI.askForNickname = function() {
|
||||||
|
// eslint-disable-next-line no-alert
|
||||||
return window.prompt('Your nickname (optional)');
|
return window.prompt('Your nickname (optional)');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets muted audio state for participant
|
* Sets muted audio state for participant
|
||||||
*/
|
*/
|
||||||
UI.setAudioMuted = function (id, muted) {
|
UI.setAudioMuted = function(id, muted) {
|
||||||
VideoLayout.onAudioMute(id, muted);
|
VideoLayout.onAudioMute(id, muted);
|
||||||
if (APP.conference.isLocalId(id)) {
|
if (APP.conference.isLocalId(id)) {
|
||||||
APP.conference.updateAudioIconEnabled();
|
APP.conference.updateAudioIconEnabled();
|
||||||
|
@ -653,7 +715,7 @@ UI.setAudioMuted = function (id, muted) {
|
||||||
/**
|
/**
|
||||||
* Sets muted video state for participant
|
* Sets muted video state for participant
|
||||||
*/
|
*/
|
||||||
UI.setVideoMuted = function (id, muted) {
|
UI.setVideoMuted = function(id, muted) {
|
||||||
VideoLayout.onVideoMute(id, muted);
|
VideoLayout.onVideoMute(id, muted);
|
||||||
if (APP.conference.isLocalId(id)) {
|
if (APP.conference.isLocalId(id)) {
|
||||||
APP.conference.updateVideoIconEnabled();
|
APP.conference.updateVideoIconEnabled();
|
||||||
|
@ -674,7 +736,7 @@ UI.updateAllVideos = () => VideoLayout.updateAllVideos();
|
||||||
* @param type the type of the event we're listening for
|
* @param type the type of the event we're listening for
|
||||||
* @param listener a function that would be called when notified
|
* @param listener a function that would be called when notified
|
||||||
*/
|
*/
|
||||||
UI.addListener = function (type, listener) {
|
UI.addListener = function(type, listener) {
|
||||||
eventEmitter.on(type, listener);
|
eventEmitter.on(type, listener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -684,7 +746,7 @@ UI.addListener = function (type, listener) {
|
||||||
* @param type the type of the event we're listening for
|
* @param type the type of the event we're listening for
|
||||||
* @param listener the listener we want to remove
|
* @param listener the listener we want to remove
|
||||||
*/
|
*/
|
||||||
UI.removeListener = function (type, listener) {
|
UI.removeListener = function(type, listener) {
|
||||||
eventEmitter.removeListener(type, listener);
|
eventEmitter.removeListener(type, listener);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -696,14 +758,15 @@ UI.removeListener = function (type, listener) {
|
||||||
*/
|
*/
|
||||||
UI.emitEvent = (type, ...options) => eventEmitter.emit(type, ...options);
|
UI.emitEvent = (type, ...options) => eventEmitter.emit(type, ...options);
|
||||||
|
|
||||||
UI.clickOnVideo = function (videoNumber) {
|
UI.clickOnVideo = function(videoNumber) {
|
||||||
let videos = $("#remoteVideos .videocontainer:not(#mixedstream)");
|
const videos = $('#remoteVideos .videocontainer:not(#mixedstream)');
|
||||||
let videosLength = videos.length;
|
const videosLength = videos.length;
|
||||||
|
|
||||||
if(videosLength <= videoNumber) {
|
if (videosLength <= videoNumber) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let videoIndex = videoNumber === 0 ? 0 : videosLength - videoNumber;
|
const videoIndex = videoNumber === 0 ? 0 : videosLength - videoNumber;
|
||||||
|
|
||||||
videos[videoIndex].click();
|
videos[videoIndex].click();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -730,7 +793,7 @@ function changeAvatar(id, avatarUrl) {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
* @param {string} email user email
|
* @param {string} email user email
|
||||||
*/
|
*/
|
||||||
UI.setUserEmail = function (id, email) {
|
UI.setUserEmail = function(id, email) {
|
||||||
// update avatar
|
// update avatar
|
||||||
Avatar.setUserEmail(id, email);
|
Avatar.setUserEmail(id, email);
|
||||||
|
|
||||||
|
@ -745,7 +808,7 @@ UI.setUserEmail = function (id, email) {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
* @param {string} avatarId user's avatar id
|
* @param {string} avatarId user's avatar id
|
||||||
*/
|
*/
|
||||||
UI.setUserAvatarID = function (id, avatarId) {
|
UI.setUserAvatarID = function(id, avatarId) {
|
||||||
// update avatar
|
// update avatar
|
||||||
Avatar.setUserAvatarID(id, avatarId);
|
Avatar.setUserAvatarID(id, avatarId);
|
||||||
|
|
||||||
|
@ -757,7 +820,7 @@ UI.setUserAvatarID = function (id, avatarId) {
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
* @param {string} url user avatar url
|
* @param {string} url user avatar url
|
||||||
*/
|
*/
|
||||||
UI.setUserAvatarUrl = function (id, url) {
|
UI.setUserAvatarUrl = function(id, url) {
|
||||||
// update avatar
|
// update avatar
|
||||||
Avatar.setUserAvatarUrl(id, url);
|
Avatar.setUserAvatarUrl(id, url);
|
||||||
|
|
||||||
|
@ -768,39 +831,40 @@ UI.setUserAvatarUrl = function (id, url) {
|
||||||
* Notify user that connection failed.
|
* Notify user that connection failed.
|
||||||
* @param {string} stropheErrorMsg raw Strophe error message
|
* @param {string} stropheErrorMsg raw Strophe error message
|
||||||
*/
|
*/
|
||||||
UI.notifyConnectionFailed = function (stropheErrorMsg) {
|
UI.notifyConnectionFailed = function(stropheErrorMsg) {
|
||||||
var message;
|
let message;
|
||||||
|
|
||||||
if (stropheErrorMsg) {
|
if (stropheErrorMsg) {
|
||||||
message = APP.translation.generateTranslationHTML(
|
message = APP.translation.generateTranslationHTML(
|
||||||
"dialog.connectErrorWithMsg", {msg: stropheErrorMsg});
|
'dialog.connectErrorWithMsg', { msg: stropheErrorMsg });
|
||||||
} else {
|
} else {
|
||||||
message = APP.translation.generateTranslationHTML(
|
message = APP.translation.generateTranslationHTML(
|
||||||
"dialog.connectError");
|
'dialog.connectError');
|
||||||
}
|
}
|
||||||
|
|
||||||
messageHandler.openDialog("dialog.error", message, true, {}, () => false);
|
messageHandler.openDialog('dialog.error', message, true, {}, () => false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify user that maximum users limit has been reached.
|
* Notify user that maximum users limit has been reached.
|
||||||
*/
|
*/
|
||||||
UI.notifyMaxUsersLimitReached = function () {
|
UI.notifyMaxUsersLimitReached = function() {
|
||||||
var message = APP.translation.generateTranslationHTML(
|
const message = APP.translation.generateTranslationHTML(
|
||||||
"dialog.maxUsersLimitReached");
|
'dialog.maxUsersLimitReached');
|
||||||
|
|
||||||
messageHandler.openDialog("dialog.error", message, true, {}, () => false);
|
messageHandler.openDialog('dialog.error', message, true, {}, () => false);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify user that he was automatically muted when joned the conference.
|
* Notify user that he was automatically muted when joned the conference.
|
||||||
*/
|
*/
|
||||||
UI.notifyInitiallyMuted = function () {
|
UI.notifyInitiallyMuted = function() {
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
null,
|
null,
|
||||||
"notify.mutedTitle",
|
'notify.mutedTitle',
|
||||||
"connected",
|
'connected',
|
||||||
"notify.muted",
|
'notify.muted',
|
||||||
null,
|
null,
|
||||||
120000);
|
120000);
|
||||||
};
|
};
|
||||||
|
@ -809,11 +873,11 @@ UI.notifyInitiallyMuted = function () {
|
||||||
* Mark user as dominant speaker.
|
* Mark user as dominant speaker.
|
||||||
* @param {string} id user id
|
* @param {string} id user id
|
||||||
*/
|
*/
|
||||||
UI.markDominantSpeaker = function (id) {
|
UI.markDominantSpeaker = function(id) {
|
||||||
VideoLayout.onDominantSpeakerChanged(id);
|
VideoLayout.onDominantSpeakerChanged(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.handleLastNEndpoints = function (leavingIds, enteringIds) {
|
UI.handleLastNEndpoints = function(leavingIds, enteringIds) {
|
||||||
VideoLayout.onLastNEndpointsChanged(leavingIds, enteringIds);
|
VideoLayout.onLastNEndpointsChanged(leavingIds, enteringIds);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -822,7 +886,7 @@ UI.handleLastNEndpoints = function (leavingIds, enteringIds) {
|
||||||
*
|
*
|
||||||
* @param {string} id the id of remote participant(MUC jid)
|
* @param {string} id the id of remote participant(MUC jid)
|
||||||
*/
|
*/
|
||||||
UI.participantConnectionStatusChanged = function (id) {
|
UI.participantConnectionStatusChanged = function(id) {
|
||||||
VideoLayout.onParticipantConnectionStatusChanged(id);
|
VideoLayout.onParticipantConnectionStatusChanged(id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -854,7 +918,7 @@ UI.updateDesktopSharingButtons
|
||||||
/**
|
/**
|
||||||
* Hide connection quality statistics from UI.
|
* Hide connection quality statistics from UI.
|
||||||
*/
|
*/
|
||||||
UI.hideStats = function () {
|
UI.hideStats = function() {
|
||||||
VideoLayout.hideStats();
|
VideoLayout.hideStats();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -862,7 +926,7 @@ UI.hideStats = function () {
|
||||||
* Mark video as interrupted or not.
|
* Mark video as interrupted or not.
|
||||||
* @param {boolean} interrupted if video is interrupted
|
* @param {boolean} interrupted if video is interrupted
|
||||||
*/
|
*/
|
||||||
UI.markVideoInterrupted = function (interrupted) {
|
UI.markVideoInterrupted = function(interrupted) {
|
||||||
if (interrupted) {
|
if (interrupted) {
|
||||||
VideoLayout.onVideoInterrupted();
|
VideoLayout.onVideoInterrupted();
|
||||||
} else {
|
} else {
|
||||||
|
@ -877,32 +941,34 @@ UI.markVideoInterrupted = function (interrupted) {
|
||||||
* @param {string} message message text
|
* @param {string} message message text
|
||||||
* @param {number} stamp timestamp when message was created
|
* @param {number} stamp timestamp when message was created
|
||||||
*/
|
*/
|
||||||
UI.addMessage = function (from, displayName, message, stamp) {
|
// eslint-disable-next-line max-params
|
||||||
|
UI.addMessage = function(from, displayName, message, stamp) {
|
||||||
Chat.updateChatConversation(from, displayName, message, stamp);
|
Chat.updateChatConversation(from, displayName, message, stamp);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.updateDTMFSupport
|
UI.updateDTMFSupport
|
||||||
= isDTMFSupported => APP.store.dispatch(showDialPadButton(isDTMFSupported));
|
= isDTMFSupported => APP.store.dispatch(showDialPadButton(isDTMFSupported));
|
||||||
|
|
||||||
UI.updateRecordingState = function (state) {
|
UI.updateRecordingState = function(state) {
|
||||||
Recording.updateRecordingState(state);
|
Recording.updateRecordingState(state);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.notifyTokenAuthFailed = function () {
|
UI.notifyTokenAuthFailed = function() {
|
||||||
messageHandler.showError( "dialog.tokenAuthFailedTitle",
|
messageHandler.showError('dialog.tokenAuthFailedTitle',
|
||||||
"dialog.tokenAuthFailed");
|
'dialog.tokenAuthFailed');
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.notifyInternalError = function () {
|
UI.notifyInternalError = function() {
|
||||||
messageHandler.showError( "dialog.internalErrorTitle",
|
messageHandler.showError('dialog.internalErrorTitle',
|
||||||
"dialog.internalError");
|
'dialog.internalError');
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.notifyFocusDisconnected = function (focus, retrySec) {
|
UI.notifyFocusDisconnected = function(focus, retrySec) {
|
||||||
messageHandler.participantNotification(
|
messageHandler.participantNotification(
|
||||||
null, "notify.focus",
|
null, 'notify.focus',
|
||||||
'disconnected', "notify.focusFail",
|
'disconnected', 'notify.focusFail',
|
||||||
{component: focus, ms: retrySec}
|
{ component: focus,
|
||||||
|
ms: retrySec }
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -911,9 +977,9 @@ UI.notifyFocusDisconnected = function (focus, retrySec) {
|
||||||
* @param {boolean} isAuthEnabled if authentication is enabled
|
* @param {boolean} isAuthEnabled if authentication is enabled
|
||||||
* @param {string} [login] current login
|
* @param {string} [login] current login
|
||||||
*/
|
*/
|
||||||
UI.updateAuthInfo = function (isAuthEnabled, login) {
|
UI.updateAuthInfo = function(isAuthEnabled, login) {
|
||||||
let showAuth = isAuthEnabled && UIUtil.isAuthenticationEnabled();
|
const showAuth = isAuthEnabled && UIUtil.isAuthenticationEnabled();
|
||||||
let loggedIn = !!login;
|
const loggedIn = Boolean(login);
|
||||||
|
|
||||||
Profile.showAuthenticationButtons(showAuth);
|
Profile.showAuthenticationButtons(showAuth);
|
||||||
|
|
||||||
|
@ -925,7 +991,7 @@ UI.updateAuthInfo = function (isAuthEnabled, login) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.onStartMutedChanged = function (startAudioMuted, startVideoMuted) {
|
UI.onStartMutedChanged = function(startAudioMuted, startVideoMuted) {
|
||||||
SettingsMenu.updateStartMutedBox(startAudioMuted, startVideoMuted);
|
SettingsMenu.updateStartMutedBox(startAudioMuted, startVideoMuted);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -935,7 +1001,7 @@ UI.onStartMutedChanged = function (startAudioMuted, startVideoMuted) {
|
||||||
* @param {boolean} isRaisedHand indicates the current state of the
|
* @param {boolean} isRaisedHand indicates the current state of the
|
||||||
* "raised hand"
|
* "raised hand"
|
||||||
*/
|
*/
|
||||||
UI.onLocalRaiseHandChanged = function (isRaisedHand) {
|
UI.onLocalRaiseHandChanged = function(isRaisedHand) {
|
||||||
eventEmitter.emit(UIEvents.LOCAL_RAISE_HAND_CHANGED, isRaisedHand);
|
eventEmitter.emit(UIEvents.LOCAL_RAISE_HAND_CHANGED, isRaisedHand);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -943,7 +1009,7 @@ UI.onLocalRaiseHandChanged = function (isRaisedHand) {
|
||||||
* Update list of available physical devices.
|
* Update list of available physical devices.
|
||||||
* @param {object[]} devices new list of available devices
|
* @param {object[]} devices new list of available devices
|
||||||
*/
|
*/
|
||||||
UI.onAvailableDevicesChanged = function (devices) {
|
UI.onAvailableDevicesChanged = function(devices) {
|
||||||
APP.store.dispatch(updateDeviceList(devices));
|
APP.store.dispatch(updateDeviceList(devices));
|
||||||
APP.conference.updateAudioIconEnabled();
|
APP.conference.updateAudioIconEnabled();
|
||||||
APP.conference.updateVideoIconEnabled();
|
APP.conference.updateVideoIconEnabled();
|
||||||
|
@ -953,7 +1019,7 @@ UI.onAvailableDevicesChanged = function (devices) {
|
||||||
* Returns the id of the current video shown on large.
|
* Returns the id of the current video shown on large.
|
||||||
* Currently used by tests (torture).
|
* Currently used by tests (torture).
|
||||||
*/
|
*/
|
||||||
UI.getLargeVideoID = function () {
|
UI.getLargeVideoID = function() {
|
||||||
return VideoLayout.getLargeVideoID();
|
return VideoLayout.getLargeVideoID();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -961,7 +1027,7 @@ UI.getLargeVideoID = function () {
|
||||||
* Returns the current video shown on large.
|
* Returns the current video shown on large.
|
||||||
* Currently used by tests (torture).
|
* Currently used by tests (torture).
|
||||||
*/
|
*/
|
||||||
UI.getLargeVideo = function () {
|
UI.getLargeVideo = function() {
|
||||||
return VideoLayout.getLargeVideo();
|
return VideoLayout.getLargeVideo();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -977,11 +1043,11 @@ UI.isPinned = userId => VideoLayout.getPinnedId() === userId;
|
||||||
/**
|
/**
|
||||||
* Shows dialog with a link to FF extension.
|
* Shows dialog with a link to FF extension.
|
||||||
*/
|
*/
|
||||||
UI.showExtensionRequiredDialog = function (url) {
|
UI.showExtensionRequiredDialog = function(url) {
|
||||||
messageHandler.openMessageDialog(
|
messageHandler.openMessageDialog(
|
||||||
"dialog.extensionRequired",
|
'dialog.extensionRequired',
|
||||||
"[html]dialog.firefoxExtensionPrompt",
|
'[html]dialog.firefoxExtensionPrompt',
|
||||||
{url: url});
|
{ url });
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -989,25 +1055,25 @@ UI.showExtensionRequiredDialog = function (url) {
|
||||||
* 2 button dialog with buttons - cancel and go to web store.
|
* 2 button dialog with buttons - cancel and go to web store.
|
||||||
* @param url {string} the url of the extension.
|
* @param url {string} the url of the extension.
|
||||||
*/
|
*/
|
||||||
UI.showExtensionExternalInstallationDialog = function (url) {
|
UI.showExtensionExternalInstallationDialog = function(url) {
|
||||||
let openedWindow = null;
|
let openedWindow = null;
|
||||||
|
|
||||||
let submitFunction = function(e,v){
|
const submitFunction = function(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (openedWindow === null || openedWindow.closed) {
|
if (openedWindow === null || openedWindow.closed) {
|
||||||
openedWindow
|
openedWindow
|
||||||
= window.open(
|
= window.open(
|
||||||
url,
|
url,
|
||||||
"extension_store_window",
|
'extension_store_window',
|
||||||
"resizable,scrollbars=yes,status=1");
|
'resizable,scrollbars=yes,status=1');
|
||||||
} else {
|
} else {
|
||||||
openedWindow.focus();
|
openedWindow.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let closeFunction = function (e, v) {
|
const closeFunction = function(e, v) {
|
||||||
if (openedWindow) {
|
if (openedWindow) {
|
||||||
// Ideally we would close the popup, but this does not seem to work
|
// Ideally we would close the popup, but this does not seem to work
|
||||||
// on Chrome. Leaving it uncommented in case it could work
|
// on Chrome. Leaving it uncommented in case it could work
|
||||||
|
@ -1037,14 +1103,14 @@ UI.showExtensionExternalInstallationDialog = function (url) {
|
||||||
* @param callback {function} function to be executed after user clicks
|
* @param callback {function} function to be executed after user clicks
|
||||||
* the install button - it should make another attempt to install the extension.
|
* the install button - it should make another attempt to install the extension.
|
||||||
*/
|
*/
|
||||||
UI.showExtensionInlineInstallationDialog = function (callback) {
|
UI.showExtensionInlineInstallationDialog = function(callback) {
|
||||||
let submitFunction = function(e,v){
|
const submitFunction = function(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let closeFunction = function (e, v) {
|
const closeFunction = function(e, v) {
|
||||||
if (!v) {
|
if (!v) {
|
||||||
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
eventEmitter.emit(UIEvents.EXTERNAL_INSTALLATION_CANCELED);
|
||||||
}
|
}
|
||||||
|
@ -1067,7 +1133,7 @@ UI.showExtensionInlineInstallationDialog = function (callback) {
|
||||||
* acquiring an audio stream.
|
* acquiring an audio stream.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
UI.showMicErrorNotification = function (micError) {
|
UI.showMicErrorNotification = function(micError) {
|
||||||
if (!micError) {
|
if (!micError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1103,7 +1169,7 @@ UI.showMicErrorNotification = function (micError) {
|
||||||
* acquiring a video stream.
|
* acquiring a video stream.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
UI.showCameraErrorNotification = function (cameraError) {
|
UI.showCameraErrorNotification = function(cameraError) {
|
||||||
if (!cameraError) {
|
if (!cameraError) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1112,8 +1178,8 @@ UI.showCameraErrorNotification = function (cameraError) {
|
||||||
|
|
||||||
const persistenceKey = `doNotShowErrorAgain-camera-${name}`;
|
const persistenceKey = `doNotShowErrorAgain-camera-${name}`;
|
||||||
|
|
||||||
const cameraJitsiTrackErrorMsg =
|
const cameraJitsiTrackErrorMsg
|
||||||
JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
|
= JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP.camera[name];
|
||||||
const cameraErrorMsg = cameraJitsiTrackErrorMsg
|
const cameraErrorMsg = cameraJitsiTrackErrorMsg
|
||||||
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
|| JITSI_TRACK_ERROR_TO_MESSAGE_KEY_MAP
|
||||||
.camera[JitsiTrackErrors.GENERAL];
|
.camera[JitsiTrackErrors.GENERAL];
|
||||||
|
@ -1136,14 +1202,14 @@ UI.showCameraErrorNotification = function (cameraError) {
|
||||||
* Shows error dialog that informs the user that no data is received from the
|
* Shows error dialog that informs the user that no data is received from the
|
||||||
* device.
|
* device.
|
||||||
*/
|
*/
|
||||||
UI.showTrackNotWorkingDialog = function (stream) {
|
UI.showTrackNotWorkingDialog = function(stream) {
|
||||||
messageHandler.openMessageDialog(
|
messageHandler.openMessageDialog(
|
||||||
"dialog.error",
|
'dialog.error',
|
||||||
stream.isAudioTrack()? "dialog.micNotSendingData" :
|
stream.isAudioTrack() ? 'dialog.micNotSendingData'
|
||||||
"dialog.cameraNotSendingData");
|
: 'dialog.cameraNotSendingData');
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.updateDevicesAvailability = function (id, devices) {
|
UI.updateDevicesAvailability = function(id, devices) {
|
||||||
VideoLayout.setDeviceAvailabilityIcons(id, devices);
|
VideoLayout.setDeviceAvailabilityIcons(id, devices);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1153,9 +1219,10 @@ UI.updateDevicesAvailability = function (id, devices) {
|
||||||
* @param {string} url video url
|
* @param {string} url video url
|
||||||
* @param {string} attributes
|
* @param {string} attributes
|
||||||
*/
|
*/
|
||||||
UI.onSharedVideoStart = function (id, url, attributes) {
|
UI.onSharedVideoStart = function(id, url, attributes) {
|
||||||
if (sharedVideoManager)
|
if (sharedVideoManager) {
|
||||||
sharedVideoManager.onSharedVideoStart(id, url, attributes);
|
sharedVideoManager.onSharedVideoStart(id, url, attributes);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1164,9 +1231,10 @@ UI.onSharedVideoStart = function (id, url, attributes) {
|
||||||
* @param {string} url video url
|
* @param {string} url video url
|
||||||
* @param {string} attributes
|
* @param {string} attributes
|
||||||
*/
|
*/
|
||||||
UI.onSharedVideoUpdate = function (id, url, attributes) {
|
UI.onSharedVideoUpdate = function(id, url, attributes) {
|
||||||
if (sharedVideoManager)
|
if (sharedVideoManager) {
|
||||||
sharedVideoManager.onSharedVideoUpdate(id, url, attributes);
|
sharedVideoManager.onSharedVideoUpdate(id, url, attributes);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1174,9 +1242,10 @@ UI.onSharedVideoUpdate = function (id, url, attributes) {
|
||||||
* @param {string} id the id of the sender of the command
|
* @param {string} id the id of the sender of the command
|
||||||
* @param {string} attributes
|
* @param {string} attributes
|
||||||
*/
|
*/
|
||||||
UI.onSharedVideoStop = function (id, attributes) {
|
UI.onSharedVideoStop = function(id, attributes) {
|
||||||
if (sharedVideoManager)
|
if (sharedVideoManager) {
|
||||||
sharedVideoManager.onSharedVideoStop(id, attributes);
|
sharedVideoManager.onSharedVideoStop(id, attributes);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1211,50 +1280,6 @@ UI.setLocalRemoteControlActiveChanged = function() {
|
||||||
VideoLayout.setLocalRemoteControlActiveChanged();
|
VideoLayout.setLocalRemoteControlActiveChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
const UIListeners = new Map([
|
|
||||||
[
|
|
||||||
UIEvents.ETHERPAD_CLICKED,
|
|
||||||
() => etherpadManager && etherpadManager.toggleEtherpad()
|
|
||||||
], [
|
|
||||||
UIEvents.SHARED_VIDEO_CLICKED,
|
|
||||||
() => sharedVideoManager && sharedVideoManager.toggleSharedVideo()
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_FULLSCREEN,
|
|
||||||
UI.toggleFullScreen
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_CHAT,
|
|
||||||
UI.toggleChat
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_SETTINGS,
|
|
||||||
() => {
|
|
||||||
// Opening of device selection is special-cased as it is a dialog
|
|
||||||
// opened through a button in settings and not directly displayed in
|
|
||||||
// settings itself. As it is not useful to only have a settings menu
|
|
||||||
// with a button to open a dialog, open the dialog directly instead.
|
|
||||||
if (interfaceConfig.SETTINGS_SECTIONS.length === 1
|
|
||||||
&& UIUtil.isSettingEnabled('devices')) {
|
|
||||||
APP.store.dispatch(openDeviceSelectionDialog());
|
|
||||||
} else {
|
|
||||||
UI.toggleSidePanel("settings_container");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_CONTACT_LIST,
|
|
||||||
UI.toggleContactList
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_PROFILE,
|
|
||||||
() => {
|
|
||||||
UI.toggleSidePanel('profile_container');
|
|
||||||
}
|
|
||||||
], [
|
|
||||||
UIEvents.TOGGLE_FILMSTRIP,
|
|
||||||
UI.handleToggleFilmstrip
|
|
||||||
], [
|
|
||||||
UIEvents.FOLLOW_ME_ENABLED,
|
|
||||||
enabled => (followMeHandler && followMeHandler.enableFollowMe(enabled))
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
// TODO: Export every function separately. For now there is no point of doing
|
// TODO: Export every function separately. For now there is no point of doing
|
||||||
// this because we are importing everything.
|
// this because we are importing everything.
|
||||||
export default UI;
|
export default UI;
|
||||||
|
|
|
@ -7,4 +7,4 @@
|
||||||
*
|
*
|
||||||
* @type {{FEEDBACK_REQUEST_IN_PROGRESS: string}}
|
* @type {{FEEDBACK_REQUEST_IN_PROGRESS: string}}
|
||||||
*/
|
*/
|
||||||
export const FEEDBACK_REQUEST_IN_PROGRESS = "FeedbackRequestInProgress";
|
export const FEEDBACK_REQUEST_IN_PROGRESS = 'FeedbackRequestInProgress';
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* global interfaceConfig */
|
/* global interfaceConfig */
|
||||||
|
|
||||||
import UIUtil from "../util/UIUtil";
|
import UIUtil from '../util/UIUtil';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Responsible for drawing audio levels.
|
* Responsible for drawing audio levels.
|
||||||
|
@ -19,29 +19,31 @@ const AudioLevels = {
|
||||||
_setDotLevel(elementID, index, opacity) {
|
_setDotLevel(elementID, index, opacity) {
|
||||||
let audioSpan
|
let audioSpan
|
||||||
= document.getElementById(elementID)
|
= document.getElementById(elementID)
|
||||||
.getElementsByClassName("audioindicator");
|
.getElementsByClassName('audioindicator');
|
||||||
|
|
||||||
// Make sure the audio span is still around.
|
// Make sure the audio span is still around.
|
||||||
if (audioSpan && audioSpan.length > 0)
|
if (audioSpan && audioSpan.length > 0) {
|
||||||
audioSpan = audioSpan[0];
|
audioSpan = audioSpan[0];
|
||||||
else
|
} else {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let audioTopDots
|
const audioTopDots
|
||||||
= audioSpan.getElementsByClassName("audiodot-top");
|
= audioSpan.getElementsByClassName('audiodot-top');
|
||||||
let audioDotMiddle
|
const audioDotMiddle
|
||||||
= audioSpan.getElementsByClassName("audiodot-middle");
|
= audioSpan.getElementsByClassName('audiodot-middle');
|
||||||
let audioBottomDots
|
const audioBottomDots
|
||||||
= audioSpan.getElementsByClassName("audiodot-bottom");
|
= audioSpan.getElementsByClassName('audiodot-bottom');
|
||||||
|
|
||||||
// First take care of the middle dot case.
|
// First take care of the middle dot case.
|
||||||
if (index === 0){
|
if (index === 0) {
|
||||||
audioDotMiddle[0].style.opacity = opacity;
|
audioDotMiddle[0].style.opacity = opacity;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Index > 0 : we are setting non-middle dots.
|
// Index > 0 : we are setting non-middle dots.
|
||||||
index--;
|
index--;// eslint-disable-line no-param-reassign
|
||||||
audioBottomDots[index].style.opacity = opacity;
|
audioBottomDots[index].style.opacity = opacity;
|
||||||
audioTopDots[this.sideDotsCount - index - 1].style.opacity = opacity;
|
audioTopDots[this.sideDotsCount - index - 1].style.opacity = opacity;
|
||||||
},
|
},
|
||||||
|
@ -52,19 +54,21 @@ const AudioLevels = {
|
||||||
* @param audioLevel the new audio level to set.
|
* @param audioLevel the new audio level to set.
|
||||||
*/
|
*/
|
||||||
updateLargeVideoAudioLevel(elementId, audioLevel) {
|
updateLargeVideoAudioLevel(elementId, audioLevel) {
|
||||||
let element = document.getElementById(elementId);
|
const element = document.getElementById(elementId);
|
||||||
|
|
||||||
if(!UIUtil.isVisible(element))
|
if (!UIUtil.isVisible(element)) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let level = parseFloat(audioLevel);
|
let level = parseFloat(audioLevel);
|
||||||
|
|
||||||
level = isNaN(level) ? 0 : level;
|
level = isNaN(level) ? 0 : level;
|
||||||
|
|
||||||
let shadowElement = element.getElementsByClassName("dynamic-shadow");
|
let shadowElement = element.getElementsByClassName('dynamic-shadow');
|
||||||
|
|
||||||
if (shadowElement && shadowElement.length > 0)
|
if (shadowElement && shadowElement.length > 0) {
|
||||||
shadowElement = shadowElement[0];
|
shadowElement = shadowElement[0];
|
||||||
|
}
|
||||||
|
|
||||||
shadowElement.style.boxShadow = this._updateLargeVideoShadow(level);
|
shadowElement.style.boxShadow = this._updateLargeVideoShadow(level);
|
||||||
},
|
},
|
||||||
|
@ -83,7 +87,7 @@ const AudioLevels = {
|
||||||
|
|
||||||
// External circle audio level.
|
// External circle audio level.
|
||||||
const ext = {
|
const ext = {
|
||||||
level: (int.level * scale * level + int.level).toFixed(0),
|
level: ((int.level * scale * level) + int.level).toFixed(0),
|
||||||
color: interfaceConfig.AUDIO_LEVEL_SECONDARY_COLOR
|
color: interfaceConfig.AUDIO_LEVEL_SECONDARY_COLOR
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -94,8 +98,8 @@ const AudioLevels = {
|
||||||
ext.blur = ext.level ? 6 : 0;
|
ext.blur = ext.level ? 6 : 0;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
`0 0 ${ int.blur }px ${ int.level }px ${ int.color }`,
|
`0 0 ${int.blur}px ${int.level}px ${int.color}`,
|
||||||
`0 0 ${ ext.blur }px ${ ext.level }px ${ ext.color }`
|
`0 0 ${ext.blur}px ${ext.level}px ${ext.color}`
|
||||||
].join(', ');
|
].join(', ');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,14 +9,14 @@ import UIUtil from '../util/UIUtil';
|
||||||
|
|
||||||
import LoginDialog from './LoginDialog';
|
import LoginDialog from './LoginDialog';
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
let externalAuthWindow;
|
let externalAuthWindow;
|
||||||
let authRequiredDialog;
|
let authRequiredDialog;
|
||||||
|
|
||||||
let isTokenAuthEnabled
|
const isTokenAuthEnabled
|
||||||
= typeof config.tokenAuthUrl === "string" && config.tokenAuthUrl.length;
|
= typeof config.tokenAuthUrl === 'string' && config.tokenAuthUrl.length;
|
||||||
let getTokenAuthUrl
|
const getTokenAuthUrl
|
||||||
= JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
|
= JitsiMeetJS.util.AuthUtil.getTokenAuthUrl.bind(null, config.tokenAuthUrl);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -26,23 +26,25 @@ let getTokenAuthUrl
|
||||||
* @param {JitsiConference} room
|
* @param {JitsiConference} room
|
||||||
* @param {string} [lockPassword] password to use if the conference is locked
|
* @param {string} [lockPassword] password to use if the conference is locked
|
||||||
*/
|
*/
|
||||||
function doExternalAuth (room, lockPassword) {
|
function doExternalAuth(room, lockPassword) {
|
||||||
if (externalAuthWindow) {
|
if (externalAuthWindow) {
|
||||||
externalAuthWindow.focus();
|
externalAuthWindow.focus();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (room.isJoined()) {
|
if (room.isJoined()) {
|
||||||
let getUrl;
|
let getUrl;
|
||||||
|
|
||||||
if (isTokenAuthEnabled) {
|
if (isTokenAuthEnabled) {
|
||||||
getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
|
getUrl = Promise.resolve(getTokenAuthUrl(room.getName(), true));
|
||||||
initJWTTokenListener(room);
|
initJWTTokenListener(room);
|
||||||
} else {
|
} else {
|
||||||
getUrl = room.getExternalAuthUrl(true);
|
getUrl = room.getExternalAuthUrl(true);
|
||||||
}
|
}
|
||||||
getUrl.then(function (url) {
|
getUrl.then(url => {
|
||||||
externalAuthWindow = LoginDialog.showExternalAuthDialog(
|
externalAuthWindow = LoginDialog.showExternalAuthDialog(
|
||||||
url,
|
url,
|
||||||
function () {
|
() => {
|
||||||
externalAuthWindow = null;
|
externalAuthWindow = null;
|
||||||
if (!isTokenAuthEnabled) {
|
if (!isTokenAuthEnabled) {
|
||||||
room.join(lockPassword);
|
room.join(lockPassword);
|
||||||
|
@ -50,14 +52,10 @@ function doExternalAuth (room, lockPassword) {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
} else if (isTokenAuthEnabled) {
|
||||||
|
redirectToTokenAuthService(room.getName());
|
||||||
} else {
|
} else {
|
||||||
// If conference has not been started yet
|
room.getExternalAuthUrl().then(UIUtil.redirect);
|
||||||
// then redirect to login page
|
|
||||||
if (isTokenAuthEnabled) {
|
|
||||||
redirectToTokenAuthService(room.getName());
|
|
||||||
} else {
|
|
||||||
room.getExternalAuthUrl().then(UIUtil.redirect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,61 +75,80 @@ function redirectToTokenAuthService(roomName) {
|
||||||
* @param room the name fo the conference room.
|
* @param room the name fo the conference room.
|
||||||
*/
|
*/
|
||||||
function initJWTTokenListener(room) {
|
function initJWTTokenListener(room) {
|
||||||
var listener = function ({ data, source }) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function listener({ data, source }) {
|
||||||
if (externalAuthWindow !== source) {
|
if (externalAuthWindow !== source) {
|
||||||
logger.warn("Ignored message not coming " +
|
logger.warn('Ignored message not coming '
|
||||||
"from external authnetication window");
|
+ 'from external authnetication window');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let jwt;
|
let jwt;
|
||||||
|
|
||||||
if (data && (jwt = data.jwtToken)) {
|
if (data && (jwt = data.jwtToken)) {
|
||||||
logger.info("Received JSON Web Token (JWT):", jwt);
|
logger.info('Received JSON Web Token (JWT):', jwt);
|
||||||
|
|
||||||
APP.store.dispatch(setJWT(jwt));
|
APP.store.dispatch(setJWT(jwt));
|
||||||
|
|
||||||
var roomName = room.getName();
|
const roomName = room.getName();
|
||||||
openConnection({retry: false, roomName: roomName })
|
|
||||||
.then(function (connection) {
|
openConnection({
|
||||||
// Start new connection
|
retry: false,
|
||||||
let newRoom = connection.initJitsiConference(
|
roomName
|
||||||
roomName, APP.conference._getConferenceOptions());
|
}).then(connection => {
|
||||||
// Authenticate from the new connection to get
|
// Start new connection
|
||||||
// the session-ID from the focus, which wil then be used
|
const newRoom = connection.initJitsiConference(
|
||||||
// to upgrade current connection's user role
|
roomName, APP.conference._getConferenceOptions());
|
||||||
newRoom.room.moderator.authenticate().then(function () {
|
|
||||||
connection.disconnect();
|
// Authenticate from the new connection to get
|
||||||
// At this point we'll have session-ID stored in
|
// the session-ID from the focus, which wil then be used
|
||||||
// the settings. It wil be used in the call below
|
// to upgrade current connection's user role
|
||||||
// to upgrade user's role
|
|
||||||
room.room.moderator.authenticate()
|
newRoom.room.moderator.authenticate()
|
||||||
.then(function () {
|
.then(() => {
|
||||||
logger.info("User role upgrade done !");
|
connection.disconnect();
|
||||||
unregister();
|
|
||||||
}).catch(function (err, errCode) {
|
// At this point we'll have session-ID stored in
|
||||||
logger.error(
|
// the settings. It wil be used in the call below
|
||||||
"Authentication failed: ", err, errCode);
|
// to upgrade user's role
|
||||||
unregister();
|
room.room.moderator.authenticate()
|
||||||
});
|
.then(() => {
|
||||||
}).catch(function (error, code) {
|
logger.info('User role upgrade done !');
|
||||||
unregister();
|
// eslint-disable-line no-use-before-define
|
||||||
connection.disconnect();
|
unregister();
|
||||||
logger.error(
|
})
|
||||||
'Authentication failed on the new connection',
|
.catch((err, errCode) => {
|
||||||
error, code);
|
logger.error('Authentication failed: ',
|
||||||
});
|
err, errCode);
|
||||||
}, function (err) {
|
unregister();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error, code) => {
|
||||||
unregister();
|
unregister();
|
||||||
logger.error("Failed to open new connection", err);
|
connection.disconnect();
|
||||||
|
logger.error(
|
||||||
|
'Authentication failed on the new connection',
|
||||||
|
error, code);
|
||||||
});
|
});
|
||||||
|
}, err => {
|
||||||
|
unregister();
|
||||||
|
logger.error('Failed to open new connection', err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
var unregister = function () {
|
|
||||||
window.removeEventListener("message", listener);
|
/**
|
||||||
};
|
*
|
||||||
|
*/
|
||||||
|
function unregister() {
|
||||||
|
window.removeEventListener('message', listener);
|
||||||
|
}
|
||||||
|
|
||||||
if (window.addEventListener) {
|
if (window.addEventListener) {
|
||||||
window.addEventListener("message", listener, false);
|
window.addEventListener('message', listener, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,7 +200,7 @@ function doXmppAuth(room, lockPassword) {
|
||||||
* @param {JitsiConference} room
|
* @param {JitsiConference} room
|
||||||
* @param {string} [lockPassword] password to use if the conference is locked
|
* @param {string} [lockPassword] password to use if the conference is locked
|
||||||
*/
|
*/
|
||||||
function authenticate (room, lockPassword) {
|
function authenticate(room, lockPassword) {
|
||||||
if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
|
if (isTokenAuthEnabled || room.isExternalAuthEnabled()) {
|
||||||
doExternalAuth(room, lockPassword);
|
doExternalAuth(room, lockPassword);
|
||||||
} else {
|
} else {
|
||||||
|
@ -198,10 +215,10 @@ function authenticate (room, lockPassword) {
|
||||||
* @param {string} [lockPassword] password to use if the conference is locked
|
* @param {string} [lockPassword] password to use if the conference is locked
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function logout (room) {
|
function logout(room) {
|
||||||
return new Promise(function (resolve) {
|
return new Promise(resolve => {
|
||||||
room.room.moderator.logout(resolve);
|
room.room.moderator.logout(resolve);
|
||||||
}).then(function (url) {
|
}).then(url => {
|
||||||
// de-authenticate conference on the fly
|
// de-authenticate conference on the fly
|
||||||
if (room.isJoined()) {
|
if (room.isJoined()) {
|
||||||
room.join();
|
room.join();
|
||||||
|
@ -241,14 +258,17 @@ function closeAuth() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function showXmppPasswordPrompt(roomName, connect) {
|
function showXmppPasswordPrompt(roomName, connect) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
let authDialog = LoginDialog.showAuthDialog(
|
const authDialog = LoginDialog.showAuthDialog(
|
||||||
function (id, password) {
|
(id, password) => {
|
||||||
connect(id, password, roomName).then(function (connection) {
|
connect(id, password, roomName).then(connection => {
|
||||||
authDialog.close();
|
authDialog.close();
|
||||||
resolve(connection);
|
resolve(connection);
|
||||||
}, function (err) {
|
}, err => {
|
||||||
if (err === JitsiConnectionErrors.PASSWORD_REQUIRED) {
|
if (err === JitsiConnectionErrors.PASSWORD_REQUIRED) {
|
||||||
authDialog.displayError(err);
|
authDialog.displayError(err);
|
||||||
} else {
|
} else {
|
||||||
|
@ -275,9 +295,10 @@ function requestAuth(roomName, connect) {
|
||||||
if (isTokenAuthEnabled) {
|
if (isTokenAuthEnabled) {
|
||||||
// This Promise never resolves as user gets redirected to another URL
|
// This Promise never resolves as user gets redirected to another URL
|
||||||
return new Promise(() => redirectToTokenAuthService(roomName));
|
return new Promise(() => redirectToTokenAuthService(roomName));
|
||||||
} else {
|
|
||||||
return showXmppPasswordPrompt(roomName, connect);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return showXmppPasswordPrompt(roomName, connect);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|
|
@ -10,9 +10,9 @@ import {
|
||||||
* @returns {string} html string
|
* @returns {string} html string
|
||||||
*/
|
*/
|
||||||
function getPasswordInputHtml() {
|
function getPasswordInputHtml() {
|
||||||
let placeholder = config.hosts.authdomain
|
const placeholder = config.hosts.authdomain
|
||||||
? "user identity"
|
? 'user identity'
|
||||||
: "user@domain.net";
|
: 'user@domain.net';
|
||||||
|
|
||||||
return `
|
return `
|
||||||
<input name="username" type="text"
|
<input name="username" type="text"
|
||||||
|
@ -29,7 +29,7 @@ function getPasswordInputHtml() {
|
||||||
*/
|
*/
|
||||||
function cancelButton() {
|
function cancelButton() {
|
||||||
return {
|
return {
|
||||||
title: APP.translation.generateTranslationHTML("dialog.Cancel"),
|
title: APP.translation.generateTranslationHTML('dialog.Cancel'),
|
||||||
value: false
|
value: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -46,14 +46,14 @@ function cancelButton() {
|
||||||
* @param {function} [cancelCallback] callback to invoke if user canceled.
|
* @param {function} [cancelCallback] callback to invoke if user canceled.
|
||||||
*/
|
*/
|
||||||
function LoginDialog(successCallback, cancelCallback) {
|
function LoginDialog(successCallback, cancelCallback) {
|
||||||
let loginButtons = [{
|
const loginButtons = [ {
|
||||||
title: APP.translation.generateTranslationHTML("dialog.Ok"),
|
title: APP.translation.generateTranslationHTML('dialog.Ok'),
|
||||||
value: true
|
value: true
|
||||||
}];
|
} ];
|
||||||
let finishedButtons = [{
|
const finishedButtons = [ {
|
||||||
title: APP.translation.generateTranslationHTML('dialog.retry'),
|
title: APP.translation.generateTranslationHTML('dialog.retry'),
|
||||||
value: 'retry'
|
value: 'retry'
|
||||||
}];
|
} ];
|
||||||
|
|
||||||
// show "cancel" button only if cancelCallback provided
|
// show "cancel" button only if cancelCallback provided
|
||||||
if (cancelCallback) {
|
if (cancelCallback) {
|
||||||
|
@ -61,17 +61,28 @@ function LoginDialog(successCallback, cancelCallback) {
|
||||||
finishedButtons.push(cancelButton());
|
finishedButtons.push(cancelButton());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const connDialog = APP.UI.messageHandler.openDialogWithStates(
|
||||||
|
states, // eslint-disable-line no-use-before-define
|
||||||
|
{
|
||||||
|
persistent: true,
|
||||||
|
closeText: ''
|
||||||
|
},
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const states = {
|
const states = {
|
||||||
login: {
|
login: {
|
||||||
titleKey: 'dialog.passwordRequired',
|
titleKey: 'dialog.passwordRequired',
|
||||||
html: getPasswordInputHtml(),
|
html: getPasswordInputHtml(),
|
||||||
buttons: loginButtons,
|
buttons: loginButtons,
|
||||||
focus: ':input:first',
|
focus: ':input:first',
|
||||||
submit: function (e, v, m, f) {
|
// eslint-disable-next-line max-params
|
||||||
|
submit(e, v, m, f) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (v) {
|
if (v) {
|
||||||
let jid = f.username;
|
const jid = f.username;
|
||||||
let password = f.password;
|
const password = f.password;
|
||||||
|
|
||||||
if (jid && password) {
|
if (jid && password) {
|
||||||
connDialog.goToState('connecting');
|
connDialog.goToState('connecting');
|
||||||
successCallback(toJid(jid, config.hosts), password);
|
successCallback(toJid(jid, config.hosts), password);
|
||||||
|
@ -84,16 +95,16 @@ function LoginDialog(successCallback, cancelCallback) {
|
||||||
},
|
},
|
||||||
connecting: {
|
connecting: {
|
||||||
titleKey: 'dialog.connecting',
|
titleKey: 'dialog.connecting',
|
||||||
html: '<div id="connectionStatus"></div>',
|
html: '<div id="connectionStatus"></div>',
|
||||||
buttons: [],
|
buttons: [],
|
||||||
defaultButton: 0
|
defaultButton: 0
|
||||||
},
|
},
|
||||||
finished: {
|
finished: {
|
||||||
titleKey: 'dialog.error',
|
titleKey: 'dialog.error',
|
||||||
html: '<div id="errorMessage"></div>',
|
html: '<div id="errorMessage"></div>',
|
||||||
buttons: finishedButtons,
|
buttons: finishedButtons,
|
||||||
defaultButton: 0,
|
defaultButton: 0,
|
||||||
submit: function (e, v) {
|
submit(e, v) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (v === 'retry') {
|
if (v === 'retry') {
|
||||||
connDialog.goToState('login');
|
connDialog.goToState('login');
|
||||||
|
@ -105,38 +116,35 @@ function LoginDialog(successCallback, cancelCallback) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var connDialog = APP.UI.messageHandler.openDialogWithStates(
|
|
||||||
states, { persistent: true, closeText: '' }, null
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Displays error message in 'finished' state which allows either to cancel
|
* Displays error message in 'finished' state which allows either to cancel
|
||||||
* or retry.
|
* or retry.
|
||||||
* @param error the key to the error to be displayed.
|
* @param error the key to the error to be displayed.
|
||||||
* @param options the options to the error message (optional)
|
* @param options the options to the error message (optional)
|
||||||
*/
|
*/
|
||||||
this.displayError = function (error, options) {
|
this.displayError = function(error, options) {
|
||||||
|
|
||||||
let finishedState = connDialog.getState('finished');
|
const finishedState = connDialog.getState('finished');
|
||||||
|
|
||||||
let errorMessageElem = finishedState.find('#errorMessage');
|
const errorMessageElem = finishedState.find('#errorMessage');
|
||||||
|
|
||||||
let messageKey;
|
let messageKey;
|
||||||
|
|
||||||
if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
|
if (error === JitsiConnectionErrors.PASSWORD_REQUIRED) {
|
||||||
// this is a password required error, as login window was already
|
// this is a password required error, as login window was already
|
||||||
// open once, this means username or password is wrong
|
// open once, this means username or password is wrong
|
||||||
messageKey = 'dialog.incorrectPassword';
|
messageKey = 'dialog.incorrectPassword';
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
messageKey = 'dialog.connectErrorWithMsg';
|
messageKey = 'dialog.connectErrorWithMsg';
|
||||||
|
|
||||||
if (!options)
|
if (!options) {
|
||||||
options = {};
|
options = {};// eslint-disable-line no-param-reassign
|
||||||
|
}
|
||||||
|
|
||||||
options.msg = error;
|
options.msg = error;
|
||||||
}
|
}
|
||||||
|
|
||||||
errorMessageElem.attr("data-i18n", messageKey);
|
errorMessageElem.attr('data-i18n', messageKey);
|
||||||
|
|
||||||
APP.translation.translateElement($(errorMessageElem), options);
|
APP.translation.translateElement($(errorMessageElem), options);
|
||||||
|
|
||||||
|
@ -147,18 +155,19 @@ function LoginDialog(successCallback, cancelCallback) {
|
||||||
* Show message as connection status.
|
* Show message as connection status.
|
||||||
* @param {string} messageKey the key to the message
|
* @param {string} messageKey the key to the message
|
||||||
*/
|
*/
|
||||||
this.displayConnectionStatus = function (messageKey) {
|
this.displayConnectionStatus = function(messageKey) {
|
||||||
let connectingState = connDialog.getState('connecting');
|
const connectingState = connDialog.getState('connecting');
|
||||||
|
|
||||||
let connectionStatus = connectingState.find('#connectionStatus');
|
const connectionStatus = connectingState.find('#connectionStatus');
|
||||||
connectionStatus.attr("data-i18n", messageKey);
|
|
||||||
|
connectionStatus.attr('data-i18n', messageKey);
|
||||||
APP.translation.translateElement($(connectionStatus));
|
APP.translation.translateElement($(connectionStatus));
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Closes LoginDialog.
|
* Closes LoginDialog.
|
||||||
*/
|
*/
|
||||||
this.close = function () {
|
this.close = function() {
|
||||||
connDialog.close();
|
connDialog.close();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -173,7 +182,7 @@ export default {
|
||||||
*
|
*
|
||||||
* @returns {LoginDialog}
|
* @returns {LoginDialog}
|
||||||
*/
|
*/
|
||||||
showAuthDialog: function (successCallback, cancelCallback) {
|
showAuthDialog(successCallback, cancelCallback) {
|
||||||
return new LoginDialog(successCallback, cancelCallback);
|
return new LoginDialog(successCallback, cancelCallback);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -183,15 +192,16 @@ export default {
|
||||||
* @param {function} callback callback to invoke when auth popup is closed.
|
* @param {function} callback callback to invoke when auth popup is closed.
|
||||||
* @returns auth dialog
|
* @returns auth dialog
|
||||||
*/
|
*/
|
||||||
showExternalAuthDialog: function (url, callback) {
|
showExternalAuthDialog(url, callback) {
|
||||||
var dialog = APP.UI.messageHandler.openCenteredPopup(
|
const dialog = APP.UI.messageHandler.openCenteredPopup(
|
||||||
url, 910, 660,
|
url, 910, 660,
|
||||||
|
|
||||||
// On closed
|
// On closed
|
||||||
callback
|
callback
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!dialog) {
|
if (!dialog) {
|
||||||
APP.UI.messageHandler.openMessageDialog(null, "dialog.popupError");
|
APP.UI.messageHandler.openMessageDialog(null, 'dialog.popupError');
|
||||||
}
|
}
|
||||||
|
|
||||||
return dialog;
|
return dialog;
|
||||||
|
@ -215,10 +225,10 @@ export default {
|
||||||
const buttonTxt = APP.translation.generateTranslationHTML(
|
const buttonTxt = APP.translation.generateTranslationHTML(
|
||||||
'dialog.IamHost'
|
'dialog.IamHost'
|
||||||
);
|
);
|
||||||
const buttons = [{
|
const buttons = [ {
|
||||||
title: buttonTxt,
|
title: buttonTxt,
|
||||||
value: 'authNow'
|
value: 'authNow'
|
||||||
}];
|
} ];
|
||||||
|
|
||||||
return APP.UI.messageHandler.openDialog(
|
return APP.UI.messageHandler.openDialog(
|
||||||
'dialog.WaitingForHost',
|
'dialog.WaitingForHost',
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
|
|
||||||
import { getAvatarURL } from '../../../react/features/base/participants';
|
import { getAvatarURL } from '../../../react/features/base/participants';
|
||||||
|
|
||||||
let users = {};
|
const users = {};
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
/**
|
/**
|
||||||
|
@ -34,17 +34,19 @@ export default {
|
||||||
* @param prop {string} name of the prop
|
* @param prop {string} name of the prop
|
||||||
* @param val {string} value to be set
|
* @param val {string} value to be set
|
||||||
*/
|
*/
|
||||||
_setUserProp: function (id, prop, val) {
|
_setUserProp(id, prop, val) {
|
||||||
// FIXME: Fixes the issue with not be able to return avatar for the
|
// FIXME: Fixes the issue with not be able to return avatar for the
|
||||||
// local user when the conference has been left. Maybe there is beter
|
// local user when the conference has been left. Maybe there is beter
|
||||||
// way to solve it.
|
// way to solve it.
|
||||||
if(!id || APP.conference.isLocalId(id)) {
|
if (!id || APP.conference.isLocalId(id)) {
|
||||||
id = "local";
|
id = 'local';// eslint-disable-line no-param-reassign
|
||||||
}
|
}
|
||||||
if(!val || (users[id] && users[id][prop] === val))
|
if (!val || (users[id] && users[id][prop] === val)) {
|
||||||
return;
|
return;
|
||||||
if(!users[id])
|
}
|
||||||
|
if (!users[id]) {
|
||||||
users[id] = {};
|
users[id] = {};
|
||||||
|
}
|
||||||
users[id][prop] = val;
|
users[id][prop] = val;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -54,8 +56,8 @@ export default {
|
||||||
* @param id id of the user
|
* @param id id of the user
|
||||||
* @param email email or nickname to be used as a hash
|
* @param email email or nickname to be used as a hash
|
||||||
*/
|
*/
|
||||||
setUserEmail: function (id, email) {
|
setUserEmail(id, email) {
|
||||||
this._setUserProp(id, "email", email);
|
this._setUserProp(id, 'email', email);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -64,8 +66,8 @@ export default {
|
||||||
* @param id id of the user
|
* @param id id of the user
|
||||||
* @param url the url for the avatar
|
* @param url the url for the avatar
|
||||||
*/
|
*/
|
||||||
setUserAvatarUrl: function (id, url) {
|
setUserAvatarUrl(id, url) {
|
||||||
this._setUserProp(id, "avatarUrl", url);
|
this._setUserProp(id, 'avatarUrl', url);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,8 +75,8 @@ export default {
|
||||||
* @param id id of the user
|
* @param id id of the user
|
||||||
* @param avatarId an id to be used for the avatar
|
* @param avatarId an id to be used for the avatar
|
||||||
*/
|
*/
|
||||||
setUserAvatarID: function (id, avatarId) {
|
setUserAvatarID(id, avatarId) {
|
||||||
this._setUserProp(id, "avatarId", avatarId);
|
this._setUserProp(id, 'avatarId', avatarId);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,10 +84,12 @@ export default {
|
||||||
* identified by its id.
|
* identified by its id.
|
||||||
* @param {string} userId user id
|
* @param {string} userId user id
|
||||||
*/
|
*/
|
||||||
getAvatarUrl: function (userId) {
|
getAvatarUrl(userId) {
|
||||||
let user;
|
let user;
|
||||||
|
|
||||||
if (!userId || APP.conference.isLocalId(userId)) {
|
if (!userId || APP.conference.isLocalId(userId)) {
|
||||||
user = users.local;
|
user = users.local;
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
userId = APP.conference.getMyUserId();
|
userId = APP.conference.getMyUserId();
|
||||||
} else {
|
} else {
|
||||||
user = users[userId];
|
user = users[userId];
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
|
|
||||||
import VideoLayout from "../videolayout/VideoLayout";
|
import VideoLayout from '../videolayout/VideoLayout';
|
||||||
import LargeContainer from '../videolayout/LargeContainer';
|
import LargeContainer from '../videolayout/LargeContainer';
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
import Filmstrip from '../videolayout/Filmstrip';
|
import Filmstrip from '../videolayout/Filmstrip';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,14 +15,21 @@ const options = $.param({
|
||||||
useMonospaceFont: false
|
useMonospaceFont: false
|
||||||
});
|
});
|
||||||
|
|
||||||
function bubbleIframeMouseMove(iframe){
|
/**
|
||||||
var existingOnMouseMove = iframe.contentWindow.onmousemove;
|
*
|
||||||
iframe.contentWindow.onmousemove = function(e){
|
*/
|
||||||
if(existingOnMouseMove) existingOnMouseMove(e);
|
function bubbleIframeMouseMove(iframe) {
|
||||||
var evt = document.createEvent("MouseEvents");
|
const existingOnMouseMove = iframe.contentWindow.onmousemove;
|
||||||
var boundingClientRect = iframe.getBoundingClientRect();
|
|
||||||
|
iframe.contentWindow.onmousemove = function(e) {
|
||||||
|
if (existingOnMouseMove) {
|
||||||
|
existingOnMouseMove(e);
|
||||||
|
}
|
||||||
|
const evt = document.createEvent('MouseEvents');
|
||||||
|
const boundingClientRect = iframe.getBoundingClientRect();
|
||||||
|
|
||||||
evt.initMouseEvent(
|
evt.initMouseEvent(
|
||||||
"mousemove",
|
'mousemove',
|
||||||
true, // bubbles
|
true, // bubbles
|
||||||
false, // not cancelable
|
false, // not cancelable
|
||||||
window,
|
window,
|
||||||
|
@ -46,27 +53,30 @@ function bubbleIframeMouseMove(iframe){
|
||||||
* Default Etherpad frame width.
|
* Default Etherpad frame width.
|
||||||
*/
|
*/
|
||||||
const DEFAULT_WIDTH = 640;
|
const DEFAULT_WIDTH = 640;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default Etherpad frame height.
|
* Default Etherpad frame height.
|
||||||
*/
|
*/
|
||||||
const DEFAULT_HEIGHT = 480;
|
const DEFAULT_HEIGHT = 480;
|
||||||
|
|
||||||
const ETHERPAD_CONTAINER_TYPE = "etherpad";
|
const ETHERPAD_CONTAINER_TYPE = 'etherpad';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Container for Etherpad iframe.
|
* Container for Etherpad iframe.
|
||||||
*/
|
*/
|
||||||
class Etherpad extends LargeContainer {
|
class Etherpad extends LargeContainer {
|
||||||
|
/**
|
||||||
constructor (domain, name) {
|
* Creates new Etherpad object
|
||||||
|
*/
|
||||||
|
constructor(domain, name) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
const iframe = document.createElement('iframe');
|
const iframe = document.createElement('iframe');
|
||||||
|
|
||||||
iframe.id = "etherpadIFrame";
|
iframe.id = 'etherpadIFrame';
|
||||||
iframe.src = domain + name + '?' + options;
|
iframe.src = `${domain + name}?${options}`;
|
||||||
iframe.frameBorder = 0;
|
iframe.frameBorder = 0;
|
||||||
iframe.scrolling = "no";
|
iframe.scrolling = 'no';
|
||||||
iframe.width = DEFAULT_WIDTH;
|
iframe.width = DEFAULT_WIDTH;
|
||||||
iframe.height = DEFAULT_HEIGHT;
|
iframe.height = DEFAULT_HEIGHT;
|
||||||
iframe.setAttribute('style', 'visibility: hidden;');
|
iframe.setAttribute('style', 'visibility: hidden;');
|
||||||
|
@ -77,15 +87,17 @@ class Etherpad extends LargeContainer {
|
||||||
document.domain = document.domain;
|
document.domain = document.domain;
|
||||||
bubbleIframeMouseMove(iframe);
|
bubbleIframeMouseMove(iframe);
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(() => {
|
||||||
const doc = iframe.contentDocument;
|
const doc = iframe.contentDocument;
|
||||||
|
|
||||||
// the iframes inside of the etherpad are
|
// the iframes inside of the etherpad are
|
||||||
// not yet loaded when the etherpad iframe is loaded
|
// not yet loaded when the etherpad iframe is loaded
|
||||||
const outer = doc.getElementsByName("ace_outer")[0];
|
const outer = doc.getElementsByName('ace_outer')[0];
|
||||||
|
|
||||||
bubbleIframeMouseMove(outer);
|
bubbleIframeMouseMove(outer);
|
||||||
|
|
||||||
const inner = doc.getElementsByName("ace_inner")[0];
|
const inner = doc.getElementsByName('ace_inner')[0];
|
||||||
|
|
||||||
bubbleIframeMouseMove(inner);
|
bubbleIframeMouseMove(inner);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
};
|
};
|
||||||
|
@ -93,47 +105,64 @@ class Etherpad extends LargeContainer {
|
||||||
this.iframe = iframe;
|
this.iframe = iframe;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isOpen () {
|
/**
|
||||||
return !!this.iframe;
|
*
|
||||||
|
*/
|
||||||
|
get isOpen() {
|
||||||
|
return Boolean(this.iframe);
|
||||||
}
|
}
|
||||||
|
|
||||||
get container () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get container() {
|
||||||
return document.getElementById('etherpad');
|
return document.getElementById('etherpad');
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
/**
|
||||||
resize (containerWidth, containerHeight, animate) {
|
*
|
||||||
let height = containerHeight - Filmstrip.getFilmstripHeight();
|
*/
|
||||||
let width = containerWidth;
|
resize(containerWidth, containerHeight) {
|
||||||
|
const height = containerHeight - Filmstrip.getFilmstripHeight();
|
||||||
|
const width = containerWidth;
|
||||||
|
|
||||||
$(this.iframe).width(width).height(height);
|
$(this.iframe)
|
||||||
|
.width(width)
|
||||||
|
.height(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
show() {
|
||||||
const $iframe = $(this.iframe);
|
const $iframe = $(this.iframe);
|
||||||
const $container = $(this.container);
|
const $container = $(this.container);
|
||||||
let self = this;
|
const self = this;
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
$iframe.fadeIn(300, function () {
|
$iframe.fadeIn(300, () => {
|
||||||
self.bodyBackground = document.body.style.background;
|
self.bodyBackground = document.body.style.background;
|
||||||
document.body.style.background = '#eeeeee';
|
document.body.style.background = '#eeeeee';
|
||||||
$iframe.css({visibility: 'visible'});
|
$iframe.css({ visibility: 'visible' });
|
||||||
$container.css({zIndex: 2});
|
$container.css({ zIndex: 2 });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
const $iframe = $(this.iframe);
|
const $iframe = $(this.iframe);
|
||||||
const $container = $(this.container);
|
const $container = $(this.container);
|
||||||
|
|
||||||
document.body.style.background = this.bodyBackground;
|
document.body.style.background = this.bodyBackground;
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
$iframe.fadeOut(300, function () {
|
$iframe.fadeOut(300, () => {
|
||||||
$iframe.css({visibility: 'hidden'});
|
$iframe.css({ visibility: 'hidden' });
|
||||||
$container.css({zIndex: 0});
|
$container.css({ zIndex: 0 });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -142,7 +171,7 @@ class Etherpad extends LargeContainer {
|
||||||
/**
|
/**
|
||||||
* @return {boolean} do not switch on dominant speaker event if on stage.
|
* @return {boolean} do not switch on dominant speaker event if on stage.
|
||||||
*/
|
*/
|
||||||
stayOnStage () {
|
stayOnStage() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -151,9 +180,12 @@ class Etherpad extends LargeContainer {
|
||||||
* Manager of the Etherpad frame.
|
* Manager of the Etherpad frame.
|
||||||
*/
|
*/
|
||||||
export default class EtherpadManager {
|
export default class EtherpadManager {
|
||||||
constructor (domain, name, eventEmitter) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(domain, name, eventEmitter) {
|
||||||
if (!domain || !name) {
|
if (!domain || !name) {
|
||||||
throw new Error("missing domain or name");
|
throw new Error('missing domain or name');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.domain = domain;
|
this.domain = domain;
|
||||||
|
@ -162,10 +194,16 @@ export default class EtherpadManager {
|
||||||
this.etherpad = null;
|
this.etherpad = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isOpen () {
|
/**
|
||||||
return !!this.etherpad;
|
*
|
||||||
|
*/
|
||||||
|
get isOpen() {
|
||||||
|
return Boolean(this.etherpad);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
isVisible() {
|
isVisible() {
|
||||||
return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
|
return VideoLayout.isLargeContainerTypeVisible(ETHERPAD_CONTAINER_TYPE);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +211,7 @@ export default class EtherpadManager {
|
||||||
/**
|
/**
|
||||||
* Create new Etherpad frame.
|
* Create new Etherpad frame.
|
||||||
*/
|
*/
|
||||||
openEtherpad () {
|
openEtherpad() {
|
||||||
this.etherpad = new Etherpad(this.domain, this.name);
|
this.etherpad = new Etherpad(this.domain, this.name);
|
||||||
VideoLayout.addLargeVideoContainer(
|
VideoLayout.addLargeVideoContainer(
|
||||||
ETHERPAD_CONTAINER_TYPE,
|
ETHERPAD_CONTAINER_TYPE,
|
||||||
|
@ -185,12 +223,12 @@ export default class EtherpadManager {
|
||||||
* Toggle Etherpad frame visibility.
|
* Toggle Etherpad frame visibility.
|
||||||
* Open new Etherpad frame if there is no Etherpad frame yet.
|
* Open new Etherpad frame if there is no Etherpad frame yet.
|
||||||
*/
|
*/
|
||||||
toggleEtherpad () {
|
toggleEtherpad() {
|
||||||
if (!this.isOpen) {
|
if (!this.isOpen) {
|
||||||
this.openEtherpad();
|
this.openEtherpad();
|
||||||
}
|
}
|
||||||
|
|
||||||
let isVisible = this.isVisible();
|
const isVisible = this.isVisible();
|
||||||
|
|
||||||
VideoLayout.showLargeVideoContainer(
|
VideoLayout.showLargeVideoContainer(
|
||||||
ETHERPAD_CONTAINER_TYPE, !isVisible);
|
ETHERPAD_CONTAINER_TYPE, !isVisible);
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
import UIUtil from '../util/UIUtil';
|
import UIUtil from '../util/UIUtil';
|
||||||
import VideoLayout from '../videolayout/VideoLayout';
|
import VideoLayout from '../videolayout/VideoLayout';
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ let dialog = null;
|
||||||
*/
|
*/
|
||||||
function _isRecordingButtonEnabled() {
|
function _isRecordingButtonEnabled() {
|
||||||
return (
|
return (
|
||||||
interfaceConfig.TOOLBAR_BUTTONS.indexOf("recording") !== -1
|
interfaceConfig.TOOLBAR_BUTTONS.indexOf('recording') !== -1
|
||||||
&& config.enableRecording
|
&& config.enableRecording
|
||||||
&& APP.conference.isRecordingSupported());
|
&& APP.conference.isRecordingSupported());
|
||||||
}
|
}
|
||||||
|
@ -95,69 +95,75 @@ function _isRecordingButtonEnabled() {
|
||||||
*/
|
*/
|
||||||
function _requestLiveStreamId() {
|
function _requestLiveStreamId() {
|
||||||
const cancelButton
|
const cancelButton
|
||||||
= APP.translation.generateTranslationHTML("dialog.Cancel");
|
= APP.translation.generateTranslationHTML('dialog.Cancel');
|
||||||
const backButton = APP.translation.generateTranslationHTML("dialog.Back");
|
const backButton = APP.translation.generateTranslationHTML('dialog.Back');
|
||||||
const startStreamingButton
|
const startStreamingButton
|
||||||
= APP.translation.generateTranslationHTML("dialog.startLiveStreaming");
|
= APP.translation.generateTranslationHTML('dialog.startLiveStreaming');
|
||||||
const streamIdRequired
|
const streamIdRequired
|
||||||
= APP.translation.generateTranslationHTML(
|
= APP.translation.generateTranslationHTML(
|
||||||
"liveStreaming.streamIdRequired");
|
'liveStreaming.streamIdRequired');
|
||||||
const streamIdHelp
|
const streamIdHelp
|
||||||
= APP.translation.generateTranslationHTML(
|
= APP.translation.generateTranslationHTML(
|
||||||
"liveStreaming.streamIdHelp");
|
'liveStreaming.streamIdHelp');
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||||
state0: {
|
state0: {
|
||||||
titleKey: "dialog.liveStreaming",
|
titleKey: 'dialog.liveStreaming',
|
||||||
html:
|
html:
|
||||||
`<input class="input-control"
|
`<input class="input-control"
|
||||||
name="streamId" type="text"
|
name="streamId" type="text"
|
||||||
data-i18n="[placeholder]dialog.streamKey"
|
data-i18n="[placeholder]dialog.streamKey"
|
||||||
autofocus><div style="text-align: right">
|
autofocus><div style="text-align: right">
|
||||||
<a class="helper-link" target="_new"
|
<a class="helper-link" target="_new"
|
||||||
href="${interfaceConfig.LIVE_STREAMING_HELP_LINK}">`
|
href="${interfaceConfig.LIVE_STREAMING_HELP_LINK}">${
|
||||||
+ streamIdHelp
|
streamIdHelp
|
||||||
+ `</a></div>`,
|
}</a></div>`,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{ title: cancelButton,
|
||||||
{title: startStreamingButton, value: true}
|
value: false },
|
||||||
|
{ title: startStreamingButton,
|
||||||
|
value: true }
|
||||||
],
|
],
|
||||||
focus: ':input:first',
|
focus: ':input:first',
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
submit: function (e, v, m, f) {
|
submit(e, v, m, f) { // eslint-disable-line max-params
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (v) {
|
if (v) {
|
||||||
if (f.streamId && f.streamId.length > 0) {
|
if (f.streamId && f.streamId.length > 0) {
|
||||||
resolve(UIUtil.escapeHtml(f.streamId));
|
resolve(UIUtil.escapeHtml(f.streamId));
|
||||||
dialog.close();
|
dialog.close();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
dialog.goToState('state1');
|
||||||
dialog.goToState('state1');
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
reject(APP.UI.messageHandler.CANCEL);
|
|
||||||
dialog.close();
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
reject(APP.UI.messageHandler.CANCEL);
|
||||||
|
dialog.close();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
state1: {
|
state1: {
|
||||||
titleKey: "dialog.liveStreaming",
|
titleKey: 'dialog.liveStreaming',
|
||||||
html: streamIdRequired,
|
html: streamIdRequired,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{ title: cancelButton,
|
||||||
{title: backButton, value: true}
|
value: false },
|
||||||
|
{ title: backButton,
|
||||||
|
value: true }
|
||||||
],
|
],
|
||||||
focus: ':input:first',
|
focus: ':input:first',
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
submit: function (e, v) {
|
submit(e, v) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (v === 0) {
|
if (v === 0) {
|
||||||
reject(APP.UI.messageHandler.CANCEL);
|
reject(APP.UI.messageHandler.CANCEL);
|
||||||
|
@ -168,7 +174,7 @@ function _requestLiveStreamId() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
close: function () {
|
close() {
|
||||||
dialog = null;
|
dialog = null;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -180,26 +186,29 @@ function _requestLiveStreamId() {
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
function _requestRecordingToken() {
|
function _requestRecordingToken() {
|
||||||
let titleKey = "dialog.recordingToken";
|
const titleKey = 'dialog.recordingToken';
|
||||||
let msgString = (
|
const msgString
|
||||||
`<input name="recordingToken" type="text"
|
= `<input name="recordingToken" type="text"
|
||||||
data-i18n="[placeholder]dialog.token"
|
data-i18n="[placeholder]dialog.token"
|
||||||
class="input-control"
|
class="input-control"
|
||||||
autofocus>`
|
autofocus>`
|
||||||
);
|
|
||||||
return new Promise(function (resolve, reject) {
|
;
|
||||||
|
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
titleKey,
|
titleKey,
|
||||||
msgString,
|
msgString,
|
||||||
leftButtonKey: 'dialog.Save',
|
leftButtonKey: 'dialog.Save',
|
||||||
submitFunction: function (e, v, m, f) {
|
submitFunction(e, v, m, f) { // eslint-disable-line max-params
|
||||||
if (v && f.recordingToken) {
|
if (v && f.recordingToken) {
|
||||||
resolve(UIUtil.escapeHtml(f.recordingToken));
|
resolve(UIUtil.escapeHtml(f.recordingToken));
|
||||||
} else {
|
} else {
|
||||||
reject(APP.UI.messageHandler.CANCEL);
|
reject(APP.UI.messageHandler.CANCEL);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
closeFunction: function () {
|
closeFunction() {
|
||||||
dialog = null;
|
dialog = null;
|
||||||
},
|
},
|
||||||
focus: ':input:first'
|
focus: ':input:first'
|
||||||
|
@ -215,18 +224,18 @@ function _requestRecordingToken() {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
function _showStopRecordingPrompt(recordingType) {
|
function _showStopRecordingPrompt(recordingType) {
|
||||||
var title;
|
let title;
|
||||||
var message;
|
let message;
|
||||||
var buttonKey;
|
let buttonKey;
|
||||||
if (recordingType === "jibri") {
|
|
||||||
title = "dialog.liveStreaming";
|
if (recordingType === 'jibri') {
|
||||||
message = "dialog.stopStreamingWarning";
|
title = 'dialog.liveStreaming';
|
||||||
buttonKey = "dialog.stopLiveStreaming";
|
message = 'dialog.stopStreamingWarning';
|
||||||
}
|
buttonKey = 'dialog.stopLiveStreaming';
|
||||||
else {
|
} else {
|
||||||
title = "dialog.recording";
|
title = 'dialog.recording';
|
||||||
message = "dialog.stopRecordingWarning";
|
message = 'dialog.stopRecordingWarning';
|
||||||
buttonKey = "dialog.stopRecording";
|
buttonKey = 'dialog.stopRecording';
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -248,7 +257,10 @@ function _showStopRecordingPrompt(recordingType) {
|
||||||
* @returns {boolean} true if the condition is met or false otherwise.
|
* @returns {boolean} true if the condition is met or false otherwise.
|
||||||
*/
|
*/
|
||||||
function isStartingStatus(status) {
|
function isStartingStatus(status) {
|
||||||
return status === JitsiRecordingStatus.PENDING || status === JitsiRecordingStatus.RETRYING;
|
return (
|
||||||
|
status === JitsiRecordingStatus.PENDING
|
||||||
|
|| status === JitsiRecordingStatus.RETRYING
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -256,7 +268,7 @@ function isStartingStatus(status) {
|
||||||
* @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
|
* @type {{init, initRecordingButton, showRecordingButton, updateRecordingState,
|
||||||
* updateRecordingUI, checkAutoRecord}}
|
* updateRecordingUI, checkAutoRecord}}
|
||||||
*/
|
*/
|
||||||
var Recording = {
|
const Recording = {
|
||||||
/**
|
/**
|
||||||
* Initializes the recording UI.
|
* Initializes the recording UI.
|
||||||
*/
|
*/
|
||||||
|
@ -267,11 +279,10 @@ var Recording = {
|
||||||
this.updateRecordingState(APP.conference.getRecordingState());
|
this.updateRecordingState(APP.conference.getRecordingState());
|
||||||
|
|
||||||
if (recordingType === 'jibri') {
|
if (recordingType === 'jibri') {
|
||||||
this.baseClass = "fa fa-play-circle";
|
this.baseClass = 'fa fa-play-circle';
|
||||||
Object.assign(this, STREAMING_TRANSLATION_KEYS);
|
Object.assign(this, STREAMING_TRANSLATION_KEYS);
|
||||||
}
|
} else {
|
||||||
else {
|
this.baseClass = 'icon-recEnable';
|
||||||
this.baseClass = "icon-recEnable";
|
|
||||||
Object.assign(this, RECORDING_TRANSLATION_KEYS);
|
Object.assign(this, RECORDING_TRANSLATION_KEYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +312,7 @@ var Recording = {
|
||||||
const selector = $('#toolbar_button_record');
|
const selector = $('#toolbar_button_record');
|
||||||
|
|
||||||
selector.addClass(this.baseClass);
|
selector.addClass(this.baseClass);
|
||||||
selector.attr("data-i18n", "[content]" + this.recordingButtonTooltip);
|
selector.attr('data-i18n', `[content]${this.recordingButtonTooltip}`);
|
||||||
APP.translation.translateElement(selector);
|
APP.translation.translateElement(selector);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -310,8 +321,8 @@ var Recording = {
|
||||||
* @param show {true} to show the recording button, {false} to hide it
|
* @param show {true} to show the recording button, {false} to hide it
|
||||||
*/
|
*/
|
||||||
showRecordingButton(show) {
|
showRecordingButton(show) {
|
||||||
let shouldShow = show && _isRecordingButtonEnabled();
|
const shouldShow = show && _isRecordingButtonEnabled();
|
||||||
let id = 'toolbar_button_record';
|
const id = 'toolbar_button_record';
|
||||||
|
|
||||||
UIUtil.setVisible(id, shouldShow);
|
UIUtil.setVisible(id, shouldShow);
|
||||||
},
|
},
|
||||||
|
@ -322,12 +333,14 @@ var Recording = {
|
||||||
*/
|
*/
|
||||||
updateRecordingState(recordingState) {
|
updateRecordingState(recordingState) {
|
||||||
// I'm the recorder, so I don't want to see any UI related to states.
|
// I'm the recorder, so I don't want to see any UI related to states.
|
||||||
if (config.iAmRecorder)
|
if (config.iAmRecorder) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// If there's no state change, we ignore the update.
|
// If there's no state change, we ignore the update.
|
||||||
if (!recordingState || this.currentState === recordingState)
|
if (!recordingState || this.currentState === recordingState) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.updateRecordingUI(recordingState);
|
this.updateRecordingUI(recordingState);
|
||||||
},
|
},
|
||||||
|
@ -338,7 +351,8 @@ var Recording = {
|
||||||
*/
|
*/
|
||||||
updateRecordingUI(recordingState) {
|
updateRecordingUI(recordingState) {
|
||||||
|
|
||||||
let oldState = this.currentState;
|
const oldState = this.currentState;
|
||||||
|
|
||||||
this.currentState = recordingState;
|
this.currentState = recordingState;
|
||||||
|
|
||||||
let labelDisplayConfiguration;
|
let labelDisplayConfiguration;
|
||||||
|
@ -366,6 +380,7 @@ var Recording = {
|
||||||
// We don't want UI changes if this is an availability change.
|
// We don't want UI changes if this is an availability change.
|
||||||
if (oldState !== JitsiRecordingStatus.ON && !wasInStartingStatus) {
|
if (oldState !== JitsiRecordingStatus.ON && !wasInStartingStatus) {
|
||||||
APP.store.dispatch(updateRecordingState({ recordingState }));
|
APP.store.dispatch(updateRecordingState({ recordingState }));
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -378,7 +393,7 @@ var Recording = {
|
||||||
|
|
||||||
this._setToolbarButtonToggled(false);
|
this._setToolbarButtonToggled(false);
|
||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(() => {
|
||||||
APP.store.dispatch(hideRecordingLabel());
|
APP.store.dispatch(hideRecordingLabel());
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
|
@ -408,7 +423,8 @@ var Recording = {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return an empty label display configuration to indicate no label
|
// Return an empty label display configuration to indicate no label
|
||||||
// should be displayed. The JitsiRecordingStatus.AVAIABLE case is handled here.
|
// should be displayed. The JitsiRecordingStatus.AVAIABLE case is
|
||||||
|
// handled here.
|
||||||
default: {
|
default: {
|
||||||
labelDisplayConfiguration = null;
|
labelDisplayConfiguration = null;
|
||||||
}
|
}
|
||||||
|
@ -450,42 +466,48 @@ var Recording = {
|
||||||
this.eventEmitter.emit(UIEvents.RECORDING_TOGGLED);
|
this.eventEmitter.emit(UIEvents.RECORDING_TOGGLED);
|
||||||
sendEvent('recording.stopped');
|
sendEvent('recording.stopped');
|
||||||
},
|
},
|
||||||
() => {});
|
() => {}); // eslint-disable-line no-empty-function
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case JitsiRecordingStatus.AVAILABLE:
|
case JitsiRecordingStatus.AVAILABLE:
|
||||||
case JitsiRecordingStatus.OFF: {
|
case JitsiRecordingStatus.OFF: {
|
||||||
if (this.recordingType === 'jibri')
|
if (this.recordingType === 'jibri') {
|
||||||
_requestLiveStreamId().then(streamId => {
|
_requestLiveStreamId()
|
||||||
|
.then(streamId => {
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
UIEvents.RECORDING_TOGGLED,
|
UIEvents.RECORDING_TOGGLED,
|
||||||
{ streamId });
|
{ streamId });
|
||||||
sendEvent('recording.started');
|
sendEvent('recording.started');
|
||||||
}).catch(reason => {
|
})
|
||||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
.catch(reason => {
|
||||||
logger.error(reason);
|
if (reason === APP.UI.messageHandler.CANCEL) {
|
||||||
else
|
|
||||||
sendEvent('recording.canceled');
|
sendEvent('recording.canceled');
|
||||||
|
} else {
|
||||||
|
logger.error(reason);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
else {
|
} else {
|
||||||
if (this.predefinedToken) {
|
if (this.predefinedToken) {
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
UIEvents.RECORDING_TOGGLED,
|
UIEvents.RECORDING_TOGGLED,
|
||||||
{ token: this.predefinedToken });
|
{ token: this.predefinedToken });
|
||||||
sendEvent('recording.started');
|
sendEvent('recording.started');
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_requestRecordingToken().then((token) => {
|
_requestRecordingToken().then(token => {
|
||||||
this.eventEmitter.emit(
|
this.eventEmitter.emit(
|
||||||
UIEvents.RECORDING_TOGGLED,
|
UIEvents.RECORDING_TOGGLED,
|
||||||
{ token });
|
{ token });
|
||||||
sendEvent('recording.started');
|
sendEvent('recording.started');
|
||||||
}).catch(reason => {
|
})
|
||||||
if (reason !== APP.UI.messageHandler.CANCEL)
|
.catch(reason => {
|
||||||
logger.error(reason);
|
if (reason === APP.UI.messageHandler.CANCEL) {
|
||||||
else
|
|
||||||
sendEvent('recording.canceled');
|
sendEvent('recording.canceled');
|
||||||
|
} else {
|
||||||
|
logger.error(reason);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -521,7 +543,7 @@ var Recording = {
|
||||||
* or not
|
* or not
|
||||||
*/
|
*/
|
||||||
_setToolbarButtonToggled(isToggled) {
|
_setToolbarButtonToggled(isToggled) {
|
||||||
$("#toolbar_button_record").toggleClass("toggled", isToggled);
|
$('#toolbar_button_record').toggleClass('toggled', isToggled);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/* global $, APP, YT, onPlayerReady, onPlayerStateChange, onPlayerError */
|
/* global $, APP, YT, onPlayerReady, onPlayerStateChange, onPlayerError */
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import UIUtil from '../util/UIUtil';
|
import UIUtil from '../util/UIUtil';
|
||||||
import UIEvents from '../../../service/UI/UIEvents';
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
|
|
||||||
import VideoLayout from "../videolayout/VideoLayout";
|
import VideoLayout from '../videolayout/VideoLayout';
|
||||||
import LargeContainer from '../videolayout/LargeContainer';
|
import LargeContainer from '../videolayout/LargeContainer';
|
||||||
import Filmstrip from '../videolayout/Filmstrip';
|
import Filmstrip from '../videolayout/Filmstrip';
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ import { dockToolbox, showToolbox } from '../../../react/features/toolbox';
|
||||||
|
|
||||||
import SharedVideoThumb from './SharedVideoThumb';
|
import SharedVideoThumb from './SharedVideoThumb';
|
||||||
|
|
||||||
export const SHARED_VIDEO_CONTAINER_TYPE = "sharedvideo";
|
export const SHARED_VIDEO_CONTAINER_TYPE = 'sharedvideo';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Example shared video link.
|
* Example shared video link.
|
||||||
* @type {string}
|
* @type {string}
|
||||||
*/
|
*/
|
||||||
const defaultSharedVideoLink = "https://www.youtube.com/watch?v=xNXN7CZk8X0";
|
const defaultSharedVideoLink = 'https://www.youtube.com/watch?v=xNXN7CZk8X0';
|
||||||
const updateInterval = 5000; // milliseconds
|
const updateInterval = 5000; // milliseconds
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,7 +36,10 @@ let dialog = null;
|
||||||
* Manager of shared video.
|
* Manager of shared video.
|
||||||
*/
|
*/
|
||||||
export default class SharedVideoManager {
|
export default class SharedVideoManager {
|
||||||
constructor (emitter) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(emitter) {
|
||||||
this.emitter = emitter;
|
this.emitter = emitter;
|
||||||
this.isSharedVideoShown = false;
|
this.isSharedVideoShown = false;
|
||||||
this.isPlayerAPILoaded = false;
|
this.isPlayerAPILoaded = false;
|
||||||
|
@ -52,10 +55,10 @@ export default class SharedVideoManager {
|
||||||
* currently on.
|
* currently on.
|
||||||
*/
|
*/
|
||||||
isSharedVideoVolumeOn() {
|
isSharedVideoVolumeOn() {
|
||||||
return (this.player
|
return this.player
|
||||||
&& this.player.getPlayerState() === YT.PlayerState.PLAYING
|
&& this.player.getPlayerState() === YT.PlayerState.PLAYING
|
||||||
&& !this.player.isMuted()
|
&& !this.player.isMuted()
|
||||||
&& this.player.getVolume() > 0);
|
&& this.player.getVolume() > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,11 +73,12 @@ export default class SharedVideoManager {
|
||||||
* Starts shared video by asking user for url, or if its already working
|
* Starts shared video by asking user for url, or if its already working
|
||||||
* asks whether the user wants to stop sharing the video.
|
* asks whether the user wants to stop sharing the video.
|
||||||
*/
|
*/
|
||||||
toggleSharedVideo () {
|
toggleSharedVideo() {
|
||||||
if (dialog)
|
if (dialog) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.isSharedVideoShown) {
|
if (!this.isSharedVideoShown) {
|
||||||
requestVideoLink().then(
|
requestVideoLink().then(
|
||||||
url => {
|
url => {
|
||||||
this.emitter.emit(
|
this.emitter.emit(
|
||||||
|
@ -86,10 +90,11 @@ export default class SharedVideoManager {
|
||||||
sendEvent('sharedvideo.canceled');
|
sendEvent('sharedvideo.canceled');
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(APP.conference.isLocalId(this.from)) {
|
if (APP.conference.isLocalId(this.from)) {
|
||||||
showStopVideoPropmpt().then(
|
showStopVideoPropmpt().then(
|
||||||
() => {
|
() => {
|
||||||
// make sure we stop updates for playing before we send stop
|
// make sure we stop updates for playing before we send stop
|
||||||
|
@ -104,13 +109,13 @@ export default class SharedVideoManager {
|
||||||
UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop');
|
UIEvents.UPDATE_SHARED_VIDEO, this.url, 'stop');
|
||||||
sendEvent('sharedvideo.stoped');
|
sendEvent('sharedvideo.stoped');
|
||||||
},
|
},
|
||||||
() => {});
|
() => {}); // eslint-disable-line no-empty-function
|
||||||
} else {
|
} else {
|
||||||
dialog = APP.UI.messageHandler.openMessageDialog(
|
dialog = APP.UI.messageHandler.openMessageDialog(
|
||||||
"dialog.shareVideoTitle",
|
'dialog.shareVideoTitle',
|
||||||
"dialog.alreadySharedVideoMsg",
|
'dialog.alreadySharedVideoMsg',
|
||||||
null,
|
null,
|
||||||
function () {
|
() => {
|
||||||
dialog = null;
|
dialog = null;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -126,9 +131,10 @@ export default class SharedVideoManager {
|
||||||
* @param url the video url
|
* @param url the video url
|
||||||
* @param attributes
|
* @param attributes
|
||||||
*/
|
*/
|
||||||
onSharedVideoStart (id, url, attributes) {
|
onSharedVideoStart(id, url, attributes) {
|
||||||
if (this.isSharedVideoShown)
|
if (this.isSharedVideoShown) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.isSharedVideoShown = true;
|
this.isSharedVideoShown = true;
|
||||||
|
|
||||||
|
@ -140,15 +146,16 @@ export default class SharedVideoManager {
|
||||||
|
|
||||||
this.mutedWithUserInteraction = APP.conference.isLocalAudioMuted();
|
this.mutedWithUserInteraction = APP.conference.isLocalAudioMuted();
|
||||||
|
|
||||||
//listen for local audio mute events
|
// listen for local audio mute events
|
||||||
this.localAudioMutedListener = this.onLocalAudioMuted.bind(this);
|
this.localAudioMutedListener = this.onLocalAudioMuted.bind(this);
|
||||||
this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener);
|
this.emitter.on(UIEvents.AUDIO_MUTED, this.localAudioMutedListener);
|
||||||
|
|
||||||
// This code loads the IFrame Player API code asynchronously.
|
// This code loads the IFrame Player API code asynchronously.
|
||||||
var tag = document.createElement('script');
|
const tag = document.createElement('script');
|
||||||
|
|
||||||
|
tag.src = 'https://www.youtube.com/iframe_api';
|
||||||
|
const firstScriptTag = document.getElementsByTagName('script')[0];
|
||||||
|
|
||||||
tag.src = "https://www.youtube.com/iframe_api";
|
|
||||||
var firstScriptTag = document.getElementsByTagName('script')[0];
|
|
||||||
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
|
||||||
|
|
||||||
// sometimes we receive errors like player not defined
|
// sometimes we receive errors like player not defined
|
||||||
|
@ -158,14 +165,16 @@ export default class SharedVideoManager {
|
||||||
// and will process any initial attributes if any
|
// and will process any initial attributes if any
|
||||||
this.initialAttributes = attributes;
|
this.initialAttributes = attributes;
|
||||||
|
|
||||||
var self = this;
|
const self = this;
|
||||||
if(self.isPlayerAPILoaded)
|
|
||||||
|
if (self.isPlayerAPILoaded) {
|
||||||
window.onYouTubeIframeAPIReady();
|
window.onYouTubeIframeAPIReady();
|
||||||
else
|
} else {
|
||||||
window.onYouTubeIframeAPIReady = function() {
|
window.onYouTubeIframeAPIReady = function() {
|
||||||
self.isPlayerAPILoaded = true;
|
self.isPlayerAPILoaded = true;
|
||||||
let showControls = APP.conference.isLocalId(self.from) ? 1 : 0;
|
const showControls
|
||||||
let p = new YT.Player('sharedVideoIFrame', {
|
= APP.conference.isLocalId(self.from) ? 1 : 0;
|
||||||
|
const p = new YT.Player('sharedVideoIFrame', {
|
||||||
height: '100%',
|
height: '100%',
|
||||||
width: '100%',
|
width: '100%',
|
||||||
videoId: self.url,
|
videoId: self.url,
|
||||||
|
@ -174,7 +183,7 @@ export default class SharedVideoManager {
|
||||||
'fs': '0',
|
'fs': '0',
|
||||||
'autoplay': 0,
|
'autoplay': 0,
|
||||||
'controls': showControls,
|
'controls': showControls,
|
||||||
'rel' : 0
|
'rel': 0
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
'onReady': onPlayerReady,
|
'onReady': onPlayerReady,
|
||||||
|
@ -185,28 +194,28 @@ export default class SharedVideoManager {
|
||||||
|
|
||||||
// add listener for volume changes
|
// add listener for volume changes
|
||||||
p.addEventListener(
|
p.addEventListener(
|
||||||
"onVolumeChange", "onVolumeChange");
|
'onVolumeChange', 'onVolumeChange');
|
||||||
|
|
||||||
if (APP.conference.isLocalId(self.from)){
|
if (APP.conference.isLocalId(self.from)) {
|
||||||
// adds progress listener that will be firing events
|
// adds progress listener that will be firing events
|
||||||
// while we are paused and we change the progress of the
|
// while we are paused and we change the progress of the
|
||||||
// video (seeking forward or backward on the video)
|
// video (seeking forward or backward on the video)
|
||||||
p.addEventListener(
|
p.addEventListener(
|
||||||
"onVideoProgress", "onVideoProgress");
|
'onVideoProgress', 'onVideoProgress');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicates that a change in state has occurred for the shared video.
|
* Indicates that a change in state has occurred for the shared video.
|
||||||
* @param event the event notifying us of the change
|
* @param event the event notifying us of the change
|
||||||
*/
|
*/
|
||||||
window.onPlayerStateChange = function(event) {
|
window.onPlayerStateChange = function(event) {
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
if (event.data == YT.PlayerState.PLAYING) {
|
if (event.data == YT.PlayerState.PLAYING) {
|
||||||
|
|
||||||
self.player = event.target;
|
self.player = event.target;
|
||||||
|
|
||||||
if(self.initialAttributes)
|
if (self.initialAttributes) {
|
||||||
{
|
|
||||||
// If a network update has occurred already now is the
|
// If a network update has occurred already now is the
|
||||||
// time to process it.
|
// time to process it.
|
||||||
self.processVideoUpdate(
|
self.processVideoUpdate(
|
||||||
|
@ -216,10 +225,12 @@ export default class SharedVideoManager {
|
||||||
self.initialAttributes = null;
|
self.initialAttributes = null;
|
||||||
}
|
}
|
||||||
self.smartAudioMute();
|
self.smartAudioMute();
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
} else if (event.data == YT.PlayerState.PAUSED) {
|
} else if (event.data == YT.PlayerState.PAUSED) {
|
||||||
self.smartAudioUnmute();
|
self.smartAudioUnmute();
|
||||||
sendEvent('sharedvideo.paused');
|
sendEvent('sharedvideo.paused');
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED);
|
self.fireSharedVideoEvent(event.data == YT.PlayerState.PAUSED);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -227,8 +238,10 @@ export default class SharedVideoManager {
|
||||||
* Track player progress while paused.
|
* Track player progress while paused.
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
window.onVideoProgress = function (event) {
|
window.onVideoProgress = function(event) {
|
||||||
let state = event.target.getPlayerState();
|
const state = event.target.getPlayerState();
|
||||||
|
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
if (state == YT.PlayerState.PAUSED) {
|
if (state == YT.PlayerState.PAUSED) {
|
||||||
self.fireSharedVideoEvent(true);
|
self.fireSharedVideoEvent(true);
|
||||||
}
|
}
|
||||||
|
@ -238,38 +251,44 @@ export default class SharedVideoManager {
|
||||||
* Gets notified for volume state changed.
|
* Gets notified for volume state changed.
|
||||||
* @param event
|
* @param event
|
||||||
*/
|
*/
|
||||||
window.onVolumeChange = function (event) {
|
window.onVolumeChange = function(event) {
|
||||||
self.fireSharedVideoEvent();
|
self.fireSharedVideoEvent();
|
||||||
|
|
||||||
// let's check, if player is not muted lets mute locally
|
// let's check, if player is not muted lets mute locally
|
||||||
if(event.data.volume > 0 && !event.data.muted) {
|
if (event.data.volume > 0 && !event.data.muted) {
|
||||||
self.smartAudioMute();
|
self.smartAudioMute();
|
||||||
}
|
} else if (event.data.volume <= 0 || event.data.muted) {
|
||||||
else if (event.data.volume <=0 || event.data.muted) {
|
|
||||||
self.smartAudioUnmute();
|
self.smartAudioUnmute();
|
||||||
}
|
}
|
||||||
sendEvent('sharedvideo.volumechanged');
|
sendEvent('sharedvideo.volumechanged');
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onPlayerReady = function(event) {
|
window.onPlayerReady = function(event) {
|
||||||
let player = event.target;
|
const player = event.target;
|
||||||
|
|
||||||
// do not relay on autoplay as it is not sending all of the events
|
// do not relay on autoplay as it is not sending all of the events
|
||||||
// in onPlayerStateChange
|
// in onPlayerStateChange
|
||||||
|
|
||||||
player.playVideo();
|
player.playVideo();
|
||||||
|
|
||||||
let thumb = new SharedVideoThumb(
|
const thumb = new SharedVideoThumb(
|
||||||
self.url, SHARED_VIDEO_CONTAINER_TYPE, VideoLayout);
|
self.url, SHARED_VIDEO_CONTAINER_TYPE, VideoLayout);
|
||||||
|
|
||||||
thumb.setDisplayName(player.getVideoData().title);
|
thumb.setDisplayName(player.getVideoData().title);
|
||||||
VideoLayout.addRemoteVideoContainer(self.url, thumb);
|
VideoLayout.addRemoteVideoContainer(self.url, thumb);
|
||||||
|
|
||||||
let iframe = player.getIframe();
|
const iframe = player.getIframe();
|
||||||
self.sharedVideo = new SharedVideoContainer(
|
|
||||||
{url, iframe, player});
|
|
||||||
|
|
||||||
//prevents pausing participants not sharing the video
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
self.sharedVideo = new SharedVideoContainer(
|
||||||
|
{ url,
|
||||||
|
iframe,
|
||||||
|
player });
|
||||||
|
|
||||||
|
// prevents pausing participants not sharing the video
|
||||||
// to pause the video
|
// to pause the video
|
||||||
if (!APP.conference.isLocalId(self.from)) {
|
if (!APP.conference.isLocalId(self.from)) {
|
||||||
$("#sharedVideo").css("pointer-events","none");
|
$('#sharedVideo').css('pointer-events', 'none');
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoLayout.addLargeVideoContainer(
|
VideoLayout.addLargeVideoContainer(
|
||||||
|
@ -285,7 +304,7 @@ export default class SharedVideoManager {
|
||||||
|
|
||||||
// If we are sending the command and we are starting the player
|
// If we are sending the command and we are starting the player
|
||||||
// we need to continuously send the player current time position
|
// we need to continuously send the player current time position
|
||||||
if(APP.conference.isLocalId(self.from)) {
|
if (APP.conference.isLocalId(self.from)) {
|
||||||
self.intervalId = setInterval(
|
self.intervalId = setInterval(
|
||||||
self.fireSharedVideoEvent.bind(self),
|
self.fireSharedVideoEvent.bind(self),
|
||||||
updateInterval);
|
updateInterval);
|
||||||
|
@ -293,7 +312,8 @@ export default class SharedVideoManager {
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onPlayerError = function(event) {
|
window.onPlayerError = function(event) {
|
||||||
logger.error("Error in the player:", event.data);
|
logger.error('Error in the player:', event.data);
|
||||||
|
|
||||||
// store the error player, so we can remove it
|
// store the error player, so we can remove it
|
||||||
self.errorInPlayer = event.target;
|
self.errorInPlayer = event.target;
|
||||||
};
|
};
|
||||||
|
@ -304,21 +324,23 @@ export default class SharedVideoManager {
|
||||||
* @param player the player to operate over
|
* @param player the player to operate over
|
||||||
* @param attributes the attributes with the player state we want
|
* @param attributes the attributes with the player state we want
|
||||||
*/
|
*/
|
||||||
processVideoUpdate (player, attributes)
|
processVideoUpdate(player, attributes) {
|
||||||
{
|
if (!attributes) {
|
||||||
if(!attributes)
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
if (attributes.state == 'playing') {
|
if (attributes.state == 'playing') {
|
||||||
|
|
||||||
let isPlayerPaused
|
const isPlayerPaused
|
||||||
= (this.player.getPlayerState() === YT.PlayerState.PAUSED);
|
= this.player.getPlayerState() === YT.PlayerState.PAUSED;
|
||||||
|
|
||||||
// If our player is currently paused force the seek.
|
// If our player is currently paused force the seek.
|
||||||
this.processTime(player, attributes, isPlayerPaused);
|
this.processTime(player, attributes, isPlayerPaused);
|
||||||
|
|
||||||
// Process mute.
|
// Process mute.
|
||||||
let isAttrMuted = (attributes.muted === "true");
|
const isAttrMuted = attributes.muted === 'true';
|
||||||
|
|
||||||
if (player.isMuted() !== isAttrMuted) {
|
if (player.isMuted() !== isAttrMuted) {
|
||||||
this.smartPlayerMute(isAttrMuted, true);
|
this.smartPlayerMute(isAttrMuted, true);
|
||||||
}
|
}
|
||||||
|
@ -326,16 +348,18 @@ export default class SharedVideoManager {
|
||||||
// Process volume
|
// Process volume
|
||||||
if (!isAttrMuted
|
if (!isAttrMuted
|
||||||
&& attributes.volume !== undefined
|
&& attributes.volume !== undefined
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
&& player.getVolume() != attributes.volume) {
|
&& player.getVolume() != attributes.volume) {
|
||||||
|
|
||||||
player.setVolume(attributes.volume);
|
player.setVolume(attributes.volume);
|
||||||
logger.info("Player change of volume:" + attributes.volume);
|
logger.info(`Player change of volume:${attributes.volume}`);
|
||||||
this.showSharedVideoMutedPopup(false);
|
this.showSharedVideoMutedPopup(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isPlayerPaused)
|
if (isPlayerPaused) {
|
||||||
player.playVideo();
|
player.playVideo();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
} else if (attributes.state == 'pause') {
|
} else if (attributes.state == 'pause') {
|
||||||
// if its not paused, pause it
|
// if its not paused, pause it
|
||||||
player.pauseVideo();
|
player.pauseVideo();
|
||||||
|
@ -350,23 +374,23 @@ export default class SharedVideoManager {
|
||||||
* @param attributes the attributes with the player state we want
|
* @param attributes the attributes with the player state we want
|
||||||
* @param forceSeek whether seek should be forced
|
* @param forceSeek whether seek should be forced
|
||||||
*/
|
*/
|
||||||
processTime (player, attributes, forceSeek)
|
processTime(player, attributes, forceSeek) {
|
||||||
{
|
if (forceSeek) {
|
||||||
if(forceSeek) {
|
logger.info('Player seekTo:', attributes.time);
|
||||||
logger.info("Player seekTo:", attributes.time);
|
|
||||||
player.seekTo(attributes.time);
|
player.seekTo(attributes.time);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check received time and current time
|
// check received time and current time
|
||||||
let currentPosition = player.getCurrentTime();
|
const currentPosition = player.getCurrentTime();
|
||||||
let diff = Math.abs(attributes.time - currentPosition);
|
const diff = Math.abs(attributes.time - currentPosition);
|
||||||
|
|
||||||
// if we drift more than the interval for checking
|
// if we drift more than the interval for checking
|
||||||
// sync, the interval is in milliseconds
|
// sync, the interval is in milliseconds
|
||||||
if(diff > updateInterval/1000) {
|
if (diff > updateInterval / 1000) {
|
||||||
logger.info("Player seekTo:", attributes.time,
|
logger.info('Player seekTo:', attributes.time,
|
||||||
" current time is:", currentPosition, " diff:", diff);
|
' current time is:', currentPosition, ' diff:', diff);
|
||||||
player.seekTo(attributes.time);
|
player.seekTo(attributes.time);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -374,24 +398,25 @@ export default class SharedVideoManager {
|
||||||
/**
|
/**
|
||||||
* Checks current state of the player and fire an event with the values.
|
* Checks current state of the player and fire an event with the values.
|
||||||
*/
|
*/
|
||||||
fireSharedVideoEvent(sendPauseEvent)
|
fireSharedVideoEvent(sendPauseEvent) {
|
||||||
{
|
|
||||||
// ignore update checks if we are not the owner of the video
|
// ignore update checks if we are not the owner of the video
|
||||||
// or there is still no player defined or we are stopped
|
// or there is still no player defined or we are stopped
|
||||||
// (in a process of stopping)
|
// (in a process of stopping)
|
||||||
if(!APP.conference.isLocalId(this.from) || !this.player
|
if (!APP.conference.isLocalId(this.from) || !this.player
|
||||||
|| !this.isSharedVideoShown)
|
|| !this.isSharedVideoShown) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const state = this.player.getPlayerState();
|
||||||
|
|
||||||
let state = this.player.getPlayerState();
|
|
||||||
// if its paused and haven't been pause - send paused
|
// if its paused and haven't been pause - send paused
|
||||||
|
|
||||||
if (state === YT.PlayerState.PAUSED && sendPauseEvent) {
|
if (state === YT.PlayerState.PAUSED && sendPauseEvent) {
|
||||||
this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
|
this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
|
||||||
this.url, 'pause', this.player.getCurrentTime());
|
this.url, 'pause', this.player.getCurrentTime());
|
||||||
}
|
} else if (state === YT.PlayerState.PLAYING) {
|
||||||
// if its playing and it was paused - send update with time
|
// if its playing and it was paused - send update with time
|
||||||
// if its playing and was playing just send update with time
|
// if its playing and was playing just send update with time
|
||||||
else if (state === YT.PlayerState.PLAYING) {
|
|
||||||
this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
|
this.emitter.emit(UIEvents.UPDATE_SHARED_VIDEO,
|
||||||
this.url, 'playing',
|
this.url, 'playing',
|
||||||
this.player.getCurrentTime(),
|
this.player.getCurrentTime(),
|
||||||
|
@ -407,20 +432,22 @@ export default class SharedVideoManager {
|
||||||
* @param url the video url
|
* @param url the video url
|
||||||
* @param attributes
|
* @param attributes
|
||||||
*/
|
*/
|
||||||
onSharedVideoUpdate (id, url, attributes) {
|
onSharedVideoUpdate(id, url, attributes) {
|
||||||
// if we are sending the event ignore
|
// if we are sending the event ignore
|
||||||
if(APP.conference.isLocalId(this.from)) {
|
if (APP.conference.isLocalId(this.from)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.isSharedVideoShown) {
|
if (!this.isSharedVideoShown) {
|
||||||
this.onSharedVideoStart(id, url, attributes);
|
this.onSharedVideoStart(id, url, attributes);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!this.player)
|
// eslint-disable-next-line no-negated-condition
|
||||||
|
if (!this.player) {
|
||||||
this.initialAttributes = attributes;
|
this.initialAttributes = attributes;
|
||||||
else {
|
} else {
|
||||||
this.processVideoUpdate(this.player, attributes);
|
this.processVideoUpdate(this.player, attributes);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,18 +458,21 @@ export default class SharedVideoManager {
|
||||||
* left and we want to remove video if the user sharing it left).
|
* left and we want to remove video if the user sharing it left).
|
||||||
* @param id the id of the sender of the command
|
* @param id the id of the sender of the command
|
||||||
*/
|
*/
|
||||||
onSharedVideoStop (id, attributes) {
|
onSharedVideoStop(id, attributes) {
|
||||||
if (!this.isSharedVideoShown)
|
if (!this.isSharedVideoShown) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(this.from !== id)
|
if (this.from !== id) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.player) {
|
if (!this.player) {
|
||||||
// if there is no error in the player till now,
|
// if there is no error in the player till now,
|
||||||
// store the initial attributes
|
// store the initial attributes
|
||||||
if (!this.errorInPlayer) {
|
if (!this.errorInPlayer) {
|
||||||
this.initialAttributes = attributes;
|
this.initialAttributes = attributes;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -458,18 +488,19 @@ export default class SharedVideoManager {
|
||||||
VideoLayout.removeLargeVideoContainer(
|
VideoLayout.removeLargeVideoContainer(
|
||||||
SHARED_VIDEO_CONTAINER_TYPE);
|
SHARED_VIDEO_CONTAINER_TYPE);
|
||||||
|
|
||||||
if(this.player) {
|
if (this.player) {
|
||||||
this.player.destroy();
|
this.player.destroy();
|
||||||
this.player = null;
|
this.player = null;
|
||||||
} // if there is an error in player, remove that instance
|
} else if (this.errorInPlayer) {
|
||||||
else if (this.errorInPlayer) {
|
// if there is an error in player, remove that instance
|
||||||
this.errorInPlayer.destroy();
|
this.errorInPlayer.destroy();
|
||||||
this.errorInPlayer = null;
|
this.errorInPlayer = null;
|
||||||
}
|
}
|
||||||
this.smartAudioUnmute();
|
this.smartAudioUnmute();
|
||||||
|
|
||||||
// revert to original behavior (prevents pausing
|
// revert to original behavior (prevents pausing
|
||||||
// for participants not sharing the video to pause it)
|
// for participants not sharing the video to pause it)
|
||||||
$("#sharedVideo").css("pointer-events","auto");
|
$('#sharedVideo').css('pointer-events', 'auto');
|
||||||
|
|
||||||
this.emitter.emit(
|
this.emitter.emit(
|
||||||
UIEvents.UPDATE_SHARED_VIDEO, null, 'removed');
|
UIEvents.UPDATE_SHARED_VIDEO, null, 'removed');
|
||||||
|
@ -488,15 +519,16 @@ export default class SharedVideoManager {
|
||||||
* @param {boolean} indicates if this mute was a result of user interaction,
|
* @param {boolean} indicates if this mute was a result of user interaction,
|
||||||
* i.e. pressing the mute button or it was programatically triggerred
|
* i.e. pressing the mute button or it was programatically triggerred
|
||||||
*/
|
*/
|
||||||
onLocalAudioMuted (muted, userInteraction) {
|
onLocalAudioMuted(muted, userInteraction) {
|
||||||
if(!this.player)
|
if (!this.player) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (muted) {
|
if (muted) {
|
||||||
this.mutedWithUserInteraction = userInteraction;
|
this.mutedWithUserInteraction = userInteraction;
|
||||||
}
|
} else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) {
|
||||||
else if (this.player.getPlayerState() !== YT.PlayerState.PAUSED) {
|
|
||||||
this.smartPlayerMute(true, false);
|
this.smartPlayerMute(true, false);
|
||||||
|
|
||||||
// Check if we need to update other participants
|
// Check if we need to update other participants
|
||||||
this.fireSharedVideoEvent();
|
this.fireSharedVideoEvent();
|
||||||
}
|
}
|
||||||
|
@ -512,13 +544,14 @@ export default class SharedVideoManager {
|
||||||
if (!this.player.isMuted() && mute) {
|
if (!this.player.isMuted() && mute) {
|
||||||
this.player.mute();
|
this.player.mute();
|
||||||
|
|
||||||
if (isVideoUpdate)
|
if (isVideoUpdate) {
|
||||||
this.smartAudioUnmute();
|
this.smartAudioUnmute();
|
||||||
}
|
}
|
||||||
else if (this.player.isMuted() && !mute) {
|
} else if (this.player.isMuted() && !mute) {
|
||||||
this.player.unMute();
|
this.player.unMute();
|
||||||
if (isVideoUpdate)
|
if (isVideoUpdate) {
|
||||||
this.smartAudioMute();
|
this.smartAudioMute();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.showSharedVideoMutedPopup(mute);
|
this.showSharedVideoMutedPopup(mute);
|
||||||
|
@ -533,7 +566,7 @@ export default class SharedVideoManager {
|
||||||
if (APP.conference.isLocalAudioMuted()
|
if (APP.conference.isLocalAudioMuted()
|
||||||
&& !this.mutedWithUserInteraction
|
&& !this.mutedWithUserInteraction
|
||||||
&& !this.isSharedVideoVolumeOn()) {
|
&& !this.isSharedVideoVolumeOn()) {
|
||||||
sendEvent("sharedvideo.audio.unmuted");
|
sendEvent('sharedvideo.audio.unmuted');
|
||||||
logger.log('Shared video: audio unmuted');
|
logger.log('Shared video: audio unmuted');
|
||||||
this.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
|
this.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
|
||||||
this.showMicMutedPopup(false);
|
this.showMicMutedPopup(false);
|
||||||
|
@ -547,7 +580,7 @@ export default class SharedVideoManager {
|
||||||
smartAudioMute() {
|
smartAudioMute() {
|
||||||
if (!APP.conference.isLocalAudioMuted()
|
if (!APP.conference.isLocalAudioMuted()
|
||||||
&& this.isSharedVideoVolumeOn()) {
|
&& this.isSharedVideoVolumeOn()) {
|
||||||
sendEvent("sharedvideo.audio.muted");
|
sendEvent('sharedvideo.audio.muted');
|
||||||
logger.log('Shared video: audio muted');
|
logger.log('Shared video: audio muted');
|
||||||
this.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
|
this.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
|
||||||
this.showMicMutedPopup(true);
|
this.showMicMutedPopup(true);
|
||||||
|
@ -559,9 +592,10 @@ export default class SharedVideoManager {
|
||||||
* of automatic mute after a shared video has started.
|
* of automatic mute after a shared video has started.
|
||||||
* @param show boolean, show or hide the notification
|
* @param show boolean, show or hide the notification
|
||||||
*/
|
*/
|
||||||
showMicMutedPopup (show) {
|
showMicMutedPopup(show) {
|
||||||
if(show)
|
if (show) {
|
||||||
this.showSharedVideoMutedPopup(false);
|
this.showSharedVideoMutedPopup(false);
|
||||||
|
}
|
||||||
|
|
||||||
APP.UI.showCustomToolbarPopup(
|
APP.UI.showCustomToolbarPopup(
|
||||||
'microphone', 'micMutedPopup', show, 5000);
|
'microphone', 'micMutedPopup', show, 5000);
|
||||||
|
@ -573,9 +607,10 @@ export default class SharedVideoManager {
|
||||||
* mic.
|
* mic.
|
||||||
* @param show boolean, show or hide the notification
|
* @param show boolean, show or hide the notification
|
||||||
*/
|
*/
|
||||||
showSharedVideoMutedPopup (show) {
|
showSharedVideoMutedPopup(show) {
|
||||||
if(show)
|
if (show) {
|
||||||
this.showMicMutedPopup(false);
|
this.showMicMutedPopup(false);
|
||||||
|
}
|
||||||
|
|
||||||
APP.UI.showCustomToolbarPopup(
|
APP.UI.showCustomToolbarPopup(
|
||||||
'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
|
'sharedvideo', 'sharedVideoMutedPopup', show, 5000);
|
||||||
|
@ -586,8 +621,10 @@ export default class SharedVideoManager {
|
||||||
* Container for shared video iframe.
|
* Container for shared video iframe.
|
||||||
*/
|
*/
|
||||||
class SharedVideoContainer extends LargeContainer {
|
class SharedVideoContainer extends LargeContainer {
|
||||||
|
/**
|
||||||
constructor ({url, iframe, player}) {
|
*
|
||||||
|
*/
|
||||||
|
constructor({ url, iframe, player }) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.$iframe = $(iframe);
|
this.$iframe = $(iframe);
|
||||||
|
@ -595,43 +632,62 @@ class SharedVideoContainer extends LargeContainer {
|
||||||
this.player = player;
|
this.player = player;
|
||||||
}
|
}
|
||||||
|
|
||||||
show () {
|
/**
|
||||||
let self = this;
|
*
|
||||||
|
*/
|
||||||
|
show() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$iframe.fadeIn(300, () => {
|
this.$iframe.fadeIn(300, () => {
|
||||||
self.bodyBackground = document.body.style.background;
|
self.bodyBackground = document.body.style.background;
|
||||||
document.body.style.background = 'black';
|
document.body.style.background = 'black';
|
||||||
this.$iframe.css({opacity: 1});
|
this.$iframe.css({ opacity: 1 });
|
||||||
APP.store.dispatch(dockToolbox(true));
|
APP.store.dispatch(dockToolbox(true));
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
/**
|
||||||
let self = this;
|
*
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
|
const self = this;
|
||||||
|
|
||||||
APP.store.dispatch(dockToolbox(false));
|
APP.store.dispatch(dockToolbox(false));
|
||||||
|
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$iframe.fadeOut(300, () => {
|
this.$iframe.fadeOut(300, () => {
|
||||||
document.body.style.background = self.bodyBackground;
|
document.body.style.background = self.bodyBackground;
|
||||||
this.$iframe.css({opacity: 0});
|
this.$iframe.css({ opacity: 0 });
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoverIn () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onHoverIn() {
|
||||||
APP.store.dispatch(showToolbox());
|
APP.store.dispatch(showToolbox());
|
||||||
}
|
}
|
||||||
|
|
||||||
get id () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
return this.url;
|
return this.url;
|
||||||
}
|
}
|
||||||
|
|
||||||
resize (containerWidth, containerHeight) {
|
/**
|
||||||
let height = containerHeight - Filmstrip.getFilmstripHeight();
|
*
|
||||||
|
*/
|
||||||
|
resize(containerWidth, containerHeight) {
|
||||||
|
const height = containerHeight - Filmstrip.getFilmstripHeight();
|
||||||
|
|
||||||
let width = containerWidth;
|
const width = containerWidth;
|
||||||
|
|
||||||
this.$iframe.width(width).height(height);
|
this.$iframe.width(width).height(height);
|
||||||
}
|
}
|
||||||
|
@ -639,7 +695,7 @@ class SharedVideoContainer extends LargeContainer {
|
||||||
/**
|
/**
|
||||||
* @return {boolean} do not switch on dominant speaker event if on stage.
|
* @return {boolean} do not switch on dominant speaker event if on stage.
|
||||||
*/
|
*/
|
||||||
stayOnStage () {
|
stayOnStage() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -650,16 +706,18 @@ class SharedVideoContainer extends LargeContainer {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
function getYoutubeLink(url) {
|
function getYoutubeLink(url) {
|
||||||
let p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;//jshint ignore:line
|
const p = /^(?:https?:\/\/)?(?:www\.)?(?:youtu\.be\/|youtube\.com\/(?:embed\/|v\/|watch\?v=|watch\?.+&v=))((\w|-){11})(?:\S+)?$/;// eslint-disable-line max-len
|
||||||
return (url.match(p)) ? RegExp.$1 : false;
|
|
||||||
|
|
||||||
|
return url.match(p) ? RegExp.$1 : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ask user if he want to close shared video.
|
* Ask user if he want to close shared video.
|
||||||
*/
|
*/
|
||||||
function showStopVideoPropmpt() {
|
function showStopVideoPropmpt() {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
let submitFunction = function(e,v) {
|
const submitFunction = function(e, v) {
|
||||||
if (v) {
|
if (v) {
|
||||||
resolve();
|
resolve();
|
||||||
} else {
|
} else {
|
||||||
|
@ -667,14 +725,14 @@ function showStopVideoPropmpt() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let closeFunction = function () {
|
const closeFunction = function() {
|
||||||
dialog = null;
|
dialog = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
dialog = APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
titleKey: "dialog.removeSharedVideoTitle",
|
titleKey: 'dialog.removeSharedVideoTitle',
|
||||||
msgKey: "dialog.removeSharedVideoMsg",
|
msgKey: 'dialog.removeSharedVideoMsg',
|
||||||
leftButtonKey: "dialog.Remove",
|
leftButtonKey: 'dialog.Remove',
|
||||||
submitFunction,
|
submitFunction,
|
||||||
closeFunction
|
closeFunction
|
||||||
});
|
});
|
||||||
|
@ -686,46 +744,53 @@ function showStopVideoPropmpt() {
|
||||||
* Dialog validates client input to allow only youtube urls.
|
* Dialog validates client input to allow only youtube urls.
|
||||||
*/
|
*/
|
||||||
function requestVideoLink() {
|
function requestVideoLink() {
|
||||||
let i18n = APP.translation;
|
const i18n = APP.translation;
|
||||||
const cancelButton = i18n.generateTranslationHTML("dialog.Cancel");
|
const cancelButton = i18n.generateTranslationHTML('dialog.Cancel');
|
||||||
const shareButton = i18n.generateTranslationHTML("dialog.Share");
|
const shareButton = i18n.generateTranslationHTML('dialog.Share');
|
||||||
const backButton = i18n.generateTranslationHTML("dialog.Back");
|
const backButton = i18n.generateTranslationHTML('dialog.Back');
|
||||||
const linkError
|
const linkError
|
||||||
= i18n.generateTranslationHTML("dialog.shareVideoLinkError");
|
= i18n.generateTranslationHTML('dialog.shareVideoLinkError');
|
||||||
|
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise((resolve, reject) => {
|
||||||
dialog = APP.UI.messageHandler.openDialogWithStates({
|
dialog = APP.UI.messageHandler.openDialogWithStates({
|
||||||
state0: {
|
state0: {
|
||||||
titleKey: "dialog.shareVideoTitle",
|
titleKey: 'dialog.shareVideoTitle',
|
||||||
html: `
|
html: `
|
||||||
<input name="sharedVideoUrl" type="text"
|
<input name='sharedVideoUrl' type='text'
|
||||||
class="input-control"
|
class='input-control'
|
||||||
data-i18n="[placeholder]defaultLink"
|
data-i18n='[placeholder]defaultLink'
|
||||||
autofocus>`,
|
autofocus>`,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{ title: cancelButton,
|
||||||
{title: shareButton, value: true}
|
value: false },
|
||||||
|
{ title: shareButton,
|
||||||
|
value: true }
|
||||||
],
|
],
|
||||||
focus: ':input:first',
|
focus: ':input:first',
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
submit: function (e, v, m, f) {
|
submit(e, v, m, f) { // eslint-disable-line max-params
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (!v) {
|
if (!v) {
|
||||||
reject('cancelled');
|
reject('cancelled');
|
||||||
dialog.close();
|
dialog.close();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let sharedVideoUrl = f.sharedVideoUrl;
|
const sharedVideoUrl = f.sharedVideoUrl;
|
||||||
|
|
||||||
if (!sharedVideoUrl) {
|
if (!sharedVideoUrl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let urlValue = encodeURI(UIUtil.escapeHtml(sharedVideoUrl));
|
const urlValue
|
||||||
let yVideoId = getYoutubeLink(urlValue);
|
= encodeURI(UIUtil.escapeHtml(sharedVideoUrl));
|
||||||
|
const yVideoId = getYoutubeLink(urlValue);
|
||||||
|
|
||||||
if (!yVideoId) {
|
if (!yVideoId) {
|
||||||
dialog.goToState('state1');
|
dialog.goToState('state1');
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -735,16 +800,18 @@ function requestVideoLink() {
|
||||||
},
|
},
|
||||||
|
|
||||||
state1: {
|
state1: {
|
||||||
titleKey: "dialog.shareVideoTitle",
|
titleKey: 'dialog.shareVideoTitle',
|
||||||
html: linkError,
|
html: linkError,
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: [
|
buttons: [
|
||||||
{title: cancelButton, value: false},
|
{ title: cancelButton,
|
||||||
{title: backButton, value: true}
|
value: false },
|
||||||
|
{ title: backButton,
|
||||||
|
value: true }
|
||||||
],
|
],
|
||||||
focus: ':input:first',
|
focus: ':input:first',
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
submit: function (e, v) {
|
submit(e, v) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (v === 0) {
|
if (v === 0) {
|
||||||
reject();
|
reject();
|
||||||
|
@ -755,7 +822,7 @@ function requestVideoLink() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
close: function () {
|
close() {
|
||||||
dialog = null;
|
dialog = null;
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
import SmallVideo from '../videolayout/SmallVideo';
|
import SmallVideo from '../videolayout/SmallVideo';
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
export default function SharedVideoThumb (url, videoType, VideoLayout)
|
/**
|
||||||
{
|
*
|
||||||
|
*/
|
||||||
|
export default function SharedVideoThumb(url, videoType, VideoLayout) {
|
||||||
this.id = url;
|
this.id = url;
|
||||||
|
|
||||||
this.url = url;
|
this.url = url;
|
||||||
this.setVideoType(videoType);
|
this.setVideoType(videoType);
|
||||||
this.videoSpanId = "sharedVideoContainer";
|
this.videoSpanId = 'sharedVideoContainer';
|
||||||
this.container = this.createContainer(this.videoSpanId);
|
this.container = this.createContainer(this.videoSpanId);
|
||||||
this.$container = $(this.container);
|
this.$container = $(this.container);
|
||||||
this.container.onclick = this.videoClick.bind(this);
|
this.container.onclick = this.videoClick.bind(this);
|
||||||
|
@ -23,42 +25,48 @@ SharedVideoThumb.prototype.constructor = SharedVideoThumb;
|
||||||
/**
|
/**
|
||||||
* hide display name
|
* hide display name
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line no-empty-function
|
||||||
|
SharedVideoThumb.prototype.setDeviceAvailabilityIcons = function() {};
|
||||||
|
|
||||||
SharedVideoThumb.prototype.setDeviceAvailabilityIcons = function () {};
|
// eslint-disable-next-line no-empty-function
|
||||||
|
SharedVideoThumb.prototype.avatarChanged = function() {};
|
||||||
|
|
||||||
SharedVideoThumb.prototype.avatarChanged = function () {};
|
SharedVideoThumb.prototype.createContainer = function(spanId) {
|
||||||
|
const container = document.createElement('span');
|
||||||
|
|
||||||
SharedVideoThumb.prototype.createContainer = function (spanId) {
|
|
||||||
var container = document.createElement('span');
|
|
||||||
container.id = spanId;
|
container.id = spanId;
|
||||||
container.className = 'videocontainer';
|
container.className = 'videocontainer';
|
||||||
|
|
||||||
// add the avatar
|
// add the avatar
|
||||||
var avatar = document.createElement('img');
|
const avatar = document.createElement('img');
|
||||||
|
|
||||||
avatar.className = 'sharedVideoAvatar';
|
avatar.className = 'sharedVideoAvatar';
|
||||||
avatar.src = "https://img.youtube.com/vi/" + this.url + "/0.jpg";
|
avatar.src = `https://img.youtube.com/vi/${this.url}/0.jpg`;
|
||||||
container.appendChild(avatar);
|
container.appendChild(avatar);
|
||||||
|
|
||||||
const displayNameContainer = document.createElement('div');
|
const displayNameContainer = document.createElement('div');
|
||||||
|
|
||||||
displayNameContainer.className = 'displayNameContainer';
|
displayNameContainer.className = 'displayNameContainer';
|
||||||
container.appendChild(displayNameContainer);
|
container.appendChild(displayNameContainer);
|
||||||
|
|
||||||
var remotes = document.getElementById('filmstripRemoteVideosContainer');
|
const remotes = document.getElementById('filmstripRemoteVideosContainer');
|
||||||
|
|
||||||
|
|
||||||
return remotes.appendChild(container);
|
return remotes.appendChild(container);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The thumb click handler.
|
* The thumb click handler.
|
||||||
*/
|
*/
|
||||||
SharedVideoThumb.prototype.videoClick = function () {
|
SharedVideoThumb.prototype.videoClick = function() {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.url);
|
this.VideoLayout.handleVideoThumbClicked(this.url);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes RemoteVideo from the page.
|
* Removes RemoteVideo from the page.
|
||||||
*/
|
*/
|
||||||
SharedVideoThumb.prototype.remove = function () {
|
SharedVideoThumb.prototype.remove = function() {
|
||||||
logger.log("Remove shared video thumb", this.id);
|
logger.log('Remove shared video thumb', this.id);
|
||||||
|
|
||||||
// Make sure that the large video is updated if are removing its
|
// Make sure that the large video is updated if are removing its
|
||||||
// corresponding small video.
|
// corresponding small video.
|
||||||
|
@ -75,8 +83,9 @@ SharedVideoThumb.prototype.remove = function () {
|
||||||
*/
|
*/
|
||||||
SharedVideoThumb.prototype.setDisplayName = function(displayName) {
|
SharedVideoThumb.prototype.setDisplayName = function(displayName) {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
logger.warn( "Unable to set displayName - " + this.videoSpanId +
|
logger.warn(`Unable to set displayName - ${this.videoSpanId
|
||||||
" does not exist");
|
} does not exist`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* global $ */
|
/* global $ */
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles open and close of the extended toolbar side panel
|
* Handles open and close of the extended toolbar side panel
|
||||||
|
@ -19,22 +19,28 @@ const SideContainerToggler = {
|
||||||
// We may not have a side toolbar container, for example, in
|
// We may not have a side toolbar container, for example, in
|
||||||
// filmstrip-only mode.
|
// filmstrip-only mode.
|
||||||
const sideToolbarContainer
|
const sideToolbarContainer
|
||||||
= document.getElementById("sideToolbarContainer");
|
= document.getElementById('sideToolbarContainer');
|
||||||
|
|
||||||
if (!sideToolbarContainer)
|
if (!sideToolbarContainer) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Adds a listener for the animationend event that would take care of
|
// Adds a listener for the animationend event that would take care of
|
||||||
// hiding all internal containers when the extendedToolbarPanel is
|
// hiding all internal containers when the extendedToolbarPanel is
|
||||||
// closed.
|
// closed.
|
||||||
sideToolbarContainer.addEventListener(
|
sideToolbarContainer.addEventListener(
|
||||||
"animationend",
|
'animationend',
|
||||||
function(e) {
|
e => {
|
||||||
if (e.animationName === "slideOutExt")
|
if (e.animationName === 'slideOutExt') {
|
||||||
$("#sideToolbarContainer").children().each(function() {
|
$('#sideToolbarContainer').children()
|
||||||
if ($(this).hasClass("show"))
|
.each(function() {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
if ($(this).hasClass('show')) {
|
||||||
SideContainerToggler.hideInnerContainer($(this));
|
SideContainerToggler.hideInnerContainer($(this));
|
||||||
|
}
|
||||||
|
/* eslint-enable no-invalid-this */
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
false);
|
false);
|
||||||
},
|
},
|
||||||
|
@ -46,21 +52,26 @@ const SideContainerToggler = {
|
||||||
* toggle
|
* toggle
|
||||||
*/
|
*/
|
||||||
toggle(elementId) {
|
toggle(elementId) {
|
||||||
let elementSelector = $(`#${elementId}`);
|
const elementSelector = $(`#${elementId}`);
|
||||||
let isSelectorVisible = elementSelector.hasClass("show");
|
const isSelectorVisible = elementSelector.hasClass('show');
|
||||||
|
|
||||||
if (isSelectorVisible) {
|
if (isSelectorVisible) {
|
||||||
this.hide();
|
this.hide();
|
||||||
}
|
} else {
|
||||||
else {
|
if (this.isVisible()) {
|
||||||
if (this.isVisible())
|
$('#sideToolbarContainer').children()
|
||||||
$("#sideToolbarContainer").children().each(function() {
|
.each(function() {
|
||||||
if ($(this).id !== elementId && $(this).hasClass("show"))
|
/* eslint-disable no-invalid-this */
|
||||||
|
if ($(this).id !== elementId && $(this).hasClass('show')) {
|
||||||
SideContainerToggler.hideInnerContainer($(this));
|
SideContainerToggler.hideInnerContainer($(this));
|
||||||
|
}
|
||||||
|
/* eslint-enable no-invalid-this */
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.isVisible())
|
if (!this.isVisible()) {
|
||||||
this.show();
|
this.show();
|
||||||
|
}
|
||||||
|
|
||||||
this.showInnerContainer(elementSelector);
|
this.showInnerContainer(elementSelector);
|
||||||
}
|
}
|
||||||
|
@ -71,7 +82,7 @@ const SideContainerToggler = {
|
||||||
* otherwise returns {false}.
|
* otherwise returns {false}.
|
||||||
*/
|
*/
|
||||||
isVisible() {
|
isVisible() {
|
||||||
return $("#sideToolbarContainer").hasClass("slideInExt");
|
return $('#sideToolbarContainer').hasClass('slideInExt');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,24 +90,27 @@ const SideContainerToggler = {
|
||||||
* {false} otherwise.
|
* {false} otherwise.
|
||||||
*/
|
*/
|
||||||
isHovered() {
|
isHovered() {
|
||||||
return $("#sideToolbarContainer:hover").length > 0;
|
return $('#sideToolbarContainer:hover').length > 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hides the side toolbar panel with a slide out animation.
|
* Hides the side toolbar panel with a slide out animation.
|
||||||
*/
|
*/
|
||||||
hide() {
|
hide() {
|
||||||
$("#sideToolbarContainer")
|
$('#sideToolbarContainer')
|
||||||
.removeClass("slideInExt").addClass("slideOutExt");
|
.removeClass('slideInExt')
|
||||||
|
.addClass('slideOutExt');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows the side toolbar panel with a slide in animation.
|
* Shows the side toolbar panel with a slide in animation.
|
||||||
*/
|
*/
|
||||||
show() {
|
show() {
|
||||||
if (!this.isVisible())
|
if (!this.isVisible()) {
|
||||||
$("#sideToolbarContainer")
|
$('#sideToolbarContainer')
|
||||||
.removeClass("slideOutExt").addClass("slideInExt");
|
.removeClass('slideOutExt')
|
||||||
|
.addClass('slideInExt');
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,7 +120,7 @@ const SideContainerToggler = {
|
||||||
* element to hide
|
* element to hide
|
||||||
*/
|
*/
|
||||||
hideInnerContainer(containerSelector) {
|
hideInnerContainer(containerSelector) {
|
||||||
containerSelector.removeClass("show").addClass("hide");
|
containerSelector.removeClass('show').addClass('hide');
|
||||||
|
|
||||||
this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
||||||
containerSelector.attr('id'), false);
|
containerSelector.attr('id'), false);
|
||||||
|
@ -124,12 +138,16 @@ const SideContainerToggler = {
|
||||||
// If we quickly show a container, while another one is animating
|
// If we quickly show a container, while another one is animating
|
||||||
// and animation never ends, so we do not really hide the first one and
|
// and animation never ends, so we do not really hide the first one and
|
||||||
// we end up with to shown panels
|
// we end up with to shown panels
|
||||||
$("#sideToolbarContainer").children().each(function() {
|
$('#sideToolbarContainer').children()
|
||||||
if ($(this).hasClass("show"))
|
.each(function() {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
|
if ($(this).hasClass('show')) {
|
||||||
SideContainerToggler.hideInnerContainer($(this));
|
SideContainerToggler.hideInnerContainer($(this));
|
||||||
|
}
|
||||||
|
/* eslint-enable no-invalid-this */
|
||||||
});
|
});
|
||||||
|
|
||||||
containerSelector.removeClass("hide").addClass("show");
|
containerSelector.removeClass('hide').addClass('show');
|
||||||
|
|
||||||
this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
this.eventEmitter.emit(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
||||||
containerSelector.attr('id'), true);
|
containerSelector.attr('id'), true);
|
||||||
|
@ -138,9 +156,9 @@ const SideContainerToggler = {
|
||||||
/**
|
/**
|
||||||
* TO FIX: do we need to resize the chat?
|
* TO FIX: do we need to resize the chat?
|
||||||
*/
|
*/
|
||||||
resize () {
|
resize() {
|
||||||
//let [width, height] = UIUtil.getSidePanelSize();
|
// let [width, height] = UIUtil.getSidePanelSize();
|
||||||
//Chat.resizeChat(width, height);
|
// Chat.resizeChat(width, height);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ import ContactListView from './contactlist/ContactListView';
|
||||||
import { isButtonEnabled } from '../../../react/features/toolbox';
|
import { isButtonEnabled } from '../../../react/features/toolbox';
|
||||||
|
|
||||||
const SidePanels = {
|
const SidePanels = {
|
||||||
init (eventEmitter) {
|
init(eventEmitter) {
|
||||||
// Initialize chat
|
// Initialize chat
|
||||||
if (isButtonEnabled('chat')) {
|
if (isButtonEnabled('chat')) {
|
||||||
Chat.init(eventEmitter);
|
Chat.init(eventEmitter);
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* global APP, $ */
|
/* global APP, $ */
|
||||||
|
|
||||||
import {processReplacements, linkify} from './Replacement';
|
import { processReplacements, linkify } from './Replacement';
|
||||||
import CommandsProcessor from './Commands';
|
import CommandsProcessor from './Commands';
|
||||||
import VideoLayout from "../../videolayout/VideoLayout";
|
import VideoLayout from '../../videolayout/VideoLayout';
|
||||||
|
|
||||||
import UIUtil from '../../util/UIUtil';
|
import UIUtil from '../../util/UIUtil';
|
||||||
import UIEvents from '../../../../service/UI/UIEvents';
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
|
@ -36,6 +36,9 @@ const htmlStr = `
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initHTML() {
|
function initHTML() {
|
||||||
$(`#${sidePanelsContainerId}`)
|
$(`#${sidePanelsContainerId}`)
|
||||||
.append(htmlStr);
|
.append(htmlStr);
|
||||||
|
@ -44,7 +47,7 @@ function initHTML() {
|
||||||
/**
|
/**
|
||||||
* The container id, which is and the element id.
|
* The container id, which is and the element id.
|
||||||
*/
|
*/
|
||||||
var CHAT_CONTAINER_ID = "chat_container";
|
const CHAT_CONTAINER_ID = 'chat_container';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates visual notification, indicating that a message has arrived.
|
* Updates visual notification, indicating that a message has arrived.
|
||||||
|
@ -66,19 +69,15 @@ function updateVisualNotification() {
|
||||||
= document.getElementById('toolbar_button_chat');
|
= document.getElementById('toolbar_button_chat');
|
||||||
const leftIndent
|
const leftIndent
|
||||||
= (UIUtil.getTextWidth(chatButtonElement)
|
= (UIUtil.getTextWidth(chatButtonElement)
|
||||||
- UIUtil.getTextWidth(unreadMsgElement))
|
- UIUtil.getTextWidth(unreadMsgElement)) / 2;
|
||||||
/ 2;
|
|
||||||
const topIndent
|
const topIndent
|
||||||
= (UIUtil.getTextHeight(chatButtonElement)
|
= ((UIUtil.getTextHeight(chatButtonElement)
|
||||||
- UIUtil.getTextHeight(unreadMsgElement))
|
- UIUtil.getTextHeight(unreadMsgElement)) / 2) - 5;
|
||||||
/ 2
|
|
||||||
- 5;
|
|
||||||
|
|
||||||
unreadMsgElement.setAttribute(
|
unreadMsgElement.setAttribute(
|
||||||
'style',
|
'style',
|
||||||
'top:' + topIndent + '; left:' + leftIndent + ';');
|
`top:${topIndent}; left:${leftIndent};`);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
unreadMsgSelector.html('');
|
unreadMsgSelector.html('');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -93,37 +92,49 @@ function updateVisualNotification() {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function getCurrentTime(stamp) {
|
function getCurrentTime(stamp) {
|
||||||
var now = (stamp? new Date(stamp): new Date());
|
const now = stamp ? new Date(stamp) : new Date();
|
||||||
var hour = now.getHours();
|
let hour = now.getHours();
|
||||||
var minute = now.getMinutes();
|
let minute = now.getMinutes();
|
||||||
var second = now.getSeconds();
|
let second = now.getSeconds();
|
||||||
if(hour.toString().length === 1) {
|
|
||||||
hour = '0'+hour;
|
if (hour.toString().length === 1) {
|
||||||
|
hour = `0${hour}`;
|
||||||
}
|
}
|
||||||
if(minute.toString().length === 1) {
|
if (minute.toString().length === 1) {
|
||||||
minute = '0'+minute;
|
minute = `0${minute}`;
|
||||||
}
|
}
|
||||||
if(second.toString().length === 1) {
|
if (second.toString().length === 1) {
|
||||||
second = '0'+second;
|
second = `0${second}`;
|
||||||
}
|
}
|
||||||
return hour+':'+minute+':'+second;
|
|
||||||
|
return `${hour}:${minute}:${second}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function toggleSmileys() {
|
function toggleSmileys() {
|
||||||
var smileys = $('#smileysContainer');
|
const smileys = $('#smileysContainer'); // eslint-disable-line no-shadow
|
||||||
if(!smileys.is(':visible')) {
|
|
||||||
smileys.show("slide", { direction: "down", duration: 300});
|
if (smileys.is(':visible')) {
|
||||||
|
smileys.hide('slide', { direction: 'down',
|
||||||
|
duration: 300 });
|
||||||
} else {
|
} else {
|
||||||
smileys.hide("slide", { direction: "down", duration: 300});
|
smileys.show('slide', { direction: 'down',
|
||||||
|
duration: 300 });
|
||||||
}
|
}
|
||||||
$('#usermsg').focus();
|
$('#usermsg').focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function addClickFunction(smiley, number) {
|
function addClickFunction(smiley, number) {
|
||||||
smiley.onclick = function addSmileyToMessage() {
|
smiley.onclick = function addSmileyToMessage() {
|
||||||
var usermsg = $('#usermsg');
|
const usermsg = $('#usermsg');
|
||||||
var message = usermsg.val();
|
let message = usermsg.val();
|
||||||
message += smileys['smiley' + number];
|
|
||||||
|
message += smileys[`smiley${number}`];
|
||||||
usermsg.val(message);
|
usermsg.val(message);
|
||||||
usermsg.get(0).setSelectionRange(message.length, message.length);
|
usermsg.get(0).setSelectionRange(message.length, message.length);
|
||||||
toggleSmileys();
|
toggleSmileys();
|
||||||
|
@ -135,35 +146,38 @@ function addClickFunction(smiley, number) {
|
||||||
* Adds the smileys container to the chat
|
* Adds the smileys container to the chat
|
||||||
*/
|
*/
|
||||||
function addSmileys() {
|
function addSmileys() {
|
||||||
var smileysContainer = document.createElement('div');
|
const smileysContainer = document.createElement('div');
|
||||||
|
|
||||||
smileysContainer.id = 'smileysContainer';
|
smileysContainer.id = 'smileysContainer';
|
||||||
for(var i = 1; i <= 21; i++) {
|
for (let i = 1; i <= 21; i++) {
|
||||||
var smileyContainer = document.createElement('div');
|
const smileyContainer = document.createElement('div');
|
||||||
smileyContainer.id = 'smiley' + i;
|
|
||||||
|
smileyContainer.id = `smiley${i}`;
|
||||||
smileyContainer.className = 'smileyContainer';
|
smileyContainer.className = 'smileyContainer';
|
||||||
var smiley = document.createElement('img');
|
const smiley = document.createElement('img');
|
||||||
smiley.src = 'images/smileys/smiley' + i + '.svg';
|
|
||||||
smiley.className = 'smiley';
|
smiley.src = `images/smileys/smiley${i}.svg`;
|
||||||
|
smiley.className = 'smiley';
|
||||||
addClickFunction(smiley, i);
|
addClickFunction(smiley, i);
|
||||||
smileyContainer.appendChild(smiley);
|
smileyContainer.appendChild(smiley);
|
||||||
smileysContainer.appendChild(smileyContainer);
|
smileysContainer.appendChild(smileyContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#chat_container").append(smileysContainer);
|
$('#chat_container').append(smileysContainer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the chat conversation.
|
* Resizes the chat conversation.
|
||||||
*/
|
*/
|
||||||
function resizeChatConversation() {
|
function resizeChatConversation() {
|
||||||
var msgareaHeight = $('#usermsg').outerHeight();
|
const msgareaHeight = $('#usermsg').outerHeight();
|
||||||
var chatspace = $('#' + CHAT_CONTAINER_ID);
|
const chatspace = $(`#${CHAT_CONTAINER_ID}`);
|
||||||
var width = chatspace.width();
|
const width = chatspace.width();
|
||||||
var chat = $('#chatconversation');
|
const chat = $('#chatconversation');
|
||||||
var smileys = $('#smileysarea');
|
const smileys = $('#smileysarea'); // eslint-disable-line no-shadow
|
||||||
|
|
||||||
smileys.height(msgareaHeight);
|
smileys.height(msgareaHeight);
|
||||||
$("#smileys").css('bottom', (msgareaHeight - 26) / 2);
|
$('#smileys').css('bottom', (msgareaHeight - 26) / 2);
|
||||||
$('#smileysContainer').css('bottom', msgareaHeight);
|
$('#smileysContainer').css('bottom', msgareaHeight);
|
||||||
chat.width(width - 10);
|
chat.width(width - 10);
|
||||||
chat.height(window.innerHeight - 15 - msgareaHeight);
|
chat.height(window.innerHeight - 15 - msgareaHeight);
|
||||||
|
@ -175,63 +189,71 @@ function resizeChatConversation() {
|
||||||
*
|
*
|
||||||
* @param id {string} input id
|
* @param id {string} input id
|
||||||
*/
|
*/
|
||||||
function deferredFocus(id){
|
function deferredFocus(id) {
|
||||||
setTimeout(() => $(`#${id}`).focus(), 400);
|
setTimeout(() => $(`#${id}`).focus(), 400);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Chat related user interface.
|
* Chat related user interface.
|
||||||
*/
|
*/
|
||||||
var Chat = {
|
const Chat = {
|
||||||
/**
|
/**
|
||||||
* Initializes chat related interface.
|
* Initializes chat related interface.
|
||||||
*/
|
*/
|
||||||
init (eventEmitter) {
|
init(eventEmitter) {
|
||||||
initHTML();
|
initHTML();
|
||||||
if (APP.conference.getLocalDisplayName()) {
|
if (APP.conference.getLocalDisplayName()) {
|
||||||
Chat.setChatConversationMode(true);
|
Chat.setChatConversationMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
$("#smileys").click(function() {
|
$('#smileys').click(() => {
|
||||||
Chat.toggleSmileys();
|
Chat.toggleSmileys();
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#nickinput').keydown(function (event) {
|
$('#nickinput').keydown(function(event) {
|
||||||
if (event.keyCode === 13) {
|
if (event.keyCode === 13) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
let val = this.value;
|
const val = this.value; // eslint-disable-line no-invalid-this
|
||||||
this.value = '';
|
|
||||||
|
this.value = '';// eslint-disable-line no-invalid-this
|
||||||
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
|
eventEmitter.emit(UIEvents.NICKNAME_CHANGED, val);
|
||||||
deferredFocus('usermsg');
|
deferredFocus('usermsg');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var usermsg = $('#usermsg');
|
const usermsg = $('#usermsg');
|
||||||
usermsg.keydown(function (event) {
|
|
||||||
|
usermsg.keydown(function(event) {
|
||||||
if (event.keyCode === 13) {
|
if (event.keyCode === 13) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
var value = this.value;
|
const value = this.value; // eslint-disable-line no-invalid-this
|
||||||
|
|
||||||
usermsg.val('').trigger('autosize.resize');
|
usermsg.val('').trigger('autosize.resize');
|
||||||
this.focus();
|
this.focus();// eslint-disable-line no-invalid-this
|
||||||
var command = new CommandsProcessor(value, eventEmitter);
|
const command = new CommandsProcessor(value, eventEmitter);
|
||||||
|
|
||||||
if (command.isCommand()) {
|
if (command.isCommand()) {
|
||||||
command.processCommand();
|
command.processCommand();
|
||||||
} else {
|
} else {
|
||||||
var message = UIUtil.escapeHtml(value);
|
const message = UIUtil.escapeHtml(value);
|
||||||
|
|
||||||
eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
|
eventEmitter.emit(UIEvents.MESSAGE_CREATED, message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var onTextAreaResize = function () {
|
const onTextAreaResize = function() {
|
||||||
resizeChatConversation();
|
resizeChatConversation();
|
||||||
Chat.scrollChatToBottom();
|
Chat.scrollChatToBottom();
|
||||||
};
|
};
|
||||||
usermsg.autosize({callback: onTextAreaResize});
|
|
||||||
|
usermsg.autosize({ callback: onTextAreaResize });
|
||||||
|
|
||||||
eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
eventEmitter.on(UIEvents.SIDE_TOOLBAR_CONTAINER_TOGGLED,
|
||||||
function(containerId, isVisible) {
|
(containerId, isVisible) => {
|
||||||
if (containerId !== CHAT_CONTAINER_ID || !isVisible)
|
if (containerId !== CHAT_CONTAINER_ID || !isVisible) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
unreadMessages = 0;
|
unreadMessages = 0;
|
||||||
updateVisualNotification();
|
updateVisualNotification();
|
||||||
|
@ -257,13 +279,14 @@ var Chat = {
|
||||||
/**
|
/**
|
||||||
* Appends the given message to the chat conversation.
|
* Appends the given message to the chat conversation.
|
||||||
*/
|
*/
|
||||||
updateChatConversation (id, displayName, message, stamp) {
|
// eslint-disable-next-line max-params
|
||||||
var divClassName = '';
|
updateChatConversation(id, displayName, message, stamp) {
|
||||||
|
let divClassName = '';
|
||||||
|
|
||||||
if (APP.conference.isLocalId(id)) {
|
if (APP.conference.isLocalId(id)) {
|
||||||
divClassName = "localuser";
|
divClassName = 'localuser';
|
||||||
} else {
|
} else {
|
||||||
divClassName = "remoteuser";
|
divClassName = 'remoteuser';
|
||||||
|
|
||||||
if (!Chat.isVisible()) {
|
if (!Chat.isVisible()) {
|
||||||
unreadMessages++;
|
unreadMessages++;
|
||||||
|
@ -275,22 +298,25 @@ var Chat = {
|
||||||
// replace links and smileys
|
// replace links and smileys
|
||||||
// Strophe already escapes special symbols on sending,
|
// Strophe already escapes special symbols on sending,
|
||||||
// so we escape here only tags to avoid double &
|
// so we escape here only tags to avoid double &
|
||||||
var escMessage = message.replace(/</g, '<').
|
const escMessage = message.replace(/</g, '<')
|
||||||
replace(/>/g, '>').replace(/\n/g, '<br/>');
|
.replace(/>/g, '>')
|
||||||
var escDisplayName = UIUtil.escapeHtml(displayName);
|
.replace(/\n/g, '<br/>');
|
||||||
|
const escDisplayName = UIUtil.escapeHtml(displayName);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
message = processReplacements(escMessage);
|
message = processReplacements(escMessage);
|
||||||
|
|
||||||
var messageContainer =
|
const messageContainer
|
||||||
'<div class="chatmessage">'+
|
= `${'<div class="chatmessage">'
|
||||||
'<img src="images/chatArrow.svg" class="chatArrow">' +
|
+ '<img src="images/chatArrow.svg" class="chatArrow">'
|
||||||
'<div class="username ' + divClassName +'">' + escDisplayName +
|
+ '<div class="username '}${divClassName}">${escDisplayName
|
||||||
'</div>' + '<div class="timestamp">' + getCurrentTime(stamp) +
|
}</div><div class="timestamp">${getCurrentTime(stamp)
|
||||||
'</div>' + '<div class="usermessage">' + message + '</div>' +
|
}</div><div class="usermessage">${message}</div>`
|
||||||
'</div>';
|
+ '</div>';
|
||||||
|
|
||||||
$('#chatconversation').append(messageContainer);
|
$('#chatconversation').append(messageContainer);
|
||||||
$('#chatconversation').animate(
|
$('#chatconversation').animate(
|
||||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
{ scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -298,25 +324,28 @@ var Chat = {
|
||||||
* @param errorMessage the received error message.
|
* @param errorMessage the received error message.
|
||||||
* @param originalText the original message.
|
* @param originalText the original message.
|
||||||
*/
|
*/
|
||||||
chatAddError (errorMessage, originalText) {
|
chatAddError(errorMessage, originalText) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
errorMessage = UIUtil.escapeHtml(errorMessage);
|
errorMessage = UIUtil.escapeHtml(errorMessage);
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
originalText = UIUtil.escapeHtml(originalText);
|
originalText = UIUtil.escapeHtml(originalText);
|
||||||
|
|
||||||
$('#chatconversation').append(
|
$('#chatconversation').append(
|
||||||
'<div class="errorMessage"><b>Error: </b>' + 'Your message' +
|
`${'<div class="errorMessage"><b>Error: </b>Your message'}${
|
||||||
(originalText? (` "${originalText}"`) : "") +
|
originalText ? ` "${originalText}"` : ''
|
||||||
' was not sent.' +
|
} was not sent.${
|
||||||
(errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
|
errorMessage ? ` Reason: ${errorMessage}` : ''}</div>`);
|
||||||
$('#chatconversation').animate(
|
$('#chatconversation').animate(
|
||||||
{ scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
|
{ scrollTop: $('#chatconversation')[0].scrollHeight }, 1000);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the subject to the UI
|
* Sets the subject to the UI
|
||||||
* @param subject the subject
|
* @param subject the subject
|
||||||
*/
|
*/
|
||||||
setSubject (subject) {
|
setSubject(subject) {
|
||||||
if (subject) {
|
if (subject) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
subject = subject.trim();
|
subject = subject.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,16 +361,17 @@ var Chat = {
|
||||||
* @param {boolean} isConversationMode if chat should be in
|
* @param {boolean} isConversationMode if chat should be in
|
||||||
* conversation mode or not.
|
* conversation mode or not.
|
||||||
*/
|
*/
|
||||||
setChatConversationMode (isConversationMode) {
|
setChatConversationMode(isConversationMode) {
|
||||||
$('#' + CHAT_CONTAINER_ID)
|
$(`#${CHAT_CONTAINER_ID}`)
|
||||||
.toggleClass('is-conversation-mode', isConversationMode);
|
.toggleClass('is-conversation-mode', isConversationMode);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resizes the chat area.
|
* Resizes the chat area.
|
||||||
*/
|
*/
|
||||||
resizeChat (width, height) {
|
resizeChat(width, height) {
|
||||||
$('#' + CHAT_CONTAINER_ID).width(width).height(height);
|
$(`#${CHAT_CONTAINER_ID}`).width(width)
|
||||||
|
.height(height);
|
||||||
|
|
||||||
resizeChatConversation();
|
resizeChatConversation();
|
||||||
},
|
},
|
||||||
|
@ -349,10 +379,11 @@ var Chat = {
|
||||||
/**
|
/**
|
||||||
* Indicates if the chat is currently visible.
|
* Indicates if the chat is currently visible.
|
||||||
*/
|
*/
|
||||||
isVisible () {
|
isVisible() {
|
||||||
return UIUtil.isVisible(
|
return UIUtil.isVisible(
|
||||||
document.getElementById(CHAT_CONTAINER_ID));
|
document.getElementById(CHAT_CONTAINER_ID));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows and hides the window with the smileys
|
* Shows and hides the window with the smileys
|
||||||
*/
|
*/
|
||||||
|
@ -361,7 +392,7 @@ var Chat = {
|
||||||
/**
|
/**
|
||||||
* Scrolls chat to the bottom.
|
* Scrolls chat to the bottom.
|
||||||
*/
|
*/
|
||||||
scrollChatToBottom () {
|
scrollChatToBottom() {
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => {
|
() => {
|
||||||
const chatconversation = $('#chatconversation');
|
const chatconversation = $('#chatconversation');
|
||||||
|
|
|
@ -7,7 +7,7 @@ import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
* @type {{String: function}}
|
* @type {{String: function}}
|
||||||
*/
|
*/
|
||||||
const commands = {
|
const commands = {
|
||||||
"topic" : processTopic
|
'topic': processTopic
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -16,13 +16,15 @@ const commands = {
|
||||||
* @returns {string} the command
|
* @returns {string} the command
|
||||||
*/
|
*/
|
||||||
function getCommand(message) {
|
function getCommand(message) {
|
||||||
if(message) {
|
if (message) {
|
||||||
for(var command in commands) {
|
for (const command in commands) {
|
||||||
if(message.indexOf("/" + command) === 0)
|
if (message.indexOf(`/${command}`) === 0) {
|
||||||
return command;
|
return command;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "";
|
|
||||||
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +32,8 @@ function getCommand(message) {
|
||||||
* @param commandArguments the arguments of the topic command.
|
* @param commandArguments the arguments of the topic command.
|
||||||
*/
|
*/
|
||||||
function processTopic(commandArguments, emitter) {
|
function processTopic(commandArguments, emitter) {
|
||||||
var topic = UIUtil.escapeHtml(commandArguments);
|
const topic = UIUtil.escapeHtml(commandArguments);
|
||||||
|
|
||||||
emitter.emit(UIEvents.SUBJECT_CHANGED, topic);
|
emitter.emit(UIEvents.SUBJECT_CHANGED, topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +44,7 @@ function processTopic(commandArguments, emitter) {
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function CommandsProcessor(message, emitter) {
|
function CommandsProcessor(message, emitter) {
|
||||||
var command = getCommand(message);
|
const command = getCommand(message);
|
||||||
|
|
||||||
this.emitter = emitter;
|
this.emitter = emitter;
|
||||||
|
|
||||||
|
@ -54,7 +57,7 @@ function CommandsProcessor(message, emitter) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var messageArgument = message.substr(command.length + 2);
|
const messageArgument = message.substr(command.length + 2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the arguments of the command.
|
* Returns the arguments of the command.
|
||||||
|
@ -70,8 +73,10 @@ function CommandsProcessor(message, emitter) {
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
CommandsProcessor.prototype.isCommand = function() {
|
CommandsProcessor.prototype.isCommand = function() {
|
||||||
if (this.getCommand())
|
if (this.getCommand()) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -79,8 +84,9 @@ CommandsProcessor.prototype.isCommand = function() {
|
||||||
* Processes the command.
|
* Processes the command.
|
||||||
*/
|
*/
|
||||||
CommandsProcessor.prototype.processCommand = function() {
|
CommandsProcessor.prototype.processCommand = function() {
|
||||||
if(!this.isCommand())
|
if (!this.isCommand()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
commands[this.getCommand()](this.getArgument(), this.emitter);
|
commands[this.getCommand()](this.getArgument(), this.emitter);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,17 +1,11 @@
|
||||||
/* jshint -W101 */
|
|
||||||
import { regexes } from './smileys';
|
import { regexes } from './smileys';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Processes links and smileys in "body"
|
* Processes links and smileys in "body"
|
||||||
*/
|
*/
|
||||||
export function processReplacements(body) {
|
export function processReplacements(body) {
|
||||||
//make links clickable
|
// make links clickable + add smileys
|
||||||
body = linkify(body);
|
return smilify(linkify(body));
|
||||||
|
|
||||||
//add smileys
|
|
||||||
body = smilify(body);
|
|
||||||
|
|
||||||
return body;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -19,20 +13,23 @@ export function processReplacements(body) {
|
||||||
* with their <a href=""></a>
|
* with their <a href=""></a>
|
||||||
*/
|
*/
|
||||||
export function linkify(inputText) {
|
export function linkify(inputText) {
|
||||||
var replacedText, replacePattern1, replacePattern2, replacePattern3;
|
let replacedText;
|
||||||
|
|
||||||
/* eslint-disable no-useless-escape */
|
/* eslint-disable no-useless-escape, max-len */
|
||||||
|
|
||||||
|
// URLs starting with http://, https://, or ftp://
|
||||||
|
const replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
||||||
|
|
||||||
//URLs starting with http://, https://, or ftp://
|
|
||||||
replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
|
|
||||||
replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
|
replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank" rel="noopener noreferrer">$1</a>');
|
||||||
|
|
||||||
//URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
// URLs starting with "www." (without // before it, or it'd re-link the ones done above).
|
||||||
replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
const replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
|
||||||
|
|
||||||
replacedText = replacedText.replace(replacePattern2, '$1<a href="https://$2" target="_blank" rel="noopener noreferrer">$2</a>');
|
replacedText = replacedText.replace(replacePattern2, '$1<a href="https://$2" target="_blank" rel="noopener noreferrer">$2</a>');
|
||||||
|
|
||||||
//Change email addresses to mailto: links.
|
// Change email addresses to mailto: links.
|
||||||
replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
|
const replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
|
||||||
|
|
||||||
replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
|
replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
|
||||||
|
|
||||||
/* eslint-enable no-useless-escape */
|
/* eslint-enable no-useless-escape */
|
||||||
|
@ -44,14 +41,16 @@ export function linkify(inputText) {
|
||||||
* Replaces common smiley strings with images
|
* Replaces common smiley strings with images
|
||||||
*/
|
*/
|
||||||
function smilify(body) {
|
function smilify(body) {
|
||||||
if(!body) {
|
if (!body) {
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(var smiley in regexes) {
|
let formattedBody = body;
|
||||||
if(regexes.hasOwnProperty(smiley)) {
|
|
||||||
body = body.replace(regexes[smiley],
|
for (const smiley in regexes) {
|
||||||
'<img class="smiley" src="images/smileys/' + smiley + '.svg">');
|
if (regexes.hasOwnProperty(smiley)) {
|
||||||
|
formattedBody = formattedBody.replace(regexes[smiley],
|
||||||
|
`<img class="smiley" src="images/smileys/${smiley}.svg">`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
export const smileys = {
|
export const smileys = {
|
||||||
smiley1: ":)",
|
smiley1: ':)',
|
||||||
smiley2: ":(",
|
smiley2: ':(',
|
||||||
smiley3: ":D",
|
smiley3: ':D',
|
||||||
smiley4: "(y)",
|
smiley4: '(y)',
|
||||||
smiley5: " :P",
|
smiley5: ' :P',
|
||||||
smiley6: "(wave)",
|
smiley6: '(wave)',
|
||||||
smiley7: "(blush)",
|
smiley7: '(blush)',
|
||||||
smiley8: "(chuckle)",
|
smiley8: '(chuckle)',
|
||||||
smiley9: "(shocked)",
|
smiley9: '(shocked)',
|
||||||
smiley10: ":*",
|
smiley10: ':*',
|
||||||
smiley11: "(n)",
|
smiley11: '(n)',
|
||||||
smiley12: "(search)",
|
smiley12: '(search)',
|
||||||
smiley13: " <3",
|
smiley13: ' <3',
|
||||||
smiley14: "(oops)",
|
smiley14: '(oops)',
|
||||||
smiley15: "(angry)",
|
smiley15: '(angry)',
|
||||||
smiley16: "(angel)",
|
smiley16: '(angel)',
|
||||||
smiley17: "(sick)",
|
smiley17: '(sick)',
|
||||||
smiley18: ";(",
|
smiley18: ';(',
|
||||||
smiley19: "(bomb)",
|
smiley19: '(bomb)',
|
||||||
smiley20: "(clap)",
|
smiley20: '(clap)',
|
||||||
smiley21: " ;)"
|
smiley21: ' ;)'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const regexes = {
|
export const regexes = {
|
||||||
|
|
|
@ -19,7 +19,7 @@ import UIUtil from '../../util/UIUtil';
|
||||||
* the term "contact" is not used elsewhere. Normally people in the conference
|
* the term "contact" is not used elsewhere. Normally people in the conference
|
||||||
* are internally refered to as "participants" or externally as "members".
|
* are internally refered to as "participants" or externally as "members".
|
||||||
*/
|
*/
|
||||||
var ContactListView = {
|
const ContactListView = {
|
||||||
/**
|
/**
|
||||||
* Creates and appends the contact list to the side panel.
|
* Creates and appends the contact list to the side panel.
|
||||||
*
|
*
|
||||||
|
@ -33,7 +33,6 @@ var ContactListView = {
|
||||||
|
|
||||||
$('#sideToolbarContainer').append(contactListPanelContainer);
|
$('#sideToolbarContainer').append(contactListPanelContainer);
|
||||||
|
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
|
@ -42,7 +41,6 @@ var ContactListView = {
|
||||||
</Provider>,
|
</Provider>,
|
||||||
contactListPanelContainer
|
contactListPanelContainer
|
||||||
);
|
);
|
||||||
/* jshint ignore:end */
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,8 +48,8 @@ var ContactListView = {
|
||||||
*
|
*
|
||||||
* @return {boolean) true if the contact list is currently visible.
|
* @return {boolean) true if the contact list is currently visible.
|
||||||
*/
|
*/
|
||||||
isVisible () {
|
isVisible() {
|
||||||
return UIUtil.isVisible(document.getElementById("contactlist"));
|
return UIUtil.isVisible(document.getElementById('contactlist'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,98 +1,117 @@
|
||||||
/* global $, APP */
|
/* global $, APP */
|
||||||
import UIUtil from "../../util/UIUtil";
|
import UIUtil from '../../util/UIUtil';
|
||||||
import UIEvents from "../../../../service/UI/UIEvents";
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
import Settings from '../../../settings/Settings';
|
import Settings from '../../../settings/Settings';
|
||||||
|
|
||||||
import { sendEvent } from '../../../../react/features/analytics';
|
import { sendEvent } from '../../../../react/features/analytics';
|
||||||
|
|
||||||
const sidePanelsContainerId = 'sideToolbarContainer';
|
const sidePanelsContainerId = 'sideToolbarContainer';
|
||||||
const htmlStr = `
|
const htmlStr = `
|
||||||
<div id="profile_container" class="sideToolbarContainer__inner">
|
<div id='profile_container' class='sideToolbarContainer__inner'>
|
||||||
<div class="title" data-i18n="profile.title"></div>
|
<div class='title' data-i18n='profile.title'></div>
|
||||||
<div class="sideToolbarBlock first">
|
<div class='sideToolbarBlock first'>
|
||||||
<label class="first" data-i18n="profile.setDisplayNameLabel">
|
<label class='first' data-i18n='profile.setDisplayNameLabel'>
|
||||||
</label>
|
</label>
|
||||||
<input class="input-control" type="text" id="setDisplayName"
|
<input class='input-control' type='text' id='setDisplayName'
|
||||||
data-i18n="[placeholder]settings.name">
|
data-i18n='[placeholder]settings.name'>
|
||||||
</div>
|
</div>
|
||||||
<div class="sideToolbarBlock">
|
<div class='sideToolbarBlock'>
|
||||||
<label data-i18n="profile.setEmailLabel"></label>
|
<label data-i18n='profile.setEmailLabel'></label>
|
||||||
<input id="setEmail" type="text" class="input-control"
|
<input id='setEmail' type='text' class='input-control'
|
||||||
data-i18n="[placeholder]profile.setEmailInput">
|
data-i18n='[placeholder]profile.setEmailInput'>
|
||||||
</div>
|
</div>
|
||||||
<div id="profile_auth_container"
|
<div id='profile_auth_container'
|
||||||
class="sideToolbarBlock auth_container">
|
class='sideToolbarBlock auth_container'>
|
||||||
<p data-i18n="toolbar.authenticate"></p>
|
<p data-i18n='toolbar.authenticate'></p>
|
||||||
<ul>
|
<ul>
|
||||||
<li id="profile_auth_identity"></li>
|
<li id='profile_auth_identity'></li>
|
||||||
<li id="profile_button_login">
|
<li id='profile_button_login'>
|
||||||
<a class="authButton" data-i18n="toolbar.login"></a>
|
<a class='authButton' data-i18n='toolbar.login'></a>
|
||||||
</li>
|
</li>
|
||||||
<li id="profile_button_logout">
|
<li id='profile_button_logout'>
|
||||||
<a class="authButton" data-i18n="toolbar.logout"></a>
|
<a class='authButton' data-i18n='toolbar.logout'></a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initHTML() {
|
function initHTML() {
|
||||||
$(`#${sidePanelsContainerId}`)
|
$(`#${sidePanelsContainerId}`)
|
||||||
.append(htmlStr);
|
.append(htmlStr);
|
||||||
|
|
||||||
// make sure we translate the panel, as adding it can be after i18n
|
// make sure we translate the panel, as adding it can be after i18n
|
||||||
// library had initialized and translated already present html
|
// library had initialized and translated already present html
|
||||||
APP.translation.translateElement($(`#${sidePanelsContainerId}`));
|
APP.translation.translateElement($(`#${sidePanelsContainerId}`));
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
init (emitter) {
|
init(emitter) {
|
||||||
initHTML();
|
initHTML();
|
||||||
// DISPLAY NAME
|
|
||||||
function updateDisplayName () {
|
/**
|
||||||
|
* Updates display name.
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function updateDisplayName() {
|
||||||
emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
|
emitter.emit(UIEvents.NICKNAME_CHANGED, $('#setDisplayName').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#setDisplayName')
|
$('#setDisplayName')
|
||||||
.val(Settings.getDisplayName())
|
.val(Settings.getDisplayName())
|
||||||
.keyup(function (event) {
|
.keyup(event => {
|
||||||
if (event.keyCode === 13) { // enter
|
if (event.keyCode === 13) { // enter
|
||||||
updateDisplayName();
|
updateDisplayName();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.focusout(updateDisplayName);
|
.focusout(updateDisplayName);
|
||||||
|
|
||||||
|
/**
|
||||||
// EMAIL
|
* Updates the email.
|
||||||
function updateEmail () {
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
function updateEmail() {
|
||||||
emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
|
emitter.emit(UIEvents.EMAIL_CHANGED, $('#setEmail').val());
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#setEmail')
|
$('#setEmail')
|
||||||
.val(Settings.getEmail())
|
.val(Settings.getEmail())
|
||||||
.keyup(function (event) {
|
.keyup(event => {
|
||||||
if (event.keyCode === 13) { // enter
|
if (event.keyCode === 13) { // enter
|
||||||
updateEmail();
|
updateEmail();
|
||||||
}
|
}
|
||||||
}).focusout(updateEmail);
|
})
|
||||||
|
.focusout(updateEmail);
|
||||||
|
|
||||||
// LOGIN
|
/**
|
||||||
function loginClicked () {
|
*
|
||||||
|
*/
|
||||||
|
function loginClicked() {
|
||||||
sendEvent('authenticate.login.clicked');
|
sendEvent('authenticate.login.clicked');
|
||||||
emitter.emit(UIEvents.AUTH_CLICKED);
|
emitter.emit(UIEvents.AUTH_CLICKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
$('#profile_button_login').click(loginClicked);
|
$('#profile_button_login').click(loginClicked);
|
||||||
|
|
||||||
// LOGOUT
|
/**
|
||||||
function logoutClicked () {
|
*
|
||||||
let titleKey = "dialog.logoutTitle";
|
*/
|
||||||
let msgKey = "dialog.logoutQuestion";
|
function logoutClicked() {
|
||||||
|
const titleKey = 'dialog.logoutTitle';
|
||||||
|
const msgKey = 'dialog.logoutQuestion';
|
||||||
|
|
||||||
sendEvent('authenticate.logout.clicked');
|
sendEvent('authenticate.logout.clicked');
|
||||||
|
|
||||||
// Ask for confirmation
|
// Ask for confirmation
|
||||||
APP.UI.messageHandler.openTwoButtonDialog({
|
APP.UI.messageHandler.openTwoButtonDialog({
|
||||||
titleKey: titleKey,
|
titleKey,
|
||||||
msgKey: msgKey,
|
msgKey,
|
||||||
leftButtonKey: "dialog.Yes",
|
leftButtonKey: 'dialog.Yes',
|
||||||
submitFunction: function (evt, yes) {
|
submitFunction(evt, yes) {
|
||||||
if (yes) {
|
if (yes) {
|
||||||
emitter.emit(UIEvents.LOGOUT);
|
emitter.emit(UIEvents.LOGOUT);
|
||||||
}
|
}
|
||||||
|
@ -107,15 +126,15 @@ export default {
|
||||||
* Check if settings menu is visible or not.
|
* Check if settings menu is visible or not.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isVisible () {
|
isVisible() {
|
||||||
return UIUtil.isVisible(document.getElementById("profile_container"));
|
return UIUtil.isVisible(document.getElementById('profile_container'));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change user display name in the settings menu.
|
* Change user display name in the settings menu.
|
||||||
* @param {string} newDisplayName
|
* @param {string} newDisplayName
|
||||||
*/
|
*/
|
||||||
changeDisplayName (newDisplayName) {
|
changeDisplayName(newDisplayName) {
|
||||||
$('#setDisplayName').val(newDisplayName);
|
$('#setDisplayName').val(newDisplayName);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -123,7 +142,7 @@ export default {
|
||||||
* Change user avatar in the settings menu.
|
* Change user avatar in the settings menu.
|
||||||
* @param {string} avatarUrl url of the new avatar
|
* @param {string} avatarUrl url of the new avatar
|
||||||
*/
|
*/
|
||||||
changeAvatar (avatarUrl) {
|
changeAvatar(avatarUrl) {
|
||||||
$('#avatar').attr('src', avatarUrl);
|
$('#avatar').attr('src', avatarUrl);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -131,7 +150,7 @@ export default {
|
||||||
* Change the value of the field for the user email.
|
* Change the value of the field for the user email.
|
||||||
* @param {string} email the new value that will be displayed in the field.
|
* @param {string} email the new value that will be displayed in the field.
|
||||||
*/
|
*/
|
||||||
changeEmail (email) {
|
changeEmail(email) {
|
||||||
$('#setEmail').val(email);
|
$('#setEmail').val(email);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -139,8 +158,9 @@ export default {
|
||||||
* Shows or hides authentication related buttons
|
* Shows or hides authentication related buttons
|
||||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||||
*/
|
*/
|
||||||
showAuthenticationButtons (show) {
|
showAuthenticationButtons(show) {
|
||||||
let id = 'profile_auth_container';
|
const id = 'profile_auth_container';
|
||||||
|
|
||||||
UIUtil.setVisible(id, show);
|
UIUtil.setVisible(id, show);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -148,8 +168,8 @@ export default {
|
||||||
* Shows/hides login button.
|
* Shows/hides login button.
|
||||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||||
*/
|
*/
|
||||||
showLoginButton (show) {
|
showLoginButton(show) {
|
||||||
let id = 'profile_button_login';
|
const id = 'profile_button_login';
|
||||||
|
|
||||||
UIUtil.setVisible(id, show);
|
UIUtil.setVisible(id, show);
|
||||||
},
|
},
|
||||||
|
@ -158,8 +178,8 @@ export default {
|
||||||
* Shows/hides logout button.
|
* Shows/hides logout button.
|
||||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||||
*/
|
*/
|
||||||
showLogoutButton (show) {
|
showLogoutButton(show) {
|
||||||
let id = 'profile_button_logout';
|
const id = 'profile_button_logout';
|
||||||
|
|
||||||
UIUtil.setVisible(id, show);
|
UIUtil.setVisible(id, show);
|
||||||
},
|
},
|
||||||
|
@ -168,10 +188,10 @@ export default {
|
||||||
* Displays user's authenticated identity name (login).
|
* Displays user's authenticated identity name (login).
|
||||||
* @param {string} authIdentity identity name to be displayed.
|
* @param {string} authIdentity identity name to be displayed.
|
||||||
*/
|
*/
|
||||||
setAuthenticatedIdentity (authIdentity) {
|
setAuthenticatedIdentity(authIdentity) {
|
||||||
let id = 'profile_auth_identity';
|
const id = 'profile_auth_identity';
|
||||||
|
|
||||||
UIUtil.setVisible(id, !!authIdentity);
|
UIUtil.setVisible(id, Boolean(authIdentity));
|
||||||
|
|
||||||
$(`#${id}`).text(authIdentity ? authIdentity : '');
|
$(`#${id}`).text(authIdentity ? authIdentity : '');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
/* global $, APP, AJS, interfaceConfig */
|
/* global $, APP, AJS, interfaceConfig */
|
||||||
import { LANGUAGES } from "../../../../react/features/base/i18n";
|
import { LANGUAGES } from '../../../../react/features/base/i18n';
|
||||||
import { openDeviceSelectionDialog }
|
import { openDeviceSelectionDialog }
|
||||||
from '../../../../react/features/device-selection';
|
from '../../../../react/features/device-selection';
|
||||||
|
|
||||||
import UIUtil from "../../util/UIUtil";
|
import UIUtil from '../../util/UIUtil';
|
||||||
import UIEvents from "../../../../service/UI/UIEvents";
|
import UIEvents from '../../../../service/UI/UIEvents';
|
||||||
|
|
||||||
const sidePanelsContainerId = 'sideToolbarContainer';
|
const sidePanelsContainerId = 'sideToolbarContainer';
|
||||||
const deviceSelectionButtonClasses
|
const deviceSelectionButtonClasses
|
||||||
|
@ -13,12 +13,12 @@ const htmlStr = `
|
||||||
<div id="settings_container" class="sideToolbarContainer__inner">
|
<div id="settings_container" class="sideToolbarContainer__inner">
|
||||||
<div class="title" data-i18n="settings.title"></div>
|
<div class="title" data-i18n="settings.title"></div>
|
||||||
<form class="aui">
|
<form class="aui">
|
||||||
<div id="languagesSelectWrapper"
|
<div id="languagesSelectWrapper"
|
||||||
class="sideToolbarBlock first hide">
|
class="sideToolbarBlock first hide">
|
||||||
<select id="languagesSelect"></select>
|
<select id="languagesSelect"></select>
|
||||||
</div>
|
</div>
|
||||||
<div id="deviceOptionsWrapper" class="hide">
|
<div id="deviceOptionsWrapper" class="hide">
|
||||||
<div id="deviceOptionsTitle" class="subTitle hide"
|
<div id="deviceOptionsTitle" class="subTitle hide"
|
||||||
data-i18n="settings.audioVideo"></div>
|
data-i18n="settings.audioVideo"></div>
|
||||||
<div class="sideToolbarBlock first">
|
<div class="sideToolbarBlock first">
|
||||||
<button
|
<button
|
||||||
|
@ -29,24 +29,24 @@ const htmlStr = `
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="moderatorOptionsWrapper" class="hide">
|
<div id="moderatorOptionsWrapper" class="hide">
|
||||||
<div id="moderatorOptionsTitle" class="subTitle hide"
|
<div id="moderatorOptionsTitle" class="subTitle hide"
|
||||||
data-i18n="settings.moderator"></div>
|
data-i18n="settings.moderator"></div>
|
||||||
<div id="startMutedOptions" class="hide">
|
<div id="startMutedOptions" class="hide">
|
||||||
<div class="sideToolbarBlock first">
|
<div class="sideToolbarBlock first">
|
||||||
<input type="checkbox" id="startAudioMuted">
|
<input type="checkbox" id="startAudioMuted">
|
||||||
<label class="startMutedLabel" for="startAudioMuted"
|
<label class="startMutedLabel" for="startAudioMuted"
|
||||||
data-i18n="settings.startAudioMuted"></label>
|
data-i18n="settings.startAudioMuted"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="sideToolbarBlock">
|
<div class="sideToolbarBlock">
|
||||||
<input type="checkbox" id="startVideoMuted">
|
<input type="checkbox" id="startVideoMuted">
|
||||||
<label class="startMutedLabel" for="startVideoMuted"
|
<label class="startMutedLabel" for="startVideoMuted"
|
||||||
data-i18n="settings.startVideoMuted"></label>
|
data-i18n="settings.startVideoMuted"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="followMeOptions" class="hide">
|
<div id="followMeOptions" class="hide">
|
||||||
<div class="sideToolbarBlock">
|
<div class="sideToolbarBlock">
|
||||||
<input type="checkbox" id="followMeCheckBox">
|
<input type="checkbox" id="followMeCheckBox">
|
||||||
<label class="followMeLabel" for="followMeCheckBox"
|
<label class="followMeLabel" for="followMeCheckBox"
|
||||||
data-i18n="settings.followMe"></label>
|
data-i18n="settings.followMe"></label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -54,9 +54,13 @@ const htmlStr = `
|
||||||
</form>
|
</form>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function initHTML() {
|
function initHTML() {
|
||||||
$(`#${sidePanelsContainerId}`)
|
$(`#${sidePanelsContainerId}`)
|
||||||
.append(htmlStr);
|
.append(htmlStr);
|
||||||
|
|
||||||
// make sure we translate the panel, as adding it can be after i18n
|
// make sure we translate the panel, as adding it can be after i18n
|
||||||
// library had initialized and translated already present html
|
// library had initialized and translated already present html
|
||||||
APP.translation.translateElement($(`#${sidePanelsContainerId}`));
|
APP.translation.translateElement($(`#${sidePanelsContainerId}`));
|
||||||
|
@ -70,8 +74,8 @@ function initHTML() {
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function generateLanguagesOptions(items, currentLang) {
|
function generateLanguagesOptions(items, currentLang) {
|
||||||
return items.map(function (lang) {
|
return items.map(lang => {
|
||||||
let attrs = {
|
const attrs = {
|
||||||
value: lang,
|
value: lang,
|
||||||
'data-i18n': `languages:${lang}`
|
'data-i18n': `languages:${lang}`
|
||||||
};
|
};
|
||||||
|
@ -80,7 +84,9 @@ function generateLanguagesOptions(items, currentLang) {
|
||||||
attrs.selected = 'selected';
|
attrs.selected = 'selected';
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrsStr = UIUtil.attrsToString(attrs);
|
const attrsStr = UIUtil.attrsToString(attrs);
|
||||||
|
|
||||||
|
|
||||||
return `<option ${attrsStr}></option>`;
|
return `<option ${attrsStr}></option>`;
|
||||||
}).join('');
|
}).join('');
|
||||||
}
|
}
|
||||||
|
@ -101,14 +107,15 @@ function initSelect2($el, onSelectedCb) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
init (emitter) {
|
init(emitter) {
|
||||||
initHTML();
|
initHTML();
|
||||||
//LANGUAGES BOX
|
|
||||||
|
// LANGUAGES BOX
|
||||||
if (UIUtil.isSettingEnabled('language')) {
|
if (UIUtil.isSettingEnabled('language')) {
|
||||||
const wrapperId = 'languagesSelectWrapper';
|
const wrapperId = 'languagesSelectWrapper';
|
||||||
const selectId = 'languagesSelect';
|
const selectId = 'languagesSelect';
|
||||||
const selectEl = AJS.$(`#${selectId}`);
|
const selectEl = AJS.$(`#${selectId}`);
|
||||||
let selectInput;
|
let selectInput; // eslint-disable-line prefer-const
|
||||||
|
|
||||||
selectEl.html(generateLanguagesOptions(
|
selectEl.html(generateLanguagesOptions(
|
||||||
LANGUAGES,
|
LANGUAGES,
|
||||||
|
@ -121,11 +128,13 @@ export default {
|
||||||
APP.translation.translateElement(selectInput);
|
APP.translation.translateElement(selectInput);
|
||||||
emitter.emit(UIEvents.LANG_CHANGED, val);
|
emitter.emit(UIEvents.LANG_CHANGED, val);
|
||||||
});
|
});
|
||||||
//find new selectInput element
|
|
||||||
|
// find new selectInput element
|
||||||
selectInput = $(`#s2id_${selectId} .select2-chosen`);
|
selectInput = $(`#s2id_${selectId} .select2-chosen`);
|
||||||
//first select fix for languages options
|
|
||||||
selectInput[0].dataset.i18n =
|
// first select fix for languages options
|
||||||
`languages:${APP.translation.getCurrentLanguage()}`;
|
selectInput[0].dataset.i18n
|
||||||
|
= `languages:${APP.translation.getCurrentLanguage()}`;
|
||||||
|
|
||||||
// translate selectInput, which is the currently selected language
|
// translate selectInput, which is the currently selected language
|
||||||
// otherwise there will be no selected option
|
// otherwise there will be no selected option
|
||||||
|
@ -133,10 +142,13 @@ export default {
|
||||||
APP.translation.translateElement(selectEl);
|
APP.translation.translateElement(selectEl);
|
||||||
|
|
||||||
APP.translation.addLanguageChangedListener(
|
APP.translation.addLanguageChangedListener(
|
||||||
lng => selectInput[0].dataset.i18n = `languages:${lng}`);
|
lng => {
|
||||||
|
selectInput[0].dataset.i18n = `languages:${lng}`;
|
||||||
|
});
|
||||||
|
|
||||||
UIUtil.setVisible(wrapperId, true);
|
UIUtil.setVisible(wrapperId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// DEVICES LIST
|
// DEVICES LIST
|
||||||
if (UIUtil.isSettingEnabled('devices')) {
|
if (UIUtil.isSettingEnabled('devices')) {
|
||||||
const wrapperId = 'deviceOptionsWrapper';
|
const wrapperId = 'deviceOptionsWrapper';
|
||||||
|
@ -145,19 +157,21 @@ export default {
|
||||||
APP.store.dispatch(openDeviceSelectionDialog()));
|
APP.store.dispatch(openDeviceSelectionDialog()));
|
||||||
|
|
||||||
// Only show the subtitle if this isn't the only setting section.
|
// Only show the subtitle if this isn't the only setting section.
|
||||||
if (interfaceConfig.SETTINGS_SECTIONS.length > 1)
|
if (interfaceConfig.SETTINGS_SECTIONS.length > 1) {
|
||||||
UIUtil.setVisible("deviceOptionsTitle", true);
|
UIUtil.setVisible('deviceOptionsTitle', true);
|
||||||
|
}
|
||||||
|
|
||||||
UIUtil.setVisible(wrapperId, true);
|
UIUtil.setVisible(wrapperId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
// MODERATOR
|
// MODERATOR
|
||||||
if (UIUtil.isSettingEnabled('moderator')) {
|
if (UIUtil.isSettingEnabled('moderator')) {
|
||||||
const wrapperId = 'moderatorOptionsWrapper';
|
const wrapperId = 'moderatorOptionsWrapper';
|
||||||
|
|
||||||
// START MUTED
|
// START MUTED
|
||||||
$("#startMutedOptions").change(function () {
|
$('#startMutedOptions').change(() => {
|
||||||
let startAudioMuted = $("#startAudioMuted").is(":checked");
|
const startAudioMuted = $('#startAudioMuted').is(':checked');
|
||||||
let startVideoMuted = $("#startVideoMuted").is(":checked");
|
const startVideoMuted = $('#startVideoMuted').is(':checked');
|
||||||
|
|
||||||
emitter.emit(
|
emitter.emit(
|
||||||
UIEvents.START_MUTED_CHANGED,
|
UIEvents.START_MUTED_CHANGED,
|
||||||
|
@ -168,8 +182,10 @@ export default {
|
||||||
|
|
||||||
// FOLLOW ME
|
// FOLLOW ME
|
||||||
const followMeToggle = document.getElementById('followMeCheckBox');
|
const followMeToggle = document.getElementById('followMeCheckBox');
|
||||||
|
|
||||||
followMeToggle.addEventListener('change', () => {
|
followMeToggle.addEventListener('change', () => {
|
||||||
const isFollowMeEnabled = followMeToggle.checked;
|
const isFollowMeEnabled = followMeToggle.checked;
|
||||||
|
|
||||||
emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
|
emitter.emit(UIEvents.FOLLOW_ME_ENABLED, isFollowMeEnabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -181,26 +197,28 @@ export default {
|
||||||
* If start audio muted/start video muted options should be visible or not.
|
* If start audio muted/start video muted options should be visible or not.
|
||||||
* @param {boolean} show
|
* @param {boolean} show
|
||||||
*/
|
*/
|
||||||
showStartMutedOptions (show) {
|
showStartMutedOptions(show) {
|
||||||
if (show && UIUtil.isSettingEnabled('moderator')) {
|
if (show && UIUtil.isSettingEnabled('moderator')) {
|
||||||
// Only show the subtitle if this isn't the only setting section.
|
// Only show the subtitle if this isn't the only setting section.
|
||||||
if (!$("#moderatorOptionsTitle").is(":visible")
|
if (!$('#moderatorOptionsTitle').is(':visible')
|
||||||
&& interfaceConfig.SETTINGS_SECTIONS.length > 1)
|
&& interfaceConfig.SETTINGS_SECTIONS.length > 1) {
|
||||||
UIUtil.setVisible("moderatorOptionsTitle", true);
|
UIUtil.setVisible('moderatorOptionsTitle', true);
|
||||||
|
}
|
||||||
|
|
||||||
UIUtil.setVisible("startMutedOptions", true);
|
UIUtil.setVisible('startMutedOptions', true);
|
||||||
} else {
|
} else {
|
||||||
// Only show the subtitle if this isn't the only setting section.
|
// Only show the subtitle if this isn't the only setting section.
|
||||||
if ($("#moderatorOptionsTitle").is(":visible"))
|
if ($('#moderatorOptionsTitle').is(':visible')) {
|
||||||
UIUtil.setVisible("moderatorOptionsTitle", false);
|
UIUtil.setVisible('moderatorOptionsTitle', false);
|
||||||
|
}
|
||||||
|
|
||||||
UIUtil.setVisible("startMutedOptions", false);
|
UIUtil.setVisible('startMutedOptions', false);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
updateStartMutedBox (startAudioMuted, startVideoMuted) {
|
updateStartMutedBox(startAudioMuted, startVideoMuted) {
|
||||||
$("#startAudioMuted").attr("checked", startAudioMuted);
|
$('#startAudioMuted').attr('checked', startAudioMuted);
|
||||||
$("#startVideoMuted").attr("checked", startVideoMuted);
|
$('#startVideoMuted').attr('checked', startVideoMuted);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -208,9 +226,9 @@ export default {
|
||||||
*
|
*
|
||||||
* @param {boolean} show {true} to show those options, {false} to hide them
|
* @param {boolean} show {true} to show those options, {false} to hide them
|
||||||
*/
|
*/
|
||||||
showFollowMeOptions (show) {
|
showFollowMeOptions(show) {
|
||||||
UIUtil.setVisible(
|
UIUtil.setVisible(
|
||||||
"followMeOptions",
|
'followMeOptions',
|
||||||
show && UIUtil.isSettingEnabled('moderator'));
|
show && UIUtil.isSettingEnabled('moderator'));
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -218,7 +236,7 @@ export default {
|
||||||
* Check if settings menu is visible or not.
|
* Check if settings menu is visible or not.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isVisible () {
|
isVisible() {
|
||||||
return UIUtil.isVisible(document.getElementById("settings_container"));
|
return UIUtil.isVisible(document.getElementById('settings_container'));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* global $, APP */
|
/* global $, APP */
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import jitsiLocalStorage from '../../util/JitsiLocalStorage';
|
import jitsiLocalStorage from '../../util/JitsiLocalStorage';
|
||||||
|
|
||||||
|
@ -31,12 +31,14 @@ let twoButtonDialog = null;
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function generateDontShowCheckbox(options) {
|
function generateDontShowCheckbox(options) {
|
||||||
if(!isDontShowAgainEnabled(options)) {
|
if (!isDontShowAgainEnabled(options)) {
|
||||||
return "";
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let checked
|
const checked
|
||||||
= (options.checked === true) ? "checked" : "";
|
= options.checked === true ? 'checked' : '';
|
||||||
|
|
||||||
|
|
||||||
return `<br />
|
return `<br />
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' ${checked} id='${options.id}' />
|
<input type='checkbox' ${checked} id='${options.id}' />
|
||||||
|
@ -54,12 +56,13 @@ function generateDontShowCheckbox(options) {
|
||||||
* false otherwise.
|
* false otherwise.
|
||||||
*/
|
*/
|
||||||
function dontShowTheDialog(options) {
|
function dontShowTheDialog(options) {
|
||||||
if(isDontShowAgainEnabled(options)) {
|
if (isDontShowAgainEnabled(options)) {
|
||||||
if(jitsiLocalStorage.getItem(options.localStorageKey || options.id)
|
if (jitsiLocalStorage.getItem(options.localStorageKey || options.id)
|
||||||
=== "true") {
|
=== 'true') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,24 +79,27 @@ function dontShowTheDialog(options) {
|
||||||
* @returns {Function} wrapped function
|
* @returns {Function} wrapped function
|
||||||
*/
|
*/
|
||||||
function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
|
function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
|
||||||
if(isDontShowAgainEnabled(options)) {
|
if (isDontShowAgainEnabled(options)) {
|
||||||
return (...args) => {
|
return (...args) => {
|
||||||
logger.debug(args, options.buttonValues);
|
logger.debug(args, options.buttonValues);
|
||||||
//args[1] is the value associated with the pressed button
|
|
||||||
if(!options.buttonValues || options.buttonValues.length === 0
|
// args[1] is the value associated with the pressed button
|
||||||
|| options.buttonValues.indexOf(args[1]) !== -1 ) {
|
if (!options.buttonValues || options.buttonValues.length === 0
|
||||||
let checkbox = $(`#${options.id}`);
|
|| options.buttonValues.indexOf(args[1]) !== -1) {
|
||||||
|
const checkbox = $(`#${options.id}`);
|
||||||
|
|
||||||
if (checkbox.length) {
|
if (checkbox.length) {
|
||||||
jitsiLocalStorage.setItem(
|
jitsiLocalStorage.setItem(
|
||||||
options.localStorageKey || options.id,
|
options.localStorageKey || options.id,
|
||||||
checkbox.prop("checked"));
|
checkbox.prop('checked'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
submitFunction(...args);
|
submitFunction(...args);
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return submitFunction;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return submitFunction;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,12 +108,12 @@ function dontShowAgainSubmitFunctionWrapper(options, submitFunction) {
|
||||||
* @returns {boolean} true if enabled and false if not.
|
* @returns {boolean} true if enabled and false if not.
|
||||||
*/
|
*/
|
||||||
function isDontShowAgainEnabled(options) {
|
function isDontShowAgainEnabled(options) {
|
||||||
return typeof options === "object";
|
return typeof options === 'object';
|
||||||
}
|
}
|
||||||
|
|
||||||
var messageHandler = {
|
const messageHandler = {
|
||||||
OK: "dialog.OK",
|
OK: 'dialog.OK',
|
||||||
CANCEL: "dialog.Cancel",
|
CANCEL: 'dialog.Cancel',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a message to the user.
|
* Shows a message to the user.
|
||||||
|
@ -120,25 +126,32 @@ var messageHandler = {
|
||||||
* the prompt is closed (optional)
|
* the prompt is closed (optional)
|
||||||
* @return the prompt that was created, or null
|
* @return the prompt that was created, or null
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
|
openMessageDialog(titleKey, messageKey, i18nOptions, closeFunction) {
|
||||||
if (!popupEnabled)
|
if (!popupEnabled) {
|
||||||
return null;
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
let dialog = $.prompt(
|
const dialog = $.prompt(
|
||||||
APP.translation.generateTranslationHTML(messageKey, i18nOptions),
|
APP.translation.generateTranslationHTML(messageKey, i18nOptions),
|
||||||
{
|
{
|
||||||
title: this._getFormattedTitleString(titleKey),
|
title: this._getFormattedTitleString(titleKey),
|
||||||
persistent: false,
|
persistent: false,
|
||||||
promptspeed: 0,
|
promptspeed: 0,
|
||||||
classes: this._getDialogClasses(),
|
classes: this._getDialogClasses(),
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
close(e, v, m, f) {
|
close(e, v, m, f) {
|
||||||
if(closeFunction)
|
if (closeFunction) {
|
||||||
closeFunction(e, v, m, f);
|
closeFunction(e, v, m, f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
APP.translation.translateElement(dialog, i18nOptions);
|
APP.translation.translateElement(dialog, i18nOptions);
|
||||||
|
|
||||||
return $.prompt.getApi();
|
return $.prompt.getApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows a message to the user with two buttons: first is given as a
|
* Shows a message to the user with two buttons: first is given as a
|
||||||
* parameter and the second is Cancel.
|
* parameter and the second is Cancel.
|
||||||
|
@ -169,8 +182,8 @@ var messageHandler = {
|
||||||
* storage. if not provided dontShowAgain.id will be used.
|
* storage. if not provided dontShowAgain.id will be used.
|
||||||
* @return the prompt that was created, or null
|
* @return the prompt that was created, or null
|
||||||
*/
|
*/
|
||||||
openTwoButtonDialog: function(options) {
|
openTwoButtonDialog(options) {
|
||||||
let {
|
const {
|
||||||
titleKey,
|
titleKey,
|
||||||
msgKey,
|
msgKey,
|
||||||
msgString,
|
msgString,
|
||||||
|
@ -182,32 +195,40 @@ var messageHandler = {
|
||||||
size,
|
size,
|
||||||
defaultButton,
|
defaultButton,
|
||||||
wrapperClass,
|
wrapperClass,
|
||||||
classes,
|
|
||||||
dontShowAgain
|
dontShowAgain
|
||||||
} = options;
|
} = options;
|
||||||
|
|
||||||
if (!popupEnabled || twoButtonDialog)
|
let { classes } = options;
|
||||||
return null;
|
|
||||||
|
|
||||||
if(dontShowTheDialog(dontShowAgain)) {
|
if (!popupEnabled || twoButtonDialog) {
|
||||||
// Maybe we should pass some parameters here? I'm not sure
|
|
||||||
// and currently we don't need any parameters.
|
|
||||||
submitFunction();
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
var buttons = [];
|
if (dontShowTheDialog(dontShowAgain)) {
|
||||||
|
// Maybe we should pass some parameters here? I'm not sure
|
||||||
|
// and currently we don't need any parameters.
|
||||||
|
submitFunction();
|
||||||
|
|
||||||
var leftButton = leftButtonKey ?
|
return null;
|
||||||
APP.translation.generateTranslationHTML(leftButtonKey) :
|
}
|
||||||
APP.translation.generateTranslationHTML('dialog.Submit');
|
|
||||||
buttons.push({ title: leftButton, value: true});
|
|
||||||
|
|
||||||
var cancelButton
|
const buttons = [];
|
||||||
= APP.translation.generateTranslationHTML("dialog.Cancel");
|
|
||||||
buttons.push({title: cancelButton, value: false});
|
const leftButton = leftButtonKey
|
||||||
|
? APP.translation.generateTranslationHTML(leftButtonKey)
|
||||||
|
: APP.translation.generateTranslationHTML('dialog.Submit');
|
||||||
|
|
||||||
|
buttons.push({ title: leftButton,
|
||||||
|
value: true });
|
||||||
|
|
||||||
|
const cancelButton
|
||||||
|
= APP.translation.generateTranslationHTML('dialog.Cancel');
|
||||||
|
|
||||||
|
buttons.push({ title: cancelButton,
|
||||||
|
value: false });
|
||||||
|
|
||||||
|
let message = msgString;
|
||||||
|
|
||||||
var message = msgString;
|
|
||||||
if (msgKey) {
|
if (msgKey) {
|
||||||
message = APP.translation.generateTranslationHTML(msgKey);
|
message = APP.translation.generateTranslationHTML(msgKey);
|
||||||
}
|
}
|
||||||
|
@ -220,20 +241,20 @@ var messageHandler = {
|
||||||
twoButtonDialog = $.prompt(message, {
|
twoButtonDialog = $.prompt(message, {
|
||||||
title: this._getFormattedTitleString(titleKey),
|
title: this._getFormattedTitleString(titleKey),
|
||||||
persistent: false,
|
persistent: false,
|
||||||
buttons: buttons,
|
buttons,
|
||||||
defaultButton: defaultButton,
|
defaultButton,
|
||||||
focus: focus,
|
focus,
|
||||||
loaded: loadedFunction,
|
loaded: loadedFunction,
|
||||||
promptspeed: 0,
|
promptspeed: 0,
|
||||||
classes,
|
classes,
|
||||||
submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
|
submit: dontShowAgainSubmitFunctionWrapper(dontShowAgain,
|
||||||
function (e, v, m, f) {
|
(e, v, m, f) => { // eslint-disable-line max-params
|
||||||
twoButtonDialog = null;
|
twoButtonDialog = null;
|
||||||
if (v && submitFunction) {
|
if (v && submitFunction) {
|
||||||
submitFunction(e, v, m, f);
|
submitFunction(e, v, m, f);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
close: function (e, v, m, f) {
|
close(e, v, m, f) { // eslint-disable-line max-params
|
||||||
twoButtonDialog = null;
|
twoButtonDialog = null;
|
||||||
if (closeFunction) {
|
if (closeFunction) {
|
||||||
closeFunction(e, v, m, f);
|
closeFunction(e, v, m, f);
|
||||||
|
@ -241,6 +262,7 @@ var messageHandler = {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
APP.translation.translateElement(twoButtonDialog);
|
APP.translation.translateElement(twoButtonDialog);
|
||||||
|
|
||||||
return $.prompt.getApi();
|
return $.prompt.getApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -270,7 +292,7 @@ var messageHandler = {
|
||||||
* @param {string} dontShowAgain.localStorageKey the key for the local
|
* @param {string} dontShowAgain.localStorageKey the key for the local
|
||||||
* storage. if not provided dontShowAgain.id will be used.
|
* storage. if not provided dontShowAgain.id will be used.
|
||||||
*/
|
*/
|
||||||
openDialog(
|
openDialog(// eslint-disable-line max-params
|
||||||
titleKey,
|
titleKey,
|
||||||
msgString,
|
msgString,
|
||||||
persistent,
|
persistent,
|
||||||
|
@ -279,29 +301,33 @@ var messageHandler = {
|
||||||
loadedFunction,
|
loadedFunction,
|
||||||
closeFunction,
|
closeFunction,
|
||||||
dontShowAgain) {
|
dontShowAgain) {
|
||||||
if (!popupEnabled)
|
if (!popupEnabled) {
|
||||||
return;
|
|
||||||
|
|
||||||
if(dontShowTheDialog(dontShowAgain)) {
|
|
||||||
// Maybe we should pass some parameters here? I'm not sure
|
|
||||||
// and currently we don't need any parameters.
|
|
||||||
submitFunction();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = {
|
if (dontShowTheDialog(dontShowAgain)) {
|
||||||
|
// Maybe we should pass some parameters here? I'm not sure
|
||||||
|
// and currently we don't need any parameters.
|
||||||
|
submitFunction();
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const args = {
|
||||||
title: this._getFormattedTitleString(titleKey),
|
title: this._getFormattedTitleString(titleKey),
|
||||||
persistent: persistent,
|
persistent,
|
||||||
buttons: buttons,
|
buttons,
|
||||||
defaultButton: 1,
|
defaultButton: 1,
|
||||||
promptspeed: 0,
|
promptspeed: 0,
|
||||||
loaded: function() {
|
loaded() {
|
||||||
if (loadedFunction) {
|
if (loadedFunction) {
|
||||||
|
// eslint-disable-next-line prefer-rest-params
|
||||||
loadedFunction.apply(this, arguments);
|
loadedFunction.apply(this, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide the close button
|
// Hide the close button
|
||||||
if (persistent) {
|
if (persistent) {
|
||||||
$(".jqiclose", this).hide();
|
$('.jqiclose', this).hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit: dontShowAgainSubmitFunctionWrapper(
|
submit: dontShowAgainSubmitFunctionWrapper(
|
||||||
|
@ -314,9 +340,11 @@ var messageHandler = {
|
||||||
args.closeText = '';
|
args.closeText = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let dialog = $.prompt(
|
const dialog = $.prompt(
|
||||||
msgString + generateDontShowCheckbox(dontShowAgain), args);
|
msgString + generateDontShowCheckbox(dontShowAgain), args);
|
||||||
|
|
||||||
APP.translation.translateElement(dialog);
|
APP.translation.translateElement(dialog);
|
||||||
|
|
||||||
return $.prompt.getApi();
|
return $.prompt.getApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -326,10 +354,13 @@ var messageHandler = {
|
||||||
* @return the title string formatted as a div.
|
* @return the title string formatted as a div.
|
||||||
*/
|
*/
|
||||||
_getFormattedTitleString(titleKey) {
|
_getFormattedTitleString(titleKey) {
|
||||||
let $titleString = $('<h2>');
|
const $titleString = $('<h2>');
|
||||||
|
|
||||||
$titleString.addClass('aui-dialog2-header-main');
|
$titleString.addClass('aui-dialog2-header-main');
|
||||||
$titleString.attr('data-i18n',titleKey);
|
$titleString.attr('data-i18n', titleKey);
|
||||||
return $('<div>').append($titleString).html();
|
|
||||||
|
return $('<div>').append($titleString)
|
||||||
|
.html();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -359,23 +390,28 @@ var messageHandler = {
|
||||||
* @param options impromptu options
|
* @param options impromptu options
|
||||||
* @param translateOptions options passed to translation
|
* @param translateOptions options passed to translation
|
||||||
*/
|
*/
|
||||||
openDialogWithStates: function (statesObject, options, translateOptions) {
|
openDialogWithStates(statesObject, options, translateOptions) {
|
||||||
if (!popupEnabled)
|
if (!popupEnabled) {
|
||||||
return;
|
return;
|
||||||
let { classes, size } = options;
|
}
|
||||||
let defaultClasses = this._getDialogClasses(size);
|
const { classes, size } = options;
|
||||||
|
const defaultClasses = this._getDialogClasses(size);
|
||||||
|
|
||||||
options.classes = Object.assign({}, defaultClasses, classes);
|
options.classes = Object.assign({}, defaultClasses, classes);
|
||||||
options.promptspeed = options.promptspeed || 0;
|
options.promptspeed = options.promptspeed || 0;
|
||||||
|
|
||||||
for (let state in statesObject) {
|
for (const state in statesObject) { // eslint-disable-line guard-for-in
|
||||||
let currentState = statesObject[state];
|
const currentState = statesObject[state];
|
||||||
if(currentState.titleKey) {
|
|
||||||
|
if (currentState.titleKey) {
|
||||||
currentState.title
|
currentState.title
|
||||||
= this._getFormattedTitleString(currentState.titleKey);
|
= this._getFormattedTitleString(currentState.titleKey);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let dialog = $.prompt(statesObject, options);
|
const dialog = $.prompt(statesObject, options);
|
||||||
|
|
||||||
APP.translation.translateElement(dialog, translateOptions);
|
APP.translation.translateElement(dialog, translateOptions);
|
||||||
|
|
||||||
return $.prompt.getApi();
|
return $.prompt.getApi();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -392,17 +428,20 @@ var messageHandler = {
|
||||||
* @returns {object} popup window object if opened successfully or undefined
|
* @returns {object} popup window object if opened successfully or undefined
|
||||||
* in case we failed to open it(popup blocked)
|
* in case we failed to open it(popup blocked)
|
||||||
*/
|
*/
|
||||||
openCenteredPopup: function (url, w, h, onPopupClosed) {
|
// eslint-disable-next-line max-params
|
||||||
if (!popupEnabled)
|
openCenteredPopup(url, w, h, onPopupClosed) {
|
||||||
|
if (!popupEnabled) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var l = window.screenX + (window.innerWidth / 2) - (w / 2);
|
const l = window.screenX + (window.innerWidth / 2) - (w / 2);
|
||||||
var t = window.screenY + (window.innerHeight / 2) - (h / 2);
|
const t = window.screenY + (window.innerHeight / 2) - (h / 2);
|
||||||
var popup = window.open(
|
const popup = window.open(
|
||||||
url, '_blank',
|
url, '_blank',
|
||||||
'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
|
String(`top=${t}, left=${l}, width=${w}, height=${h}`));
|
||||||
|
|
||||||
if (popup && onPopupClosed) {
|
if (popup && onPopupClosed) {
|
||||||
var pollTimer = window.setInterval(function () {
|
const pollTimer = window.setInterval(() => {
|
||||||
if (popup.closed !== false) {
|
if (popup.closed !== false) {
|
||||||
window.clearInterval(pollTimer);
|
window.clearInterval(pollTimer);
|
||||||
onPopupClosed();
|
onPopupClosed();
|
||||||
|
@ -420,10 +459,11 @@ var messageHandler = {
|
||||||
* @param msgKey the text of the message
|
* @param msgKey the text of the message
|
||||||
* @param error the error that is being reported
|
* @param error the error that is being reported
|
||||||
*/
|
*/
|
||||||
openReportDialog: function(titleKey, msgKey, error) {
|
openReportDialog(titleKey, msgKey, error) {
|
||||||
this.openMessageDialog(titleKey, msgKey);
|
this.openMessageDialog(titleKey, msgKey);
|
||||||
logger.log(error);
|
logger.log(error);
|
||||||
//FIXME send the error to the server
|
|
||||||
|
// FIXME send the error to the server
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -431,14 +471,7 @@ var messageHandler = {
|
||||||
* @param titleKey the title of the message.
|
* @param titleKey the title of the message.
|
||||||
* @param msgKey the text of the message.
|
* @param msgKey the text of the message.
|
||||||
*/
|
*/
|
||||||
showError: function(titleKey, msgKey) {
|
showError(titleKey = 'dialog.oops', msgKey = 'dialog.defaultError') {
|
||||||
|
|
||||||
if (!titleKey) {
|
|
||||||
titleKey = "dialog.oops";
|
|
||||||
}
|
|
||||||
if (!msgKey) {
|
|
||||||
msgKey = "dialog.defaultError";
|
|
||||||
}
|
|
||||||
messageHandler.openMessageDialog(titleKey, msgKey);
|
messageHandler.openMessageDialog(titleKey, msgKey);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -454,7 +487,7 @@ var messageHandler = {
|
||||||
* @param messageArguments object with the arguments for the message.
|
* @param messageArguments object with the arguments for the message.
|
||||||
* @param optional configurations for the notification (e.g. timeout)
|
* @param optional configurations for the notification (e.g. timeout)
|
||||||
*/
|
*/
|
||||||
participantNotification(
|
participantNotification( // eslint-disable-line max-params
|
||||||
displayName,
|
displayName,
|
||||||
displayNameKey,
|
displayNameKey,
|
||||||
cls,
|
cls,
|
||||||
|
@ -484,12 +517,12 @@ var messageHandler = {
|
||||||
* translation.
|
* translation.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
notify: function(titleKey, messageKey, messageArguments) {
|
notify(titleKey, messageKey, messageArguments) {
|
||||||
this.participantNotification(
|
this.participantNotification(
|
||||||
null, titleKey, null, messageKey, messageArguments);
|
null, titleKey, null, messageKey, messageArguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
enablePopups: function (enable) {
|
enablePopups(enable) {
|
||||||
popupEnabled = enable;
|
popupEnabled = enable;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -498,8 +531,8 @@ var messageHandler = {
|
||||||
* false otherwise
|
* false otherwise
|
||||||
* @returns {boolean} isOpened
|
* @returns {boolean} isOpened
|
||||||
*/
|
*/
|
||||||
isDialogOpened: function () {
|
isDialogOpened() {
|
||||||
return !!$.prompt.getCurrentStateName();
|
return Boolean($.prompt.getCurrentStateName());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ const IndicatorFontSizes = {
|
||||||
/**
|
/**
|
||||||
* Created by hristo on 12/22/14.
|
* Created by hristo on 12/22/14.
|
||||||
*/
|
*/
|
||||||
var UIUtil = {
|
const UIUtil = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the available video width.
|
* Returns the available video width.
|
||||||
|
@ -43,17 +43,18 @@ var UIUtil = {
|
||||||
/**
|
/**
|
||||||
* Changes the style class of the element given by id.
|
* Changes the style class of the element given by id.
|
||||||
*/
|
*/
|
||||||
buttonClick: function(id, classname) {
|
buttonClick(id, classname) {
|
||||||
// add the class to the clicked element
|
// add the class to the clicked element
|
||||||
$("#" + id).toggleClass(classname);
|
$(`#${id}`).toggleClass(classname);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the text width for the given element.
|
* Returns the text width for the given element.
|
||||||
*
|
*
|
||||||
* @param el the element
|
* @param el the element
|
||||||
*/
|
*/
|
||||||
getTextWidth(el) {
|
getTextWidth(el) {
|
||||||
return (el.clientWidth + 1);
|
return el.clientWidth + 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,7 +63,7 @@ var UIUtil = {
|
||||||
* @param el the element
|
* @param el the element
|
||||||
*/
|
*/
|
||||||
getTextHeight(el) {
|
getTextHeight(el) {
|
||||||
return (el.clientHeight + 1);
|
return el.clientHeight + 1;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,7 +79,8 @@ var UIUtil = {
|
||||||
* Escapes the given text.
|
* Escapes the given text.
|
||||||
*/
|
*/
|
||||||
escapeHtml(unsafeText) {
|
escapeHtml(unsafeText) {
|
||||||
return $('<div/>').text(unsafeText).html();
|
return $('<div/>').text(unsafeText)
|
||||||
|
.html();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,22 +90,27 @@ var UIUtil = {
|
||||||
* @returns {string} unescaped html string.
|
* @returns {string} unescaped html string.
|
||||||
*/
|
*/
|
||||||
unescapeHtml(safe) {
|
unescapeHtml(safe) {
|
||||||
return $('<div />').html(safe).text();
|
return $('<div />').html(safe)
|
||||||
|
.text();
|
||||||
},
|
},
|
||||||
|
|
||||||
imageToGrayScale(canvas) {
|
imageToGrayScale(canvas) {
|
||||||
var context = canvas.getContext('2d');
|
const context = canvas.getContext('2d');
|
||||||
var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
|
const imgData = context.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
var pixels = imgData.data;
|
const pixels = imgData.data;
|
||||||
|
|
||||||
for (var i = 0, n = pixels.length; i < n; i += 4) {
|
for (let i = 0, n = pixels.length; i < n; i += 4) {
|
||||||
var grayscale
|
const grayscale
|
||||||
= pixels[i] * 0.3 + pixels[i+1] * 0.59 + pixels[i+2] * 0.11;
|
= (pixels[i] * 0.3)
|
||||||
pixels[i ] = grayscale; // red
|
+ (pixels[i + 1] * 0.59)
|
||||||
pixels[i+1] = grayscale; // green
|
+ (pixels[i + 2] * 0.11);
|
||||||
pixels[i+2] = grayscale; // blue
|
|
||||||
|
pixels[i] = grayscale; // red
|
||||||
|
pixels[i + 1] = grayscale; // green
|
||||||
|
pixels[i + 2] = grayscale; // blue
|
||||||
// pixels[i+3] is alpha
|
// pixels[i+3] is alpha
|
||||||
}
|
}
|
||||||
|
|
||||||
// redraw the image in black & white
|
// redraw the image in black & white
|
||||||
context.putImageData(imgData, 0, 0);
|
context.putImageData(imgData, 0, 0);
|
||||||
},
|
},
|
||||||
|
@ -114,7 +121,8 @@ var UIUtil = {
|
||||||
* @param newChild the new element that will be inserted into the container
|
* @param newChild the new element that will be inserted into the container
|
||||||
*/
|
*/
|
||||||
prependChild(container, newChild) {
|
prependChild(container, newChild) {
|
||||||
var firstChild = container.childNodes[0];
|
const firstChild = container.childNodes[0];
|
||||||
|
|
||||||
if (firstChild) {
|
if (firstChild) {
|
||||||
container.insertBefore(newChild, firstChild);
|
container.insertBefore(newChild, firstChild);
|
||||||
} else {
|
} else {
|
||||||
|
@ -152,6 +160,7 @@ var UIUtil = {
|
||||||
*/
|
*/
|
||||||
setVisible(id, visible) {
|
setVisible(id, visible) {
|
||||||
let element;
|
let element;
|
||||||
|
|
||||||
if (id instanceof HTMLElement) {
|
if (id instanceof HTMLElement) {
|
||||||
element = id;
|
element = id;
|
||||||
} else {
|
} else {
|
||||||
|
@ -162,20 +171,20 @@ var UIUtil = {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!visible)
|
if (!visible) {
|
||||||
element.classList.add('hide');
|
element.classList.add('hide');
|
||||||
else if (element.classList.contains('hide')) {
|
} else if (element.classList.contains('hide')) {
|
||||||
element.classList.remove('hide');
|
element.classList.remove('hide');
|
||||||
}
|
}
|
||||||
|
|
||||||
let type = this._getElementDefaultDisplay(element.tagName);
|
const type = this._getElementDefaultDisplay(element.tagName);
|
||||||
let className = SHOW_CLASSES[type];
|
const className = SHOW_CLASSES[type];
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
element.classList.add(className);
|
element.classList.add(className);
|
||||||
}
|
} else if (element.classList.contains(className)) {
|
||||||
else if (element.classList.contains(className))
|
|
||||||
element.classList.remove(className);
|
element.classList.remove(className);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -185,10 +194,11 @@ var UIUtil = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getElementDefaultDisplay(tag) {
|
_getElementDefaultDisplay(tag) {
|
||||||
let tempElement = document.createElement(tag);
|
const tempElement = document.createElement(tag);
|
||||||
|
|
||||||
document.body.appendChild(tempElement);
|
document.body.appendChild(tempElement);
|
||||||
let style = window.getComputedStyle(tempElement).display;
|
const style = window.getComputedStyle(tempElement).display;
|
||||||
|
|
||||||
document.body.removeChild(tempElement);
|
document.body.removeChild(tempElement);
|
||||||
|
|
||||||
return style;
|
return style;
|
||||||
|
@ -203,7 +213,7 @@ var UIUtil = {
|
||||||
*/
|
*/
|
||||||
setVisibleBySelector(jquerySelector, isVisible) {
|
setVisibleBySelector(jquerySelector, isVisible) {
|
||||||
if (jquerySelector && jquerySelector.length > 0) {
|
if (jquerySelector && jquerySelector.length > 0) {
|
||||||
jquerySelector.css("visibility", isVisible ? "visible" : "hidden");
|
jquerySelector.css('visibility', isVisible ? 'visible' : 'hidden');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -264,7 +274,8 @@ var UIUtil = {
|
||||||
*/
|
*/
|
||||||
attrsToString(attrs) {
|
attrsToString(attrs) {
|
||||||
return (
|
return (
|
||||||
Object.keys(attrs).map(key => ` ${key}="${attrs[key]}"`).join(' '));
|
Object.keys(attrs).map(key => ` ${key}="${attrs[key]}"`)
|
||||||
|
.join(' '));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -275,7 +286,7 @@ var UIUtil = {
|
||||||
* @param {el} The DOM element we'd like to check for visibility
|
* @param {el} The DOM element we'd like to check for visibility
|
||||||
*/
|
*/
|
||||||
isVisible(el) {
|
isVisible(el) {
|
||||||
return (el.offsetParent !== null);
|
return el.offsetParent !== null;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -288,26 +299,33 @@ var UIUtil = {
|
||||||
* element
|
* element
|
||||||
*/
|
*/
|
||||||
animateShowElement(selector, show, hideDelay) {
|
animateShowElement(selector, show, hideDelay) {
|
||||||
if(show) {
|
if (show) {
|
||||||
if (!selector.is(":visible"))
|
if (!selector.is(':visible')) {
|
||||||
selector.css("display", "inline-block");
|
selector.css('display', 'inline-block');
|
||||||
|
}
|
||||||
|
|
||||||
selector.fadeIn(300,
|
selector.fadeIn(300,
|
||||||
() => {selector.css({opacity: 1});}
|
() => {
|
||||||
|
selector.css({ opacity: 1 });
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
if (hideDelay && hideDelay > 0)
|
if (hideDelay && hideDelay > 0) {
|
||||||
setTimeout(
|
setTimeout(
|
||||||
() => {
|
() => {
|
||||||
selector.fadeOut(
|
selector.fadeOut(
|
||||||
300,
|
300,
|
||||||
() => { selector.css({opacity: 0}); });
|
() => {
|
||||||
|
selector.css({ opacity: 0 });
|
||||||
|
});
|
||||||
},
|
},
|
||||||
hideDelay);
|
hideDelay);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
selector.fadeOut(300,
|
selector.fadeOut(300,
|
||||||
() => {selector.css({opacity: 0});}
|
() => {
|
||||||
|
selector.css({ opacity: 0 });
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -318,7 +336,7 @@ var UIUtil = {
|
||||||
* @param cssValue the string value we obtain when querying css properties
|
* @param cssValue the string value we obtain when querying css properties
|
||||||
*/
|
*/
|
||||||
parseCssInt(cssValue) {
|
parseCssInt(cssValue) {
|
||||||
return parseInt(cssValue) || 0;
|
return parseInt(cssValue, 10) || 0;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -332,8 +350,8 @@ var UIUtil = {
|
||||||
aLinkElement.attr('href', link);
|
aLinkElement.attr('href', link);
|
||||||
} else {
|
} else {
|
||||||
aLinkElement.css({
|
aLinkElement.css({
|
||||||
"pointer-events": "none",
|
'pointer-events': 'none',
|
||||||
"cursor": "default"
|
'cursor': 'default'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
import { setFilmstripVisibility } from '../../../react/features/filmstrip';
|
import { setFilmstripVisibility } from '../../../react/features/filmstrip';
|
||||||
|
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
import UIUtil from "../util/UIUtil";
|
import UIUtil from '../util/UIUtil';
|
||||||
|
|
||||||
import { sendEvent } from '../../../react/features/analytics';
|
import { sendEvent } from '../../../react/features/analytics';
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const Filmstrip = {
|
||||||
* @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
|
* @param eventEmitter the {EventEmitter} through which {Filmstrip} is to
|
||||||
* emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
|
* emit/fire {UIEvents} (such as {UIEvents.TOGGLED_FILMSTRIP}).
|
||||||
*/
|
*/
|
||||||
init (eventEmitter) {
|
init(eventEmitter) {
|
||||||
this.iconMenuDownClassName = 'icon-menu-down';
|
this.iconMenuDownClassName = 'icon-menu-down';
|
||||||
this.iconMenuUpClassName = 'icon-menu-up';
|
this.iconMenuUpClassName = 'icon-menu-up';
|
||||||
this.filmstripContainerClassName = 'filmstrip';
|
this.filmstripContainerClassName = 'filmstrip';
|
||||||
|
@ -33,13 +33,14 @@ const Filmstrip = {
|
||||||
* Initializes the filmstrip toolbar.
|
* Initializes the filmstrip toolbar.
|
||||||
*/
|
*/
|
||||||
_initFilmstripToolbar() {
|
_initFilmstripToolbar() {
|
||||||
let toolbarContainerHTML = this._generateToolbarHTML();
|
const toolbarContainerHTML = this._generateToolbarHTML();
|
||||||
let className = this.filmstripContainerClassName;
|
const className = this.filmstripContainerClassName;
|
||||||
let container = document.querySelector(`.${className}`);
|
const container = document.querySelector(`.${className}`);
|
||||||
|
|
||||||
UIUtil.prependChild(container, toolbarContainerHTML);
|
UIUtil.prependChild(container, toolbarContainerHTML);
|
||||||
|
|
||||||
let iconSelector = '#toggleFilmstripButton i';
|
const iconSelector = '#toggleFilmstripButton i';
|
||||||
|
|
||||||
this.toggleFilmstripIcon = document.querySelector(iconSelector);
|
this.toggleFilmstripIcon = document.querySelector(iconSelector);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -49,8 +50,9 @@ const Filmstrip = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_generateToolbarHTML() {
|
_generateToolbarHTML() {
|
||||||
let container = document.createElement('div');
|
const container = document.createElement('div');
|
||||||
let isVisible = this.isFilmstripVisible();
|
const isVisible = this.isFilmstripVisible();
|
||||||
|
|
||||||
container.className = 'filmstrip__toolbar';
|
container.className = 'filmstrip__toolbar';
|
||||||
container.innerHTML = `
|
container.innerHTML = `
|
||||||
<button id="toggleFilmstripButton">
|
<button id="toggleFilmstripButton">
|
||||||
|
@ -81,14 +83,15 @@ const Filmstrip = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_registerToggleFilmstripShortcut() {
|
_registerToggleFilmstripShortcut() {
|
||||||
let shortcut = 'F';
|
const shortcut = 'F';
|
||||||
let shortcutAttr = 'filmstripPopover';
|
const shortcutAttr = 'filmstripPopover';
|
||||||
let description = 'keyboardShortcuts.toggleFilmstrip';
|
const description = 'keyboardShortcuts.toggleFilmstrip';
|
||||||
|
|
||||||
// Important:
|
// Important:
|
||||||
// Firing the event instead of executing toggleFilmstrip method because
|
// Firing the event instead of executing toggleFilmstrip method because
|
||||||
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
// it's important to hide the filmstrip by UI.toggleFilmstrip in order
|
||||||
// to correctly resize the video area.
|
// to correctly resize the video area.
|
||||||
let handler = () => this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
const handler = () => this.eventEmitter.emit(UIEvents.TOGGLE_FILMSTRIP);
|
||||||
|
|
||||||
APP.keyboardshortcut.registerShortcut(
|
APP.keyboardshortcut.registerShortcut(
|
||||||
shortcut,
|
shortcut,
|
||||||
|
@ -102,8 +105,9 @@ const Filmstrip = {
|
||||||
* Changes classes of icon for showing down state
|
* Changes classes of icon for showing down state
|
||||||
*/
|
*/
|
||||||
showMenuDownIcon() {
|
showMenuDownIcon() {
|
||||||
let icon = this.toggleFilmstripIcon;
|
const icon = this.toggleFilmstripIcon;
|
||||||
if(icon) {
|
|
||||||
|
if (icon) {
|
||||||
icon.classList.add(this.iconMenuDownClassName);
|
icon.classList.add(this.iconMenuDownClassName);
|
||||||
icon.classList.remove(this.iconMenuUpClassName);
|
icon.classList.remove(this.iconMenuUpClassName);
|
||||||
}
|
}
|
||||||
|
@ -113,8 +117,9 @@ const Filmstrip = {
|
||||||
* Changes classes of icon for showing up state
|
* Changes classes of icon for showing up state
|
||||||
*/
|
*/
|
||||||
showMenuUpIcon() {
|
showMenuUpIcon() {
|
||||||
let icon = this.toggleFilmstripIcon;
|
const icon = this.toggleFilmstripIcon;
|
||||||
if(icon) {
|
|
||||||
|
if (icon) {
|
||||||
icon.classList.add(this.iconMenuUpClassName);
|
icon.classList.add(this.iconMenuUpClassName);
|
||||||
icon.classList.remove(this.iconMenuDownClassName);
|
icon.classList.remove(this.iconMenuDownClassName);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +142,9 @@ const Filmstrip = {
|
||||||
*/
|
*/
|
||||||
toggleFilmstrip(visible, sendAnalytics = true) {
|
toggleFilmstrip(visible, sendAnalytics = true) {
|
||||||
const isVisibleDefined = typeof visible === 'boolean';
|
const isVisibleDefined = typeof visible === 'boolean';
|
||||||
|
|
||||||
if (!isVisibleDefined) {
|
if (!isVisibleDefined) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
visible = this.isFilmstripVisible();
|
visible = this.isFilmstripVisible();
|
||||||
} else if (this.isFilmstripVisible() === visible) {
|
} else if (this.isFilmstripVisible() === visible) {
|
||||||
return;
|
return;
|
||||||
|
@ -145,7 +152,7 @@ const Filmstrip = {
|
||||||
if (sendAnalytics) {
|
if (sendAnalytics) {
|
||||||
sendEvent('toolbar.filmstrip.toggled');
|
sendEvent('toolbar.filmstrip.toggled');
|
||||||
}
|
}
|
||||||
this.filmstrip.toggleClass("hidden");
|
this.filmstrip.toggleClass('hidden');
|
||||||
|
|
||||||
if (visible) {
|
if (visible) {
|
||||||
this.showMenuUpIcon();
|
this.showMenuUpIcon();
|
||||||
|
@ -190,9 +197,10 @@ const Filmstrip = {
|
||||||
// display should be.
|
// display should be.
|
||||||
if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
|
if (this.isFilmstripVisible() && !interfaceConfig.VERTICAL_FILMSTRIP) {
|
||||||
return $(`.${this.filmstripContainerClassName}`).outerHeight();
|
return $(`.${this.filmstripContainerClassName}`).outerHeight();
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,9 +208,9 @@ const Filmstrip = {
|
||||||
* @returns {*|{localVideo, remoteVideo}}
|
* @returns {*|{localVideo, remoteVideo}}
|
||||||
*/
|
*/
|
||||||
calculateThumbnailSize() {
|
calculateThumbnailSize() {
|
||||||
let availableSizes = this.calculateAvailableSize();
|
const availableSizes = this.calculateAvailableSize();
|
||||||
let width = availableSizes.availableWidth;
|
const width = availableSizes.availableWidth;
|
||||||
let height = availableSizes.availableHeight;
|
const height = availableSizes.availableHeight;
|
||||||
|
|
||||||
return this.calculateThumbnailSizeFromAvailable(width, height);
|
return this.calculateThumbnailSizeFromAvailable(width, height);
|
||||||
},
|
},
|
||||||
|
@ -215,17 +223,17 @@ const Filmstrip = {
|
||||||
*/
|
*/
|
||||||
calculateAvailableSize() {
|
calculateAvailableSize() {
|
||||||
let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
|
let availableHeight = interfaceConfig.FILM_STRIP_MAX_HEIGHT;
|
||||||
let thumbs = this.getThumbs(true);
|
const thumbs = this.getThumbs(true);
|
||||||
let numvids = thumbs.remoteThumbs.length;
|
const numvids = thumbs.remoteThumbs.length;
|
||||||
|
|
||||||
let localVideoContainer = $("#localVideoContainer");
|
const localVideoContainer = $('#localVideoContainer');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the videoAreaAvailableWidth is set we use this one to calculate
|
* If the videoAreaAvailableWidth is set we use this one to calculate
|
||||||
* the filmstrip width, because we're probably in a state where the
|
* the filmstrip width, because we're probably in a state where the
|
||||||
* filmstrip size hasn't been updated yet, but it will be.
|
* filmstrip size hasn't been updated yet, but it will be.
|
||||||
*/
|
*/
|
||||||
let videoAreaAvailableWidth
|
const videoAreaAvailableWidth
|
||||||
= UIUtil.getAvailableVideoWidth()
|
= UIUtil.getAvailableVideoWidth()
|
||||||
- this._getFilmstripExtraPanelsWidth()
|
- this._getFilmstripExtraPanelsWidth()
|
||||||
- UIUtil.parseCssInt(this.filmstrip.css('right'), 10)
|
- UIUtil.parseCssInt(this.filmstrip.css('right'), 10)
|
||||||
|
@ -238,9 +246,9 @@ const Filmstrip = {
|
||||||
let availableWidth = videoAreaAvailableWidth;
|
let availableWidth = videoAreaAvailableWidth;
|
||||||
|
|
||||||
// If local thumb is not hidden
|
// If local thumb is not hidden
|
||||||
if(thumbs.localThumb) {
|
if (thumbs.localThumb) {
|
||||||
availableWidth = Math.floor(
|
availableWidth = Math.floor(
|
||||||
(videoAreaAvailableWidth - (
|
videoAreaAvailableWidth - (
|
||||||
UIUtil.parseCssInt(
|
UIUtil.parseCssInt(
|
||||||
localVideoContainer.css('borderLeftWidth'), 10)
|
localVideoContainer.css('borderLeftWidth'), 10)
|
||||||
+ UIUtil.parseCssInt(
|
+ UIUtil.parseCssInt(
|
||||||
|
@ -252,7 +260,7 @@ const Filmstrip = {
|
||||||
+ UIUtil.parseCssInt(
|
+ UIUtil.parseCssInt(
|
||||||
localVideoContainer.css('marginLeft'), 10)
|
localVideoContainer.css('marginLeft'), 10)
|
||||||
+ UIUtil.parseCssInt(
|
+ UIUtil.parseCssInt(
|
||||||
localVideoContainer.css('marginRight'), 10)))
|
localVideoContainer.css('marginRight'), 10))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -260,9 +268,10 @@ const Filmstrip = {
|
||||||
// filmstrip mode we don't need to calculate further any adjustments
|
// filmstrip mode we don't need to calculate further any adjustments
|
||||||
// to width based on the number of videos present.
|
// to width based on the number of videos present.
|
||||||
if (numvids && !interfaceConfig.VERTICAL_FILMSTRIP) {
|
if (numvids && !interfaceConfig.VERTICAL_FILMSTRIP) {
|
||||||
let remoteVideoContainer = thumbs.remoteThumbs.eq(0);
|
const remoteVideoContainer = thumbs.remoteThumbs.eq(0);
|
||||||
|
|
||||||
availableWidth = Math.floor(
|
availableWidth = Math.floor(
|
||||||
(videoAreaAvailableWidth - numvids * (
|
videoAreaAvailableWidth - (numvids * (
|
||||||
UIUtil.parseCssInt(
|
UIUtil.parseCssInt(
|
||||||
remoteVideoContainer.css('borderLeftWidth'), 10)
|
remoteVideoContainer.css('borderLeftWidth'), 10)
|
||||||
+ UIUtil.parseCssInt(
|
+ UIUtil.parseCssInt(
|
||||||
|
@ -278,7 +287,8 @@ const Filmstrip = {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let maxHeight
|
const maxHeight
|
||||||
|
|
||||||
// If the MAX_HEIGHT property hasn't been specified
|
// If the MAX_HEIGHT property hasn't been specified
|
||||||
// we have the static value.
|
// we have the static value.
|
||||||
= Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
|
= Math.min(interfaceConfig.FILM_STRIP_MAX_HEIGHT || 120,
|
||||||
|
@ -287,7 +297,8 @@ const Filmstrip = {
|
||||||
availableHeight
|
availableHeight
|
||||||
= Math.min(maxHeight, window.innerHeight - 18);
|
= Math.min(maxHeight, window.innerHeight - 18);
|
||||||
|
|
||||||
return { availableWidth, availableHeight };
|
return { availableWidth,
|
||||||
|
availableHeight };
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -300,15 +311,19 @@ const Filmstrip = {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_getFilmstripExtraPanelsWidth() {
|
_getFilmstripExtraPanelsWidth() {
|
||||||
let className = this.filmstripContainerClassName;
|
const className = this.filmstripContainerClassName;
|
||||||
let width = 0;
|
let width = 0;
|
||||||
|
|
||||||
$(`.${className}`)
|
$(`.${className}`)
|
||||||
.children()
|
.children()
|
||||||
.each(function () {
|
.each(function() {
|
||||||
|
/* eslint-disable no-invalid-this */
|
||||||
if (this.id !== 'remoteVideos') {
|
if (this.id !== 'remoteVideos') {
|
||||||
width += $(this).outerWidth();
|
width += $(this).outerWidth();
|
||||||
}
|
}
|
||||||
|
/* eslint-enable no-invalid-this */
|
||||||
});
|
});
|
||||||
|
|
||||||
return width;
|
return width;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -362,16 +377,17 @@ const Filmstrip = {
|
||||||
|
|
||||||
const remoteThumbsInRow = interfaceConfig.VERTICAL_FILMSTRIP
|
const remoteThumbsInRow = interfaceConfig.VERTICAL_FILMSTRIP
|
||||||
? 0 : this.getThumbs(true).remoteThumbs.length;
|
? 0 : this.getThumbs(true).remoteThumbs.length;
|
||||||
const remoteLocalWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO /
|
const remoteLocalWidthRatio = interfaceConfig.REMOTE_THUMBNAIL_RATIO
|
||||||
interfaceConfig.LOCAL_THUMBNAIL_RATIO;
|
/ interfaceConfig.LOCAL_THUMBNAIL_RATIO;
|
||||||
const lW = Math.min(availableWidth /
|
const lW = Math.min(availableWidth
|
||||||
(remoteLocalWidthRatio * remoteThumbsInRow + 1), availableHeight *
|
/ ((remoteLocalWidthRatio * remoteThumbsInRow) + 1), availableHeight
|
||||||
interfaceConfig.LOCAL_THUMBNAIL_RATIO);
|
* interfaceConfig.LOCAL_THUMBNAIL_RATIO);
|
||||||
const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
|
const h = lW / interfaceConfig.LOCAL_THUMBNAIL_RATIO;
|
||||||
|
|
||||||
const remoteVideoWidth = lW * remoteLocalWidthRatio;
|
const remoteVideoWidth = lW * remoteLocalWidthRatio;
|
||||||
|
|
||||||
let localVideo;
|
let localVideo;
|
||||||
|
|
||||||
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
||||||
localVideo = {
|
localVideo = {
|
||||||
thumbWidth: remoteVideoWidth,
|
thumbWidth: remoteVideoWidth,
|
||||||
|
@ -401,28 +417,32 @@ const Filmstrip = {
|
||||||
* @param forceUpdate
|
* @param forceUpdate
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line max-params
|
||||||
resizeThumbnails(local, remote, animate = false, forceUpdate = false) {
|
resizeThumbnails(local, remote, animate = false, forceUpdate = false) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let thumbs = this.getThumbs(!forceUpdate);
|
const thumbs = this.getThumbs(!forceUpdate);
|
||||||
let promises = [];
|
const promises = [];
|
||||||
|
|
||||||
if(thumbs.localThumb) {
|
if (thumbs.localThumb) {
|
||||||
promises.push(new Promise((resolve) => {
|
// eslint-disable-next-line no-shadow
|
||||||
|
promises.push(new Promise(resolve => {
|
||||||
thumbs.localThumb.animate({
|
thumbs.localThumb.animate({
|
||||||
height: local.thumbHeight,
|
height: local.thumbHeight,
|
||||||
width: local.thumbWidth
|
width: local.thumbWidth
|
||||||
}, this._getAnimateOptions(animate, resolve));
|
}, this._getAnimateOptions(animate, resolve));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if(thumbs.remoteThumbs) {
|
if (thumbs.remoteThumbs) {
|
||||||
promises.push(new Promise((resolve) => {
|
// eslint-disable-next-line no-shadow
|
||||||
|
promises.push(new Promise(resolve => {
|
||||||
thumbs.remoteThumbs.animate({
|
thumbs.remoteThumbs.animate({
|
||||||
height: remote.thumbHeight,
|
height: remote.thumbHeight,
|
||||||
width: remote.thumbWidth
|
width: remote.thumbWidth
|
||||||
}, this._getAnimateOptions(animate, resolve));
|
}, this._getAnimateOptions(animate, resolve));
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
promises.push(new Promise((resolve) => {
|
// eslint-disable-next-line no-shadow
|
||||||
|
promises.push(new Promise(resolve => {
|
||||||
// Let CSS take care of height in vertical filmstrip mode.
|
// Let CSS take care of height in vertical filmstrip mode.
|
||||||
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
if (interfaceConfig.VERTICAL_FILMSTRIP) {
|
||||||
$('#filmstripLocalVideo').animate({
|
$('#filmstripLocalVideo').animate({
|
||||||
|
@ -438,9 +458,10 @@ const Filmstrip = {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
promises.push(new Promise(() => {
|
promises.push(new Promise(() => {
|
||||||
let { localThumb } = this.getThumbs();
|
const { localThumb } = this.getThumbs();
|
||||||
let height = localThumb ? localThumb.height() : 0;
|
const height = localThumb ? localThumb.height() : 0;
|
||||||
let fontSize = UIUtil.getIndicatorFontSize(height);
|
const fontSize = UIUtil.getIndicatorFontSize(height);
|
||||||
|
|
||||||
this.filmstrip.find('.indicator').animate({
|
this.filmstrip.find('.indicator').animate({
|
||||||
fontSize
|
fontSize
|
||||||
}, this._getAnimateOptions(animate, resolve));
|
}, this._getAnimateOptions(animate, resolve));
|
||||||
|
@ -471,24 +492,27 @@ const Filmstrip = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns thumbnails of the filmstrip
|
* Returns thumbnails of the filmstrip
|
||||||
* @param only_visible
|
* @param onlyVisible
|
||||||
* @returns {object} thumbnails
|
* @returns {object} thumbnails
|
||||||
*/
|
*/
|
||||||
getThumbs(only_visible = false) {
|
getThumbs(onlyVisible = false) {
|
||||||
let selector = 'span';
|
let selector = 'span';
|
||||||
if (only_visible) {
|
|
||||||
|
if (onlyVisible) {
|
||||||
selector += ':visible';
|
selector += ':visible';
|
||||||
}
|
}
|
||||||
|
|
||||||
let localThumb = $("#localVideoContainer");
|
const localThumb = $('#localVideoContainer');
|
||||||
let remoteThumbs = this.filmstripRemoteVideos.children(selector);
|
const remoteThumbs = this.filmstripRemoteVideos.children(selector);
|
||||||
|
|
||||||
// Exclude the local video container if it has been hidden.
|
// Exclude the local video container if it has been hidden.
|
||||||
if (localThumb.hasClass("hidden")) {
|
if (localThumb.hasClass('hidden')) {
|
||||||
return { remoteThumbs };
|
return { remoteThumbs };
|
||||||
} else {
|
|
||||||
return { remoteThumbs, localThumb };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return { remoteThumbs,
|
||||||
|
localThumb };
|
||||||
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3,19 +3,19 @@
|
||||||
* Base class for all Large containers which we can show.
|
* Base class for all Large containers which we can show.
|
||||||
*/
|
*/
|
||||||
export default class LargeContainer {
|
export default class LargeContainer {
|
||||||
|
/* eslint-disable no-unused-vars, no-empty-function */
|
||||||
/**
|
/**
|
||||||
* Show this container.
|
* Show this container.
|
||||||
* @returns Promise
|
* @returns Promise
|
||||||
*/
|
*/
|
||||||
show () {
|
show() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide this container.
|
* Hide this container.
|
||||||
* @returns Promise
|
* @returns Promise
|
||||||
*/
|
*/
|
||||||
hide () {
|
hide() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,20 +24,19 @@ export default class LargeContainer {
|
||||||
* @param {number} containerHeight available height
|
* @param {number} containerHeight available height
|
||||||
* @param {boolean} animate if container should animate it's resize process
|
* @param {boolean} animate if container should animate it's resize process
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
resize(containerWidth, containerHeight, animate) {
|
||||||
resize (containerWidth, containerHeight, animate) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for "hover in" events.
|
* Handler for "hover in" events.
|
||||||
*/
|
*/
|
||||||
onHoverIn (e) { // eslint-disable-line no-unused-vars
|
onHoverIn(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handler for "hover out" events.
|
* Handler for "hover out" events.
|
||||||
*/
|
*/
|
||||||
onHoverOut (e) { // eslint-disable-line no-unused-vars
|
onHoverOut(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,14 +45,14 @@ export default class LargeContainer {
|
||||||
* @param {JitsiTrack?} stream new stream
|
* @param {JitsiTrack?} stream new stream
|
||||||
* @param {string} videoType video type
|
* @param {string} videoType video type
|
||||||
*/
|
*/
|
||||||
setStream (userID, stream, videoType) {// eslint-disable-line no-unused-vars
|
setStream(userID, stream, videoType) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show or hide user avatar.
|
* Show or hide user avatar.
|
||||||
* @param {boolean} show
|
* @param {boolean} show
|
||||||
*/
|
*/
|
||||||
showAvatar (show) { // eslint-disable-line no-unused-vars
|
showAvatar(show) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -61,6 +60,8 @@ export default class LargeContainer {
|
||||||
* when the container is on stage.
|
* when the container is on stage.
|
||||||
* @return {boolean}
|
* @return {boolean}
|
||||||
*/
|
*/
|
||||||
stayOnStage () {
|
stayOnStage() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-enable no-unused-vars, no-empty-function */
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { Provider } from 'react-redux';
|
||||||
import { PresenceLabel } from '../../../react/features/presence-status';
|
import { PresenceLabel } from '../../../react/features/presence-status';
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import {
|
import {
|
||||||
JitsiParticipantConnectionStatus
|
JitsiParticipantConnectionStatus
|
||||||
|
@ -16,15 +16,16 @@ import {
|
||||||
updateKnownLargeVideoResolution
|
updateKnownLargeVideoResolution
|
||||||
} from '../../../react/features/large-video';
|
} from '../../../react/features/large-video';
|
||||||
|
|
||||||
import Avatar from "../avatar/Avatar";
|
import Avatar from '../avatar/Avatar';
|
||||||
import {createDeferred} from '../../util/helpers';
|
import { createDeferred } from '../../util/helpers';
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
import UIUtil from "../util/UIUtil";
|
import UIUtil from '../util/UIUtil';
|
||||||
import {VideoContainer, VIDEO_CONTAINER_TYPE} from "./VideoContainer";
|
import { VideoContainer, VIDEO_CONTAINER_TYPE } from './VideoContainer';
|
||||||
|
|
||||||
import AudioLevels from "../audio_levels/AudioLevels";
|
import AudioLevels from '../audio_levels/AudioLevels';
|
||||||
|
|
||||||
const DESKTOP_CONTAINER_TYPE = 'desktop';
|
const DESKTOP_CONTAINER_TYPE = 'desktop';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time interval in milliseconds to check the video resolution of the video
|
* The time interval in milliseconds to check the video resolution of the video
|
||||||
* being displayed.
|
* being displayed.
|
||||||
|
@ -49,7 +50,10 @@ export default class LargeVideoManager {
|
||||||
|| containerType === DESKTOP_CONTAINER_TYPE;
|
|| containerType === DESKTOP_CONTAINER_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (emitter) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
constructor(emitter) {
|
||||||
/**
|
/**
|
||||||
* The map of <tt>LargeContainer</tt>s where the key is the video
|
* The map of <tt>LargeContainer</tt>s where the key is the video
|
||||||
* container type.
|
* container type.
|
||||||
|
@ -59,6 +63,7 @@ export default class LargeVideoManager {
|
||||||
this.eventEmitter = emitter;
|
this.eventEmitter = emitter;
|
||||||
|
|
||||||
this.state = VIDEO_CONTAINER_TYPE;
|
this.state = VIDEO_CONTAINER_TYPE;
|
||||||
|
|
||||||
// FIXME: We are passing resizeContainer as parameter which is calling
|
// FIXME: We are passing resizeContainer as parameter which is calling
|
||||||
// Container.resize. Probably there's better way to implement this.
|
// Container.resize. Probably there's better way to implement this.
|
||||||
this.videoContainer = new VideoContainer(
|
this.videoContainer = new VideoContainer(
|
||||||
|
@ -125,7 +130,10 @@ export default class LargeVideoManager {
|
||||||
this.removePresenceLabel();
|
this.removePresenceLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoverIn (e) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onHoverIn(e) {
|
||||||
if (!this.state) {
|
if (!this.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -134,7 +142,10 @@ export default class LargeVideoManager {
|
||||||
container.onHoverIn(e);
|
container.onHoverIn(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
onHoverOut (e) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
onHoverOut(e) {
|
||||||
if (!this.state) {
|
if (!this.state) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -146,9 +157,10 @@ export default class LargeVideoManager {
|
||||||
/**
|
/**
|
||||||
* Called when the media connection has been interrupted.
|
* Called when the media connection has been interrupted.
|
||||||
*/
|
*/
|
||||||
onVideoInterrupted () {
|
onVideoInterrupted() {
|
||||||
this.enableLocalConnectionProblemFilter(true);
|
this.enableLocalConnectionProblemFilter(true);
|
||||||
this._setLocalConnectionMessage("connection.RECONNECTING");
|
this._setLocalConnectionMessage('connection.RECONNECTING');
|
||||||
|
|
||||||
// Show the message only if the video is currently being displayed
|
// Show the message only if the video is currently being displayed
|
||||||
this.showLocalConnectionMessage(
|
this.showLocalConnectionMessage(
|
||||||
LargeVideoManager.isVideoContainer(this.state));
|
LargeVideoManager.isVideoContainer(this.state));
|
||||||
|
@ -157,17 +169,25 @@ export default class LargeVideoManager {
|
||||||
/**
|
/**
|
||||||
* Called when the media connection has been restored.
|
* Called when the media connection has been restored.
|
||||||
*/
|
*/
|
||||||
onVideoRestored () {
|
onVideoRestored() {
|
||||||
this.enableLocalConnectionProblemFilter(false);
|
this.enableLocalConnectionProblemFilter(false);
|
||||||
this.showLocalConnectionMessage(false);
|
this.showLocalConnectionMessage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
get id () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
const container = this.getCurrentContainer();
|
const container = this.getCurrentContainer();
|
||||||
|
|
||||||
|
|
||||||
return container.id;
|
return container.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
scheduleLargeVideoUpdate () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
scheduleLargeVideoUpdate() {
|
||||||
if (this.updateInProcess || !this.newStreamData) {
|
if (this.updateInProcess || !this.newStreamData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -175,6 +195,7 @@ export default class LargeVideoManager {
|
||||||
this.updateInProcess = true;
|
this.updateInProcess = true;
|
||||||
|
|
||||||
// Include hide()/fadeOut only if we're switching between users
|
// Include hide()/fadeOut only if we're switching between users
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
const isUserSwitch = this.newStreamData.id != this.id;
|
const isUserSwitch = this.newStreamData.id != this.id;
|
||||||
const container = this.getCurrentContainer();
|
const container = this.getCurrentContainer();
|
||||||
const preUpdate = isUserSwitch ? container.hide() : Promise.resolve();
|
const preUpdate = isUserSwitch ? container.hide() : Promise.resolve();
|
||||||
|
@ -190,9 +211,11 @@ export default class LargeVideoManager {
|
||||||
|
|
||||||
this.newStreamData = null;
|
this.newStreamData = null;
|
||||||
|
|
||||||
logger.info("hover in %s", id);
|
logger.info('hover in %s', id);
|
||||||
this.state = videoType;
|
this.state = videoType;
|
||||||
|
// eslint-disable-next-line no-shadow
|
||||||
const container = this.getCurrentContainer();
|
const container = this.getCurrentContainer();
|
||||||
|
|
||||||
container.setStream(id, stream, videoType);
|
container.setStream(id, stream, videoType);
|
||||||
|
|
||||||
// change the avatar url on large
|
// change the avatar url on large
|
||||||
|
@ -215,7 +238,7 @@ export default class LargeVideoManager {
|
||||||
=== JitsiParticipantConnectionStatus.ACTIVE
|
=== JitsiParticipantConnectionStatus.ACTIVE
|
||||||
|| wasUsersImageCached);
|
|| wasUsersImageCached);
|
||||||
|
|
||||||
let showAvatar
|
const showAvatar
|
||||||
= isVideoContainer
|
= isVideoContainer
|
||||||
&& (APP.conference.isAudioOnly() || !isVideoRenderable);
|
&& (APP.conference.isAudioOnly() || !isVideoRenderable);
|
||||||
|
|
||||||
|
@ -225,6 +248,7 @@ export default class LargeVideoManager {
|
||||||
// but we still should show watermark
|
// but we still should show watermark
|
||||||
if (showAvatar) {
|
if (showAvatar) {
|
||||||
this.showWatermark(true);
|
this.showWatermark(true);
|
||||||
|
|
||||||
// If the intention of this switch is to show the avatar
|
// If the intention of this switch is to show the avatar
|
||||||
// we need to make sure that the video is hidden
|
// we need to make sure that the video is hidden
|
||||||
promise = container.hide();
|
promise = container.hide();
|
||||||
|
@ -246,10 +270,10 @@ export default class LargeVideoManager {
|
||||||
let messageKey = null;
|
let messageKey = null;
|
||||||
|
|
||||||
if (isConnectionInterrupted) {
|
if (isConnectionInterrupted) {
|
||||||
messageKey = "connection.USER_CONNECTION_INTERRUPTED";
|
messageKey = 'connection.USER_CONNECTION_INTERRUPTED';
|
||||||
} else if (connectionStatus
|
} else if (connectionStatus
|
||||||
=== JitsiParticipantConnectionStatus.INACTIVE) {
|
=== JitsiParticipantConnectionStatus.INACTIVE) {
|
||||||
messageKey = "connection.LOW_BANDWIDTH";
|
messageKey = 'connection.LOW_BANDWIDTH';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure no notification about remote failure is shown as
|
// Make sure no notification about remote failure is shown as
|
||||||
|
@ -302,21 +326,23 @@ export default class LargeVideoManager {
|
||||||
this.videoContainer.showRemoteConnectionProblemIndicator(
|
this.videoContainer.showRemoteConnectionProblemIndicator(
|
||||||
showProblemsIndication);
|
showProblemsIndication);
|
||||||
|
|
||||||
if (!messageKey) {
|
if (messageKey) {
|
||||||
// Hide the message
|
|
||||||
this.showRemoteConnectionMessage(false);
|
|
||||||
} else {
|
|
||||||
// Get user's display name
|
// Get user's display name
|
||||||
let displayName
|
const displayName
|
||||||
= APP.conference.getParticipantDisplayName(id);
|
= APP.conference.getParticipantDisplayName(id);
|
||||||
|
|
||||||
this._setRemoteConnectionMessage(
|
this._setRemoteConnectionMessage(
|
||||||
messageKey,
|
messageKey,
|
||||||
{ displayName: displayName });
|
{ displayName });
|
||||||
|
|
||||||
// Show it now only if the VideoContainer is on top
|
// Show it now only if the VideoContainer is on top
|
||||||
this.showRemoteConnectionMessage(
|
this.showRemoteConnectionMessage(
|
||||||
LargeVideoManager.isVideoContainer(this.state));
|
LargeVideoManager.isVideoContainer(this.state));
|
||||||
|
} else {
|
||||||
|
// Hide the message
|
||||||
|
this.showRemoteConnectionMessage(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -327,7 +353,7 @@ export default class LargeVideoManager {
|
||||||
* @param {string?} videoType new video type
|
* @param {string?} videoType new video type
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
updateLargeVideo (userID, stream, videoType) {
|
updateLargeVideo(userID, stream, videoType) {
|
||||||
if (this.newStreamData) {
|
if (this.newStreamData) {
|
||||||
this.newStreamData.reject();
|
this.newStreamData.reject();
|
||||||
}
|
}
|
||||||
|
@ -345,7 +371,7 @@ export default class LargeVideoManager {
|
||||||
/**
|
/**
|
||||||
* Update container size.
|
* Update container size.
|
||||||
*/
|
*/
|
||||||
updateContainerSize () {
|
updateContainerSize() {
|
||||||
this.width = UIUtil.getAvailableVideoWidth();
|
this.width = UIUtil.getAvailableVideoWidth();
|
||||||
this.height = window.innerHeight;
|
this.height = window.innerHeight;
|
||||||
}
|
}
|
||||||
|
@ -355,8 +381,9 @@ export default class LargeVideoManager {
|
||||||
* @param {string} type type of container which should be resized.
|
* @param {string} type type of container which should be resized.
|
||||||
* @param {boolean} [animate=false] if resize process should be animated.
|
* @param {boolean} [animate=false] if resize process should be animated.
|
||||||
*/
|
*/
|
||||||
resizeContainer (type, animate = false) {
|
resizeContainer(type, animate = false) {
|
||||||
let container = this.getContainer(type);
|
const container = this.getContainer(type);
|
||||||
|
|
||||||
container.resize(this.width, this.height, animate);
|
container.resize(this.width, this.height, animate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -364,7 +391,7 @@ export default class LargeVideoManager {
|
||||||
* Resize all Large containers.
|
* Resize all Large containers.
|
||||||
* @param {boolean} animate if resize process should be animated.
|
* @param {boolean} animate if resize process should be animated.
|
||||||
*/
|
*/
|
||||||
resize (animate) {
|
resize(animate) {
|
||||||
// resize all containers
|
// resize all containers
|
||||||
Object.keys(this.containers)
|
Object.keys(this.containers)
|
||||||
.forEach(type => this.resizeContainer(type, animate));
|
.forEach(type => this.resizeContainer(type, animate));
|
||||||
|
@ -384,15 +411,15 @@ export default class LargeVideoManager {
|
||||||
*
|
*
|
||||||
* @param enable <tt>true</tt> to enable, <tt>false</tt> to disable
|
* @param enable <tt>true</tt> to enable, <tt>false</tt> to disable
|
||||||
*/
|
*/
|
||||||
enableLocalConnectionProblemFilter (enable) {
|
enableLocalConnectionProblemFilter(enable) {
|
||||||
this.videoContainer.enableLocalConnectionProblemFilter(enable);
|
this.videoContainer.enableLocalConnectionProblemFilter(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates the src of the dominant speaker avatar
|
* Updates the src of the dominant speaker avatar
|
||||||
*/
|
*/
|
||||||
updateAvatar (avatarUrl) {
|
updateAvatar(avatarUrl) {
|
||||||
$("#dominantSpeakerAvatar").attr('src', avatarUrl);
|
$('#dominantSpeakerAvatar').attr('src', avatarUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -400,8 +427,8 @@ export default class LargeVideoManager {
|
||||||
*
|
*
|
||||||
* @param lvl the new audio level to set
|
* @param lvl the new audio level to set
|
||||||
*/
|
*/
|
||||||
updateLargeVideoAudioLevel (lvl) {
|
updateLargeVideoAudioLevel(lvl) {
|
||||||
AudioLevels.updateLargeVideoAudioLevel("dominantSpeaker", lvl);
|
AudioLevels.updateLargeVideoAudioLevel('dominantSpeaker', lvl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -418,19 +445,18 @@ export default class LargeVideoManager {
|
||||||
|
|
||||||
if (isConnectionMessageVisible) {
|
if (isConnectionMessageVisible) {
|
||||||
this.removePresenceLabel();
|
this.removePresenceLabel();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const presenceLabelContainer = $('#remotePresenceMessage');
|
const presenceLabelContainer = $('#remotePresenceMessage');
|
||||||
|
|
||||||
if (presenceLabelContainer.length) {
|
if (presenceLabelContainer.length) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<PresenceLabel participantID = { id } />
|
<PresenceLabel participantID = { id } />
|
||||||
</Provider>,
|
</Provider>,
|
||||||
presenceLabelContainer.get(0));
|
presenceLabelContainer.get(0));
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,9 +469,7 @@ export default class LargeVideoManager {
|
||||||
const presenceLabelContainer = $('#remotePresenceMessage');
|
const presenceLabelContainer = $('#remotePresenceMessage');
|
||||||
|
|
||||||
if (presenceLabelContainer.length) {
|
if (presenceLabelContainer.length) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.unmountComponentAtNode(presenceLabelContainer.get(0));
|
ReactDOM.unmountComponentAtNode(presenceLabelContainer.get(0));
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,7 +477,7 @@ export default class LargeVideoManager {
|
||||||
* Show or hide watermark.
|
* Show or hide watermark.
|
||||||
* @param {boolean} show
|
* @param {boolean} show
|
||||||
*/
|
*/
|
||||||
showWatermark (show) {
|
showWatermark(show) {
|
||||||
$('.watermark').css('visibility', show ? 'visible' : 'hidden');
|
$('.watermark').css('visibility', show ? 'visible' : 'hidden');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,12 +487,13 @@ export default class LargeVideoManager {
|
||||||
* displayed or not. If missing the condition will be based on the value
|
* displayed or not. If missing the condition will be based on the value
|
||||||
* obtained from {@link APP.conference.isConnectionInterrupted}.
|
* obtained from {@link APP.conference.isConnectionInterrupted}.
|
||||||
*/
|
*/
|
||||||
showLocalConnectionMessage (show) {
|
showLocalConnectionMessage(show) {
|
||||||
if (typeof show !== 'boolean') {
|
if (typeof show !== 'boolean') {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
show = APP.conference.isConnectionInterrupted();
|
show = APP.conference.isConnectionInterrupted();
|
||||||
}
|
}
|
||||||
|
|
||||||
let id = 'localConnectionMessage';
|
const id = 'localConnectionMessage';
|
||||||
|
|
||||||
UIUtil.setVisible(id, show);
|
UIUtil.setVisible(id, show);
|
||||||
|
|
||||||
|
@ -489,11 +514,12 @@ export default class LargeVideoManager {
|
||||||
* obtained form "APP.conference" and the message will be displayed if
|
* obtained form "APP.conference" and the message will be displayed if
|
||||||
* the user's connection is either interrupted or inactive.
|
* the user's connection is either interrupted or inactive.
|
||||||
*/
|
*/
|
||||||
showRemoteConnectionMessage (show) {
|
showRemoteConnectionMessage(show) {
|
||||||
if (typeof show !== 'boolean') {
|
if (typeof show !== 'boolean') {
|
||||||
const connStatus
|
const connStatus
|
||||||
= APP.conference.getParticipantConnectionStatus(this.id);
|
= APP.conference.getParticipantConnectionStatus(this.id);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
show = !APP.conference.isLocalId(this.id)
|
show = !APP.conference.isLocalId(this.id)
|
||||||
&& (connStatus === JitsiParticipantConnectionStatus.INTERRUPTED
|
&& (connStatus === JitsiParticipantConnectionStatus.INTERRUPTED
|
||||||
|| connStatus
|
|| connStatus
|
||||||
|
@ -501,7 +527,8 @@ export default class LargeVideoManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (show) {
|
if (show) {
|
||||||
$('#remoteConnectionMessage').css({display: "block"});
|
$('#remoteConnectionMessage').css({ display: 'block' });
|
||||||
|
|
||||||
// 'videoConnectionMessage' message conflicts with 'avatarMessage',
|
// 'videoConnectionMessage' message conflicts with 'avatarMessage',
|
||||||
// so it must be hidden
|
// so it must be hidden
|
||||||
this.showLocalConnectionMessage(false);
|
this.showLocalConnectionMessage(false);
|
||||||
|
@ -520,11 +547,11 @@ export default class LargeVideoManager {
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_setRemoteConnectionMessage (msgKey, msgOptions) {
|
_setRemoteConnectionMessage(msgKey, msgOptions) {
|
||||||
if (msgKey) {
|
if (msgKey) {
|
||||||
$('#remoteConnectionMessage')
|
$('#remoteConnectionMessage')
|
||||||
.attr("data-i18n", msgKey)
|
.attr('data-i18n', msgKey)
|
||||||
.attr("data-i18n-options", JSON.stringify(msgOptions));
|
.attr('data-i18n-options', JSON.stringify(msgOptions));
|
||||||
APP.translation.translateElement(
|
APP.translation.translateElement(
|
||||||
$('#remoteConnectionMessage'), msgOptions);
|
$('#remoteConnectionMessage'), msgOptions);
|
||||||
}
|
}
|
||||||
|
@ -539,9 +566,9 @@ export default class LargeVideoManager {
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_setLocalConnectionMessage (msgKey) {
|
_setLocalConnectionMessage(msgKey) {
|
||||||
$('#localConnectionMessage')
|
$('#localConnectionMessage')
|
||||||
.attr("data-i18n", msgKey);
|
.attr('data-i18n', msgKey);
|
||||||
APP.translation.translateElement($('#localConnectionMessage'));
|
APP.translation.translateElement($('#localConnectionMessage'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -550,7 +577,7 @@ export default class LargeVideoManager {
|
||||||
* @param {string} type container type
|
* @param {string} type container type
|
||||||
* @param {LargeContainer} container container to add.
|
* @param {LargeContainer} container container to add.
|
||||||
*/
|
*/
|
||||||
addContainer (type, container) {
|
addContainer(type, container) {
|
||||||
if (this.containers[type]) {
|
if (this.containers[type]) {
|
||||||
throw new Error(`container of type ${type} already exist`);
|
throw new Error(`container of type ${type} already exist`);
|
||||||
}
|
}
|
||||||
|
@ -564,8 +591,8 @@ export default class LargeVideoManager {
|
||||||
* @param {string} type container type.
|
* @param {string} type container type.
|
||||||
* @returns {LargeContainer}
|
* @returns {LargeContainer}
|
||||||
*/
|
*/
|
||||||
getContainer (type) {
|
getContainer(type) {
|
||||||
let container = this.containers[type];
|
const container = this.containers[type];
|
||||||
|
|
||||||
if (!container) {
|
if (!container) {
|
||||||
throw new Error(`container of type ${type} doesn't exist`);
|
throw new Error(`container of type ${type} doesn't exist`);
|
||||||
|
@ -598,7 +625,7 @@ export default class LargeVideoManager {
|
||||||
* Remove Large container of specified type.
|
* Remove Large container of specified type.
|
||||||
* @param {string} type container type.
|
* @param {string} type container type.
|
||||||
*/
|
*/
|
||||||
removeContainer (type) {
|
removeContainer(type) {
|
||||||
if (!this.containers[type]) {
|
if (!this.containers[type]) {
|
||||||
throw new Error(`container of type ${type} doesn't exist`);
|
throw new Error(`container of type ${type} doesn't exist`);
|
||||||
}
|
}
|
||||||
|
@ -612,15 +639,17 @@ export default class LargeVideoManager {
|
||||||
* @param {string} type container type.
|
* @param {string} type container type.
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
showContainer (type) {
|
showContainer(type) {
|
||||||
if (this.state === type) {
|
if (this.state === type) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
let oldContainer = this.containers[this.state];
|
const oldContainer = this.containers[this.state];
|
||||||
|
|
||||||
// FIXME when video is being replaced with other content we need to hide
|
// FIXME when video is being replaced with other content we need to hide
|
||||||
// companion icons/messages. It would be best if the container would
|
// companion icons/messages. It would be best if the container would
|
||||||
// be taking care of it by itself, but that is a bigger refactoring
|
// be taking care of it by itself, but that is a bigger refactoring
|
||||||
|
|
||||||
if (LargeVideoManager.isVideoContainer(this.state)) {
|
if (LargeVideoManager.isVideoContainer(this.state)) {
|
||||||
this.showWatermark(false);
|
this.showWatermark(false);
|
||||||
this.showLocalConnectionMessage(false);
|
this.showLocalConnectionMessage(false);
|
||||||
|
@ -629,7 +658,7 @@ export default class LargeVideoManager {
|
||||||
oldContainer.hide();
|
oldContainer.hide();
|
||||||
|
|
||||||
this.state = type;
|
this.state = type;
|
||||||
let container = this.getContainer(type);
|
const container = this.getContainer(type);
|
||||||
|
|
||||||
return container.show().then(() => {
|
return container.show().then(() => {
|
||||||
if (LargeVideoManager.isVideoContainer(type)) {
|
if (LargeVideoManager.isVideoContainer(type)) {
|
||||||
|
@ -638,6 +667,7 @@ export default class LargeVideoManager {
|
||||||
// the container would be taking care of it by itself, but that
|
// the container would be taking care of it by itself, but that
|
||||||
// is a bigger refactoring
|
// is a bigger refactoring
|
||||||
this.showWatermark(true);
|
this.showWatermark(true);
|
||||||
|
|
||||||
// "avatar" and "video connection" can not be displayed both
|
// "avatar" and "video connection" can not be displayed both
|
||||||
// at the same time, but the latter is of higher priority and it
|
// at the same time, but the latter is of higher priority and it
|
||||||
// will hide the avatar one if will be displayed.
|
// will hide the avatar one if will be displayed.
|
||||||
|
|
|
@ -9,29 +9,33 @@ import { JitsiTrackEvents } from '../../../react/features/base/lib-jitsi-meet';
|
||||||
import { VideoTrack } from '../../../react/features/base/media';
|
import { VideoTrack } from '../../../react/features/base/media';
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
import SmallVideo from "./SmallVideo";
|
import SmallVideo from './SmallVideo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function LocalVideo(VideoLayout, emitter) {
|
function LocalVideo(VideoLayout, emitter) {
|
||||||
this.videoSpanId = "localVideoContainer";
|
this.videoSpanId = 'localVideoContainer';
|
||||||
|
|
||||||
this.container = this.createContainer();
|
this.container = this.createContainer();
|
||||||
this.$container = $(this.container);
|
this.$container = $(this.container);
|
||||||
$("#filmstripLocalVideo").append(this.container);
|
$('#filmstripLocalVideo').append(this.container);
|
||||||
|
|
||||||
this.localVideoId = null;
|
this.localVideoId = null;
|
||||||
this.bindHoverHandler();
|
this.bindHoverHandler();
|
||||||
if(config.enableLocalVideoFlip)
|
if (config.enableLocalVideoFlip) {
|
||||||
this._buildContextMenu();
|
this._buildContextMenu();
|
||||||
|
}
|
||||||
this.isLocal = true;
|
this.isLocal = true;
|
||||||
this.emitter = emitter;
|
this.emitter = emitter;
|
||||||
this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP
|
this.statsPopoverLocation = interfaceConfig.VERTICAL_FILMSTRIP
|
||||||
? 'left top' : 'top center';
|
? 'left top' : 'top center';
|
||||||
|
|
||||||
Object.defineProperty(this, 'id', {
|
Object.defineProperty(this, 'id', {
|
||||||
get: function () {
|
get() {
|
||||||
return APP.conference.getMyUserId();
|
return APP.conference.getMyUserId();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -49,8 +53,9 @@ function LocalVideo(VideoLayout, emitter) {
|
||||||
LocalVideo.prototype = Object.create(SmallVideo.prototype);
|
LocalVideo.prototype = Object.create(SmallVideo.prototype);
|
||||||
LocalVideo.prototype.constructor = LocalVideo;
|
LocalVideo.prototype.constructor = LocalVideo;
|
||||||
|
|
||||||
LocalVideo.prototype.createContainer = function () {
|
LocalVideo.prototype.createContainer = function() {
|
||||||
const containerSpan = document.createElement('span');
|
const containerSpan = document.createElement('span');
|
||||||
|
|
||||||
containerSpan.classList.add('videocontainer');
|
containerSpan.classList.add('videocontainer');
|
||||||
containerSpan.id = this.videoSpanId;
|
containerSpan.id = this.videoSpanId;
|
||||||
|
|
||||||
|
@ -72,24 +77,25 @@ LocalVideo.prototype.createContainer = function () {
|
||||||
LocalVideo.prototype.setDisplayName = function(displayName) {
|
LocalVideo.prototype.setDisplayName = function(displayName) {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
logger.warn(
|
logger.warn(
|
||||||
"Unable to set displayName - " + this.videoSpanId +
|
`Unable to set displayName - ${this.videoSpanId
|
||||||
" does not exist");
|
} does not exist`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateDisplayName({
|
this.updateDisplayName({
|
||||||
allowEditing: true,
|
allowEditing: true,
|
||||||
displayName: displayName,
|
displayName,
|
||||||
displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
|
displayNameSuffix: interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME,
|
||||||
elementID: 'localDisplayName',
|
elementID: 'localDisplayName',
|
||||||
participantID: this.id
|
participantID: this.id
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
LocalVideo.prototype.changeVideo = function (stream) {
|
LocalVideo.prototype.changeVideo = function(stream) {
|
||||||
this.videoStream = stream;
|
this.videoStream = stream;
|
||||||
|
|
||||||
let localVideoClick = (event) => {
|
const localVideoClick = event => {
|
||||||
// TODO Checking the classes is a workround to allow events to bubble
|
// TODO Checking the classes is a workround to allow events to bubble
|
||||||
// into the DisplayName component if it was clicked. React's synthetic
|
// into the DisplayName component if it was clicked. React's synthetic
|
||||||
// events will fire after jQuery handlers execute, so stop propogation
|
// events will fire after jQuery handlers execute, so stop propogation
|
||||||
|
@ -125,11 +131,10 @@ LocalVideo.prototype.changeVideo = function (stream) {
|
||||||
this.$container.off('click');
|
this.$container.off('click');
|
||||||
this.$container.on('click', localVideoClick);
|
this.$container.on('click', localVideoClick);
|
||||||
|
|
||||||
this.localVideoId = 'localVideo_' + stream.getId();
|
this.localVideoId = `localVideo_${stream.getId()}`;
|
||||||
|
|
||||||
var localVideoContainer = document.getElementById('localVideoWrapper');
|
const localVideoContainer = document.getElementById('localVideoWrapper');
|
||||||
|
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<VideoTrack
|
<VideoTrack
|
||||||
|
@ -138,13 +143,15 @@ LocalVideo.prototype.changeVideo = function (stream) {
|
||||||
</Provider>,
|
</Provider>,
|
||||||
localVideoContainer
|
localVideoContainer
|
||||||
);
|
);
|
||||||
/* jshint ignore:end */
|
|
||||||
|
|
||||||
let isVideo = stream.videoType != "desktop";
|
// eslint-disable-next-line eqeqeq
|
||||||
|
const isVideo = stream.videoType != 'desktop';
|
||||||
|
|
||||||
this._enableDisableContextMenu(isVideo);
|
this._enableDisableContextMenu(isVideo);
|
||||||
this.setFlipX(isVideo? APP.settings.getLocalFlipX() : false);
|
this.setFlipX(isVideo ? APP.settings.getLocalFlipX() : false);
|
||||||
|
|
||||||
|
const endedHandler = () => {
|
||||||
|
|
||||||
let endedHandler = () => {
|
|
||||||
// Only remove if there is no video and not a transition state.
|
// Only remove if there is no video and not a transition state.
|
||||||
// Previous non-react logic created a new video element with each track
|
// Previous non-react logic created a new video element with each track
|
||||||
// removal whereas react reuses the video component so it could be the
|
// removal whereas react reuses the video component so it could be the
|
||||||
|
@ -160,6 +167,7 @@ LocalVideo.prototype.changeVideo = function (stream) {
|
||||||
}
|
}
|
||||||
stream.off(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
stream.off(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
stream.on(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
stream.on(JitsiTrackEvents.LOCAL_TRACK_STOPPED, endedHandler);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -172,15 +180,14 @@ LocalVideo.prototype.setVisible = function(visible) {
|
||||||
|
|
||||||
// We toggle the hidden class as an indication to other interested parties
|
// We toggle the hidden class as an indication to other interested parties
|
||||||
// that this container has been hidden on purpose.
|
// that this container has been hidden on purpose.
|
||||||
this.$container.toggleClass("hidden");
|
this.$container.toggleClass('hidden');
|
||||||
|
|
||||||
// We still show/hide it as we need to overwrite the style property if we
|
// We still show/hide it as we need to overwrite the style property if we
|
||||||
// want our action to take effect. Toggling the display property through
|
// want our action to take effect. Toggling the display property through
|
||||||
// the above css class didn't succeed in overwriting the style.
|
// the above css class didn't succeed in overwriting the style.
|
||||||
if (visible) {
|
if (visible) {
|
||||||
this.$container.show();
|
this.$container.show();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
this.$container.hide();
|
this.$container.hide();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -189,39 +196,41 @@ LocalVideo.prototype.setVisible = function(visible) {
|
||||||
* Sets the flipX state of the video.
|
* Sets the flipX state of the video.
|
||||||
* @param val {boolean} true for flipped otherwise false;
|
* @param val {boolean} true for flipped otherwise false;
|
||||||
*/
|
*/
|
||||||
LocalVideo.prototype.setFlipX = function (val) {
|
LocalVideo.prototype.setFlipX = function(val) {
|
||||||
this.emitter.emit(UIEvents.LOCAL_FLIPX_CHANGED, val);
|
this.emitter.emit(UIEvents.LOCAL_FLIPX_CHANGED, val);
|
||||||
if(!this.localVideoId)
|
if (!this.localVideoId) {
|
||||||
return;
|
return;
|
||||||
if(val) {
|
}
|
||||||
this.selectVideoElement().addClass("flipVideoX");
|
if (val) {
|
||||||
|
this.selectVideoElement().addClass('flipVideoX');
|
||||||
} else {
|
} else {
|
||||||
this.selectVideoElement().removeClass("flipVideoX");
|
this.selectVideoElement().removeClass('flipVideoX');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the context menu for the local video.
|
* Builds the context menu for the local video.
|
||||||
*/
|
*/
|
||||||
LocalVideo.prototype._buildContextMenu = function () {
|
LocalVideo.prototype._buildContextMenu = function() {
|
||||||
$.contextMenu({
|
$.contextMenu({
|
||||||
selector: '#' + this.videoSpanId,
|
selector: `#${this.videoSpanId}`,
|
||||||
zIndex: 10000,
|
zIndex: 10000,
|
||||||
items: {
|
items: {
|
||||||
flip: {
|
flip: {
|
||||||
name: "Flip",
|
name: 'Flip',
|
||||||
callback: () => {
|
callback: () => {
|
||||||
let val = !APP.settings.getLocalFlipX();
|
const val = !APP.settings.getLocalFlipX();
|
||||||
|
|
||||||
this.setFlipX(val);
|
this.setFlipX(val);
|
||||||
APP.settings.setLocalFlipX(val);
|
APP.settings.setLocalFlipX(val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
events: {
|
events: {
|
||||||
show : function(options){
|
show(options) {
|
||||||
options.items.flip.name =
|
options.items.flip.name
|
||||||
APP.translation.generateTranslationHTML(
|
= APP.translation.generateTranslationHTML(
|
||||||
"videothumbnail.flip");
|
'videothumbnail.flip');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -231,9 +240,10 @@ LocalVideo.prototype._buildContextMenu = function () {
|
||||||
* Enables or disables the context menu for the local video.
|
* Enables or disables the context menu for the local video.
|
||||||
* @param enable {boolean} true for enable, false for disable
|
* @param enable {boolean} true for enable, false for disable
|
||||||
*/
|
*/
|
||||||
LocalVideo.prototype._enableDisableContextMenu = function (enable) {
|
LocalVideo.prototype._enableDisableContextMenu = function(enable) {
|
||||||
if(this.$container.contextMenu)
|
if (this.$container.contextMenu) {
|
||||||
this.$container.contextMenu(enable);
|
this.$container.contextMenu(enable);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export default LocalVideo;
|
export default LocalVideo;
|
||||||
|
|
|
@ -18,11 +18,11 @@ import {
|
||||||
} from '../../../react/features/remote-video-menu';
|
} from '../../../react/features/remote-video-menu';
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
|
|
||||||
import SmallVideo from "./SmallVideo";
|
import SmallVideo from './SmallVideo';
|
||||||
import UIUtils from "../util/UIUtil";
|
import UIUtils from '../util/UIUtil';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new instance of the <tt>RemoteVideo</tt>.
|
* Creates new instance of the <tt>RemoteVideo</tt>.
|
||||||
|
@ -52,6 +52,7 @@ function RemoteVideo(user, VideoLayout, emitter) {
|
||||||
this.isLocal = false;
|
this.isLocal = false;
|
||||||
this.popupMenuIsHovered = false;
|
this.popupMenuIsHovered = false;
|
||||||
this._isRemoteControlSessionActive = false;
|
this._isRemoteControlSessionActive = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flag is set to <tt>true</tt> after the 'onplay' event has been
|
* The flag is set to <tt>true</tt> after the 'onplay' event has been
|
||||||
* triggered on the current video element. It goes back to <tt>false</tt>
|
* triggered on the current video element. It goes back to <tt>false</tt>
|
||||||
|
@ -60,6 +61,7 @@ function RemoteVideo(user, VideoLayout, emitter) {
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
*/
|
*/
|
||||||
this.wasVideoPlayed = false;
|
this.wasVideoPlayed = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The flag is set to <tt>true</tt> if remote participant's video gets muted
|
* The flag is set to <tt>true</tt> if remote participant's video gets muted
|
||||||
* during his media connection disruption. This is to prevent black video
|
* during his media connection disruption. This is to prevent black video
|
||||||
|
@ -107,9 +109,11 @@ RemoteVideo.prototype.addRemoteVideoContainer = function() {
|
||||||
* @private
|
* @private
|
||||||
* NOTE: extends SmallVideo's method
|
* NOTE: extends SmallVideo's method
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._isHovered = function () {
|
RemoteVideo.prototype._isHovered = function() {
|
||||||
let isHovered = SmallVideo.prototype._isHovered.call(this)
|
const isHovered = SmallVideo.prototype._isHovered.call(this)
|
||||||
|| this.popupMenuIsHovered;
|
|| this.popupMenuIsHovered;
|
||||||
|
|
||||||
|
|
||||||
return isHovered;
|
return isHovered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -119,7 +123,7 @@ RemoteVideo.prototype._isHovered = function () {
|
||||||
* @returns {Element|*} the constructed element, containing popup menu items
|
* @returns {Element|*} the constructed element, containing popup menu items
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._generatePopupContent = function () {
|
RemoteVideo.prototype._generatePopupContent = function() {
|
||||||
if (interfaceConfig.filmStripOnly) {
|
if (interfaceConfig.filmStripOnly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -139,14 +143,13 @@ RemoteVideo.prototype._generatePopupContent = function () {
|
||||||
&& ((!APP.remoteControl.active && !this._isRemoteControlSessionActive)
|
&& ((!APP.remoteControl.active && !this._isRemoteControlSessionActive)
|
||||||
|| APP.remoteControl.controller.activeParticipant === this.id)) {
|
|| APP.remoteControl.controller.activeParticipant === this.id)) {
|
||||||
if (controller.getRequestedParticipant() === this.id) {
|
if (controller.getRequestedParticipant() === this.id) {
|
||||||
onRemoteControlToggle = () => {};
|
|
||||||
remoteControlState = REMOTE_CONTROL_MENU_STATES.REQUESTING;
|
remoteControlState = REMOTE_CONTROL_MENU_STATES.REQUESTING;
|
||||||
} else if (!controller.isStarted()) {
|
} else if (controller.isStarted()) {
|
||||||
onRemoteControlToggle = this._requestRemoteControlPermissions;
|
|
||||||
remoteControlState = REMOTE_CONTROL_MENU_STATES.NOT_STARTED;
|
|
||||||
} else {
|
|
||||||
onRemoteControlToggle = this._stopRemoteControl;
|
onRemoteControlToggle = this._stopRemoteControl;
|
||||||
remoteControlState = REMOTE_CONTROL_MENU_STATES.STARTED;
|
remoteControlState = REMOTE_CONTROL_MENU_STATES.STARTED;
|
||||||
|
} else {
|
||||||
|
onRemoteControlToggle = this._requestRemoteControlPermissions;
|
||||||
|
remoteControlState = REMOTE_CONTROL_MENU_STATES.NOT_STARTED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,7 +164,6 @@ RemoteVideo.prototype._generatePopupContent = function () {
|
||||||
const { isModerator } = APP.conference;
|
const { isModerator } = APP.conference;
|
||||||
const participantID = this.id;
|
const participantID = this.id;
|
||||||
|
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
|
@ -169,7 +171,7 @@ RemoteVideo.prototype._generatePopupContent = function () {
|
||||||
initialVolumeValue = { initialVolumeValue }
|
initialVolumeValue = { initialVolumeValue }
|
||||||
isAudioMuted = { this.isAudioMuted }
|
isAudioMuted = { this.isAudioMuted }
|
||||||
isModerator = { isModerator }
|
isModerator = { isModerator }
|
||||||
onMenuDisplay = { this._onRemoteVideoMenuDisplay.bind(this) }
|
onMenuDisplay = {this._onRemoteVideoMenuDisplay.bind(this)}
|
||||||
onRemoteControlToggle = { onRemoteControlToggle }
|
onRemoteControlToggle = { onRemoteControlToggle }
|
||||||
onVolumeChange = { onVolumeChange }
|
onVolumeChange = { onVolumeChange }
|
||||||
participantID = { participantID }
|
participantID = { participantID }
|
||||||
|
@ -177,10 +179,9 @@ RemoteVideo.prototype._generatePopupContent = function () {
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
remoteVideoMenuContainer);
|
remoteVideoMenuContainer);
|
||||||
/* jshint ignore:end */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
RemoteVideo.prototype._onRemoteVideoMenuDisplay = function () {
|
RemoteVideo.prototype._onRemoteVideoMenuDisplay = function() {
|
||||||
this.updateRemoteVideoMenu();
|
this.updateRemoteVideoMenu();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -201,7 +202,7 @@ RemoteVideo.prototype.setRemoteControlActiveStatus = function(isActive) {
|
||||||
* @param {boolean} isSupported
|
* @param {boolean} isSupported
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.setRemoteControlSupport = function(isSupported = false) {
|
RemoteVideo.prototype.setRemoteControlSupport = function(isSupported = false) {
|
||||||
if(this._supportsRemoteControl === isSupported) {
|
if (this._supportsRemoteControl === isSupported) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._supportsRemoteControl = isSupported;
|
this._supportsRemoteControl = isSupported;
|
||||||
|
@ -211,24 +212,26 @@ RemoteVideo.prototype.setRemoteControlSupport = function(isSupported = false) {
|
||||||
/**
|
/**
|
||||||
* Requests permissions for remote control session.
|
* Requests permissions for remote control session.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._requestRemoteControlPermissions = function () {
|
RemoteVideo.prototype._requestRemoteControlPermissions = function() {
|
||||||
APP.remoteControl.controller.requestPermissions(
|
APP.remoteControl.controller.requestPermissions(
|
||||||
this.id, this.VideoLayout.getLargeVideoWrapper()).then(result => {
|
this.id, this.VideoLayout.getLargeVideoWrapper()).then(result => {
|
||||||
if(result === null) {
|
if (result === null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.updateRemoteVideoMenu();
|
this.updateRemoteVideoMenu();
|
||||||
APP.UI.messageHandler.notify(
|
APP.UI.messageHandler.notify(
|
||||||
"dialog.remoteControlTitle",
|
'dialog.remoteControlTitle',
|
||||||
(result === false) ? "dialog.remoteControlDeniedMessage"
|
result === false ? 'dialog.remoteControlDeniedMessage'
|
||||||
: "dialog.remoteControlAllowedMessage",
|
: 'dialog.remoteControlAllowedMessage',
|
||||||
{user: this.user.getDisplayName()
|
{ user: this.user.getDisplayName()
|
||||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME}
|
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME }
|
||||||
);
|
);
|
||||||
if(result === true) {//the remote control permissions has been granted
|
if (result === true) {
|
||||||
|
// the remote control permissions has been granted
|
||||||
// pin the controlled participant
|
// pin the controlled participant
|
||||||
let pinnedId = this.VideoLayout.getPinnedId();
|
const pinnedId = this.VideoLayout.getPinnedId();
|
||||||
if(pinnedId !== this.id) {
|
|
||||||
|
if (pinnedId !== this.id) {
|
||||||
this.VideoLayout.handleVideoThumbClicked(this.id);
|
this.VideoLayout.handleVideoThumbClicked(this.id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -236,10 +239,10 @@ RemoteVideo.prototype._requestRemoteControlPermissions = function () {
|
||||||
logger.error(error);
|
logger.error(error);
|
||||||
this.updateRemoteVideoMenu();
|
this.updateRemoteVideoMenu();
|
||||||
APP.UI.messageHandler.notify(
|
APP.UI.messageHandler.notify(
|
||||||
"dialog.remoteControlTitle",
|
'dialog.remoteControlTitle',
|
||||||
"dialog.remoteControlErrorMessage",
|
'dialog.remoteControlErrorMessage',
|
||||||
{user: this.user.getDisplayName()
|
{ user: this.user.getDisplayName()
|
||||||
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME}
|
|| interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME }
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
this.updateRemoteVideoMenu();
|
this.updateRemoteVideoMenu();
|
||||||
|
@ -248,7 +251,7 @@ RemoteVideo.prototype._requestRemoteControlPermissions = function () {
|
||||||
/**
|
/**
|
||||||
* Stops remote control session.
|
* Stops remote control session.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._stopRemoteControl = function () {
|
RemoteVideo.prototype._stopRemoteControl = function() {
|
||||||
// send message about stopping
|
// send message about stopping
|
||||||
APP.remoteControl.controller.stop();
|
APP.remoteControl.controller.stop();
|
||||||
this.updateRemoteVideoMenu();
|
this.updateRemoteVideoMenu();
|
||||||
|
@ -259,7 +262,7 @@ RemoteVideo.prototype._stopRemoteControl = function () {
|
||||||
*
|
*
|
||||||
* @returns {Element} audio element
|
* @returns {Element} audio element
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._getAudioElement = function () {
|
RemoteVideo.prototype._getAudioElement = function() {
|
||||||
return this._audioStreamElement;
|
return this._audioStreamElement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -268,8 +271,10 @@ RemoteVideo.prototype._getAudioElement = function () {
|
||||||
*
|
*
|
||||||
* @returns {boolean} true if the volume can be adjusted.
|
* @returns {boolean} true if the volume can be adjusted.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._canSetAudioVolume = function () {
|
RemoteVideo.prototype._canSetAudioVolume = function() {
|
||||||
const audioElement = this._getAudioElement();
|
const audioElement = this._getAudioElement();
|
||||||
|
|
||||||
|
|
||||||
return audioElement && audioElement.volume !== undefined;
|
return audioElement && audioElement.volume !== undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -278,7 +283,7 @@ RemoteVideo.prototype._canSetAudioVolume = function () {
|
||||||
*
|
*
|
||||||
* @param {int} newVal - The value to set the slider to.
|
* @param {int} newVal - The value to set the slider to.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._setAudioVolume = function (newVal) {
|
RemoteVideo.prototype._setAudioVolume = function(newVal) {
|
||||||
if (this._canSetAudioVolume()) {
|
if (this._canSetAudioVolume()) {
|
||||||
this._getAudioElement().volume = newVal;
|
this._getAudioElement().volume = newVal;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +294,7 @@ RemoteVideo.prototype._setAudioVolume = function (newVal) {
|
||||||
*
|
*
|
||||||
* @param isMuted the new muted state to update to
|
* @param isMuted the new muted state to update to
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.updateRemoteVideoMenu = function (
|
RemoteVideo.prototype.updateRemoteVideoMenu = function(
|
||||||
isMuted = this.isAudioMuted) {
|
isMuted = this.isAudioMuted) {
|
||||||
this.isAudioMuted = isMuted;
|
this.isAudioMuted = isMuted;
|
||||||
|
|
||||||
|
@ -302,6 +307,7 @@ RemoteVideo.prototype.updateRemoteVideoMenu = function (
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.setVideoMutedView = function(isMuted) {
|
RemoteVideo.prototype.setVideoMutedView = function(isMuted) {
|
||||||
SmallVideo.prototype.setVideoMutedView.call(this, isMuted);
|
SmallVideo.prototype.setVideoMutedView.call(this, isMuted);
|
||||||
|
|
||||||
// Update 'mutedWhileDisconnected' flag
|
// Update 'mutedWhileDisconnected' flag
|
||||||
this._figureOutMutedWhileDisconnected();
|
this._figureOutMutedWhileDisconnected();
|
||||||
};
|
};
|
||||||
|
@ -314,6 +320,7 @@ RemoteVideo.prototype.setVideoMutedView = function(isMuted) {
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype._figureOutMutedWhileDisconnected = function() {
|
RemoteVideo.prototype._figureOutMutedWhileDisconnected = function() {
|
||||||
const isActive = this.isConnectionActive();
|
const isActive = this.isConnectionActive();
|
||||||
|
|
||||||
if (!isActive && this.isVideoMuted) {
|
if (!isActive && this.isVideoMuted) {
|
||||||
this.mutedWhileDisconnected = true;
|
this.mutedWhileDisconnected = true;
|
||||||
} else if (isActive && !this.isVideoMuted) {
|
} else if (isActive && !this.isVideoMuted) {
|
||||||
|
@ -326,7 +333,7 @@ RemoteVideo.prototype._figureOutMutedWhileDisconnected = function() {
|
||||||
* given <tt>parentElement</tt>.
|
* given <tt>parentElement</tt>.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.addRemoteVideoMenu = function () {
|
RemoteVideo.prototype.addRemoteVideoMenu = function() {
|
||||||
if (interfaceConfig.filmStripOnly) {
|
if (interfaceConfig.filmStripOnly) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -343,22 +350,24 @@ RemoteVideo.prototype.addRemoteVideoMenu = function () {
|
||||||
* @param stream the MediaStream
|
* @param stream the MediaStream
|
||||||
* @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
|
* @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.removeRemoteStreamElement = function (stream) {
|
RemoteVideo.prototype.removeRemoteStreamElement = function(stream) {
|
||||||
if (!this.container)
|
if (!this.container) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
var isVideo = stream.isVideoTrack();
|
const isVideo = stream.isVideoTrack();
|
||||||
|
|
||||||
|
const elementID = SmallVideo.getStreamElementID(stream);
|
||||||
|
const select = $(`#${elementID}`);
|
||||||
|
|
||||||
var elementID = SmallVideo.getStreamElementID(stream);
|
|
||||||
var select = $('#' + elementID);
|
|
||||||
select.remove();
|
select.remove();
|
||||||
|
|
||||||
if (isVideo) {
|
if (isVideo) {
|
||||||
this.wasVideoPlayed = false;
|
this.wasVideoPlayed = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info((isVideo ? "Video" : "Audio") +
|
logger.info(`${isVideo ? 'Video' : 'Audio'
|
||||||
" removed " + this.id, select);
|
} removed ${this.id}`, select);
|
||||||
|
|
||||||
// when removing only the video element and we are on stage
|
// when removing only the video element and we are on stage
|
||||||
// update the stage
|
// update the stage
|
||||||
|
@ -386,15 +395,16 @@ RemoteVideo.prototype.isConnectionActive = function() {
|
||||||
* The remote video is considered "playable" once the stream has started
|
* The remote video is considered "playable" once the stream has started
|
||||||
* according to the {@link #hasVideoStarted} result.
|
* according to the {@link #hasVideoStarted} result.
|
||||||
* It will be allowed to display video also in
|
* It will be allowed to display video also in
|
||||||
* {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video was ever played
|
* {@link JitsiParticipantConnectionStatus.INTERRUPTED} if the video was ever
|
||||||
* and was not muted while not in ACTIVE state. This basically means that there
|
* played and was not muted while not in ACTIVE state. This basically means
|
||||||
* is stalled video image cached that could be displayed. It's used to show
|
* that there is stalled video image cached that could be displayed. It's used
|
||||||
* "grey video image" in user's thumbnail when there are connectivity issues.
|
* to show "grey video image" in user's thumbnail when there are connectivity
|
||||||
|
* issues.
|
||||||
*
|
*
|
||||||
* @inheritdoc
|
* @inheritdoc
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.isVideoPlayable = function () {
|
RemoteVideo.prototype.isVideoPlayable = function() {
|
||||||
const connectionState
|
const connectionState
|
||||||
= APP.conference.getParticipantConnectionStatus(this.id);
|
= APP.conference.getParticipantConnectionStatus(this.id);
|
||||||
|
|
||||||
|
@ -408,7 +418,7 @@ RemoteVideo.prototype.isVideoPlayable = function () {
|
||||||
/**
|
/**
|
||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.updateView = function () {
|
RemoteVideo.prototype.updateView = function() {
|
||||||
this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
|
this.$container.toggleClass('audio-only', APP.conference.isAudioOnly());
|
||||||
|
|
||||||
this.updateConnectionStatusIndicator();
|
this.updateConnectionStatusIndicator();
|
||||||
|
@ -421,7 +431,7 @@ RemoteVideo.prototype.updateView = function () {
|
||||||
/**
|
/**
|
||||||
* Updates the UI to reflect user's connectivity status.
|
* Updates the UI to reflect user's connectivity status.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.updateConnectionStatusIndicator = function () {
|
RemoteVideo.prototype.updateConnectionStatusIndicator = function() {
|
||||||
const connectionStatus = this.user.getConnectionStatus();
|
const connectionStatus = this.user.getConnectionStatus();
|
||||||
|
|
||||||
logger.debug(`${this.id} thumbnail connection status: ${connectionStatus}`);
|
logger.debug(`${this.id} thumbnail connection status: ${connectionStatus}`);
|
||||||
|
@ -433,18 +443,20 @@ RemoteVideo.prototype.updateConnectionStatusIndicator = function () {
|
||||||
|
|
||||||
const isInterrupted
|
const isInterrupted
|
||||||
= connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED;
|
= connectionStatus === JitsiParticipantConnectionStatus.INTERRUPTED;
|
||||||
|
|
||||||
// Toggle thumbnail video problem filter
|
// Toggle thumbnail video problem filter
|
||||||
|
|
||||||
this.selectVideoElement().toggleClass(
|
this.selectVideoElement().toggleClass(
|
||||||
"videoThumbnailProblemFilter", isInterrupted);
|
'videoThumbnailProblemFilter', isInterrupted);
|
||||||
this.$avatar().toggleClass(
|
this.$avatar().toggleClass(
|
||||||
"videoThumbnailProblemFilter", isInterrupted);
|
'videoThumbnailProblemFilter', isInterrupted);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes RemoteVideo from the page.
|
* Removes RemoteVideo from the page.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.remove = function () {
|
RemoteVideo.prototype.remove = function() {
|
||||||
logger.log("Remove thumbnail", this.id);
|
logger.log('Remove thumbnail', this.id);
|
||||||
|
|
||||||
this.removeAudioLevelIndicator();
|
this.removeAudioLevelIndicator();
|
||||||
|
|
||||||
|
@ -470,30 +482,34 @@ RemoteVideo.prototype.remove = function () {
|
||||||
// Make sure that the large video is updated if are removing its
|
// Make sure that the large video is updated if are removing its
|
||||||
// corresponding small video.
|
// corresponding small video.
|
||||||
this.VideoLayout.updateAfterThumbRemoved(this.id);
|
this.VideoLayout.updateAfterThumbRemoved(this.id);
|
||||||
|
|
||||||
// Remove whole container
|
// Remove whole container
|
||||||
if (this.container.parentNode) {
|
if (this.container.parentNode) {
|
||||||
this.container.parentNode.removeChild(this.container);
|
this.container.parentNode.removeChild(this.container);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
RemoteVideo.prototype.waitForPlayback = function (streamElement, stream) {
|
RemoteVideo.prototype.waitForPlayback = function(streamElement, stream) {
|
||||||
|
|
||||||
|
const webRtcStream = stream.getOriginalStream();
|
||||||
|
const isVideo = stream.isVideoTrack();
|
||||||
|
|
||||||
var webRtcStream = stream.getOriginalStream();
|
|
||||||
var isVideo = stream.isVideoTrack();
|
|
||||||
if (!isVideo || webRtcStream.id === 'mixedmslabel') {
|
if (!isVideo || webRtcStream.id === 'mixedmslabel') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var self = this;
|
const self = this;
|
||||||
|
|
||||||
// Triggers when video playback starts
|
// Triggers when video playback starts
|
||||||
var onPlayingHandler = function () {
|
const onPlayingHandler = function() {
|
||||||
self.wasVideoPlayed = true;
|
self.wasVideoPlayed = true;
|
||||||
self.VideoLayout.remoteVideoActive(streamElement, self.id);
|
self.VideoLayout.remoteVideoActive(streamElement, self.id);
|
||||||
streamElement.onplaying = null;
|
streamElement.onplaying = null;
|
||||||
|
|
||||||
// Refresh to show the video
|
// Refresh to show the video
|
||||||
self.updateView();
|
self.updateView();
|
||||||
};
|
};
|
||||||
|
|
||||||
streamElement.onplaying = onPlayingHandler;
|
streamElement.onplaying = onPlayingHandler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -503,23 +519,25 @@ RemoteVideo.prototype.waitForPlayback = function (streamElement, stream) {
|
||||||
* @returns {boolean} true if this RemoteVideo has a video stream for which
|
* @returns {boolean} true if this RemoteVideo has a video stream for which
|
||||||
* the playback has been started.
|
* the playback has been started.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.hasVideoStarted = function () {
|
RemoteVideo.prototype.hasVideoStarted = function() {
|
||||||
return this.wasVideoPlayed;
|
return this.wasVideoPlayed;
|
||||||
};
|
};
|
||||||
|
|
||||||
RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
RemoteVideo.prototype.addRemoteStreamElement = function(stream) {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let isVideo = stream.isVideoTrack();
|
const isVideo = stream.isVideoTrack();
|
||||||
|
|
||||||
isVideo ? this.videoStream = stream : this.audioStream = stream;
|
isVideo ? this.videoStream = stream : this.audioStream = stream;
|
||||||
|
|
||||||
if (isVideo)
|
if (isVideo) {
|
||||||
this.setVideoType(stream.videoType);
|
this.setVideoType(stream.videoType);
|
||||||
|
}
|
||||||
|
|
||||||
// Add click handler.
|
// Add click handler.
|
||||||
let onClickHandler = (event) => {
|
const onClickHandler = event => {
|
||||||
const $source = $(event.target || event.srcElement);
|
const $source = $(event.target || event.srcElement);
|
||||||
const { classList } = event.target;
|
const { classList } = event.target;
|
||||||
|
|
||||||
|
@ -546,12 +564,15 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.container.onclick = onClickHandler;
|
this.container.onclick = onClickHandler;
|
||||||
|
|
||||||
if(!stream.getOriginalStream())
|
if (!stream.getOriginalStream()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let streamElement = SmallVideo.createStreamElement(stream);
|
let streamElement = SmallVideo.createStreamElement(stream);
|
||||||
|
|
||||||
|
@ -591,8 +612,9 @@ RemoteVideo.prototype.addRemoteStreamElement = function (stream) {
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.setDisplayName = function(displayName) {
|
RemoteVideo.prototype.setDisplayName = function(displayName) {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
logger.warn( "Unable to set displayName - " + this.videoSpanId +
|
logger.warn(`Unable to set displayName - ${this.videoSpanId
|
||||||
" does not exist");
|
} does not exist`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -610,7 +632,7 @@ RemoteVideo.prototype.setDisplayName = function(displayName) {
|
||||||
* @param videoElementId the id of local or remote video element.
|
* @param videoElementId the id of local or remote video element.
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
||||||
var menuSpan = this.$container.find('.remotevideomenu');
|
const menuSpan = this.$container.find('.remotevideomenu');
|
||||||
|
|
||||||
if (menuSpan.length) {
|
if (menuSpan.length) {
|
||||||
ReactDOM.unmountComponentAtNode(menuSpan.get(0));
|
ReactDOM.unmountComponentAtNode(menuSpan.get(0));
|
||||||
|
@ -625,18 +647,16 @@ RemoteVideo.prototype.removeRemoteVideoMenu = function() {
|
||||||
*
|
*
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.addPresenceLabel = function () {
|
RemoteVideo.prototype.addPresenceLabel = function() {
|
||||||
const presenceLabelContainer
|
const presenceLabelContainer
|
||||||
= this.container.querySelector('.presence-label-container');
|
= this.container.querySelector('.presence-label-container');
|
||||||
|
|
||||||
if (presenceLabelContainer) {
|
if (presenceLabelContainer) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<PresenceLabel participantID = { this.id } />
|
<PresenceLabel participantID = { this.id } />
|
||||||
</Provider>,
|
</Provider>,
|
||||||
presenceLabelContainer);
|
presenceLabelContainer);
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -645,7 +665,7 @@ RemoteVideo.prototype.addPresenceLabel = function () {
|
||||||
*
|
*
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
RemoteVideo.prototype.removePresenceLabel = function () {
|
RemoteVideo.prototype.removePresenceLabel = function() {
|
||||||
const presenceLabelContainer
|
const presenceLabelContainer
|
||||||
= this.container.querySelector('.presence-label-container');
|
= this.container.querySelector('.presence-label-container');
|
||||||
|
|
||||||
|
@ -654,8 +674,9 @@ RemoteVideo.prototype.removePresenceLabel = function () {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
RemoteVideo.createContainer = function (spanId) {
|
RemoteVideo.createContainer = function(spanId) {
|
||||||
const container = document.createElement('span');
|
const container = document.createElement('span');
|
||||||
|
|
||||||
container.id = spanId;
|
container.id = spanId;
|
||||||
container.className = 'videocontainer';
|
container.className = 'videocontainer';
|
||||||
|
|
||||||
|
@ -669,7 +690,9 @@ RemoteVideo.createContainer = function (spanId) {
|
||||||
<div class ='presence-label-container'></div>
|
<div class ='presence-label-container'></div>
|
||||||
<span class = 'remotevideomenu'></span>`;
|
<span class = 'remotevideomenu'></span>`;
|
||||||
|
|
||||||
var remotes = document.getElementById('filmstripRemoteVideosContainer');
|
const remotes = document.getElementById('filmstripRemoteVideosContainer');
|
||||||
|
|
||||||
|
|
||||||
return remotes.appendChild(container);
|
return remotes.appendChild(container);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -25,11 +25,11 @@ import {
|
||||||
} from '../../../react/features/filmstrip';
|
} from '../../../react/features/filmstrip';
|
||||||
/* eslint-enable no-unused-vars */
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import Avatar from "../avatar/Avatar";
|
import Avatar from '../avatar/Avatar';
|
||||||
import UIUtil from "../util/UIUtil";
|
import UIUtil from '../util/UIUtil';
|
||||||
import UIEvents from "../../../service/UI/UIEvents";
|
import UIEvents from '../../../service/UI/UIEvents';
|
||||||
|
|
||||||
const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
|
const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
|
||||||
|
|
||||||
|
@ -39,6 +39,7 @@ const RTCUIHelper = JitsiMeetJS.util.RTCUIHelper;
|
||||||
* @constant
|
* @constant
|
||||||
*/
|
*/
|
||||||
const DISPLAY_VIDEO = 0;
|
const DISPLAY_VIDEO = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display mode constant used when the user's avatar is being displayed on
|
* Display mode constant used when the user's avatar is being displayed on
|
||||||
* the small video.
|
* the small video.
|
||||||
|
@ -46,6 +47,7 @@ const DISPLAY_VIDEO = 0;
|
||||||
* @constant
|
* @constant
|
||||||
*/
|
*/
|
||||||
const DISPLAY_AVATAR = 1;
|
const DISPLAY_AVATAR = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display mode constant used when neither video nor avatar is being displayed
|
* Display mode constant used when neither video nor avatar is being displayed
|
||||||
* on the small video. And we just show the display name.
|
* on the small video. And we just show the display name.
|
||||||
|
@ -70,6 +72,9 @@ const DISPLAY_VIDEO_WITH_NAME = 3;
|
||||||
*/
|
*/
|
||||||
const DISPLAY_AVATAR_WITH_NAME = 4;
|
const DISPLAY_AVATAR_WITH_NAME = 4;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
function SmallVideo(VideoLayout) {
|
function SmallVideo(VideoLayout) {
|
||||||
this._isModerator = false;
|
this._isModerator = false;
|
||||||
this.isAudioMuted = false;
|
this.isAudioMuted = false;
|
||||||
|
@ -80,6 +85,7 @@ function SmallVideo(VideoLayout) {
|
||||||
this.VideoLayout = VideoLayout;
|
this.VideoLayout = VideoLayout;
|
||||||
this.videoIsHovered = false;
|
this.videoIsHovered = false;
|
||||||
this.hideDisplayName = false;
|
this.hideDisplayName = false;
|
||||||
|
|
||||||
// we can stop updating the thumbnail
|
// we can stop updating the thumbnail
|
||||||
this.disableUpdateView = false;
|
this.disableUpdateView = false;
|
||||||
|
|
||||||
|
@ -136,7 +142,7 @@ function SmallVideo(VideoLayout) {
|
||||||
*
|
*
|
||||||
* @returns the identifier of this small video
|
* @returns the identifier of this small video
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.getId = function () {
|
SmallVideo.prototype.getId = function() {
|
||||||
return this.id;
|
return this.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +151,7 @@ SmallVideo.prototype.getId = function () {
|
||||||
* @return <tt>true</tt> if this small video isn't currently visible and
|
* @return <tt>true</tt> if this small video isn't currently visible and
|
||||||
* <tt>false</tt> - otherwise.
|
* <tt>false</tt> - otherwise.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.isVisible = function () {
|
SmallVideo.prototype.isVisible = function() {
|
||||||
return this.$container.is(':visible');
|
return this.$container.is(':visible');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -153,9 +159,10 @@ SmallVideo.prototype.isVisible = function () {
|
||||||
* Enables / disables the device availability icons for this small video.
|
* Enables / disables the device availability icons for this small video.
|
||||||
* @param {enable} set to {true} to enable and {false} to disable
|
* @param {enable} set to {true} to enable and {false} to disable
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.enableDeviceAvailabilityIcons = function (enable) {
|
SmallVideo.prototype.enableDeviceAvailabilityIcons = function(enable) {
|
||||||
if (typeof enable === "undefined")
|
if (typeof enable === 'undefined') {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.deviceAvailabilityIconsEnabled = enable;
|
this.deviceAvailabilityIconsEnabled = enable;
|
||||||
};
|
};
|
||||||
|
@ -164,32 +171,34 @@ SmallVideo.prototype.enableDeviceAvailabilityIcons = function (enable) {
|
||||||
* Sets the device "non" availability icons.
|
* Sets the device "non" availability icons.
|
||||||
* @param devices the devices, which will be checked for availability
|
* @param devices the devices, which will be checked for availability
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
|
SmallVideo.prototype.setDeviceAvailabilityIcons = function(devices) {
|
||||||
if (!this.deviceAvailabilityIconsEnabled)
|
if (!this.deviceAvailabilityIconsEnabled) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(!this.container)
|
if (!this.container) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var noMic = this.$container.find('.noMic');
|
const noMic = this.$container.find('.noMic');
|
||||||
var noVideo = this.$container.find('.noVideo');
|
const noVideo = this.$container.find('.noVideo');
|
||||||
|
|
||||||
noMic.remove();
|
noMic.remove();
|
||||||
noVideo.remove();
|
noVideo.remove();
|
||||||
if (!devices.audio) {
|
if (!devices.audio) {
|
||||||
this.container.appendChild(
|
this.container.appendChild(
|
||||||
document.createElement("div")).setAttribute("class", "noMic");
|
document.createElement('div')).setAttribute('class', 'noMic');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!devices.video) {
|
if (!devices.video) {
|
||||||
this.container.appendChild(
|
this.container.appendChild(
|
||||||
document.createElement("div")).setAttribute("class", "noVideo");
|
document.createElement('div')).setAttribute('class', 'noVideo');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!devices.audio && !devices.video) {
|
if (!devices.audio && !devices.video) {
|
||||||
noMic.css("background-position", "75%");
|
noMic.css('background-position', '75%');
|
||||||
noVideo.css("background-position", "25%");
|
noVideo.css('background-position', '25%');
|
||||||
noVideo.css("background-color", "transparent");
|
noVideo.css('background-color', 'transparent');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -200,7 +209,7 @@ SmallVideo.prototype.setDeviceAvailabilityIcons = function (devices) {
|
||||||
* lib-jitsi-meet.
|
* lib-jitsi-meet.
|
||||||
* @param videoType 'camera' or 'desktop', or 'sharedvideo'.
|
* @param videoType 'camera' or 'desktop', or 'sharedvideo'.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.setVideoType = function (videoType) {
|
SmallVideo.prototype.setVideoType = function(videoType) {
|
||||||
this.videoType = videoType;
|
this.videoType = videoType;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -211,21 +220,22 @@ SmallVideo.prototype.setVideoType = function (videoType) {
|
||||||
* lib-jitsi-meet.
|
* lib-jitsi-meet.
|
||||||
* @returns {String} 'camera', 'screen', 'sharedvideo', or undefined.
|
* @returns {String} 'camera', 'screen', 'sharedvideo', or undefined.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.getVideoType = function () {
|
SmallVideo.prototype.getVideoType = function() {
|
||||||
return this.videoType;
|
return this.videoType;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an audio or video element for a particular MediaStream.
|
* Creates an audio or video element for a particular MediaStream.
|
||||||
*/
|
*/
|
||||||
SmallVideo.createStreamElement = function (stream) {
|
SmallVideo.createStreamElement = function(stream) {
|
||||||
let isVideo = stream.isVideoTrack();
|
const isVideo = stream.isVideoTrack();
|
||||||
|
|
||||||
let element = isVideo
|
const element = isVideo
|
||||||
? document.createElement('video')
|
? document.createElement('video')
|
||||||
: document.createElement('audio');
|
: document.createElement('audio');
|
||||||
|
|
||||||
if (isVideo) {
|
if (isVideo) {
|
||||||
element.setAttribute("muted", "true");
|
element.setAttribute('muted', 'true');
|
||||||
}
|
}
|
||||||
|
|
||||||
RTCUIHelper.setAutoPlay(element, true);
|
RTCUIHelper.setAutoPlay(element, true);
|
||||||
|
@ -238,8 +248,8 @@ SmallVideo.createStreamElement = function (stream) {
|
||||||
/**
|
/**
|
||||||
* Returns the element id for a particular MediaStream.
|
* Returns the element id for a particular MediaStream.
|
||||||
*/
|
*/
|
||||||
SmallVideo.getStreamElementID = function (stream) {
|
SmallVideo.getStreamElementID = function(stream) {
|
||||||
let isVideo = stream.isVideoTrack();
|
const isVideo = stream.isVideoTrack();
|
||||||
|
|
||||||
return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
|
return (isVideo ? 'remoteVideo_' : 'remoteAudio_') + stream.getId();
|
||||||
};
|
};
|
||||||
|
@ -247,7 +257,7 @@ SmallVideo.getStreamElementID = function (stream) {
|
||||||
/**
|
/**
|
||||||
* Configures hoverIn/hoverOut handlers. Depends on connection indicator.
|
* Configures hoverIn/hoverOut handlers. Depends on connection indicator.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.bindHoverHandler = function () {
|
SmallVideo.prototype.bindHoverHandler = function() {
|
||||||
// Add hover handler
|
// Add hover handler
|
||||||
this.$container.hover(
|
this.$container.hover(
|
||||||
() => {
|
() => {
|
||||||
|
@ -268,7 +278,7 @@ SmallVideo.prototype.bindHoverHandler = function () {
|
||||||
|
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.removeConnectionIndicator = function () {
|
SmallVideo.prototype.removeConnectionIndicator = function() {
|
||||||
this._showConnectionIndicator = false;
|
this._showConnectionIndicator = false;
|
||||||
|
|
||||||
this.updateIndicators();
|
this.updateIndicators();
|
||||||
|
@ -279,7 +289,7 @@ SmallVideo.prototype.removeConnectionIndicator = function () {
|
||||||
|
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateConnectionStatus = function (connectionStatus) {
|
SmallVideo.prototype.updateConnectionStatus = function(connectionStatus) {
|
||||||
this._connectionStatus = connectionStatus;
|
this._connectionStatus = connectionStatus;
|
||||||
this.updateIndicators();
|
this.updateIndicators();
|
||||||
};
|
};
|
||||||
|
@ -290,7 +300,7 @@ SmallVideo.prototype.updateConnectionStatus = function (connectionStatus) {
|
||||||
* @param {boolean} isMuted indicates if the muted element should be shown
|
* @param {boolean} isMuted indicates if the muted element should be shown
|
||||||
* or hidden
|
* or hidden
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.showAudioIndicator = function (isMuted) {
|
SmallVideo.prototype.showAudioIndicator = function(isMuted) {
|
||||||
this.isAudioMuted = isMuted;
|
this.isAudioMuted = isMuted;
|
||||||
this.updateStatusBar();
|
this.updateStatusBar();
|
||||||
};
|
};
|
||||||
|
@ -315,12 +325,11 @@ SmallVideo.prototype.setVideoMutedView = function(isMuted) {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateStatusBar = function () {
|
SmallVideo.prototype.updateStatusBar = function() {
|
||||||
const statusBarContainer
|
const statusBarContainer
|
||||||
= this.container.querySelector('.videocontainer__toolbar');
|
= this.container.querySelector('.videocontainer__toolbar');
|
||||||
const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
|
const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
|
||||||
|
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
<div>
|
<div>
|
||||||
|
@ -339,13 +348,12 @@ SmallVideo.prototype.updateStatusBar = function () {
|
||||||
</div>
|
</div>
|
||||||
</I18nextProvider>,
|
</I18nextProvider>,
|
||||||
statusBarContainer);
|
statusBarContainer);
|
||||||
/* jshint ignore:end */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the element indicating the moderator(owner) of the conference.
|
* Adds the element indicating the moderator(owner) of the conference.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.addModeratorIndicator = function () {
|
SmallVideo.prototype.addModeratorIndicator = function() {
|
||||||
this._isModerator = true;
|
this._isModerator = true;
|
||||||
this.updateStatusBar();
|
this.updateStatusBar();
|
||||||
};
|
};
|
||||||
|
@ -355,7 +363,7 @@ SmallVideo.prototype.addModeratorIndicator = function () {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.addAudioLevelIndicator = function () {
|
SmallVideo.prototype.addAudioLevelIndicator = function() {
|
||||||
let audioLevelContainer = this._getAudioLevelContainer();
|
let audioLevelContainer = this._getAudioLevelContainer();
|
||||||
|
|
||||||
if (audioLevelContainer) {
|
if (audioLevelContainer) {
|
||||||
|
@ -374,7 +382,7 @@ SmallVideo.prototype.addAudioLevelIndicator = function () {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.removeAudioLevelIndicator = function () {
|
SmallVideo.prototype.removeAudioLevelIndicator = function() {
|
||||||
const audioLevelContainer = this._getAudioLevelContainer();
|
const audioLevelContainer = this._getAudioLevelContainer();
|
||||||
|
|
||||||
if (audioLevelContainer) {
|
if (audioLevelContainer) {
|
||||||
|
@ -388,16 +396,14 @@ SmallVideo.prototype.removeAudioLevelIndicator = function () {
|
||||||
* @param lvl the new audio level to set
|
* @param lvl the new audio level to set
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateAudioLevelIndicator = function (lvl = 0) {
|
SmallVideo.prototype.updateAudioLevelIndicator = function(lvl = 0) {
|
||||||
const audioLevelContainer = this._getAudioLevelContainer();
|
const audioLevelContainer = this._getAudioLevelContainer();
|
||||||
|
|
||||||
if (audioLevelContainer) {
|
if (audioLevelContainer) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AudioLevelIndicator
|
<AudioLevelIndicator
|
||||||
audioLevel = { lvl }/>,
|
audioLevel = { lvl }/>,
|
||||||
audioLevelContainer);
|
audioLevelContainer);
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -407,14 +413,14 @@ SmallVideo.prototype.updateAudioLevelIndicator = function (lvl = 0) {
|
||||||
*
|
*
|
||||||
* @returns {HTMLElement} The DOM element that holds the AudioLevelIndicator.
|
* @returns {HTMLElement} The DOM element that holds the AudioLevelIndicator.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype._getAudioLevelContainer = function () {
|
SmallVideo.prototype._getAudioLevelContainer = function() {
|
||||||
return this.container.querySelector('.audioindicator-container');
|
return this.container.querySelector('.audioindicator-container');
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the element indicating the moderator(owner) of the conference.
|
* Removes the element indicating the moderator(owner) of the conference.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.removeModeratorIndicator = function () {
|
SmallVideo.prototype.removeModeratorIndicator = function() {
|
||||||
this._isModerator = false;
|
this._isModerator = false;
|
||||||
this.updateStatusBar();
|
this.updateStatusBar();
|
||||||
};
|
};
|
||||||
|
@ -429,7 +435,7 @@ SmallVideo.prototype.removeModeratorIndicator = function () {
|
||||||
* this function to access the video element via the 0th element of the returned
|
* this function to access the video element via the 0th element of the returned
|
||||||
* array (after checking its length of course!).
|
* array (after checking its length of course!).
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.selectVideoElement = function () {
|
SmallVideo.prototype.selectVideoElement = function() {
|
||||||
return $(RTCUIHelper.findVideoElement(this.container));
|
return $(RTCUIHelper.findVideoElement(this.container));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -439,7 +445,7 @@ SmallVideo.prototype.selectVideoElement = function () {
|
||||||
* @return {jQuery|HTMLElement} a jQuery selector pointing to the HTML image
|
* @return {jQuery|HTMLElement} a jQuery selector pointing to the HTML image
|
||||||
* element which displays the user's avatar.
|
* element which displays the user's avatar.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.$avatar = function () {
|
SmallVideo.prototype.$avatar = function() {
|
||||||
return this.$container.find('.avatar-container');
|
return this.$container.find('.avatar-container');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -449,7 +455,7 @@ SmallVideo.prototype.$avatar = function () {
|
||||||
* @return {jQuery} a jQuery selector pointing to the display name element of
|
* @return {jQuery} a jQuery selector pointing to the display name element of
|
||||||
* the video thumbnail
|
* the video thumbnail
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.$displayName = function () {
|
SmallVideo.prototype.$displayName = function() {
|
||||||
return this.$container.find('.displayNameContainer');
|
return this.$container.find('.displayNameContainer');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -459,12 +465,11 @@ SmallVideo.prototype.$displayName = function () {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateDisplayName = function (props) {
|
SmallVideo.prototype.updateDisplayName = function(props) {
|
||||||
const displayNameContainer
|
const displayNameContainer
|
||||||
= this.container.querySelector('.displayNameContainer');
|
= this.container.querySelector('.displayNameContainer');
|
||||||
|
|
||||||
if (displayNameContainer) {
|
if (displayNameContainer) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<Provider store = { APP.store }>
|
<Provider store = { APP.store }>
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
|
@ -472,7 +477,6 @@ SmallVideo.prototype.updateDisplayName = function (props) {
|
||||||
</I18nextProvider>
|
</I18nextProvider>
|
||||||
</Provider>,
|
</Provider>,
|
||||||
displayNameContainer);
|
displayNameContainer);
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -482,7 +486,7 @@ SmallVideo.prototype.updateDisplayName = function (props) {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.removeDisplayName = function () {
|
SmallVideo.prototype.removeDisplayName = function() {
|
||||||
const displayNameContainer
|
const displayNameContainer
|
||||||
= this.container.querySelector('.displayNameContainer');
|
= this.container.querySelector('.displayNameContainer');
|
||||||
|
|
||||||
|
@ -498,18 +502,17 @@ SmallVideo.prototype.removeDisplayName = function () {
|
||||||
* @param isFocused indicates if the thumbnail should be focused/pinned or not
|
* @param isFocused indicates if the thumbnail should be focused/pinned or not
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.focus = function(isFocused) {
|
SmallVideo.prototype.focus = function(isFocused) {
|
||||||
var focusedCssClass = "videoContainerFocused";
|
const focusedCssClass = 'videoContainerFocused';
|
||||||
var isFocusClassEnabled = this.$container.hasClass(focusedCssClass);
|
const isFocusClassEnabled = this.$container.hasClass(focusedCssClass);
|
||||||
|
|
||||||
if (!isFocused && isFocusClassEnabled) {
|
if (!isFocused && isFocusClassEnabled) {
|
||||||
this.$container.removeClass(focusedCssClass);
|
this.$container.removeClass(focusedCssClass);
|
||||||
}
|
} else if (isFocused && !isFocusClassEnabled) {
|
||||||
else if (isFocused && !isFocusClassEnabled) {
|
|
||||||
this.$container.addClass(focusedCssClass);
|
this.$container.addClass(focusedCssClass);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SmallVideo.prototype.hasVideo = function () {
|
SmallVideo.prototype.hasVideo = function() {
|
||||||
return this.selectVideoElement().length !== 0;
|
return this.selectVideoElement().length !== 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -520,7 +523,7 @@ SmallVideo.prototype.hasVideo = function () {
|
||||||
* @return {boolean} <tt>true</tt> if the user is displayed on the large video
|
* @return {boolean} <tt>true</tt> if the user is displayed on the large video
|
||||||
* or <tt>false</tt> otherwise.
|
* or <tt>false</tt> otherwise.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.isCurrentlyOnLargeVideo = function () {
|
SmallVideo.prototype.isCurrentlyOnLargeVideo = function() {
|
||||||
return this.VideoLayout.isCurrentlyOnLarge(this.id);
|
return this.VideoLayout.isCurrentlyOnLarge(this.id);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -550,13 +553,14 @@ SmallVideo.prototype.selectDisplayMode = function() {
|
||||||
&& this.selectVideoElement().length
|
&& this.selectVideoElement().length
|
||||||
&& !APP.conference.isAudioOnly()) {
|
&& !APP.conference.isAudioOnly()) {
|
||||||
// check hovering and change state to video with name
|
// check hovering and change state to video with name
|
||||||
return this._isHovered() ?
|
return this._isHovered()
|
||||||
DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
|
? DISPLAY_VIDEO_WITH_NAME : DISPLAY_VIDEO;
|
||||||
} else {
|
|
||||||
// check hovering and change state to avatar with name
|
|
||||||
return this._isHovered() ?
|
|
||||||
DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// check hovering and change state to avatar with name
|
||||||
|
return this._isHovered()
|
||||||
|
? DISPLAY_AVATAR_WITH_NAME : DISPLAY_AVATAR;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -565,7 +569,7 @@ SmallVideo.prototype.selectDisplayMode = function() {
|
||||||
* indicator is shown(hovered).
|
* indicator is shown(hovered).
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype._isHovered = function () {
|
SmallVideo.prototype._isHovered = function() {
|
||||||
return this.videoIsHovered || this._popoverIsHovered;
|
return this.videoIsHovered || this._popoverIsHovered;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -577,42 +581,49 @@ SmallVideo.prototype._isHovered = function () {
|
||||||
* @param show whether we should show the avatar or not
|
* @param show whether we should show the avatar or not
|
||||||
* video because there is no dominant speaker and no focused speaker
|
* video because there is no dominant speaker and no focused speaker
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateView = function () {
|
SmallVideo.prototype.updateView = function() {
|
||||||
if (this.disableUpdateView)
|
if (this.disableUpdateView) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.hasAvatar) {
|
if (!this.hasAvatar) {
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
// Init avatar
|
// Init avatar
|
||||||
this.avatarChanged(Avatar.getAvatarUrl(this.id));
|
this.avatarChanged(Avatar.getAvatarUrl(this.id));
|
||||||
} else {
|
} else {
|
||||||
logger.error("Unable to init avatar - no id", this);
|
logger.error('Unable to init avatar - no id', this);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine whether video, avatar or blackness should be displayed
|
// Determine whether video, avatar or blackness should be displayed
|
||||||
let displayMode = this.selectDisplayMode();
|
const displayMode = this.selectDisplayMode();
|
||||||
|
|
||||||
// Show/hide video.
|
// Show/hide video.
|
||||||
|
|
||||||
UIUtil.setVisibleBySelector(this.selectVideoElement(),
|
UIUtil.setVisibleBySelector(this.selectVideoElement(),
|
||||||
(displayMode === DISPLAY_VIDEO
|
displayMode === DISPLAY_VIDEO
|
||||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
|
|| displayMode === DISPLAY_VIDEO_WITH_NAME);
|
||||||
|
|
||||||
// Show/hide the avatar.
|
// Show/hide the avatar.
|
||||||
UIUtil.setVisibleBySelector(this.$avatar(),
|
UIUtil.setVisibleBySelector(this.$avatar(),
|
||||||
(displayMode === DISPLAY_AVATAR
|
displayMode === DISPLAY_AVATAR
|
||||||
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
|
|| displayMode === DISPLAY_AVATAR_WITH_NAME);
|
||||||
|
|
||||||
// Show/hide the display name.
|
// Show/hide the display name.
|
||||||
UIUtil.setVisibleBySelector(this.$displayName(),
|
UIUtil.setVisibleBySelector(this.$displayName(),
|
||||||
!this.hideDisplayName
|
!this.hideDisplayName
|
||||||
&& (displayMode === DISPLAY_BLACKNESS_WITH_NAME
|
&& (displayMode === DISPLAY_BLACKNESS_WITH_NAME
|
||||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME
|
|| displayMode === DISPLAY_VIDEO_WITH_NAME
|
||||||
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
|
|| displayMode === DISPLAY_AVATAR_WITH_NAME));
|
||||||
|
|
||||||
// show hide overlay when there is a video or avatar under
|
// show hide overlay when there is a video or avatar under
|
||||||
// the display name
|
// the display name
|
||||||
UIUtil.setVisibleBySelector(this.$container.find(
|
UIUtil.setVisibleBySelector(this.$container.find(
|
||||||
'.videocontainer__hoverOverlay'),
|
'.videocontainer__hoverOverlay'),
|
||||||
(displayMode === DISPLAY_AVATAR_WITH_NAME
|
displayMode === DISPLAY_AVATAR_WITH_NAME
|
||||||
|| displayMode === DISPLAY_VIDEO_WITH_NAME));
|
|| displayMode === DISPLAY_VIDEO_WITH_NAME);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -622,19 +633,18 @@ SmallVideo.prototype.updateView = function () {
|
||||||
* @param {string} avatarUrl - The uri to the avatar image.
|
* @param {string} avatarUrl - The uri to the avatar image.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.avatarChanged = function (avatarUrl) {
|
SmallVideo.prototype.avatarChanged = function(avatarUrl) {
|
||||||
const thumbnail = this.$avatar().get(0);
|
const thumbnail = this.$avatar().get(0);
|
||||||
|
|
||||||
this.hasAvatar = true;
|
this.hasAvatar = true;
|
||||||
|
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<AvatarDisplay
|
<AvatarDisplay
|
||||||
className = 'userAvatar'
|
className = 'userAvatar'
|
||||||
uri = { avatarUrl } />,
|
uri = { avatarUrl } />,
|
||||||
thumbnail
|
thumbnail
|
||||||
);
|
);
|
||||||
/* jshint ignore:end */
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -644,7 +654,7 @@ SmallVideo.prototype.avatarChanged = function (avatarUrl) {
|
||||||
*
|
*
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.removeAvatar = function () {
|
SmallVideo.prototype.removeAvatar = function() {
|
||||||
const thumbnail = this.$avatar().get(0);
|
const thumbnail = this.$avatar().get(0);
|
||||||
|
|
||||||
if (thumbnail) {
|
if (thumbnail) {
|
||||||
|
@ -656,15 +666,17 @@ SmallVideo.prototype.removeAvatar = function () {
|
||||||
* Shows or hides the dominant speaker indicator.
|
* Shows or hides the dominant speaker indicator.
|
||||||
* @param show whether to show or hide.
|
* @param show whether to show or hide.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
SmallVideo.prototype.showDominantSpeakerIndicator = function(show) {
|
||||||
// Don't create and show dominant speaker indicator if
|
// Don't create and show dominant speaker indicator if
|
||||||
// DISABLE_DOMINANT_SPEAKER_INDICATOR is true
|
// DISABLE_DOMINANT_SPEAKER_INDICATOR is true
|
||||||
if (interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR)
|
if (interfaceConfig.DISABLE_DOMINANT_SPEAKER_INDICATOR) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
logger.warn( "Unable to set dominant speaker indicator - "
|
logger.warn(`Unable to set dominant speaker indicator - ${
|
||||||
+ this.videoSpanId + " does not exist");
|
this.videoSpanId} does not exist`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -677,10 +689,11 @@ SmallVideo.prototype.showDominantSpeakerIndicator = function (show) {
|
||||||
* Shows or hides the raised hand indicator.
|
* Shows or hides the raised hand indicator.
|
||||||
* @param show whether to show or hide.
|
* @param show whether to show or hide.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.showRaisedHandIndicator = function (show) {
|
SmallVideo.prototype.showRaisedHandIndicator = function(show) {
|
||||||
if (!this.container) {
|
if (!this.container) {
|
||||||
logger.warn( "Unable to raised hand indication - "
|
logger.warn(`Unable to raised hand indication - ${
|
||||||
+ this.videoSpanId + " does not exist");
|
this.videoSpanId} does not exist`);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -695,26 +708,31 @@ SmallVideo.prototype.showRaisedHandIndicator = function (show) {
|
||||||
* is added, and will fire a RESOLUTION_CHANGED event.
|
* is added, and will fire a RESOLUTION_CHANGED event.
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.waitForResolutionChange = function() {
|
SmallVideo.prototype.waitForResolutionChange = function() {
|
||||||
let beforeChange = window.performance.now();
|
const beforeChange = window.performance.now();
|
||||||
let videos = this.selectVideoElement();
|
const videos = this.selectVideoElement();
|
||||||
if (!videos || !videos.length || videos.length <= 0)
|
|
||||||
|
if (!videos || !videos.length || videos.length <= 0) {
|
||||||
return;
|
return;
|
||||||
let video = videos[0];
|
}
|
||||||
let oldWidth = video.videoWidth;
|
const video = videos[0];
|
||||||
let oldHeight = video.videoHeight;
|
const oldWidth = video.videoWidth;
|
||||||
|
const oldHeight = video.videoHeight;
|
||||||
|
|
||||||
video.onresize = () => {
|
video.onresize = () => {
|
||||||
|
// eslint-disable-next-line eqeqeq
|
||||||
if (video.videoWidth != oldWidth || video.videoHeight != oldHeight) {
|
if (video.videoWidth != oldWidth || video.videoHeight != oldHeight) {
|
||||||
// Only run once.
|
// Only run once.
|
||||||
video.onresize = null;
|
video.onresize = null;
|
||||||
|
|
||||||
let delay = window.performance.now() - beforeChange;
|
const delay = window.performance.now() - beforeChange;
|
||||||
let emitter = this.VideoLayout.getEventEmitter();
|
const emitter = this.VideoLayout.getEventEmitter();
|
||||||
|
|
||||||
if (emitter) {
|
if (emitter) {
|
||||||
emitter.emit(
|
emitter.emit(
|
||||||
UIEvents.RESOLUTION_CHANGED,
|
UIEvents.RESOLUTION_CHANGED,
|
||||||
this.getId(),
|
this.getId(),
|
||||||
oldWidth + "x" + oldHeight,
|
`${oldWidth}x${oldHeight}`,
|
||||||
video.videoWidth + "x" + video.videoHeight,
|
`${video.videoWidth}x${video.videoHeight}`,
|
||||||
delay);
|
delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -735,11 +753,12 @@ SmallVideo.prototype.waitForResolutionChange = function() {
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.initBrowserSpecificProperties = function() {
|
SmallVideo.prototype.initBrowserSpecificProperties = function() {
|
||||||
|
|
||||||
var userAgent = window.navigator.userAgent;
|
const userAgent = window.navigator.userAgent;
|
||||||
if (userAgent.indexOf("QtWebEngine") > -1
|
|
||||||
&& (userAgent.indexOf("Windows") > -1
|
if (userAgent.indexOf('QtWebEngine') > -1
|
||||||
|| userAgent.indexOf("Linux") > -1)) {
|
&& (userAgent.indexOf('Windows') > -1
|
||||||
this.$container.css("overflow", "hidden");
|
|| userAgent.indexOf('Linux') > -1)) {
|
||||||
|
this.$container.css('overflow', 'hidden');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -751,7 +770,7 @@ SmallVideo.prototype.initBrowserSpecificProperties = function() {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype.updateIndicators = function () {
|
SmallVideo.prototype.updateIndicators = function() {
|
||||||
const indicatorToolbar
|
const indicatorToolbar
|
||||||
= this.container.querySelector('.videocontainer__toptoolbar');
|
= this.container.querySelector('.videocontainer__toptoolbar');
|
||||||
|
|
||||||
|
@ -760,7 +779,6 @@ SmallVideo.prototype.updateIndicators = function () {
|
||||||
|| !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
|
|| !interfaceConfig.CONNECTION_INDICATOR_AUTO_HIDE_ENABLED;
|
||||||
const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
|
const tooltipPosition = interfaceConfig.VERTICAL_FILMSTRIP ? 'left' : 'top';
|
||||||
|
|
||||||
/* jshint ignore:start */
|
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<I18nextProvider i18n = { i18next }>
|
<I18nextProvider i18n = { i18next }>
|
||||||
<div>
|
<div>
|
||||||
|
@ -788,7 +806,6 @@ SmallVideo.prototype.updateIndicators = function () {
|
||||||
</I18nextProvider>,
|
</I18nextProvider>,
|
||||||
indicatorToolbar
|
indicatorToolbar
|
||||||
);
|
);
|
||||||
/* jshint ignore:end */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -798,7 +815,7 @@ SmallVideo.prototype.updateIndicators = function () {
|
||||||
* @private
|
* @private
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype._unmountIndicators = function () {
|
SmallVideo.prototype._unmountIndicators = function() {
|
||||||
const indicatorToolbar
|
const indicatorToolbar
|
||||||
= this.container.querySelector('.videocontainer__toptoolbar');
|
= this.container.querySelector('.videocontainer__toptoolbar');
|
||||||
|
|
||||||
|
@ -815,7 +832,7 @@ SmallVideo.prototype._unmountIndicators = function () {
|
||||||
* currently over the connection indicator popover.
|
* currently over the connection indicator popover.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
SmallVideo.prototype._onPopoverHover = function (popoverIsHovered) {
|
SmallVideo.prototype._onPopoverHover = function(popoverIsHovered) {
|
||||||
this._popoverIsHovered = popoverIsHovered;
|
this._popoverIsHovered = popoverIsHovered;
|
||||||
this.updateView();
|
this.updateView();
|
||||||
};
|
};
|
||||||
|
|
|
@ -23,16 +23,17 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
* @param videoSpaceHeight the height of the available space
|
* @param videoSpaceHeight the height of the available space
|
||||||
* @return an array with 2 elements, the video width and the video height
|
* @return an array with 2 elements, the video width and the video height
|
||||||
*/
|
*/
|
||||||
function computeDesktopVideoSize(
|
function computeDesktopVideoSize( // eslint-disable-line max-params
|
||||||
videoWidth,
|
videoWidth,
|
||||||
videoHeight,
|
videoHeight,
|
||||||
videoSpaceWidth,
|
videoSpaceWidth,
|
||||||
videoSpaceHeight) {
|
videoSpaceHeight) {
|
||||||
let aspectRatio = videoWidth / videoHeight;
|
const aspectRatio = videoWidth / videoHeight;
|
||||||
|
|
||||||
let availableWidth = Math.max(videoWidth, videoSpaceWidth);
|
let availableWidth = Math.max(videoWidth, videoSpaceWidth);
|
||||||
let availableHeight = Math.max(videoHeight, videoSpaceHeight);
|
let availableHeight = Math.max(videoHeight, videoSpaceHeight);
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
videoSpaceHeight -= Filmstrip.getFilmstripHeight();
|
videoSpaceHeight -= Filmstrip.getFilmstripHeight();
|
||||||
|
|
||||||
if (availableWidth / aspectRatio >= videoSpaceHeight) {
|
if (availableWidth / aspectRatio >= videoSpaceHeight) {
|
||||||
|
@ -60,13 +61,14 @@ function computeDesktopVideoSize(
|
||||||
* @param videoSpaceHeight the height of the video space
|
* @param videoSpaceHeight the height of the video space
|
||||||
* @return an array with 2 elements, the video width and the video height
|
* @return an array with 2 elements, the video width and the video height
|
||||||
*/
|
*/
|
||||||
function computeCameraVideoSize(
|
function computeCameraVideoSize( // eslint-disable-line max-params
|
||||||
videoWidth,
|
videoWidth,
|
||||||
videoHeight,
|
videoHeight,
|
||||||
videoSpaceWidth,
|
videoSpaceWidth,
|
||||||
videoSpaceHeight,
|
videoSpaceHeight,
|
||||||
videoLayoutFit) {
|
videoLayoutFit) {
|
||||||
const aspectRatio = videoWidth / videoHeight;
|
const aspectRatio = videoWidth / videoHeight;
|
||||||
|
|
||||||
switch (videoLayoutFit) {
|
switch (videoLayoutFit) {
|
||||||
case 'height':
|
case 'height':
|
||||||
return [ videoSpaceHeight * aspectRatio, videoSpaceHeight ];
|
return [ videoSpaceHeight * aspectRatio, videoSpaceHeight ];
|
||||||
|
@ -78,10 +80,10 @@ function computeCameraVideoSize(
|
||||||
|| Infinity;
|
|| Infinity;
|
||||||
|
|
||||||
if (videoSpaceRatio === aspectRatio) {
|
if (videoSpaceRatio === aspectRatio) {
|
||||||
return [videoSpaceWidth, videoSpaceHeight];
|
return [ videoSpaceWidth, videoSpaceHeight ];
|
||||||
}
|
}
|
||||||
|
|
||||||
let [ width, height] = computeCameraVideoSize(
|
let [ width, height ] = computeCameraVideoSize(
|
||||||
videoWidth,
|
videoWidth,
|
||||||
videoHeight,
|
videoHeight,
|
||||||
videoSpaceWidth,
|
videoSpaceWidth,
|
||||||
|
@ -97,7 +99,8 @@ function computeCameraVideoSize(
|
||||||
height = maxHeight;
|
height = maxHeight;
|
||||||
width = height * aspectRatio;
|
width = height * aspectRatio;
|
||||||
}
|
}
|
||||||
return [width, height];
|
|
||||||
|
return [ width, height ];
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return [ videoWidth, videoHeight ];
|
return [ videoWidth, videoHeight ];
|
||||||
|
@ -111,7 +114,7 @@ function computeCameraVideoSize(
|
||||||
* @return an array with 2 elements, the horizontal indent and the vertical
|
* @return an array with 2 elements, the horizontal indent and the vertical
|
||||||
* indent
|
* indent
|
||||||
*/
|
*/
|
||||||
function getCameraVideoPosition(
|
function getCameraVideoPosition( // eslint-disable-line max-params
|
||||||
videoWidth,
|
videoWidth,
|
||||||
videoHeight,
|
videoHeight,
|
||||||
videoSpaceWidth,
|
videoSpaceWidth,
|
||||||
|
@ -120,13 +123,15 @@ function getCameraVideoPosition(
|
||||||
// full screen mode and this is why we use the screen height in this case.
|
// full screen mode and this is why we use the screen height in this case.
|
||||||
// Need to think it further at some point and implement it properly.
|
// Need to think it further at some point and implement it properly.
|
||||||
if (UIUtil.isFullScreen()) {
|
if (UIUtil.isFullScreen()) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
videoSpaceHeight = window.innerHeight;
|
videoSpaceHeight = window.innerHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
const horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
||||||
let verticalIndent = (videoSpaceHeight - videoHeight) / 2;
|
const verticalIndent = (videoSpaceHeight - videoHeight) / 2;
|
||||||
|
|
||||||
return { horizontalIndent, verticalIndent };
|
return { horizontalIndent,
|
||||||
|
verticalIndent };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -137,11 +142,12 @@ function getCameraVideoPosition(
|
||||||
* indent
|
* indent
|
||||||
*/
|
*/
|
||||||
function getDesktopVideoPosition(videoWidth, videoHeight, videoSpaceWidth) {
|
function getDesktopVideoPosition(videoWidth, videoHeight, videoSpaceWidth) {
|
||||||
let horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
const horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
|
||||||
|
|
||||||
let verticalIndent = 0;// Top aligned
|
const verticalIndent = 0;// Top aligned
|
||||||
|
|
||||||
return { horizontalIndent, verticalIndent };
|
return { horizontalIndent,
|
||||||
|
verticalIndent };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -149,15 +155,24 @@ function getDesktopVideoPosition(videoWidth, videoHeight, videoSpaceWidth) {
|
||||||
*/
|
*/
|
||||||
export class VideoContainer extends LargeContainer {
|
export class VideoContainer extends LargeContainer {
|
||||||
// FIXME: With Temasys we have to re-select everytime
|
// FIXME: With Temasys we have to re-select everytime
|
||||||
get $video () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get $video() {
|
||||||
return $('#largeVideo');
|
return $('#largeVideo');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
get $videoBackground() {
|
get $videoBackground() {
|
||||||
return $('#largeVideoBackground');
|
return $('#largeVideoBackground');
|
||||||
}
|
}
|
||||||
|
|
||||||
get id () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
get id() {
|
||||||
return this.userId;
|
return this.userId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,7 +183,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @param emitter {EventEmitter} the event emitter that will be used by
|
* @param emitter {EventEmitter} the event emitter that will be used by
|
||||||
* this instance.
|
* this instance.
|
||||||
*/
|
*/
|
||||||
constructor (resizeContainer, emitter) {
|
constructor(resizeContainer, emitter) {
|
||||||
super();
|
super();
|
||||||
this.stream = null;
|
this.stream = null;
|
||||||
this.userId = null;
|
this.userId = null;
|
||||||
|
@ -213,15 +228,17 @@ export class VideoContainer extends LargeContainer {
|
||||||
|
|
||||||
this.avatarHeight = $('#dominantSpeakerAvatar').height();
|
this.avatarHeight = $('#dominantSpeakerAvatar').height();
|
||||||
|
|
||||||
var onPlayingCallback = function (event) {
|
const onPlayingCallback = function(event) {
|
||||||
if (typeof resizeContainer === 'function') {
|
if (typeof resizeContainer === 'function') {
|
||||||
resizeContainer(event);
|
resizeContainer(event);
|
||||||
}
|
}
|
||||||
this.wasVideoRendered = true;
|
this.wasVideoRendered = true;
|
||||||
}.bind(this);
|
}.bind(this);
|
||||||
|
|
||||||
// This does not work with Temasys plugin - has to be a property to be
|
// This does not work with Temasys plugin - has to be a property to be
|
||||||
// copied between new <object> elements
|
// copied between new <object> elements
|
||||||
//this.$video.on('play', onPlay);
|
// this.$video.on('play', onPlay);
|
||||||
|
|
||||||
this.$video[0].onplaying = onPlayingCallback;
|
this.$video[0].onplaying = onPlayingCallback;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -254,7 +271,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @param {boolean} enable <tt>true</tt> if the filter is to be enabled or
|
* @param {boolean} enable <tt>true</tt> if the filter is to be enabled or
|
||||||
* <tt>false</tt> otherwise.
|
* <tt>false</tt> otherwise.
|
||||||
*/
|
*/
|
||||||
enableLocalConnectionProblemFilter (enable) {
|
enableLocalConnectionProblemFilter(enable) {
|
||||||
this.$video.toggleClass('videoProblemFilter', enable);
|
this.$video.toggleClass('videoProblemFilter', enable);
|
||||||
this.$videoBackground.toggleClass('videoProblemFilter', enable);
|
this.$videoBackground.toggleClass('videoProblemFilter', enable);
|
||||||
}
|
}
|
||||||
|
@ -271,8 +288,10 @@ export class VideoContainer extends LargeContainer {
|
||||||
* Get size of video element.
|
* Get size of video element.
|
||||||
* @returns {{width, height}}
|
* @returns {{width, height}}
|
||||||
*/
|
*/
|
||||||
getStreamSize () {
|
getStreamSize() {
|
||||||
let video = this.$video[0];
|
const video = this.$video[0];
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
width: video.videoWidth,
|
width: video.videoWidth,
|
||||||
height: video.videoHeight
|
height: video.videoHeight
|
||||||
|
@ -286,7 +305,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @returns {{availableWidth, availableHeight}}
|
* @returns {{availableWidth, availableHeight}}
|
||||||
*/
|
*/
|
||||||
getVideoSize(containerWidth, containerHeight) {
|
getVideoSize(containerWidth, containerHeight) {
|
||||||
let { width, height } = this.getStreamSize();
|
const { width, height } = this.getStreamSize();
|
||||||
|
|
||||||
if (this.stream && this.isScreenSharing()) {
|
if (this.stream && this.isScreenSharing()) {
|
||||||
return computeDesktopVideoSize(width,
|
return computeDesktopVideoSize(width,
|
||||||
|
@ -302,6 +321,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
interfaceConfig.VIDEO_LAYOUT_FIT);
|
interfaceConfig.VIDEO_LAYOUT_FIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable max-params */
|
||||||
/**
|
/**
|
||||||
* Calculate optimal video position (offset for top left corner)
|
* Calculate optimal video position (offset for top left corner)
|
||||||
* for specified video size and container size.
|
* for specified video size and container size.
|
||||||
|
@ -311,18 +331,20 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @param {number} containerHeight container height
|
* @param {number} containerHeight container height
|
||||||
* @returns {{horizontalIndent, verticalIndent}}
|
* @returns {{horizontalIndent, verticalIndent}}
|
||||||
*/
|
*/
|
||||||
getVideoPosition (width, height, containerWidth, containerHeight) {
|
getVideoPosition(width, height, containerWidth, containerHeight) {
|
||||||
|
/* eslint-enable max-params */
|
||||||
if (this.stream && this.isScreenSharing()) {
|
if (this.stream && this.isScreenSharing()) {
|
||||||
return getDesktopVideoPosition( width,
|
return getDesktopVideoPosition(width,
|
||||||
height,
|
|
||||||
containerWidth,
|
|
||||||
containerHeight);
|
|
||||||
} else {
|
|
||||||
return getCameraVideoPosition( width,
|
|
||||||
height,
|
height,
|
||||||
containerWidth,
|
containerWidth,
|
||||||
containerHeight);
|
containerHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return getCameraVideoPosition(width,
|
||||||
|
height,
|
||||||
|
containerWidth,
|
||||||
|
containerHeight);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -346,18 +368,23 @@ export class VideoContainer extends LargeContainer {
|
||||||
*/
|
*/
|
||||||
_positionParticipantStatus($element) {
|
_positionParticipantStatus($element) {
|
||||||
if (this.avatarDisplayed) {
|
if (this.avatarDisplayed) {
|
||||||
let $avatarImage = $('#dominantSpeakerAvatar');
|
const $avatarImage = $('#dominantSpeakerAvatar');
|
||||||
|
|
||||||
$element.css(
|
$element.css(
|
||||||
'top',
|
'top',
|
||||||
$avatarImage.offset().top + $avatarImage.height() + 10);
|
$avatarImage.offset().top + $avatarImage.height() + 10);
|
||||||
} else {
|
} else {
|
||||||
let height = $element.height();
|
const height = $element.height();
|
||||||
let parentHeight = $element.parent().height();
|
const parentHeight = $element.parent().height();
|
||||||
$element.css('top', (parentHeight/2) - (height/2));
|
|
||||||
|
$element.css('top', (parentHeight / 2) - (height / 2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
resize (containerWidth, containerHeight, animate = false) {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
resize(containerWidth, containerHeight, animate = false) {
|
||||||
// XXX Prevent TypeError: undefined is not an object when the Web
|
// XXX Prevent TypeError: undefined is not an object when the Web
|
||||||
// browser does not support WebRTC (yet).
|
// browser does not support WebRTC (yet).
|
||||||
if (this.$video.length === 0) {
|
if (this.$video.length === 0) {
|
||||||
|
@ -366,32 +393,35 @@ export class VideoContainer extends LargeContainer {
|
||||||
|
|
||||||
this._hideVideoBackground();
|
this._hideVideoBackground();
|
||||||
|
|
||||||
let [ width, height ]
|
const [ width, height ]
|
||||||
= this.getVideoSize(containerWidth, containerHeight);
|
= this.getVideoSize(containerWidth, containerHeight);
|
||||||
|
|
||||||
if ((containerWidth > width) || (containerHeight > height)) {
|
if ((containerWidth > width) || (containerHeight > height)) {
|
||||||
this._showVideoBackground();
|
this._showVideoBackground();
|
||||||
const css
|
const css
|
||||||
= containerWidth > width
|
= containerWidth > width
|
||||||
? { width: '100%', height: 'auto' }
|
? { width: '100%',
|
||||||
: { width: 'auto', height: '100%' };
|
height: 'auto' }
|
||||||
|
: { width: 'auto',
|
||||||
|
height: '100%' };
|
||||||
|
|
||||||
this.$videoBackground.css(css);
|
this.$videoBackground.css(css);
|
||||||
}
|
}
|
||||||
|
|
||||||
let { horizontalIndent, verticalIndent }
|
const { horizontalIndent, verticalIndent }
|
||||||
= this.getVideoPosition(width, height,
|
= this.getVideoPosition(width, height,
|
||||||
containerWidth, containerHeight);
|
containerWidth, containerHeight);
|
||||||
|
|
||||||
// update avatar position
|
// update avatar position
|
||||||
let top = containerHeight / 2 - this.avatarHeight / 4 * 3;
|
const top = (containerHeight / 2) - (this.avatarHeight / 4 * 3);
|
||||||
|
|
||||||
this.$avatar.css('top', top);
|
this.$avatar.css('top', top);
|
||||||
|
|
||||||
this.positionRemoteStatusMessages();
|
this.positionRemoteStatusMessages();
|
||||||
|
|
||||||
this.$wrapper.animate({
|
this.$wrapper.animate({
|
||||||
width: width,
|
width,
|
||||||
height: height,
|
height,
|
||||||
|
|
||||||
top: verticalIndent,
|
top: verticalIndent,
|
||||||
bottom: verticalIndent,
|
bottom: verticalIndent,
|
||||||
|
@ -422,22 +452,24 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @param {JitsiTrack?} stream new stream
|
* @param {JitsiTrack?} stream new stream
|
||||||
* @param {string} videoType video type
|
* @param {string} videoType video type
|
||||||
*/
|
*/
|
||||||
setStream (userID, stream, videoType) {
|
setStream(userID, stream, videoType) {
|
||||||
this.userId = userID;
|
this.userId = userID;
|
||||||
if (this.stream === stream) {
|
if (this.stream === stream) {
|
||||||
// Handles the use case for the remote participants when the
|
// Handles the use case for the remote participants when the
|
||||||
// videoType is received with delay after turning on/off the
|
// videoType is received with delay after turning on/off the
|
||||||
// desktop sharing.
|
// desktop sharing.
|
||||||
if(this.videoType !== videoType) {
|
if (this.videoType !== videoType) {
|
||||||
this.videoType = videoType;
|
this.videoType = videoType;
|
||||||
this.resizeContainer();
|
this.resizeContainer();
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
// The stream has changed, so the image will be lost on detach
|
|
||||||
this.wasVideoRendered = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The stream has changed, so the image will be lost on detach
|
||||||
|
this.wasVideoRendered = false;
|
||||||
|
|
||||||
|
|
||||||
// detach old stream
|
// detach old stream
|
||||||
if (this.stream) {
|
if (this.stream) {
|
||||||
this.stream.detach(this.$video[0]);
|
this.stream.detach(this.$video[0]);
|
||||||
|
@ -475,8 +507,9 @@ export class VideoContainer extends LargeContainer {
|
||||||
*/
|
*/
|
||||||
setLocalFlipX(val) {
|
setLocalFlipX(val) {
|
||||||
this.localFlipX = val;
|
this.localFlipX = val;
|
||||||
if(!this.$video || !this.stream || !this.stream.isLocal())
|
if (!this.$video || !this.stream || !this.stream.isLocal()) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
this.$video.css({
|
this.$video.css({
|
||||||
transform: this.localFlipX ? 'scaleX(-1)' : 'none'
|
transform: this.localFlipX ? 'scaleX(-1)' : 'none'
|
||||||
});
|
});
|
||||||
|
@ -491,7 +524,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
* Check if current video stream is screen sharing.
|
* Check if current video stream is screen sharing.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isScreenSharing () {
|
isScreenSharing() {
|
||||||
return this.videoType === 'desktop';
|
return this.videoType === 'desktop';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -499,7 +532,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
* Show or hide user avatar.
|
* Show or hide user avatar.
|
||||||
* @param {boolean} show
|
* @param {boolean} show
|
||||||
*/
|
*/
|
||||||
showAvatar (show) {
|
showAvatar(show) {
|
||||||
// TO FIX: Video background need to be black, so that we don't have a
|
// TO FIX: Video background need to be black, so that we don't have a
|
||||||
// flickering effect when scrolling between videos and have the screen
|
// flickering effect when scrolling between videos and have the screen
|
||||||
// move to grey before going back to video. Avatars though can have the
|
// move to grey before going back to video. Avatars though can have the
|
||||||
|
@ -521,26 +554,28 @@ export class VideoContainer extends LargeContainer {
|
||||||
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
* @param {boolean} show <tt>true</tt> to show or <tt>false</tt> to hide
|
||||||
* the indication.
|
* the indication.
|
||||||
*/
|
*/
|
||||||
showRemoteConnectionProblemIndicator (show) {
|
showRemoteConnectionProblemIndicator(show) {
|
||||||
this.$video.toggleClass('remoteVideoProblemFilter', show);
|
this.$video.toggleClass('remoteVideoProblemFilter', show);
|
||||||
this.$videoBackground.toggleClass('remoteVideoProblemFilter', show);
|
this.$videoBackground.toggleClass('remoteVideoProblemFilter', show);
|
||||||
|
|
||||||
this.$avatar.toggleClass('remoteVideoProblemFilter', show);
|
this.$avatar.toggleClass('remoteVideoProblemFilter', show);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We are doing fadeOut/fadeIn animations on parent div which wraps
|
|
||||||
// largeVideo, because when Temasys plugin is in use it replaces
|
|
||||||
// <video> elements with plugin <object> tag. In Safari jQuery is
|
|
||||||
// unable to store values on this plugin object which breaks all
|
|
||||||
// animation effects performed on it directly.
|
|
||||||
|
|
||||||
show () {
|
/**
|
||||||
|
* We are doing fadeOut/fadeIn animations on parent div which wraps
|
||||||
|
* largeVideo, because when Temasys plugin is in use it replaces
|
||||||
|
* <video> elements with plugin <object> tag. In Safari jQuery is
|
||||||
|
* unable to store values on this plugin object which breaks all
|
||||||
|
* animation effects performed on it directly.
|
||||||
|
*/
|
||||||
|
show() {
|
||||||
// its already visible
|
// its already visible
|
||||||
if (this.isVisible) {
|
if (this.isVisible) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
this.$wrapperParent.css('visibility', 'visible').fadeTo(
|
this.$wrapperParent.css('visibility', 'visible').fadeTo(
|
||||||
FADE_DURATION_MS,
|
FADE_DURATION_MS,
|
||||||
1,
|
1,
|
||||||
|
@ -552,16 +587,20 @@ export class VideoContainer extends LargeContainer {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
hide () {
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
hide() {
|
||||||
// as the container is hidden/replaced by another container
|
// as the container is hidden/replaced by another container
|
||||||
// hide its avatar
|
// hide its avatar
|
||||||
this.showAvatar(false);
|
this.showAvatar(false);
|
||||||
|
|
||||||
// its already hidden
|
// its already hidden
|
||||||
if (!this.isVisible) {
|
if (!this.isVisible) {
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise(resolve => {
|
||||||
this.$wrapperParent.fadeTo(FADE_DURATION_MS, 0, () => {
|
this.$wrapperParent.fadeTo(FADE_DURATION_MS, 0, () => {
|
||||||
this.$wrapperParent.css('visibility', 'hidden');
|
this.$wrapperParent.css('visibility', 'hidden');
|
||||||
this.isVisible = false;
|
this.isVisible = false;
|
||||||
|
@ -573,7 +612,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
/**
|
/**
|
||||||
* @return {boolean} switch on dominant speaker event if on stage.
|
* @return {boolean} switch on dominant speaker event if on stage.
|
||||||
*/
|
*/
|
||||||
stayOnStage () {
|
stayOnStage() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -586,9 +625,9 @@ export class VideoContainer extends LargeContainer {
|
||||||
* on the large video.
|
* on the large video.
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
setLargeVideoBackground (isAvatar) {
|
setLargeVideoBackground(isAvatar) {
|
||||||
$('#largeVideoContainer').css('background',
|
$('#largeVideoContainer').css('background',
|
||||||
(this.videoType === VIDEO_CONTAINER_TYPE && !isAvatar)
|
this.videoType === VIDEO_CONTAINER_TYPE && !isAvatar
|
||||||
? '#000' : interfaceConfig.DEFAULT_BACKGROUND);
|
? '#000' : interfaceConfig.DEFAULT_BACKGROUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -631,6 +670,7 @@ export class VideoContainer extends LargeContainer {
|
||||||
// do not care. Some browsers (at this time, only Edge is known) don't
|
// do not care. Some browsers (at this time, only Edge is known) don't
|
||||||
// return a promise from .play(), so check before trying to catch.
|
// return a promise from .play(), so check before trying to catch.
|
||||||
const res = this.$videoBackground[0].play();
|
const res = this.$videoBackground[0].play();
|
||||||
|
|
||||||
if (typeof res !== 'undefined') {
|
if (typeof res !== 'undefined') {
|
||||||
res.catch(reason => logger.error(reason));
|
res.catch(reason => logger.error(reason));
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,4 +1,4 @@
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The modules stores information about the URL used to start the conference and
|
* The modules stores information about the URL used to start the conference and
|
||||||
|
@ -24,9 +24,9 @@ export default class ConferenceUrl {
|
||||||
* from the sample URL.
|
* from the sample URL.
|
||||||
*/
|
*/
|
||||||
constructor(location) {
|
constructor(location) {
|
||||||
logger.info("Stored original conference URL: " + location.href);
|
logger.info(`Stored original conference URL: ${location.href}`);
|
||||||
logger.info(
|
logger.info(
|
||||||
"Conference URL for invites: " + location.protocol + "//"
|
`Conference URL for invites: ${location.protocol}//${
|
||||||
+ location.host + location.pathname);
|
location.host}${location.pathname}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
/* global APP, JitsiMeetJS */
|
/* global APP, JitsiMeetJS */
|
||||||
|
|
||||||
let currentAudioInputDevices,
|
let currentAudioInputDevices,
|
||||||
currentVideoInputDevices,
|
currentAudioOutputDevices,
|
||||||
currentAudioOutputDevices;
|
currentVideoInputDevices;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if currently selected audio output device should be changed after
|
* Determines if currently selected audio output device should be changed after
|
||||||
|
@ -16,14 +16,14 @@ function getNewAudioOutputDevice(newDevices) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectedAudioOutputDeviceId = APP.settings.getAudioOutputDeviceId();
|
const selectedAudioOutputDeviceId = APP.settings.getAudioOutputDeviceId();
|
||||||
let availableAudioOutputDevices = newDevices.filter(
|
const availableAudioOutputDevices = newDevices.filter(
|
||||||
d => d.kind === 'audiooutput');
|
d => d.kind === 'audiooutput');
|
||||||
|
|
||||||
// Switch to 'default' audio output device if we don't have the selected one
|
// Switch to 'default' audio output device if we don't have the selected one
|
||||||
// available anymore.
|
// available anymore.
|
||||||
if (selectedAudioOutputDeviceId !== 'default' &&
|
if (selectedAudioOutputDeviceId !== 'default'
|
||||||
!availableAudioOutputDevices.find(d =>
|
&& !availableAudioOutputDevices.find(d =>
|
||||||
d.deviceId === selectedAudioOutputDeviceId)) {
|
d.deviceId === selectedAudioOutputDeviceId)) {
|
||||||
return 'default';
|
return 'default';
|
||||||
}
|
}
|
||||||
|
@ -38,10 +38,10 @@ function getNewAudioOutputDevice(newDevices) {
|
||||||
* if audio input device should not be changed.
|
* if audio input device should not be changed.
|
||||||
*/
|
*/
|
||||||
function getNewAudioInputDevice(newDevices, localAudio) {
|
function getNewAudioInputDevice(newDevices, localAudio) {
|
||||||
let availableAudioInputDevices = newDevices.filter(
|
const availableAudioInputDevices = newDevices.filter(
|
||||||
d => d.kind === 'audioinput');
|
d => d.kind === 'audioinput');
|
||||||
let selectedAudioInputDeviceId = APP.settings.getMicDeviceId();
|
const selectedAudioInputDeviceId = APP.settings.getMicDeviceId();
|
||||||
let selectedAudioInputDevice = availableAudioInputDevices.find(
|
const selectedAudioInputDevice = availableAudioInputDevices.find(
|
||||||
d => d.deviceId === selectedAudioInputDeviceId);
|
d => d.deviceId === selectedAudioInputDeviceId);
|
||||||
|
|
||||||
// Here we handle case when no device was initially plugged, but
|
// Here we handle case when no device was initially plugged, but
|
||||||
|
@ -51,18 +51,17 @@ function getNewAudioInputDevice(newDevices, localAudio) {
|
||||||
// If we have new audio device and permission to use it was granted
|
// If we have new audio device and permission to use it was granted
|
||||||
// (label is not an empty string), then we will try to use the first
|
// (label is not an empty string), then we will try to use the first
|
||||||
// available device.
|
// available device.
|
||||||
if (availableAudioInputDevices.length &&
|
if (availableAudioInputDevices.length
|
||||||
availableAudioInputDevices[0].label !== '') {
|
&& availableAudioInputDevices[0].label !== '') {
|
||||||
return availableAudioInputDevices[0].deviceId;
|
return availableAudioInputDevices[0].deviceId;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (selectedAudioInputDevice
|
||||||
|
&& selectedAudioInputDeviceId !== localAudio.getDeviceId()) {
|
||||||
|
|
||||||
// And here we handle case when we already have some device working,
|
// And here we handle case when we already have some device working,
|
||||||
// but we plug-in a "preferred" (previously selected in settings, stored
|
// but we plug-in a "preferred" (previously selected in settings, stored
|
||||||
// in local storage) device.
|
// in local storage) device.
|
||||||
if (selectedAudioInputDevice &&
|
return selectedAudioInputDeviceId;
|
||||||
selectedAudioInputDeviceId !== localAudio.getDeviceId()) {
|
|
||||||
return selectedAudioInputDeviceId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,10 +74,10 @@ function getNewAudioInputDevice(newDevices, localAudio) {
|
||||||
* if video input device should not be changed.
|
* if video input device should not be changed.
|
||||||
*/
|
*/
|
||||||
function getNewVideoInputDevice(newDevices, localVideo) {
|
function getNewVideoInputDevice(newDevices, localVideo) {
|
||||||
let availableVideoInputDevices = newDevices.filter(
|
const availableVideoInputDevices = newDevices.filter(
|
||||||
d => d.kind === 'videoinput');
|
d => d.kind === 'videoinput');
|
||||||
let selectedVideoInputDeviceId = APP.settings.getCameraDeviceId();
|
const selectedVideoInputDeviceId = APP.settings.getCameraDeviceId();
|
||||||
let selectedVideoInputDevice = availableVideoInputDevices.find(
|
const selectedVideoInputDevice = availableVideoInputDevices.find(
|
||||||
d => d.deviceId === selectedVideoInputDeviceId);
|
d => d.deviceId === selectedVideoInputDeviceId);
|
||||||
|
|
||||||
// Here we handle case when no video input device was initially plugged,
|
// Here we handle case when no video input device was initially plugged,
|
||||||
|
@ -88,18 +87,16 @@ function getNewVideoInputDevice(newDevices, localVideo) {
|
||||||
// If we have new video device and permission to use it was granted
|
// If we have new video device and permission to use it was granted
|
||||||
// (label is not an empty string), then we will try to use the first
|
// (label is not an empty string), then we will try to use the first
|
||||||
// available device.
|
// available device.
|
||||||
if (availableVideoInputDevices.length &&
|
if (availableVideoInputDevices.length
|
||||||
availableVideoInputDevices[0].label !== '') {
|
&& availableVideoInputDevices[0].label !== '') {
|
||||||
return availableVideoInputDevices[0].deviceId;
|
return availableVideoInputDevices[0].deviceId;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (selectedVideoInputDevice
|
||||||
|
&& selectedVideoInputDeviceId !== localVideo.getDeviceId()) {
|
||||||
// And here we handle case when we already have some device working,
|
// And here we handle case when we already have some device working,
|
||||||
// but we plug-in a "preferred" (previously selected in settings, stored
|
// but we plug-in a "preferred" (previously selected in settings, stored
|
||||||
// in local storage) device.
|
// in local storage) device.
|
||||||
if (selectedVideoInputDevice &&
|
return selectedVideoInputDeviceId;
|
||||||
selectedVideoInputDeviceId !== localVideo.getDeviceId()) {
|
|
||||||
return selectedVideoInputDeviceId;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,19 +110,21 @@ export default {
|
||||||
getDevicesFromListByKind(devices, kind) {
|
getDevicesFromListByKind(devices, kind) {
|
||||||
return devices.filter(d => d.kind === kind);
|
return devices.filter(d => d.kind === kind);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores lists of current 'audioinput', 'videoinput' and 'audiooutput'
|
* Stores lists of current 'audioinput', 'videoinput' and 'audiooutput'
|
||||||
* devices.
|
* devices.
|
||||||
* @param {MediaDeviceInfo[]} devices
|
* @param {MediaDeviceInfo[]} devices
|
||||||
*/
|
*/
|
||||||
setCurrentMediaDevices(devices) {
|
setCurrentMediaDevices(devices) {
|
||||||
currentAudioInputDevices =
|
currentAudioInputDevices
|
||||||
this.getDevicesFromListByKind(devices, 'audioinput');
|
= this.getDevicesFromListByKind(devices, 'audioinput');
|
||||||
currentVideoInputDevices =
|
currentVideoInputDevices
|
||||||
this.getDevicesFromListByKind(devices, 'videoinput');
|
= this.getDevicesFromListByKind(devices, 'videoinput');
|
||||||
currentAudioOutputDevices =
|
currentAudioOutputDevices
|
||||||
this.getDevicesFromListByKind(devices, 'audiooutput');
|
= this.getDevicesFromListByKind(devices, 'audiooutput');
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns lists of current 'audioinput', 'videoinput' and 'audiooutput'
|
* Returns lists of current 'audioinput', 'videoinput' and 'audiooutput'
|
||||||
* devices.
|
* devices.
|
||||||
|
@ -142,6 +141,7 @@ export default {
|
||||||
audiooutput: currentAudioOutputDevices
|
audiooutput: currentAudioOutputDevices
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if currently selected media devices should be changed after
|
* Determines if currently selected media devices should be changed after
|
||||||
* list of available devices has been changed.
|
* list of available devices has been changed.
|
||||||
|
@ -155,18 +155,19 @@ export default {
|
||||||
* audiooutput: (string|undefined)
|
* audiooutput: (string|undefined)
|
||||||
* }}
|
* }}
|
||||||
*/
|
*/
|
||||||
getNewMediaDevicesAfterDeviceListChanged(
|
getNewMediaDevicesAfterDeviceListChanged( // eslint-disable-line max-params
|
||||||
newDevices,
|
newDevices,
|
||||||
isSharingScreen,
|
isSharingScreen,
|
||||||
localVideo,
|
localVideo,
|
||||||
localAudio) {
|
localAudio) {
|
||||||
return {
|
return {
|
||||||
audioinput: getNewAudioInputDevice(newDevices, localAudio),
|
audioinput: getNewAudioInputDevice(newDevices, localAudio),
|
||||||
videoinput: !isSharingScreen &&
|
videoinput: !isSharingScreen
|
||||||
getNewVideoInputDevice(newDevices, localVideo),
|
&& getNewVideoInputDevice(newDevices, localVideo),
|
||||||
audiooutput: getNewAudioOutputDevice(newDevices)
|
audiooutput: getNewAudioOutputDevice(newDevices)
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to create new local tracks for new devices obtained after device
|
* Tries to create new local tracks for new devices obtained after device
|
||||||
* list changed. Shows error dialog in case of failures.
|
* list changed. Shows error dialog in case of failures.
|
||||||
|
@ -181,21 +182,22 @@ export default {
|
||||||
micDeviceId) {
|
micDeviceId) {
|
||||||
let audioTrackError;
|
let audioTrackError;
|
||||||
let videoTrackError;
|
let videoTrackError;
|
||||||
let audioRequested = !!micDeviceId;
|
const audioRequested = Boolean(micDeviceId);
|
||||||
let videoRequested = !!cameraDeviceId;
|
const videoRequested = Boolean(cameraDeviceId);
|
||||||
|
|
||||||
if (audioRequested && videoRequested) {
|
if (audioRequested && videoRequested) {
|
||||||
// First we try to create both audio and video tracks together.
|
// First we try to create both audio and video tracks together.
|
||||||
return (
|
return (
|
||||||
createLocalTracks({
|
createLocalTracks({
|
||||||
devices: ['audio', 'video'],
|
devices: [ 'audio', 'video' ],
|
||||||
cameraDeviceId: cameraDeviceId,
|
cameraDeviceId,
|
||||||
micDeviceId: micDeviceId
|
micDeviceId
|
||||||
})
|
})
|
||||||
|
|
||||||
// If we fail to do this, try to create them separately.
|
// If we fail to do this, try to create them separately.
|
||||||
.catch(() => Promise.all([
|
.catch(() => Promise.all([
|
||||||
createAudioTrack(false).then(([stream]) => stream),
|
createAudioTrack(false).then(([ stream ]) => stream),
|
||||||
createVideoTrack(false).then(([stream]) => stream)
|
createVideoTrack(false).then(([ stream ]) => stream)
|
||||||
]))
|
]))
|
||||||
.then(tracks => {
|
.then(tracks => {
|
||||||
if (audioTrackError) {
|
if (audioTrackError) {
|
||||||
|
@ -212,34 +214,42 @@ export default {
|
||||||
return createVideoTrack();
|
return createVideoTrack();
|
||||||
} else if (audioRequested && !videoRequested) {
|
} else if (audioRequested && !videoRequested) {
|
||||||
return createAudioTrack();
|
return createAudioTrack();
|
||||||
} else {
|
|
||||||
return Promise.resolve([]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Promise.resolve([]);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function createAudioTrack(showError) {
|
function createAudioTrack(showError) {
|
||||||
return (
|
return (
|
||||||
createLocalTracks({
|
createLocalTracks({
|
||||||
devices: ['audio'],
|
devices: [ 'audio' ],
|
||||||
cameraDeviceId: null,
|
cameraDeviceId: null,
|
||||||
micDeviceId: micDeviceId
|
micDeviceId
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
audioTrackError = err;
|
audioTrackError = err;
|
||||||
showError && APP.UI.showMicErrorNotification(err);
|
showError && APP.UI.showMicErrorNotification(err);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
function createVideoTrack(showError) {
|
function createVideoTrack(showError) {
|
||||||
return (
|
return (
|
||||||
createLocalTracks({
|
createLocalTracks({
|
||||||
devices: ['video'],
|
devices: [ 'video' ],
|
||||||
cameraDeviceId: cameraDeviceId,
|
cameraDeviceId,
|
||||||
micDeviceId: null
|
micDeviceId: null
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
videoTrackError = err;
|
videoTrackError = err;
|
||||||
showError && APP.UI.showCameraErrorNotification(err);
|
showError && APP.UI.showCameraErrorNotification(err);
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,47 +11,6 @@ const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
*/
|
*/
|
||||||
let keyboardShortcutDialog = null;
|
let keyboardShortcutDialog = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialise global shortcuts.
|
|
||||||
* Global shortcuts are shortcuts for features that don't have a button or
|
|
||||||
* link associated with the action. In other words they represent actions
|
|
||||||
* triggered _only_ with a shortcut.
|
|
||||||
*/
|
|
||||||
function initGlobalShortcuts() {
|
|
||||||
KeyboardShortcut.registerShortcut("ESCAPE", null, function() {
|
|
||||||
showKeyboardShortcutsPanel(false);
|
|
||||||
});
|
|
||||||
|
|
||||||
KeyboardShortcut.registerShortcut("?", null, function() {
|
|
||||||
sendEvent("shortcut.shortcut.help");
|
|
||||||
showKeyboardShortcutsPanel(true);
|
|
||||||
}, "keyboardShortcuts.toggleShortcuts");
|
|
||||||
|
|
||||||
// register SPACE shortcut in two steps to insure visibility of help message
|
|
||||||
KeyboardShortcut.registerShortcut(" ", null, function() {
|
|
||||||
sendEvent("shortcut.talk.clicked");
|
|
||||||
logger.log('Talk shortcut pressed');
|
|
||||||
APP.conference.muteAudio(true);
|
|
||||||
});
|
|
||||||
KeyboardShortcut._addShortcutToHelp("SPACE","keyboardShortcuts.pushToTalk");
|
|
||||||
|
|
||||||
if(!interfaceConfig.filmStripOnly) {
|
|
||||||
KeyboardShortcut.registerShortcut("T", null, () => {
|
|
||||||
sendEvent("shortcut.speakerStats.clicked");
|
|
||||||
APP.store.dispatch(toggleDialog(SpeakerStats, {
|
|
||||||
conference: APP.conference
|
|
||||||
}));
|
|
||||||
}, "keyboardShortcuts.showSpeakerStats");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FIXME: Currently focus keys are directly implemented below in onkeyup.
|
|
||||||
* They should be moved to the SmallVideo instead.
|
|
||||||
*/
|
|
||||||
KeyboardShortcut._addShortcutToHelp("0", "keyboardShortcuts.focusLocal");
|
|
||||||
KeyboardShortcut._addShortcutToHelp("1-9", "keyboardShortcuts.focusRemote");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows or hides the keyboard shortcuts dialog.
|
* Shows or hides the keyboard shortcuts dialog.
|
||||||
* @param {boolean} show whether to show or hide the dialog
|
* @param {boolean} show whether to show or hide the dialog
|
||||||
|
@ -60,8 +19,8 @@ function showKeyboardShortcutsPanel(show) {
|
||||||
if (show
|
if (show
|
||||||
&& !APP.UI.messageHandler.isDialogOpened()
|
&& !APP.UI.messageHandler.isDialogOpened()
|
||||||
&& keyboardShortcutDialog === null) {
|
&& keyboardShortcutDialog === null) {
|
||||||
let msg = $('#keyboard-shortcuts').html();
|
const msg = $('#keyboard-shortcuts').html();
|
||||||
let buttons = { Close: true };
|
const buttons = { Close: true };
|
||||||
|
|
||||||
keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
|
keyboardShortcutDialog = APP.UI.messageHandler.openDialog(
|
||||||
'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
|
'keyboardShortcuts.keyboardShortcuts', msg, true, buttons);
|
||||||
|
@ -75,7 +34,7 @@ function showKeyboardShortcutsPanel(show) {
|
||||||
* Map of shortcuts. When a shortcut is registered it enters the mapping.
|
* Map of shortcuts. When a shortcut is registered it enters the mapping.
|
||||||
* @type {{}}
|
* @type {{}}
|
||||||
*/
|
*/
|
||||||
let _shortcuts = {};
|
const _shortcuts = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the keyboard shortcuts are enabled and false if not.
|
* True if the keyboard shortcuts are enabled and false if not.
|
||||||
|
@ -87,43 +46,42 @@ let enabled = true;
|
||||||
* Maps keycode to character, id of popover for given function and function.
|
* Maps keycode to character, id of popover for given function and function.
|
||||||
*/
|
*/
|
||||||
const KeyboardShortcut = {
|
const KeyboardShortcut = {
|
||||||
init: function () {
|
init() {
|
||||||
initGlobalShortcuts();
|
this._initGlobalShortcuts();
|
||||||
|
|
||||||
var self = this;
|
window.onkeyup = e => {
|
||||||
window.onkeyup = function(e) {
|
if (!enabled) {
|
||||||
if(!enabled) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var key = self._getKeyboardKey(e).toUpperCase();
|
const key = this._getKeyboardKey(e).toUpperCase();
|
||||||
var num = parseInt(key, 10);
|
const num = parseInt(key, 10);
|
||||||
if(!($(":focus").is("input[type=text]") ||
|
|
||||||
$(":focus").is("input[type=password]") ||
|
if (!($(':focus').is('input[type=text]')
|
||||||
$(":focus").is("textarea"))) {
|
|| $(':focus').is('input[type=password]')
|
||||||
|
|| $(':focus').is('textarea'))) {
|
||||||
if (_shortcuts.hasOwnProperty(key)) {
|
if (_shortcuts.hasOwnProperty(key)) {
|
||||||
_shortcuts[key].function(e);
|
_shortcuts[key].function(e);
|
||||||
}
|
} else if (!isNaN(num) && num >= 0 && num <= 9) {
|
||||||
else if (!isNaN(num) && num >= 0 && num <= 9) {
|
|
||||||
APP.UI.clickOnVideo(num);
|
APP.UI.clickOnVideo(num);
|
||||||
}
|
}
|
||||||
//esc while the smileys are visible hides them
|
|
||||||
} else if (key === "ESCAPE" &&
|
// esc while the smileys are visible hides them
|
||||||
$('#smileysContainer').is(':visible')) {
|
} else if (key === 'ESCAPE'
|
||||||
|
&& $('#smileysContainer').is(':visible')) {
|
||||||
APP.UI.toggleSmileys();
|
APP.UI.toggleSmileys();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onkeydown = function(e) {
|
window.onkeydown = e => {
|
||||||
if(!enabled) {
|
if (!enabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!($(":focus").is("input[type=text]") ||
|
if (!($(':focus').is('input[type=text]')
|
||||||
$(":focus").is("input[type=password]") ||
|
|| $(':focus').is('input[type=password]')
|
||||||
$(":focus").is("textarea"))) {
|
|| $(':focus').is('textarea'))) {
|
||||||
var key = self._getKeyboardKey(e).toUpperCase();
|
if (this._getKeyboardKey(e).toUpperCase() === ' ') {
|
||||||
if(key === " ") {
|
if (APP.conference.isLocalAudioMuted()) {
|
||||||
if(APP.conference.isLocalAudioMuted()) {
|
sendEvent('shortcut.talk.released');
|
||||||
sendEvent("shortcut.talk.released");
|
|
||||||
logger.log('Talk shortcut released');
|
logger.log('Talk shortcut released');
|
||||||
APP.conference.muteAudio(false);
|
APP.conference.muteAudio(false);
|
||||||
}
|
}
|
||||||
|
@ -136,7 +94,7 @@ const KeyboardShortcut = {
|
||||||
* Enables/Disables the keyboard shortcuts.
|
* Enables/Disables the keyboard shortcuts.
|
||||||
* @param {boolean} value - the new value.
|
* @param {boolean} value - the new value.
|
||||||
*/
|
*/
|
||||||
enable: function (value) {
|
enable(value) {
|
||||||
enabled = value;
|
enabled = value;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -151,19 +109,20 @@ const KeyboardShortcut = {
|
||||||
* @param helpDescription the description of the shortcut that would appear
|
* @param helpDescription the description of the shortcut that would appear
|
||||||
* in the help menu
|
* in the help menu
|
||||||
*/
|
*/
|
||||||
registerShortcut(
|
registerShortcut(// eslint-disable-line max-params
|
||||||
shortcutChar,
|
shortcutChar,
|
||||||
shortcutAttr,
|
shortcutAttr,
|
||||||
exec,
|
exec,
|
||||||
helpDescription) {
|
helpDescription) {
|
||||||
_shortcuts[shortcutChar] = {
|
_shortcuts[shortcutChar] = {
|
||||||
character: shortcutChar,
|
character: shortcutChar,
|
||||||
shortcutAttr: shortcutAttr,
|
shortcutAttr,
|
||||||
function: exec
|
function: exec
|
||||||
};
|
};
|
||||||
|
|
||||||
if (helpDescription)
|
if (helpDescription) {
|
||||||
this._addShortcutToHelp(shortcutChar, helpDescription);
|
this._addShortcutToHelp(shortcutChar, helpDescription);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -172,7 +131,7 @@ const KeyboardShortcut = {
|
||||||
* @param shortcutChar unregisters the given shortcut, which means it will
|
* @param shortcutChar unregisters the given shortcut, which means it will
|
||||||
* no longer be usable
|
* no longer be usable
|
||||||
*/
|
*/
|
||||||
unregisterShortcut: function(shortcutChar) {
|
unregisterShortcut(shortcutChar) {
|
||||||
_shortcuts.remove(shortcutChar);
|
_shortcuts.remove(shortcutChar);
|
||||||
|
|
||||||
this._removeShortcutFromHelp(shortcutChar);
|
this._removeShortcutFromHelp(shortcutChar);
|
||||||
|
@ -186,44 +145,47 @@ const KeyboardShortcut = {
|
||||||
* or an empty string if the shortcutAttr is null, an empty string or not
|
* or an empty string if the shortcutAttr is null, an empty string or not
|
||||||
* found in the shortcut mapping
|
* found in the shortcut mapping
|
||||||
*/
|
*/
|
||||||
getShortcutTooltip: function (shortcutAttr) {
|
getShortcutTooltip(shortcutAttr) {
|
||||||
if (typeof shortcutAttr === "string" && shortcutAttr.length > 0) {
|
if (typeof shortcutAttr === 'string' && shortcutAttr.length > 0) {
|
||||||
for (var key in _shortcuts) {
|
for (const key in _shortcuts) {
|
||||||
if (_shortcuts.hasOwnProperty(key)
|
if (_shortcuts.hasOwnProperty(key)
|
||||||
&& _shortcuts[key].shortcutAttr
|
&& _shortcuts[key].shortcutAttr
|
||||||
&& _shortcuts[key].shortcutAttr === shortcutAttr) {
|
&& _shortcuts[key].shortcutAttr === shortcutAttr) {
|
||||||
return " (" + _shortcuts[key].character + ")";
|
return ` (${_shortcuts[key].character})`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return "";
|
return '';
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param e a KeyboardEvent
|
* @param e a KeyboardEvent
|
||||||
* @returns {string} e.key or something close if not supported
|
* @returns {string} e.key or something close if not supported
|
||||||
*/
|
*/
|
||||||
_getKeyboardKey: function (e) {
|
_getKeyboardKey(e) {
|
||||||
if (typeof e.key === "string") {
|
if (typeof e.key === 'string') {
|
||||||
return e.key;
|
return e.key;
|
||||||
}
|
}
|
||||||
if (e.type === "keypress"
|
if (e.type === 'keypress'
|
||||||
&& ((e.which >= 32 && e.which <= 126)
|
&& ((e.which >= 32 && e.which <= 126)
|
||||||
|| (e.which >= 160 && e.which <= 255) )) {
|
|| (e.which >= 160 && e.which <= 255))) {
|
||||||
return String.fromCharCode(e.which);
|
return String.fromCharCode(e.which);
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to fallback (0-9A-Za-z and QWERTY keyboard)
|
// try to fallback (0-9A-Za-z and QWERTY keyboard)
|
||||||
switch (e.which) {
|
switch (e.which) {
|
||||||
case 27:
|
case 27:
|
||||||
return "Escape";
|
return 'Escape';
|
||||||
case 191:
|
case 191:
|
||||||
return e.shiftKey ? "?" : "/";
|
return e.shiftKey ? '?' : '/';
|
||||||
}
|
}
|
||||||
if (e.shiftKey || e.type === "keypress") {
|
if (e.shiftKey || e.type === 'keypress') {
|
||||||
return String.fromCharCode(e.which);
|
return String.fromCharCode(e.which);
|
||||||
} else {
|
|
||||||
return String.fromCharCode(e.which).toLowerCase();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return String.fromCharCode(e.which).toLowerCase();
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,36 +195,41 @@ const KeyboardShortcut = {
|
||||||
* @param shortcutDescriptionKey the description of the shortcut
|
* @param shortcutDescriptionKey the description of the shortcut
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_addShortcutToHelp: function (shortcutChar, shortcutDescriptionKey) {
|
_addShortcutToHelp(shortcutChar, shortcutDescriptionKey) {
|
||||||
|
|
||||||
|
const listElement = document.createElement('li');
|
||||||
|
const itemClass = 'shortcuts-list__item';
|
||||||
|
|
||||||
let listElement = document.createElement("li");
|
|
||||||
let itemClass = 'shortcuts-list__item';
|
|
||||||
listElement.className = itemClass;
|
listElement.className = itemClass;
|
||||||
listElement.id = shortcutChar;
|
listElement.id = shortcutChar;
|
||||||
|
|
||||||
let spanElement = document.createElement("span");
|
const spanElement = document.createElement('span');
|
||||||
spanElement.className = "item-action";
|
|
||||||
|
spanElement.className = 'item-action';
|
||||||
|
|
||||||
|
const kbdElement = document.createElement('kbd');
|
||||||
|
const classes = 'aui-label regular-key';
|
||||||
|
|
||||||
let kbdElement = document.createElement("kbd");
|
|
||||||
let classes = 'aui-label regular-key';
|
|
||||||
kbdElement.className = classes;
|
kbdElement.className = classes;
|
||||||
kbdElement.innerHTML = shortcutChar;
|
kbdElement.innerHTML = shortcutChar;
|
||||||
spanElement.appendChild(kbdElement);
|
spanElement.appendChild(kbdElement);
|
||||||
|
|
||||||
let descriptionElement = document.createElement("span");
|
const descriptionElement = document.createElement('span');
|
||||||
let descriptionClass = "shortcuts-list__description";
|
const descriptionClass = 'shortcuts-list__description';
|
||||||
|
|
||||||
descriptionElement.className = descriptionClass;
|
descriptionElement.className = descriptionClass;
|
||||||
descriptionElement.setAttribute("data-i18n", shortcutDescriptionKey);
|
descriptionElement.setAttribute('data-i18n', shortcutDescriptionKey);
|
||||||
APP.translation.translateElement($(descriptionElement));
|
APP.translation.translateElement($(descriptionElement));
|
||||||
|
|
||||||
listElement.appendChild(spanElement);
|
listElement.appendChild(spanElement);
|
||||||
listElement.appendChild(descriptionElement);
|
listElement.appendChild(descriptionElement);
|
||||||
|
|
||||||
let parentListElement
|
const parentListElement
|
||||||
= document.getElementById("keyboard-shortcuts-list");
|
= document.getElementById('keyboard-shortcuts-list');
|
||||||
|
|
||||||
if (parentListElement)
|
if (parentListElement) {
|
||||||
parentListElement.appendChild(listElement);
|
parentListElement.appendChild(listElement);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -270,14 +237,57 @@ const KeyboardShortcut = {
|
||||||
* help dialog
|
* help dialog
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_removeShortcutFromHelp: function (shortcutChar) {
|
_removeShortcutFromHelp(shortcutChar) {
|
||||||
var parentListElement
|
const parentListElement
|
||||||
= document.getElementById("keyboard-shortcuts-list");
|
= document.getElementById('keyboard-shortcuts-list');
|
||||||
|
|
||||||
var shortcutElement = document.getElementById(shortcutChar);
|
const shortcutElement = document.getElementById(shortcutChar);
|
||||||
|
|
||||||
if (shortcutElement)
|
if (shortcutElement) {
|
||||||
parentListElement.removeChild(shortcutElement);
|
parentListElement.removeChild(shortcutElement);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise global shortcuts.
|
||||||
|
* Global shortcuts are shortcuts for features that don't have a button or
|
||||||
|
* link associated with the action. In other words they represent actions
|
||||||
|
* triggered _only_ with a shortcut.
|
||||||
|
*/
|
||||||
|
_initGlobalShortcuts() {
|
||||||
|
this.registerShortcut('ESCAPE', null, () => {
|
||||||
|
showKeyboardShortcutsPanel(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.registerShortcut('?', null, () => {
|
||||||
|
sendEvent('shortcut.shortcut.help');
|
||||||
|
showKeyboardShortcutsPanel(true);
|
||||||
|
}, 'keyboardShortcuts.toggleShortcuts');
|
||||||
|
|
||||||
|
// register SPACE shortcut in two steps to insure visibility of help
|
||||||
|
// message
|
||||||
|
this.registerShortcut(' ', null, () => {
|
||||||
|
sendEvent('shortcut.talk.clicked');
|
||||||
|
logger.log('Talk shortcut pressed');
|
||||||
|
APP.conference.muteAudio(true);
|
||||||
|
});
|
||||||
|
this._addShortcutToHelp('SPACE', 'keyboardShortcuts.pushToTalk');
|
||||||
|
|
||||||
|
if (!interfaceConfig.filmStripOnly) {
|
||||||
|
this.registerShortcut('T', null, () => {
|
||||||
|
sendEvent('shortcut.speakerStats.clicked');
|
||||||
|
APP.store.dispatch(toggleDialog(SpeakerStats, {
|
||||||
|
conference: APP.conference
|
||||||
|
}));
|
||||||
|
}, 'keyboardShortcuts.showSpeakerStats');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FIXME: Currently focus keys are directly implemented below in
|
||||||
|
* onkeyup. They should be moved to the SmallVideo instead.
|
||||||
|
*/
|
||||||
|
this._addShortcutToHelp('0', 'keyboardShortcuts.focusLocal');
|
||||||
|
this._addShortcutToHelp('1-9', 'keyboardShortcuts.focusRemote');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -5,74 +5,76 @@
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
export const KEYS = {
|
export const KEYS = {
|
||||||
BACKSPACE: "backspace" ,
|
BACKSPACE: 'backspace',
|
||||||
DELETE : "delete",
|
DELETE: 'delete',
|
||||||
RETURN : "enter",
|
RETURN: 'enter',
|
||||||
TAB : "tab",
|
TAB: 'tab',
|
||||||
ESCAPE : "escape",
|
ESCAPE: 'escape',
|
||||||
UP : "up",
|
UP: 'up',
|
||||||
DOWN : "down",
|
DOWN: 'down',
|
||||||
RIGHT : "right",
|
RIGHT: 'right',
|
||||||
LEFT : "left",
|
LEFT: 'left',
|
||||||
HOME : "home",
|
HOME: 'home',
|
||||||
END : "end",
|
END: 'end',
|
||||||
PAGEUP : "pageup",
|
PAGEUP: 'pageup',
|
||||||
PAGEDOWN : "pagedown",
|
PAGEDOWN: 'pagedown',
|
||||||
|
|
||||||
F1 : "f1",
|
F1: 'f1',
|
||||||
F2 : "f2",
|
F2: 'f2',
|
||||||
F3 : "f3",
|
F3: 'f3',
|
||||||
F4 : "f4",
|
F4: 'f4',
|
||||||
F5 : "f5",
|
F5: 'f5',
|
||||||
F6 : "f6",
|
F6: 'f6',
|
||||||
F7 : "f7",
|
F7: 'f7',
|
||||||
F8 : "f8",
|
F8: 'f8',
|
||||||
F9 : "f9",
|
F9: 'f9',
|
||||||
F10 : "f10",
|
F10: 'f10',
|
||||||
F11 : "f11",
|
F11: 'f11',
|
||||||
F12 : "f12",
|
F12: 'f12',
|
||||||
META : "command",
|
META: 'command',
|
||||||
CMD_L: "command",
|
CMD_L: 'command',
|
||||||
CMD_R: "command",
|
CMD_R: 'command',
|
||||||
ALT : "alt",
|
ALT: 'alt',
|
||||||
CONTROL : "control",
|
CONTROL: 'control',
|
||||||
SHIFT : "shift",
|
SHIFT: 'shift',
|
||||||
CAPS_LOCK: "caps_lock", //not supported by robotjs
|
CAPS_LOCK: 'caps_lock', // not supported by robotjs
|
||||||
SPACE : "space",
|
SPACE: 'space',
|
||||||
PRINTSCREEN : "printscreen",
|
PRINTSCREEN: 'printscreen',
|
||||||
INSERT : "insert",
|
INSERT: 'insert',
|
||||||
|
|
||||||
NUMPAD_0 : "numpad_0",
|
NUMPAD_0: 'numpad_0',
|
||||||
NUMPAD_1 : "numpad_1",
|
NUMPAD_1: 'numpad_1',
|
||||||
NUMPAD_2 : "numpad_2",
|
NUMPAD_2: 'numpad_2',
|
||||||
NUMPAD_3 : "numpad_3",
|
NUMPAD_3: 'numpad_3',
|
||||||
NUMPAD_4 : "numpad_4",
|
NUMPAD_4: 'numpad_4',
|
||||||
NUMPAD_5 : "numpad_5",
|
NUMPAD_5: 'numpad_5',
|
||||||
NUMPAD_6 : "numpad_6",
|
NUMPAD_6: 'numpad_6',
|
||||||
NUMPAD_7 : "numpad_7",
|
NUMPAD_7: 'numpad_7',
|
||||||
NUMPAD_8 : "numpad_8",
|
NUMPAD_8: 'numpad_8',
|
||||||
NUMPAD_9 : "numpad_9",
|
NUMPAD_9: 'numpad_9',
|
||||||
|
|
||||||
COMMA: ",",
|
COMMA: ',',
|
||||||
|
|
||||||
PERIOD: ".",
|
PERIOD: '.',
|
||||||
SEMICOLON: ";",
|
SEMICOLON: ';',
|
||||||
QUOTE: "'",
|
QUOTE: '\'',
|
||||||
BRACKET_LEFT: "[",
|
BRACKET_LEFT: '[',
|
||||||
BRACKET_RIGHT: "]",
|
BRACKET_RIGHT: ']',
|
||||||
BACKQUOTE: "`",
|
BACKQUOTE: '`',
|
||||||
BACKSLASH: "\\",
|
BACKSLASH: '\\',
|
||||||
MINUS: "-",
|
MINUS: '-',
|
||||||
EQUAL: "=",
|
EQUAL: '=',
|
||||||
SLASH: "/"
|
SLASH: '/'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* eslint-disable max-len */
|
||||||
/**
|
/**
|
||||||
* Mapping between the key codes and keys deined in KEYS.
|
* Mapping between the key codes and keys deined in KEYS.
|
||||||
* The mappings are based on
|
* The mappings are based on
|
||||||
* https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Specifications
|
* https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode#Specifications
|
||||||
*/
|
*/
|
||||||
let keyCodeToKey = {
|
/* eslint-enable max-len */
|
||||||
|
const keyCodeToKey = {
|
||||||
8: KEYS.BACKSPACE,
|
8: KEYS.BACKSPACE,
|
||||||
9: KEYS.TAB,
|
9: KEYS.TAB,
|
||||||
13: KEYS.RETURN,
|
13: KEYS.RETURN,
|
||||||
|
@ -141,15 +143,16 @@ let keyCodeToKey = {
|
||||||
/**
|
/**
|
||||||
* Generate codes for digit keys (0-9)
|
* Generate codes for digit keys (0-9)
|
||||||
*/
|
*/
|
||||||
for(let i = 0; i < 10; i++) {
|
for (let i = 0; i < 10; i++) {
|
||||||
keyCodeToKey[i + 48] = `${i}`;
|
keyCodeToKey[i + 48] = `${i}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate codes for letter keys (a-z)
|
* Generate codes for letter keys (a-z)
|
||||||
*/
|
*/
|
||||||
for(let i = 0; i < 26; i++) {
|
for (let i = 0; i < 26; i++) {
|
||||||
let keyCode = i + 65;
|
const keyCode = i + 65;
|
||||||
|
|
||||||
keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase();
|
keyCodeToKey[keyCode] = String.fromCharCode(keyCode).toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,20 @@
|
||||||
/**
|
/**
|
||||||
* The (name of the) command which transports the recorder info.
|
* The (name of the) command which transports the recorder info.
|
||||||
*/
|
*/
|
||||||
const _USER_INFO_COMMAND = "userinfo";
|
const _USER_INFO_COMMAND = 'userinfo';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Recorder class is meant to take care of recorder related presence
|
* The Recorder class is meant to take care of recorder related presence
|
||||||
* commands.
|
* commands.
|
||||||
*/
|
*/
|
||||||
class Recorder {
|
class Recorder {
|
||||||
|
/**
|
||||||
|
* Creates new recorder instance.
|
||||||
|
*/
|
||||||
constructor() {
|
constructor() {
|
||||||
if (config.iAmRecorder)
|
if (config.iAmRecorder) {
|
||||||
this._sendRecorderInfo();
|
this._sendRecorderInfo();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -20,7 +24,7 @@ class Recorder {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
_sendRecorderInfo() {
|
_sendRecorderInfo() {
|
||||||
var commands = APP.conference.commands;
|
const commands = APP.conference.commands;
|
||||||
|
|
||||||
// XXX The "Follow Me" command represents a snapshot of all states
|
// XXX The "Follow Me" command represents a snapshot of all states
|
||||||
// which are to be followed so don't forget to removeCommand before
|
// which are to be followed so don't forget to removeCommand before
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* global JitsiMeetJS */
|
/* global JitsiMeetJS */
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
import UIUtil from '../UI/util/UIUtil';
|
import UIUtil from '../UI/util/UIUtil';
|
||||||
import jitsiLocalStorage from '../util/JitsiLocalStorage';
|
import jitsiLocalStorage from '../util/JitsiLocalStorage';
|
||||||
|
@ -7,34 +7,35 @@ import { randomHexString } from '../../react/features/base/util';
|
||||||
|
|
||||||
let avatarUrl = '';
|
let avatarUrl = '';
|
||||||
|
|
||||||
let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("email") || '');
|
let email = UIUtil.unescapeHtml(jitsiLocalStorage.getItem('email') || '');
|
||||||
let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem("avatarId") || '');
|
let avatarId = UIUtil.unescapeHtml(jitsiLocalStorage.getItem('avatarId') || '');
|
||||||
|
|
||||||
if (!avatarId) {
|
if (!avatarId) {
|
||||||
// if there is no avatar id, we generate a unique one and use it forever
|
// if there is no avatar id, we generate a unique one and use it forever
|
||||||
avatarId = randomHexString(32);
|
avatarId = randomHexString(32);
|
||||||
jitsiLocalStorage.setItem("avatarId", avatarId);
|
jitsiLocalStorage.setItem('avatarId', avatarId);
|
||||||
}
|
}
|
||||||
|
|
||||||
let localFlipX = JSON.parse(jitsiLocalStorage.getItem("localFlipX") || true);
|
let localFlipX = JSON.parse(jitsiLocalStorage.getItem('localFlipX') || true);
|
||||||
let displayName = UIUtil.unescapeHtml(
|
let displayName = UIUtil.unescapeHtml(
|
||||||
jitsiLocalStorage.getItem("displayname") || '');
|
jitsiLocalStorage.getItem('displayname') || '');
|
||||||
let cameraDeviceId = jitsiLocalStorage.getItem("cameraDeviceId") || '';
|
let cameraDeviceId = jitsiLocalStorage.getItem('cameraDeviceId') || '';
|
||||||
let micDeviceId = jitsiLocalStorage.getItem("micDeviceId") || '';
|
let micDeviceId = jitsiLocalStorage.getItem('micDeviceId') || '';
|
||||||
let welcomePageDisabled = JSON.parse(
|
let welcomePageDisabled = JSON.parse(
|
||||||
jitsiLocalStorage.getItem("welcomePageDisabled") || false);
|
jitsiLocalStorage.getItem('welcomePageDisabled') || false);
|
||||||
|
|
||||||
// Currently audio output device change is supported only in Chrome and
|
// Currently audio output device change is supported only in Chrome and
|
||||||
// default output always has 'default' device ID
|
// default output always has 'default' device ID
|
||||||
let audioOutputDeviceId = jitsiLocalStorage.getItem("audioOutputDeviceId")
|
const audioOutputDeviceId = jitsiLocalStorage.getItem('audioOutputDeviceId')
|
||||||
|| 'default';
|
|| 'default';
|
||||||
|
|
||||||
if (audioOutputDeviceId !==
|
if (audioOutputDeviceId
|
||||||
JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
|
!== JitsiMeetJS.mediaDevices.getAudioOutputDevice()) {
|
||||||
JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
|
JitsiMeetJS.mediaDevices.setAudioOutputDevice(audioOutputDeviceId)
|
||||||
.catch((ex) => {
|
.catch(ex => {
|
||||||
logger.warn('Failed to set audio output device from local ' +
|
logger.warn('Failed to set audio output device from local '
|
||||||
'storage. Default audio output device will be used' +
|
+ 'storage. Default audio output device will be used'
|
||||||
'instead.', ex);
|
+ 'instead.', ex);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,19 +47,20 @@ export default {
|
||||||
* @param {string} newDisplayName unescaped display name for the local user
|
* @param {string} newDisplayName unescaped display name for the local user
|
||||||
* @param {boolean} disableLocalStore disables local store the display name
|
* @param {boolean} disableLocalStore disables local store the display name
|
||||||
*/
|
*/
|
||||||
setDisplayName (newDisplayName, disableLocalStore) {
|
setDisplayName(newDisplayName, disableLocalStore) {
|
||||||
displayName = newDisplayName;
|
displayName = newDisplayName;
|
||||||
|
|
||||||
if (!disableLocalStore)
|
if (!disableLocalStore) {
|
||||||
jitsiLocalStorage.setItem("displayname",
|
jitsiLocalStorage.setItem('displayname',
|
||||||
UIUtil.escapeHtml(displayName));
|
UIUtil.escapeHtml(displayName));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the escaped display name currently used by the user
|
* Returns the escaped display name currently used by the user
|
||||||
* @returns {string} currently valid user display name.
|
* @returns {string} currently valid user display name.
|
||||||
*/
|
*/
|
||||||
getDisplayName: function () {
|
getDisplayName() {
|
||||||
return displayName;
|
return displayName;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -67,18 +69,19 @@ export default {
|
||||||
* @param {string} newEmail new email for the local user
|
* @param {string} newEmail new email for the local user
|
||||||
* @param {boolean} disableLocalStore disables local store the email
|
* @param {boolean} disableLocalStore disables local store the email
|
||||||
*/
|
*/
|
||||||
setEmail: function (newEmail, disableLocalStore) {
|
setEmail(newEmail, disableLocalStore) {
|
||||||
email = newEmail;
|
email = newEmail;
|
||||||
|
|
||||||
if (!disableLocalStore)
|
if (!disableLocalStore) {
|
||||||
jitsiLocalStorage.setItem("email", UIUtil.escapeHtml(newEmail));
|
jitsiLocalStorage.setItem('email', UIUtil.escapeHtml(newEmail));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns email address of the local user.
|
* Returns email address of the local user.
|
||||||
* @returns {string} email
|
* @returns {string} email
|
||||||
*/
|
*/
|
||||||
getEmail: function () {
|
getEmail() {
|
||||||
return email;
|
return email;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -86,7 +89,7 @@ export default {
|
||||||
* Returns avatar id of the local user.
|
* Returns avatar id of the local user.
|
||||||
* @returns {string} avatar id
|
* @returns {string} avatar id
|
||||||
*/
|
*/
|
||||||
getAvatarId: function () {
|
getAvatarId() {
|
||||||
return avatarId;
|
return avatarId;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -94,7 +97,7 @@ export default {
|
||||||
* Sets new avatarUrl for local user and saves it to the local storage.
|
* Sets new avatarUrl for local user and saves it to the local storage.
|
||||||
* @param {string} newAvatarUrl new avatarUrl for the local user
|
* @param {string} newAvatarUrl new avatarUrl for the local user
|
||||||
*/
|
*/
|
||||||
setAvatarUrl: function (newAvatarUrl) {
|
setAvatarUrl(newAvatarUrl) {
|
||||||
avatarUrl = newAvatarUrl;
|
avatarUrl = newAvatarUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -102,7 +105,7 @@ export default {
|
||||||
* Returns avatarUrl address of the local user.
|
* Returns avatarUrl address of the local user.
|
||||||
* @returns {string} avatarUrl
|
* @returns {string} avatarUrl
|
||||||
*/
|
*/
|
||||||
getAvatarUrl: function () {
|
getAvatarUrl() {
|
||||||
return avatarUrl;
|
return avatarUrl;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -110,16 +113,16 @@ export default {
|
||||||
* Sets new flipX state of local video and saves it to the local storage.
|
* Sets new flipX state of local video and saves it to the local storage.
|
||||||
* @param {string} val flipX state of local video
|
* @param {string} val flipX state of local video
|
||||||
*/
|
*/
|
||||||
setLocalFlipX: function (val) {
|
setLocalFlipX(val) {
|
||||||
localFlipX = val;
|
localFlipX = val;
|
||||||
jitsiLocalStorage.setItem("localFlipX", val);
|
jitsiLocalStorage.setItem('localFlipX', val);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns flipX state of local video.
|
* Returns flipX state of local video.
|
||||||
* @returns {string} flipX
|
* @returns {string} flipX
|
||||||
*/
|
*/
|
||||||
getLocalFlipX: function () {
|
getLocalFlipX() {
|
||||||
return localFlipX;
|
return localFlipX;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -128,19 +131,21 @@ export default {
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
getCameraDeviceId: function () {
|
getCameraDeviceId() {
|
||||||
return cameraDeviceId;
|
return cameraDeviceId;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set device id of the camera which is currently in use.
|
* Set device id of the camera which is currently in use.
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @param {string} newId new camera device id
|
* @param {string} newId new camera device id
|
||||||
* @param {boolean} whether we need to store the value
|
* @param {boolean} whether we need to store the value
|
||||||
*/
|
*/
|
||||||
setCameraDeviceId: function (newId, store) {
|
setCameraDeviceId(newId, store) {
|
||||||
cameraDeviceId = newId;
|
cameraDeviceId = newId;
|
||||||
if (store)
|
if (store) {
|
||||||
jitsiLocalStorage.setItem("cameraDeviceId", newId);
|
jitsiLocalStorage.setItem('cameraDeviceId', newId);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -148,19 +153,21 @@ export default {
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
getMicDeviceId: function () {
|
getMicDeviceId() {
|
||||||
return micDeviceId;
|
return micDeviceId;
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set device id of the microphone which is currently in use.
|
* Set device id of the microphone which is currently in use.
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @param {string} newId new microphone device id
|
* @param {string} newId new microphone device id
|
||||||
* @param {boolean} whether we need to store the value
|
* @param {boolean} whether we need to store the value
|
||||||
*/
|
*/
|
||||||
setMicDeviceId: function (newId, store) {
|
setMicDeviceId(newId, store) {
|
||||||
micDeviceId = newId;
|
micDeviceId = newId;
|
||||||
if (store)
|
if (store) {
|
||||||
jitsiLocalStorage.setItem("micDeviceId", newId);
|
jitsiLocalStorage.setItem('micDeviceId', newId);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -168,26 +175,27 @@ export default {
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @returns {String}
|
* @returns {String}
|
||||||
*/
|
*/
|
||||||
getAudioOutputDeviceId: function () {
|
getAudioOutputDeviceId() {
|
||||||
return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
|
return JitsiMeetJS.mediaDevices.getAudioOutputDevice();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set device id of the audio output device which is currently in use.
|
* Set device id of the audio output device which is currently in use.
|
||||||
* Empty string stands for default device.
|
* Empty string stands for default device.
|
||||||
* @param {string} newId='default' - new audio output device id
|
* @param {string} newId='default' - new audio output device id
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
setAudioOutputDeviceId: function (newId = 'default') {
|
setAudioOutputDeviceId(newId = 'default') {
|
||||||
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
return JitsiMeetJS.mediaDevices.setAudioOutputDevice(newId)
|
||||||
.then(() =>
|
.then(() =>
|
||||||
jitsiLocalStorage.setItem("audioOutputDeviceId", newId));
|
jitsiLocalStorage.setItem('audioOutputDeviceId', newId));
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if welcome page is enabled or not.
|
* Check if welcome page is enabled or not.
|
||||||
* @returns {boolean}
|
* @returns {boolean}
|
||||||
*/
|
*/
|
||||||
isWelcomePageEnabled () {
|
isWelcomePageEnabled() {
|
||||||
return !welcomePageDisabled;
|
return !welcomePageDisabled;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -195,8 +203,8 @@ export default {
|
||||||
* Enable or disable welcome page.
|
* Enable or disable welcome page.
|
||||||
* @param {boolean} enabled if welcome page should be enabled or not
|
* @param {boolean} enabled if welcome page should be enabled or not
|
||||||
*/
|
*/
|
||||||
setWelcomePageEnabled (enabled) {
|
setWelcomePageEnabled(enabled) {
|
||||||
welcomePageDisabled = !enabled;
|
welcomePageDisabled = !enabled;
|
||||||
jitsiLocalStorage.setItem("welcomePageDisabled", welcomePageDisabled);
|
jitsiLocalStorage.setItem('welcomePageDisabled', welcomePageDisabled);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,11 +16,20 @@ function _onI18nInitialized() {
|
||||||
$('[data-i18n]').localize();
|
$('[data-i18n]').localize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
class Translation {
|
class Translation {
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
addLanguageChangedListener(listener: Function) {
|
addLanguageChangedListener(listener: Function) {
|
||||||
i18next.on('languageChanged', listener);
|
i18next.on('languageChanged', listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
generateTranslationHTML(key: string, options: Object) {
|
generateTranslationHTML(key: string, options: Object) {
|
||||||
const optAttr
|
const optAttr
|
||||||
= options ? ` data-i18n-options='${JSON.stringify(options)}'` : '';
|
= options ? ` data-i18n-options='${JSON.stringify(options)}'` : '';
|
||||||
|
@ -31,23 +40,36 @@ class Translation {
|
||||||
return `<span data-i18n="${key}"${optAttr}>${text}</span>`;
|
return `<span data-i18n="${key}"${optAttr}>${text}</span>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
getCurrentLanguage() {
|
getCurrentLanguage() {
|
||||||
return i18next.lng();
|
return i18next.lng();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
init() {
|
init() {
|
||||||
jqueryI18next.init(i18next, $, { useOptionsAttr: true });
|
jqueryI18next.init(i18next, $, { useOptionsAttr: true });
|
||||||
|
|
||||||
if (i18next.isInitialized)
|
if (i18next.isInitialized) {
|
||||||
_onI18nInitialized();
|
_onI18nInitialized();
|
||||||
else
|
} else {
|
||||||
i18next.on('initialized', _onI18nInitialized);
|
i18next.on('initialized', _onI18nInitialized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
setLanguage(language: string = DEFAULT_LANGUAGE) {
|
setLanguage(language: string = DEFAULT_LANGUAGE) {
|
||||||
i18next.setLng(language, {}, _onI18nInitialized);
|
i18next.setLng(language, {}, _onI18nInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
translateElement(selector: Object, options: Object) {
|
translateElement(selector: Object, options: Object) {
|
||||||
// XXX i18next expects undefined if options are missing.
|
// XXX i18next expects undefined if options are missing.
|
||||||
selector.localize(options ? options : undefined);
|
selector.localize(options ? options : undefined);
|
||||||
|
|
|
@ -65,6 +65,7 @@ export default class PostMessageTransportBackend {
|
||||||
* transport.
|
* transport.
|
||||||
*/
|
*/
|
||||||
constructor({ enableLegacyFormat, postisOptions } = {}) {
|
constructor({ enableLegacyFormat, postisOptions } = {}) {
|
||||||
|
// eslint-disable-next-line new-cap
|
||||||
this.postis = Postis({
|
this.postis = Postis({
|
||||||
...DEFAULT_POSTIS_OPTIONS,
|
...DEFAULT_POSTIS_OPTIONS,
|
||||||
...postisOptions
|
...postisOptions
|
||||||
|
|
|
@ -6,6 +6,7 @@ const logger = Logger.getLogger(__filename);
|
||||||
* Dummy implementation of Storage interface with empty methods.
|
* Dummy implementation of Storage interface with empty methods.
|
||||||
*/
|
*/
|
||||||
class DummyLocalStorage {
|
class DummyLocalStorage {
|
||||||
|
/* eslint-disable no-empty-function */
|
||||||
/**
|
/**
|
||||||
* Empty function
|
* Empty function
|
||||||
*/
|
*/
|
||||||
|
@ -20,6 +21,7 @@ class DummyLocalStorage {
|
||||||
* Empty function
|
* Empty function
|
||||||
*/
|
*/
|
||||||
removeItem() { }
|
removeItem() { }
|
||||||
|
/* eslint-enable no-empty-function */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -37,15 +37,17 @@ export default class JitsiMeetLogStorage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let logJSON = '{"log' + this.counter + '":"\n';
|
let logJSON = `{"log${this.counter}":"\n`;
|
||||||
|
|
||||||
for (let i = 0, len = logEntries.length; i < len; i++) {
|
for (let i = 0, len = logEntries.length; i < len; i++) {
|
||||||
let logEntry = logEntries[i];
|
const logEntry = logEntries[i];
|
||||||
|
|
||||||
if (typeof logEntry === 'object') {
|
if (typeof logEntry === 'object') {
|
||||||
// Aggregated message
|
// Aggregated message
|
||||||
logJSON += '(' + logEntry.count + ') ' + logEntry.text + '\n';
|
logJSON += `(${logEntry.count}) ${logEntry.text}\n`;
|
||||||
} else {
|
} else {
|
||||||
// Regular message
|
// Regular message
|
||||||
logJSON += logEntry + '\n';
|
logJSON += `${logEntry}\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logJSON += '"}';
|
logJSON += '"}';
|
||||||
|
@ -60,7 +62,7 @@ export default class JitsiMeetLogStorage {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// NOTE console is intentional here
|
// NOTE console is intentional here
|
||||||
console.error(
|
console.error(
|
||||||
"Failed to store the logs: ", logJSON, error);
|
'Failed to store the logs: ', logJSON, error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
const logger = require("jitsi-meet-logger").getLogger(__filename);
|
const logger = require('jitsi-meet-logger').getLogger(__filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create deferred object.
|
* Create deferred object.
|
||||||
|
@ -40,7 +40,7 @@ export function replace(url) {
|
||||||
* @param e {Error} the error
|
* @param e {Error} the error
|
||||||
* @param msg {string} [optional] the message printed in addition to the error
|
* @param msg {string} [optional] the message printed in addition to the error
|
||||||
*/
|
*/
|
||||||
export function reportError(e, msg = "") {
|
export function reportError(e, msg = '') {
|
||||||
logger.error(msg, e);
|
logger.error(msg, e);
|
||||||
window.onerror && window.onerror(msg, null, null, null, e);
|
window.onerror && window.onerror(msg, null, null, null, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,48 +6,12 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'plugins': [
|
'plugins': [
|
||||||
|
|
||||||
// ESLint's rule no-duplicate-imports does not understand Flow's import
|
|
||||||
// type. Fortunately, eslint-plugin-import understands Flow's import
|
|
||||||
// type.
|
|
||||||
'import',
|
|
||||||
'jsdoc',
|
'jsdoc',
|
||||||
'react',
|
'react',
|
||||||
'react-native'
|
'react-native'
|
||||||
],
|
],
|
||||||
'rules': {
|
'rules': {
|
||||||
// Possible Errors group
|
// Possible Errors group
|
||||||
'no-cond-assign': 2,
|
|
||||||
'no-console': 0,
|
|
||||||
'no-constant-condition': 2,
|
|
||||||
'no-control-regex': 2,
|
|
||||||
'no-debugger': 2,
|
|
||||||
'no-dupe-args': 2,
|
|
||||||
'no-dupe-keys': 2,
|
|
||||||
'no-duplicate-case': 2,
|
|
||||||
'no-empty': 2,
|
|
||||||
'no-empty-character-class': 2,
|
|
||||||
'no-ex-assign': 2,
|
|
||||||
'no-extra-boolean-cast': 2,
|
|
||||||
'no-extra-parens': [
|
|
||||||
'error',
|
|
||||||
'all',
|
|
||||||
{ 'nestedBinaryExpressions': false }
|
|
||||||
],
|
|
||||||
'no-extra-semi': 2,
|
|
||||||
'no-func-assign': 2,
|
|
||||||
'no-inner-declarations': 2,
|
|
||||||
'no-invalid-regexp': 2,
|
|
||||||
'no-irregular-whitespace': 2,
|
|
||||||
'no-negated-in-lhs': 2,
|
|
||||||
'no-obj-calls': 2,
|
|
||||||
'no-prototype-builtins': 0,
|
|
||||||
'no-regex-spaces': 2,
|
|
||||||
'no-sparse-arrays': 2,
|
|
||||||
'no-unexpected-multiline': 2,
|
|
||||||
'no-unreachable': 2,
|
|
||||||
'no-unsafe-finally': 2,
|
|
||||||
'use-isnan': 2,
|
|
||||||
|
|
||||||
// Currently, we are using both valid-jsdoc and 'jsdoc' plugin. In the
|
// Currently, we are using both valid-jsdoc and 'jsdoc' plugin. In the
|
||||||
// future we might stick to one as soon as it has all the features.
|
// future we might stick to one as soon as it has all the features.
|
||||||
|
@ -74,234 +38,11 @@ module.exports = {
|
||||||
'requireReturnType': true
|
'requireReturnType': true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
'valid-typeof': 2,
|
|
||||||
|
|
||||||
// Best Practices group
|
// Best Practices group
|
||||||
'accessor-pairs': 0,
|
|
||||||
'array-callback-return': 2,
|
|
||||||
'block-scoped-var': 0,
|
|
||||||
'complexity': 0,
|
|
||||||
'consistent-return': 0,
|
|
||||||
'curly': 2,
|
|
||||||
'default-case': 0,
|
|
||||||
'dot-location': [ 'error', 'property' ],
|
|
||||||
'dot-notation': 2,
|
|
||||||
'eqeqeq': 2,
|
|
||||||
'guard-for-in': 2,
|
|
||||||
'no-alert': 2,
|
|
||||||
'no-caller': 2,
|
|
||||||
'no-case-declarations': 2,
|
|
||||||
'no-div-regex': 0,
|
|
||||||
'no-else-return': 2,
|
|
||||||
'no-empty-function': 2,
|
|
||||||
'no-empty-pattern': 2,
|
|
||||||
'no-eq-null': 2,
|
|
||||||
'no-eval': 2,
|
|
||||||
'no-extend-native': 2,
|
|
||||||
'no-extra-bind': 2,
|
|
||||||
'no-extra-label': 2,
|
|
||||||
'no-fallthrough': 2,
|
|
||||||
'no-floating-decimal': 2,
|
|
||||||
'no-implicit-coercion': 2,
|
|
||||||
'no-implicit-globals': 2,
|
|
||||||
'no-implied-eval': 2,
|
|
||||||
'no-invalid-this': 2,
|
|
||||||
'no-iterator': 2,
|
|
||||||
'no-labels': 2,
|
|
||||||
'no-lone-blocks': 2,
|
|
||||||
'no-loop-func': 2,
|
|
||||||
'no-magic-numbers': 0,
|
|
||||||
'no-multi-spaces': 2,
|
|
||||||
'no-multi-str': 2,
|
|
||||||
'no-native-reassign': 2,
|
|
||||||
'no-new': 2,
|
|
||||||
'no-new-func': 2,
|
|
||||||
'no-new-wrappers': 2,
|
|
||||||
'no-octal': 2,
|
|
||||||
'no-octal-escape': 2,
|
|
||||||
'no-param-reassign': 2,
|
|
||||||
'no-proto': 2,
|
|
||||||
'no-redeclare': 2,
|
|
||||||
'no-return-assign': 2,
|
|
||||||
'no-script-url': 2,
|
|
||||||
'no-self-assign': 2,
|
|
||||||
'no-self-compare': 2,
|
|
||||||
'no-sequences': 2,
|
|
||||||
'no-throw-literal': 2,
|
|
||||||
'no-unmodified-loop-condition': 2,
|
|
||||||
'no-unused-expressions': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'allowShortCircuit': true,
|
|
||||||
'allowTernary': true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'no-unused-labels': 2,
|
|
||||||
'no-useless-call': 2,
|
|
||||||
'no-useless-concat': 2,
|
|
||||||
'no-useless-escape': 2,
|
|
||||||
'no-void': 2,
|
|
||||||
'no-warning-comments': 0,
|
|
||||||
'no-with': 2,
|
|
||||||
'radix': 2,
|
|
||||||
'vars-on-top': 2,
|
|
||||||
'wrap-iife': [ 'error', 'inside' ],
|
|
||||||
'yoda': 2,
|
|
||||||
|
|
||||||
// Strict Mode group
|
|
||||||
'strict': 2,
|
|
||||||
|
|
||||||
// Variables group
|
|
||||||
'init-declarations': 0,
|
|
||||||
'no-catch-shadow': 2,
|
|
||||||
'no-delete-var': 2,
|
|
||||||
'no-label-var': 2,
|
|
||||||
'no-restricted-globals': 0,
|
|
||||||
'no-shadow': 2,
|
|
||||||
'no-shadow-restricted-names': 2,
|
|
||||||
'no-undef': 2,
|
|
||||||
'no-undef-init': 2,
|
|
||||||
'no-undefined': 0,
|
|
||||||
'no-unused-vars': 2,
|
|
||||||
'no-use-before-define': [ 'error', { 'functions': false } ],
|
|
||||||
|
|
||||||
// Stylistic issues group
|
|
||||||
'array-bracket-spacing': [
|
|
||||||
'error',
|
|
||||||
'always',
|
|
||||||
{ 'objectsInArrays': true }
|
|
||||||
],
|
|
||||||
'block-spacing': [ 'error', 'always' ],
|
|
||||||
'brace-style': 2,
|
|
||||||
'camelcase': 2,
|
|
||||||
'comma-dangle': 2,
|
|
||||||
'comma-spacing': 2,
|
|
||||||
'comma-style': 2,
|
|
||||||
'computed-property-spacing': 2,
|
|
||||||
'consistent-this': [ 'error', 'self' ],
|
|
||||||
'eol-last': 2,
|
|
||||||
'func-names': 0,
|
|
||||||
'func-style': 0,
|
|
||||||
'id-blacklist': 0,
|
|
||||||
'id-length': 0,
|
|
||||||
'id-match': 0,
|
|
||||||
'jsx-quotes': [ 'error', 'prefer-single' ],
|
'jsx-quotes': [ 'error', 'prefer-single' ],
|
||||||
'key-spacing': 2,
|
|
||||||
'keyword-spacing': 2,
|
|
||||||
'linebreak-style': [ 'error', 'unix' ],
|
|
||||||
'lines-around-comment': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'allowBlockStart': true,
|
|
||||||
'allowObjectStart': true,
|
|
||||||
'beforeBlockComment': true,
|
|
||||||
'beforeLineComment': true
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'max-depth': 2,
|
|
||||||
'max-len': [ 'error', 80 ],
|
|
||||||
'max-lines': 0,
|
|
||||||
'max-nested-callbacks': 2,
|
|
||||||
'max-params': 2,
|
|
||||||
'max-statements': 0,
|
|
||||||
'max-statements-per-line': 2,
|
|
||||||
'multiline-ternary': 0,
|
|
||||||
'new-cap': 2,
|
|
||||||
'new-parens': 2,
|
|
||||||
'newline-after-var': 2,
|
|
||||||
'newline-before-return': 2,
|
|
||||||
'newline-per-chained-call': 2,
|
|
||||||
'no-array-constructor': 2,
|
|
||||||
'no-bitwise': 2,
|
|
||||||
'no-continue': 2,
|
|
||||||
'no-inline-comments': 0,
|
|
||||||
'no-lonely-if': 2,
|
|
||||||
'no-mixed-operators': 2,
|
|
||||||
'no-mixed-spaces-and-tabs': 2,
|
|
||||||
'no-multiple-empty-lines': 2,
|
|
||||||
'no-negated-condition': 2,
|
|
||||||
'no-nested-ternary': 0,
|
|
||||||
'no-new-object': 2,
|
|
||||||
'no-plusplus': 0,
|
|
||||||
'no-restricted-syntax': 0,
|
|
||||||
'no-spaced-func': 2,
|
|
||||||
'no-tabs': 2,
|
|
||||||
'no-ternary': 0,
|
|
||||||
'no-trailing-spaces': 2,
|
|
||||||
'no-underscore-dangle': 0,
|
|
||||||
'no-unneeded-ternary': 2,
|
|
||||||
'no-whitespace-before-property': 2,
|
|
||||||
'object-curly-newline': 0,
|
|
||||||
'object-curly-spacing': [ 'error', 'always' ],
|
|
||||||
'object-property-newline': 2,
|
|
||||||
'one-var': 0,
|
|
||||||
'one-var-declaration-per-line': 0,
|
|
||||||
'operator-assignment': 0,
|
|
||||||
'operator-linebreak': [ 'error', 'before' ],
|
|
||||||
'padded-blocks': 0,
|
|
||||||
'quote-props': 0,
|
|
||||||
'quotes': [ 'error', 'single' ],
|
|
||||||
'require-jsdoc': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
'require': {
|
|
||||||
'ClassDeclaration': true,
|
|
||||||
'FunctionDeclaration': true,
|
|
||||||
'MethodDefinition': true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
'semi': [ 'error', 'always' ],
|
|
||||||
'semi-spacing': 2,
|
|
||||||
'sort-vars': 2,
|
|
||||||
'space-before-blocks': 2,
|
|
||||||
'space-before-function-paren': [ 'error', 'never' ],
|
|
||||||
'space-in-parens': [ 'error', 'never' ],
|
|
||||||
'space-infix-ops': 2,
|
|
||||||
'space-unary-ops': 2,
|
|
||||||
'spaced-comment': 2,
|
|
||||||
'unicode-bom': 0,
|
|
||||||
'wrap-regex': 0,
|
|
||||||
|
|
||||||
// ES6 group rules
|
// ES6 group rules
|
||||||
'arrow-body-style': [
|
|
||||||
'error',
|
|
||||||
'as-needed',
|
|
||||||
{ requireReturnForObjectLiteral: true }
|
|
||||||
],
|
|
||||||
'arrow-parens': [ 'error', 'as-needed' ],
|
|
||||||
'arrow-spacing': 2,
|
|
||||||
'constructor-super': 2,
|
|
||||||
'generator-star-spacing': 2,
|
|
||||||
'no-class-assign': 2,
|
|
||||||
'no-confusing-arrow': 2,
|
|
||||||
'no-const-assign': 2,
|
|
||||||
'no-dupe-class-members': 2,
|
|
||||||
'no-new-symbol': 2,
|
|
||||||
'no-restricted-imports': 0,
|
|
||||||
'no-this-before-super': 2,
|
|
||||||
'no-useless-computed-key': 2,
|
|
||||||
'no-useless-constructor': 2,
|
|
||||||
'no-useless-rename': 2,
|
|
||||||
'no-var': 2,
|
|
||||||
'object-shorthand': [
|
|
||||||
'error',
|
|
||||||
'always',
|
|
||||||
{ 'avoidQuotes': true }
|
|
||||||
],
|
|
||||||
'prefer-arrow-callback': [ 'error', { 'allowNamedFunctions': true } ],
|
|
||||||
'prefer-const': 2,
|
|
||||||
'prefer-reflect': 0,
|
|
||||||
'prefer-rest-params': 2,
|
|
||||||
'prefer-spread': 2,
|
|
||||||
'prefer-template': 2,
|
|
||||||
'require-yield': 2,
|
|
||||||
'rest-spread-spacing': 2,
|
|
||||||
'sort-imports': 0,
|
|
||||||
'template-curly-spacing': 2,
|
|
||||||
'yield-star-spacing': 2,
|
|
||||||
|
|
||||||
'import/no-duplicates': 2,
|
|
||||||
|
|
||||||
// JsDoc plugin rules group. The following rules are in addition to
|
// JsDoc plugin rules group. The following rules are in addition to
|
||||||
// valid-jsdoc rule.
|
// valid-jsdoc rule.
|
||||||
|
|
|
@ -1,50 +1,58 @@
|
||||||
export default {
|
export default {
|
||||||
NICKNAME_CHANGED: "UI.nickname_changed",
|
NICKNAME_CHANGED: 'UI.nickname_changed',
|
||||||
SELECTED_ENDPOINT: "UI.selected_endpoint",
|
SELECTED_ENDPOINT: 'UI.selected_endpoint',
|
||||||
PINNED_ENDPOINT: "UI.pinned_endpoint",
|
PINNED_ENDPOINT: 'UI.pinned_endpoint',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that local user created text message.
|
* Notifies that local user created text message.
|
||||||
*/
|
*/
|
||||||
MESSAGE_CREATED: "UI.message_created",
|
MESSAGE_CREATED: 'UI.message_created',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that local user changed language.
|
* Notifies that local user changed language.
|
||||||
*/
|
*/
|
||||||
LANG_CHANGED: "UI.lang_changed",
|
LANG_CHANGED: 'UI.lang_changed',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that local user changed email.
|
* Notifies that local user changed email.
|
||||||
*/
|
*/
|
||||||
EMAIL_CHANGED: "UI.email_changed",
|
EMAIL_CHANGED: 'UI.email_changed',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that "start muted" settings changed.
|
* Notifies that "start muted" settings changed.
|
||||||
*/
|
*/
|
||||||
START_MUTED_CHANGED: "UI.start_muted_changed",
|
START_MUTED_CHANGED: 'UI.start_muted_changed',
|
||||||
AUDIO_MUTED: "UI.audio_muted",
|
AUDIO_MUTED: 'UI.audio_muted',
|
||||||
VIDEO_MUTED: "UI.video_muted",
|
VIDEO_MUTED: 'UI.video_muted',
|
||||||
VIDEO_UNMUTING_WHILE_AUDIO_ONLY: "UI.video_unmuting_while_audio_only",
|
VIDEO_UNMUTING_WHILE_AUDIO_ONLY: 'UI.video_unmuting_while_audio_only',
|
||||||
ETHERPAD_CLICKED: "UI.etherpad_clicked",
|
ETHERPAD_CLICKED: 'UI.etherpad_clicked',
|
||||||
SHARED_VIDEO_CLICKED: "UI.start_shared_video",
|
SHARED_VIDEO_CLICKED: 'UI.start_shared_video',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates shared video with params: url, state, time(optional)
|
* Updates shared video with params: url, state, time(optional)
|
||||||
* Where url is the video link, state is stop/start/pause and time is the
|
* Where url is the video link, state is stop/start/pause and time is the
|
||||||
* current video playing time.
|
* current video playing time.
|
||||||
*/
|
*/
|
||||||
UPDATE_SHARED_VIDEO: "UI.update_shared_video",
|
UPDATE_SHARED_VIDEO: 'UI.update_shared_video',
|
||||||
USER_KICKED: "UI.user_kicked",
|
USER_KICKED: 'UI.user_kicked',
|
||||||
REMOTE_AUDIO_MUTED: "UI.remote_audio_muted",
|
REMOTE_AUDIO_MUTED: 'UI.remote_audio_muted',
|
||||||
TOGGLE_FULLSCREEN: "UI.toogle_fullscreen",
|
TOGGLE_FULLSCREEN: 'UI.toogle_fullscreen',
|
||||||
FULLSCREEN_TOGGLED: "UI.fullscreen_toggled",
|
FULLSCREEN_TOGGLED: 'UI.fullscreen_toggled',
|
||||||
AUTH_CLICKED: "UI.auth_clicked",
|
AUTH_CLICKED: 'UI.auth_clicked',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the audio only mode was toggled.
|
* Notifies that the audio only mode was toggled.
|
||||||
*/
|
*/
|
||||||
TOGGLE_AUDIO_ONLY: "UI.toggle_audioonly",
|
TOGGLE_AUDIO_ONLY: 'UI.toggle_audioonly',
|
||||||
TOGGLE_CHAT: "UI.toggle_chat",
|
TOGGLE_CHAT: 'UI.toggle_chat',
|
||||||
TOGGLE_SETTINGS: "UI.toggle_settings",
|
TOGGLE_SETTINGS: 'UI.toggle_settings',
|
||||||
TOGGLE_CONTACT_LIST: "UI.toggle_contact_list",
|
TOGGLE_CONTACT_LIST: 'UI.toggle_contact_list',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the profile toolbar button has been clicked.
|
* Notifies that the profile toolbar button has been clicked.
|
||||||
*/
|
*/
|
||||||
TOGGLE_PROFILE: "UI.toggle_profile",
|
TOGGLE_PROFILE: 'UI.toggle_profile',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that a command to toggle the filmstrip has been issued. The
|
* Notifies that a command to toggle the filmstrip has been issued. The
|
||||||
* event may optionally specify a {Boolean} (primitive) value to assign to
|
* event may optionally specify a {Boolean} (primitive) value to assign to
|
||||||
|
@ -56,7 +64,8 @@ export default {
|
||||||
*
|
*
|
||||||
* @see {TOGGLED_FILMSTRIP}
|
* @see {TOGGLED_FILMSTRIP}
|
||||||
*/
|
*/
|
||||||
TOGGLE_FILMSTRIP: "UI.toggle_filmstrip",
|
TOGGLE_FILMSTRIP: 'UI.toggle_filmstrip',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the filmstrip was (actually) toggled. The event supplies a
|
* Notifies that the filmstrip was (actually) toggled. The event supplies a
|
||||||
* {Boolean} (primitive) value indicating the visibility of the filmstrip
|
* {Boolean} (primitive) value indicating the visibility of the filmstrip
|
||||||
|
@ -64,59 +73,59 @@ export default {
|
||||||
*
|
*
|
||||||
* @see {TOGGLE_FILMSTRIP}
|
* @see {TOGGLE_FILMSTRIP}
|
||||||
*/
|
*/
|
||||||
TOGGLED_FILMSTRIP: "UI.toggled_filmstrip",
|
TOGGLED_FILMSTRIP: 'UI.toggled_filmstrip',
|
||||||
|
|
||||||
TOGGLE_SCREENSHARING: "UI.toggle_screensharing",
|
TOGGLE_SCREENSHARING: 'UI.toggle_screensharing',
|
||||||
TOGGLED_SHARED_DOCUMENT: "UI.toggled_shared_document",
|
TOGGLED_SHARED_DOCUMENT: 'UI.toggled_shared_document',
|
||||||
CONTACT_CLICKED: "UI.contact_clicked",
|
CONTACT_CLICKED: 'UI.contact_clicked',
|
||||||
HANGUP: "UI.hangup",
|
HANGUP: 'UI.hangup',
|
||||||
LOGOUT: "UI.logout",
|
LOGOUT: 'UI.logout',
|
||||||
RECORDING_TOGGLED: "UI.recording_toggled",
|
RECORDING_TOGGLED: 'UI.recording_toggled',
|
||||||
SUBJECT_CHANGED: "UI.subject_changed",
|
SUBJECT_CHANGED: 'UI.subject_changed',
|
||||||
VIDEO_DEVICE_CHANGED: "UI.video_device_changed",
|
VIDEO_DEVICE_CHANGED: 'UI.video_device_changed',
|
||||||
AUDIO_DEVICE_CHANGED: "UI.audio_device_changed",
|
AUDIO_DEVICE_CHANGED: 'UI.audio_device_changed',
|
||||||
AUDIO_OUTPUT_DEVICE_CHANGED: "UI.audio_output_device_changed",
|
AUDIO_OUTPUT_DEVICE_CHANGED: 'UI.audio_output_device_changed',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies interested listeners that the follow-me feature is enabled or
|
* Notifies interested listeners that the follow-me feature is enabled or
|
||||||
* disabled.
|
* disabled.
|
||||||
*/
|
*/
|
||||||
FOLLOW_ME_ENABLED: "UI.follow_me_enabled",
|
FOLLOW_ME_ENABLED: 'UI.follow_me_enabled',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that flipX property of the local video is changed.
|
* Notifies that flipX property of the local video is changed.
|
||||||
*/
|
*/
|
||||||
LOCAL_FLIPX_CHANGED: "UI.local_flipx_changed",
|
LOCAL_FLIPX_CHANGED: 'UI.local_flipx_changed',
|
||||||
|
|
||||||
// An event which indicates that the resolution of a remote video has
|
// An event which indicates that the resolution of a remote video has
|
||||||
// changed.
|
// changed.
|
||||||
RESOLUTION_CHANGED: "UI.resolution_changed",
|
RESOLUTION_CHANGED: 'UI.resolution_changed',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the button "Cancel" is pressed on the dialog for
|
* Notifies that the button "Cancel" is pressed on the dialog for
|
||||||
* external extension installation.
|
* external extension installation.
|
||||||
*/
|
*/
|
||||||
EXTERNAL_INSTALLATION_CANCELED: "UI.external_installation_canceled",
|
EXTERNAL_INSTALLATION_CANCELED: 'UI.external_installation_canceled',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the side toolbar container has been toggled. The actual
|
* Notifies that the side toolbar container has been toggled. The actual
|
||||||
* event must contain the identifier of the container that has been toggled
|
* event must contain the identifier of the container that has been toggled
|
||||||
* and information about toggle on or off.
|
* and information about toggle on or off.
|
||||||
*/
|
*/
|
||||||
SIDE_TOOLBAR_CONTAINER_TOGGLED: "UI.side_container_toggled",
|
SIDE_TOOLBAR_CONTAINER_TOGGLED: 'UI.side_container_toggled',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the raise hand has been changed.
|
* Notifies that the raise hand has been changed.
|
||||||
*/
|
*/
|
||||||
LOCAL_RAISE_HAND_CHANGED: "UI.local_raise_hand_changed",
|
LOCAL_RAISE_HAND_CHANGED: 'UI.local_raise_hand_changed',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the avatar is displayed or not on the largeVideo.
|
* Notifies that the avatar is displayed or not on the largeVideo.
|
||||||
*/
|
*/
|
||||||
LARGE_VIDEO_AVATAR_VISIBLE: "UI.large_video_avatar_visible",
|
LARGE_VIDEO_AVATAR_VISIBLE: 'UI.large_video_avatar_visible',
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notifies that the displayed particpant id on the largeVideo is changed.
|
* Notifies that the displayed particpant id on the largeVideo is changed.
|
||||||
*/
|
*/
|
||||||
LARGE_VIDEO_ID_CHANGED: "UI.large_video_id_changed"
|
LARGE_VIDEO_ID_CHANGED: 'UI.large_video_id_changed'
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* The value for the "var" attribute of feature tag in disco-info packets.
|
* The value for the "var" attribute of feature tag in disco-info packets.
|
||||||
*/
|
*/
|
||||||
export const DISCO_REMOTE_CONTROL_FEATURE
|
export const DISCO_REMOTE_CONTROL_FEATURE
|
||||||
= "http://jitsi.org/meet/remotecontrol";
|
= 'http://jitsi.org/meet/remotecontrol';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Types of remote-control events.
|
* Types of remote-control events.
|
||||||
|
@ -10,17 +10,17 @@ export const DISCO_REMOTE_CONTROL_FEATURE
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
export const EVENTS = {
|
export const EVENTS = {
|
||||||
mousemove: "mousemove",
|
mousemove: 'mousemove',
|
||||||
mousedown: "mousedown",
|
mousedown: 'mousedown',
|
||||||
mouseup: "mouseup",
|
mouseup: 'mouseup',
|
||||||
mousedblclick: "mousedblclick",
|
mousedblclick: 'mousedblclick',
|
||||||
mousescroll: "mousescroll",
|
mousescroll: 'mousescroll',
|
||||||
keydown: "keydown",
|
keydown: 'keydown',
|
||||||
keyup: "keyup",
|
keyup: 'keyup',
|
||||||
permissions: "permissions",
|
permissions: 'permissions',
|
||||||
start: "start",
|
start: 'start',
|
||||||
stop: "stop",
|
stop: 'stop',
|
||||||
supported: "supported"
|
supported: 'supported'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,7 +29,7 @@ export const EVENTS = {
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
export const REQUESTS = {
|
export const REQUESTS = {
|
||||||
start: "start"
|
start: 'start'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,16 +38,16 @@ export const REQUESTS = {
|
||||||
* @enum {string}
|
* @enum {string}
|
||||||
*/
|
*/
|
||||||
export const PERMISSIONS_ACTIONS = {
|
export const PERMISSIONS_ACTIONS = {
|
||||||
request: "request",
|
request: 'request',
|
||||||
grant: "grant",
|
grant: 'grant',
|
||||||
deny: "deny",
|
deny: 'deny',
|
||||||
error: "error"
|
error: 'error'
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The type of remote control messages.
|
* The type of remote control messages.
|
||||||
*/
|
*/
|
||||||
export const REMOTE_CONTROL_MESSAGE_NAME = "remote-control";
|
export const REMOTE_CONTROL_MESSAGE_NAME = 'remote-control';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The remote control event.
|
* The remote control event.
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
/* global interfaceConfig */
|
/* global interfaceConfig */
|
||||||
//list of tips
|
// list of tips
|
||||||
var hints = [
|
const hints = [
|
||||||
"You can pin participants by clicking on their thumbnails.",// jshint ignore:line
|
'You can pin participants by clicking on their thumbnails.',
|
||||||
"You can tell others you have something to say by using the \"Raise Hand\" feature",// jshint ignore:line
|
'You can tell others you have something to say by using the "Raise Hand" '
|
||||||
"You can learn about key shortcuts by pressing Shift+?",// jshint ignore:line
|
+ 'feature',
|
||||||
"You can learn more about the state of everyone's connection by hovering on the bars in their thumbnail",// jshint ignore:line
|
'You can learn about key shortcuts by pressing Shift+?',
|
||||||
"You can hide all thumbnails by using the button in the bottom right corner"// jshint ignore:line
|
'You can learn more about the state of everyone\'s connection by hovering '
|
||||||
|
+ 'on the bars in their thumbnail',
|
||||||
|
'You can hide all thumbnails by using the button in the bottom right corner'
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -13,9 +15,9 @@ var hints = [
|
||||||
*
|
*
|
||||||
* @return {string} the hint message.
|
* @return {string} the hint message.
|
||||||
*/
|
*/
|
||||||
function getHint(){
|
function getHint() {
|
||||||
var l = hints.length - 1;
|
const l = hints.length - 1;
|
||||||
var n = Math.round(Math.random() * l);
|
const n = Math.round(Math.random() * l);
|
||||||
|
|
||||||
return hints[n];
|
return hints[n];
|
||||||
}
|
}
|
||||||
|
@ -27,28 +29,30 @@ function getHint(){
|
||||||
* @param id {string} element identificator
|
* @param id {string} element identificator
|
||||||
* @param msg {string} text message
|
* @param msg {string} text message
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
function insertTextMsg(id, msg) {
|
||||||
function insertTextMsg(id, msg){
|
const el = document.getElementById(id);
|
||||||
var el = document.getElementById(id);
|
|
||||||
|
|
||||||
if (el)
|
if (el) {
|
||||||
el.innerHTML = msg;
|
el.innerHTML = msg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the hint and thanks messages. Will be executed on load event.
|
* Sets the hint and thanks messages. Will be executed on load event.
|
||||||
*/
|
*/
|
||||||
function onLoad() {
|
function onLoad() {
|
||||||
//Works only for close2.html because close.html doesn't have this element.
|
// Works only for close2.html because close.html doesn't have this element.
|
||||||
insertTextMsg('thanksMessage',
|
insertTextMsg('thanksMessage',
|
||||||
'Thank you for using ' + interfaceConfig.APP_NAME);
|
`Thank you for using ${interfaceConfig.APP_NAME}`);
|
||||||
|
|
||||||
// If there is a setting show a special message only for the guests
|
// If there is a setting show a special message only for the guests
|
||||||
if (interfaceConfig.CLOSE_PAGE_GUEST_HINT) {
|
if (interfaceConfig.CLOSE_PAGE_GUEST_HINT) {
|
||||||
if ( window.sessionStorage.getItem('guest') === 'true' ) {
|
if (window.sessionStorage.getItem('guest') === 'true') {
|
||||||
var element = document.getElementById('hintQuestion');
|
const element = document.getElementById('hintQuestion');
|
||||||
|
|
||||||
element.classList.add('hide');
|
element.classList.add('hide');
|
||||||
insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
|
insertTextMsg('hintMessage', interfaceConfig.CLOSE_PAGE_GUEST_HINT);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
const process = require('process');
|
const process = require('process');
|
||||||
const webpack = require('webpack');
|
const webpack = require('webpack');
|
||||||
|
|
||||||
const aui_css = `${__dirname}/node_modules/@atlassian/aui/dist/aui/css/`;
|
const auiCSS = `${__dirname}/node_modules/@atlassian/aui/dist/aui/css/`;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The URL of the Jitsi Meet deployment to be proxy to in the context of
|
* The URL of the Jitsi Meet deployment to be proxy to in the context of
|
||||||
|
@ -15,6 +15,8 @@ const devServerProxyTarget
|
||||||
const minimize
|
const minimize
|
||||||
= process.argv.indexOf('-p') !== -1
|
= process.argv.indexOf('-p') !== -1
|
||||||
|| process.argv.indexOf('--optimize-minimize') !== -1;
|
|| process.argv.indexOf('--optimize-minimize') !== -1;
|
||||||
|
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
const node_modules = `${__dirname}/node_modules/`;
|
const node_modules = `${__dirname}/node_modules/`;
|
||||||
const plugins = [
|
const plugins = [
|
||||||
new webpack.LoaderOptionsPlugin({
|
new webpack.LoaderOptionsPlugin({
|
||||||
|
@ -62,8 +64,7 @@ const config = {
|
||||||
rules: [ {
|
rules: [ {
|
||||||
// Transpile ES2015 (aka ES6) to ES5. Accept the JSX syntax by React
|
// Transpile ES2015 (aka ES6) to ES5. Accept the JSX syntax by React
|
||||||
// as well.
|
// as well.
|
||||||
|
exclude: node_modules, // eslint-disable-line camelcase
|
||||||
exclude: node_modules,
|
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
options: {
|
options: {
|
||||||
// XXX The require.resolve bellow solves failures to locate the
|
// XXX The require.resolve bellow solves failures to locate the
|
||||||
|
@ -113,10 +114,10 @@ const config = {
|
||||||
// Emit the static assets of AUI such as images that are referenced
|
// Emit the static assets of AUI such as images that are referenced
|
||||||
// by CSS into the output path.
|
// by CSS into the output path.
|
||||||
|
|
||||||
include: aui_css,
|
include: auiCSS,
|
||||||
loader: 'file-loader',
|
loader: 'file-loader',
|
||||||
options: {
|
options: {
|
||||||
context: aui_css,
|
context: auiCSS,
|
||||||
name: '[path][name].[ext]'
|
name: '[path][name].[ext]'
|
||||||
},
|
},
|
||||||
test: /\.(gif|png|svg)$/
|
test: /\.(gif|png|svg)$/
|
||||||
|
@ -210,9 +211,10 @@ function devServerProxyBypass({ path }) {
|
||||||
const configs = module.exports;
|
const configs = module.exports;
|
||||||
|
|
||||||
/* eslint-disable indent */
|
/* eslint-disable indent */
|
||||||
|
let formattedPath = path;
|
||||||
|
|
||||||
if ((Array.isArray(configs) ? configs : Array(configs)).some(c => {
|
if ((Array.isArray(configs) ? configs : Array(configs)).some(c => {
|
||||||
if (path.startsWith(c.output.publicPath)) {
|
if (formattedPath.startsWith(c.output.publicPath)) {
|
||||||
if (!minimize) {
|
if (!minimize) {
|
||||||
// Since webpack-dev-server is serving non-minimized
|
// Since webpack-dev-server is serving non-minimized
|
||||||
// artifacts, serve them even if the minimized ones are
|
// artifacts, serve them even if the minimized ones are
|
||||||
|
@ -220,18 +222,23 @@ function devServerProxyBypass({ path }) {
|
||||||
Object.keys(c.entry).some(e => {
|
Object.keys(c.entry).some(e => {
|
||||||
const name = `${e}.min.js`;
|
const name = `${e}.min.js`;
|
||||||
|
|
||||||
if (path.indexOf(name) !== -1) {
|
if (formattedPath.indexOf(name) !== -1) {
|
||||||
path = path.replace(name, `${e}.js`);
|
formattedPath
|
||||||
|
= formattedPath.replace(name, `${e}.js`);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
})) {
|
})) {
|
||||||
return path;
|
return formattedPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-enable indent */
|
/* eslint-enable indent */
|
||||||
|
|
Loading…
Reference in New Issue