'use strict';
/**
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const padutils = require('./pad_utils').padutils;
const hooks = require('./pluginfw/hooks');
let myUserInfo = {};
let colorPickerOpen = false;
let colorPickerSetup = false;
const paduserlist = (() => {
const rowManager = (() => {
// The row manager handles rendering rows of the user list and animating
// their insertion, removal, and reordering. It manipulates TD height
// and TD opacity.
const nextRowId = () => `usertr${nextRowId.counter++}`;
nextRowId.counter = 1;
// objects are shared; fields are "domId","data","animationStep"
const rowsFadingOut = []; // unordered set
const rowsFadingIn = []; // unordered set
const rowsPresent = []; // in order
const ANIMATION_START = -12; // just starting to fade in
const ANIMATION_END = 12; // just finishing fading out
const animateStep = () => {
// animation must be symmetrical
for (let i = rowsFadingIn.length - 1; i >= 0; i--) { // backwards to allow removal
const row = rowsFadingIn[i];
const step = ++row.animationStep;
const animHeight = getAnimationHeight(step, row.animationPower);
const node = rowNode(row);
const baseOpacity = (row.opacity === undefined ? 1 : row.opacity);
if (step <= -OPACITY_STEPS) {
node.find('td').height(animHeight);
} else if (step === -OPACITY_STEPS + 1) {
node.empty().append(createUserRowTds(animHeight, row.data))
.find('td').css('opacity', baseOpacity * 1 / OPACITY_STEPS);
} else if (step < 0) {
node.find('td').css('opacity', baseOpacity * (OPACITY_STEPS - (-step)) / OPACITY_STEPS)
.height(animHeight);
} else if (step === 0) {
// set HTML in case modified during animation
node.empty().append(createUserRowTds(animHeight, row.data))
.find('td').css('opacity', baseOpacity * 1).height(animHeight);
rowsFadingIn.splice(i, 1); // remove from set
}
}
for (let i = rowsFadingOut.length - 1; i >= 0; i--) { // backwards to allow removal
const row = rowsFadingOut[i];
const step = ++row.animationStep;
const node = rowNode(row);
const animHeight = getAnimationHeight(step, row.animationPower);
const baseOpacity = (row.opacity === undefined ? 1 : row.opacity);
if (step < OPACITY_STEPS) {
node.find('td').css('opacity', baseOpacity * (OPACITY_STEPS - step) / OPACITY_STEPS)
.height(animHeight);
} else if (step === OPACITY_STEPS) {
node.empty().append(createEmptyRowTds(animHeight));
} else if (step <= ANIMATION_END) {
node.find('td').height(animHeight);
} else {
rowsFadingOut.splice(i, 1); // remove from set
node.remove();
}
}
handleOtherUserInputs();
return (rowsFadingIn.length > 0) || (rowsFadingOut.length > 0); // is more to do
};
const getAnimationHeight = (step, power) => {
let a = Math.abs(step / 12);
if (power === 2) a **= 2;
else if (power === 3) a **= 3;
else if (power === 4) a **= 4;
else if (power >= 5) a **= 5;
return Math.round(26 * (1 - a));
};
const OPACITY_STEPS = 6;
const ANIMATION_STEP_TIME = 20;
const LOWER_FRAMERATE_FACTOR = 2;
const {scheduleAnimation} =
padutils.makeAnimationScheduler(animateStep, ANIMATION_STEP_TIME, LOWER_FRAMERATE_FACTOR);
const NUMCOLS = 4;
// we do lots of manipulation of table rows and stuff that JQuery makes ok, despite
// IE's poor handling when manipulating the DOM directly.
const createEmptyRowTds = (height) => $('
')
.attr('colspan', NUMCOLS)
.css('border', 0)
.css('height', `${height}px`);
const isNameEditable = (data) => (!data.name) && (data.status !== 'Disconnected');
const replaceUserRowContents = (tr, height, data) => {
const tds = createUserRowTds(height, data);
if (isNameEditable(data) && tr.find('td.usertdname input:enabled').length > 0) {
// preserve input field node
tds.each((i, td) => {
const oldTd = $(tr.find('td').get(i));
if (!oldTd.hasClass('usertdname')) {
oldTd.replaceWith(td);
} else {
// Prevent leak. I'm not 100% confident that this is necessary, but it shouldn't hurt.
$(td).remove();
}
});
} else {
tr.empty().append(tds);
}
return tr;
};
const createUserRowTds = (height, data) => {
let name;
if (data.name) {
name = document.createTextNode(data.name);
} else {
name = $('')
.attr('data-l10n-id', 'pad.userlist.unnamed')
.attr('type', 'text')
.addClass('editempty')
.addClass('newinput')
.attr('value', html10n.get('pad.userlist.unnamed'));
if (isNameEditable(data)) name.attr('disabled', 'disabled');
}
return $()
.add($('