etherpad-lite/src/static/js/pad_userlist.js

821 lines
23 KiB
JavaScript
Raw Normal View History

2012-04-09 17:42:09 +02:00
/**
* This code is mostly from the old Etherpad. Please help us to comment this code.
* This helps other people to understand this code better and helps them to improve it.
* TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
*/
2011-03-26 14:10:41 +01:00
/**
* Copyright 2009 Google Inc.
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* 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
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* http://www.apache.org/licenses/LICENSE-2.0
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* 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.
*/
2012-03-07 02:27:03 +01:00
var padutils = require('./pad_utils').padutils;
var hooks = require('./pluginfw/hooks');
var myUserInfo = {};
var colorPickerOpen = false;
var colorPickerSetup = false;
var previousColorId = 0;
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
var paduserlist = (function()
{
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
var rowManager = (function()
{
2011-03-26 14:10:41 +01:00
// The row manager handles rendering rows of the user list and animating
// their insertion, removal, and reordering. It manipulates TD height
// and TD opacity.
2011-07-07 19:59:34 +02:00
function nextRowId()
{
return "usertr" + (nextRowId.counter++);
2011-03-26 14:10:41 +01:00
}
nextRowId.counter = 1;
// objects are shared; fields are "domId","data","animationStep"
var rowsFadingOut = []; // unordered set
var rowsFadingIn = []; // unordered set
var rowsPresent = []; // in order
var ANIMATION_START = -12; // just starting to fade in
var ANIMATION_END = 12; // just finishing fading out
2011-07-07 19:59:34 +02:00
function getAnimationHeight(step, power)
{
var a = Math.abs(step / 12);
if (power == 2) a = a * a;
else if (power == 3) a = a * a * a;
else if (power == 4) a = a * a * a * a;
else if (power >= 5) a = a * a * a * a * a;
return Math.round(26 * (1 - a));
2011-03-26 14:10:41 +01:00
}
var OPACITY_STEPS = 6;
var ANIMATION_STEP_TIME = 20;
var LOWER_FRAMERATE_FACTOR = 2;
2011-07-07 19:59:34 +02:00
var scheduleAnimation = padutils.makeAnimationScheduler(animateStep, ANIMATION_STEP_TIME, LOWER_FRAMERATE_FACTOR).scheduleAnimation;
2011-03-26 14:10:41 +01:00
var 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.
2011-07-07 19:59:34 +02:00
function getEmptyRowHtml(height)
{
return '<td colspan="' + NUMCOLS + '" style="border:0;height:' + height + 'px"><!-- --></td>';
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function isNameEditable(data)
{
return (!data.name) && (data.status != 'Disconnected');
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function replaceUserRowContents(tr, height, data)
{
2011-03-26 14:10:41 +01:00
var tds = getUserRowHtml(height, data).match(/<td.*?<\/td>/gi);
2011-07-07 19:59:34 +02:00
if (isNameEditable(data) && tr.find("td.usertdname input:enabled").length > 0)
{
2011-03-26 14:10:41 +01:00
// preserve input field node
2011-07-07 19:59:34 +02:00
for (var i = 0; i < tds.length; i++)
{
2011-03-26 14:10:41 +01:00
var oldTd = $(tr.find("td").get(i));
2011-07-07 19:59:34 +02:00
if (!oldTd.hasClass('usertdname'))
{
2011-03-26 14:10:41 +01:00
oldTd.replaceWith(tds[i]);
}
}
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
tr.html(tds.join(''));
}
return tr;
}
2011-07-07 19:59:34 +02:00
function getUserRowHtml(height, data)
{
2011-03-26 14:10:41 +01:00
var nameHtml;
var isGuest = (data.id.charAt(0) != 'p');
2011-07-07 19:59:34 +02:00
if (data.name)
{
2011-03-26 14:10:41 +01:00
nameHtml = padutils.escapeHtml(data.name);
2011-07-07 19:59:34 +02:00
if (isGuest && pad.getIsProPad())
{
nameHtml += ' ('+_(pad_userlist.guest)+')';
2011-03-26 14:10:41 +01:00
}
}
2011-07-07 19:59:34 +02:00
else
{
nameHtml = '<input type="text" class="editempty newinput" value="'+_('pad_userlist.unnamed')+'" ' + (isNameEditable(data) ? '' : 'disabled="disabled" ') + '/>';
2011-03-26 14:10:41 +01:00
}
return ['<td style="height:', height, 'px" class="usertdswatch"><div class="swatch" style="background:' + data.color + '">&nbsp;</div></td>', '<td style="height:', height, 'px" class="usertdname">', nameHtml, '</td>', '<td style="height:', height, 'px" class="activity">', padutils.escapeHtml(data.activity), '</td>'].join('');
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function getRowHtml(id, innerHtml)
{
return '<tr id="' + id + '">' + innerHtml + '</tr>';
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function rowNode(row)
{
return $("#" + row.domId);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function handleRowData(row)
{
if (row.data && row.data.status == 'Disconnected')
{
2011-03-26 14:10:41 +01:00
row.opacity = 0.5;
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
delete row.opacity;
}
}
2011-07-07 19:59:34 +02:00
function handleRowNode(tr, data)
{
if (data.titleText)
{
2011-03-26 14:10:41 +01:00
var titleText = data.titleText;
2011-07-07 19:59:34 +02:00
window.setTimeout(function()
{
/* tr.attr('title', titleText)*/
2011-07-07 19:59:34 +02:00
}, 0);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
tr.removeAttr('title');
}
}
2011-07-07 19:59:34 +02:00
function handleOtherUserInputs()
{
2011-03-26 14:10:41 +01:00
// handle 'INPUT' elements for naming other unnamed users
2011-07-07 19:59:34 +02:00
$("#otheruserstable input.newinput").each(function()
{
2011-03-26 14:10:41 +01:00
var input = $(this);
var tr = input.closest("tr");
2011-07-07 19:59:34 +02:00
if (tr.length > 0)
{
2011-03-26 14:10:41 +01:00
var index = tr.parent().children().index(tr);
2011-07-07 19:59:34 +02:00
if (index >= 0)
{
2011-03-26 14:10:41 +01:00
var userId = rowsPresent[index].data.id;
rowManagerMakeNameEditor($(this), userId);
}
}
}).removeClass('newinput');
}
// animationPower is 0 to skip animation, 1 for linear, 2 for quadratic, etc.
2011-07-07 19:59:34 +02:00
function insertRow(position, data, animationPower)
{
2011-03-26 14:10:41 +01:00
position = Math.max(0, Math.min(rowsPresent.length, position));
animationPower = (animationPower === undefined ? 4 : animationPower);
var domId = nextRowId();
2011-07-07 19:59:34 +02:00
var row = {
data: data,
animationStep: ANIMATION_START,
domId: domId,
animationPower: animationPower
};
2011-03-26 14:10:41 +01:00
handleRowData(row);
rowsPresent.splice(position, 0, row);
var tr;
2011-07-07 19:59:34 +02:00
if (animationPower == 0)
{
2011-03-26 14:10:41 +01:00
tr = $(getRowHtml(domId, getUserRowHtml(getAnimationHeight(0), data)));
row.animationStep = 0;
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
rowsFadingIn.push(row);
tr = $(getRowHtml(domId, getEmptyRowHtml(getAnimationHeight(ANIMATION_START))));
}
handleRowNode(tr, data);
2011-07-07 19:59:34 +02:00
if (position == 0)
{
2011-03-26 14:10:41 +01:00
$("table#otheruserstable").prepend(tr);
}
2011-07-07 19:59:34 +02:00
else
{
rowNode(rowsPresent[position - 1]).after(tr);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
if (animationPower != 0)
{
2011-03-26 14:10:41 +01:00
scheduleAnimation();
}
handleOtherUserInputs();
return row;
}
2011-07-07 19:59:34 +02:00
function updateRow(position, data)
{
2011-03-26 14:10:41 +01:00
var row = rowsPresent[position];
2011-07-07 19:59:34 +02:00
if (row)
{
2011-03-26 14:10:41 +01:00
row.data = data;
handleRowData(row);
2011-07-07 19:59:34 +02:00
if (row.animationStep == 0)
{
2011-03-26 14:10:41 +01:00
// not currently animating
var tr = rowNode(row);
2011-07-07 19:59:34 +02:00
replaceUserRowContents(tr, getAnimationHeight(0), row.data).find("td").css('opacity', (row.opacity === undefined ? 1 : row.opacity));
2011-03-26 14:10:41 +01:00
handleRowNode(tr, data);
handleOtherUserInputs();
}
}
}
2011-07-07 19:59:34 +02:00
function removeRow(position, animationPower)
{
2011-03-26 14:10:41 +01:00
animationPower = (animationPower === undefined ? 4 : animationPower);
var row = rowsPresent[position];
2011-07-07 19:59:34 +02:00
if (row)
{
2011-03-26 14:10:41 +01:00
rowsPresent.splice(position, 1); // remove
2011-07-07 19:59:34 +02:00
if (animationPower == 0)
{
2011-03-26 14:10:41 +01:00
rowNode(row).remove();
}
2011-07-07 19:59:34 +02:00
else
{
row.animationStep = -row.animationStep; // use symmetry
2011-03-26 14:10:41 +01:00
row.animationPower = animationPower;
rowsFadingOut.push(row);
scheduleAnimation();
}
}
}
// newPosition is position after the row has been removed
2011-07-07 19:59:34 +02:00
function moveRow(oldPosition, newPosition, animationPower)
{
2011-03-26 14:10:41 +01:00
animationPower = (animationPower === undefined ? 1 : animationPower); // linear is best
var row = rowsPresent[oldPosition];
2011-07-07 19:59:34 +02:00
if (row && oldPosition != newPosition)
{
2011-03-26 14:10:41 +01:00
var rowData = row.data;
removeRow(oldPosition, animationPower);
insertRow(newPosition, rowData, animationPower);
}
}
2011-07-07 19:59:34 +02:00
function animateStep()
{
2011-03-26 14:10:41 +01:00
// animation must be symmetrical
2011-07-07 19:59:34 +02:00
for (var i = rowsFadingIn.length - 1; i >= 0; i--)
{ // backwards to allow removal
2011-03-26 14:10:41 +01:00
var row = rowsFadingIn[i];
var step = ++row.animationStep;
var animHeight = getAnimationHeight(step, row.animationPower);
var node = rowNode(row);
var baseOpacity = (row.opacity === undefined ? 1 : row.opacity);
2011-07-07 19:59:34 +02:00
if (step <= -OPACITY_STEPS)
{
2011-03-26 14:10:41 +01:00
node.find("td").height(animHeight);
}
2011-07-07 19:59:34 +02:00
else if (step == -OPACITY_STEPS + 1)
{
node.html(getUserRowHtml(animHeight, row.data)).find("td").css('opacity', baseOpacity * 1 / OPACITY_STEPS);
2011-03-26 14:10:41 +01:00
handleRowNode(node, row.data);
}
2011-07-07 19:59:34 +02:00
else if (step < 0)
{
node.find("td").css('opacity', baseOpacity * (OPACITY_STEPS - (-step)) / OPACITY_STEPS).height(animHeight);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else if (step == 0)
{
2011-03-26 14:10:41 +01:00
// set HTML in case modified during animation
2011-07-07 19:59:34 +02:00
node.html(getUserRowHtml(animHeight, row.data)).find("td").css('opacity', baseOpacity * 1).height(animHeight);
2011-03-26 14:10:41 +01:00
handleRowNode(node, row.data);
rowsFadingIn.splice(i, 1); // remove from set
}
}
2011-07-07 19:59:34 +02:00
for (var i = rowsFadingOut.length - 1; i >= 0; i--)
{ // backwards to allow removal
2011-03-26 14:10:41 +01:00
var row = rowsFadingOut[i];
var step = ++row.animationStep;
var node = rowNode(row);
var animHeight = getAnimationHeight(step, row.animationPower);
var baseOpacity = (row.opacity === undefined ? 1 : row.opacity);
2011-07-07 19:59:34 +02:00
if (step < OPACITY_STEPS)
{
node.find("td").css('opacity', baseOpacity * (OPACITY_STEPS - step) / OPACITY_STEPS).height(animHeight);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else if (step == OPACITY_STEPS)
{
2011-03-26 14:10:41 +01:00
node.html(getEmptyRowHtml(animHeight));
}
2011-07-07 19:59:34 +02:00
else if (step <= ANIMATION_END)
{
2011-03-26 14:10:41 +01:00
node.find("td").height(animHeight);
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
rowsFadingOut.splice(i, 1); // remove from set
node.remove();
}
}
handleOtherUserInputs();
return (rowsFadingIn.length > 0) || (rowsFadingOut.length > 0); // is more to do
}
var self = {
insertRow: insertRow,
removeRow: removeRow,
moveRow: moveRow,
updateRow: updateRow
};
return self;
}()); ////////// rowManager
var otherUsersInfo = [];
var otherUsersData = [];
2011-07-07 19:59:34 +02:00
function rowManagerMakeNameEditor(jnode, userId)
{
setUpEditable(jnode, function()
{
2011-03-26 14:10:41 +01:00
var existingIndex = findExistingIndex(userId);
2011-07-07 19:59:34 +02:00
if (existingIndex >= 0)
{
2011-03-26 14:10:41 +01:00
return otherUsersInfo[existingIndex].name || '';
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
return '';
}
2011-07-07 19:59:34 +02:00
}, function(newName)
{
if (!newName)
{
2011-03-26 14:10:41 +01:00
jnode.addClass("editempty");
jnode.val(_('pad_userlist.unnamed'));
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
jnode.attr('disabled', 'disabled');
pad.suggestUserName(userId, newName);
}
});
}
2011-07-07 19:59:34 +02:00
function findExistingIndex(userId)
{
2011-03-26 14:10:41 +01:00
var existingIndex = -1;
2011-07-07 19:59:34 +02:00
for (var i = 0; i < otherUsersInfo.length; i++)
{
if (otherUsersInfo[i].userId == userId)
{
2011-03-26 14:10:41 +01:00
existingIndex = i;
break;
}
}
return existingIndex;
}
2011-07-07 19:59:34 +02:00
function setUpEditable(jqueryNode, valueGetter, valueSetter)
{
jqueryNode.bind('focus', function(evt)
{
2011-03-26 14:10:41 +01:00
var oldValue = valueGetter();
2011-07-07 19:59:34 +02:00
if (jqueryNode.val() !== oldValue)
{
2011-03-26 14:10:41 +01:00
jqueryNode.val(oldValue);
}
jqueryNode.addClass("editactive").removeClass("editempty");
});
2011-07-07 19:59:34 +02:00
jqueryNode.bind('blur', function(evt)
{
2011-03-26 14:10:41 +01:00
var newValue = jqueryNode.removeClass("editactive").val();
valueSetter(newValue);
});
2011-07-07 19:59:34 +02:00
padutils.bindEnterAndEscape(jqueryNode, function onEnter()
{
2011-03-26 14:10:41 +01:00
jqueryNode.blur();
2011-07-07 19:59:34 +02:00
}, function onEscape()
{
2011-03-26 14:10:41 +01:00
jqueryNode.val(valueGetter()).blur();
});
jqueryNode.removeAttr('disabled').addClass('editable');
}
2011-07-07 19:59:34 +02:00
function updateInviteNotice()
{
if (otherUsersInfo.length == 0)
{
2011-03-26 14:10:41 +01:00
$("#otheruserstable").hide();
$("#nootherusers").show();
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
$("#nootherusers").hide();
$("#otheruserstable").show();
}
}
var knocksToIgnore = {};
var guestPromptFlashState = 0;
var guestPromptFlash = padutils.makeAnimationScheduler(
2011-07-07 19:59:34 +02:00
function()
{
var prompts = $("#guestprompts .guestprompt");
if (prompts.length == 0)
{
return false; // no more to do
}
guestPromptFlashState = 1 - guestPromptFlashState;
if (guestPromptFlashState)
{
prompts.css('background', '#ffa');
}
else
{
prompts.css('background', '#ffe');
}
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
return true;
}, 1000);
2011-03-26 14:10:41 +01:00
var pad = undefined;
2011-03-26 14:10:41 +01:00
var self = {
init: function(myInitialUserInfo, _pad)
2011-07-07 19:59:34 +02:00
{
pad = _pad;
2011-03-26 14:10:41 +01:00
self.setMyUserInfo(myInitialUserInfo);
2011-04-07 21:08:41 +02:00
2011-03-26 14:10:41 +01:00
$("#otheruserstable tr").remove();
2011-07-07 19:59:34 +02:00
if (pad.getUserIsGuest())
{
2011-03-26 14:10:41 +01:00
$("#myusernameedit").addClass('myusernameedithoverable');
2011-07-07 19:59:34 +02:00
setUpEditable($("#myusernameedit"), function()
{
return myUserInfo.name || '';
}, function(newValue)
{
myUserInfo.name = newValue;
pad.notifyChangeName(newValue);
// wrap with setTimeout to do later because we get
// a double "blur" fire in IE...
window.setTimeout(function()
{
self.renderMyUserInfo();
}, 0);
});
2011-03-26 14:10:41 +01:00
}
// color picker
$("#myswatchbox").click(showColorPicker);
2011-07-07 19:59:34 +02:00
$("#mycolorpicker .pickerswatchouter").click(function()
{
2011-03-26 14:10:41 +01:00
$("#mycolorpicker .pickerswatchouter").removeClass('picked');
$(this).addClass('picked');
});
2011-07-07 19:59:34 +02:00
$("#mycolorpickersave").click(function()
{
2011-03-26 14:10:41 +01:00
closeColorPicker(true);
});
2011-07-07 19:59:34 +02:00
$("#mycolorpickercancel").click(function()
{
2011-03-26 14:10:41 +01:00
closeColorPicker(false);
});
//
},
2011-07-07 19:59:34 +02:00
setMyUserInfo: function(info)
{
//translate the colorId
if(typeof info.colorId == "number")
{
info.colorId = clientVars.colorPalette[info.colorId];
}
2011-07-07 19:59:34 +02:00
myUserInfo = $.extend(
{}, info);
2011-03-26 14:10:41 +01:00
2011-04-07 20:45:28 +02:00
self.renderMyUserInfo();
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
userJoinOrUpdate: function(info)
{
if ((!info.userId) || (info.userId == myUserInfo.userId))
{
2011-03-26 14:10:41 +01:00
// not sure how this would happen
return;
}
hooks.callAll('userJoinOrUpdate', {
userInfo: info
});
2011-03-26 14:10:41 +01:00
var userData = {};
userData.color = typeof info.colorId == "number" ? clientVars.colorPalette[info.colorId] : info.colorId;
2011-03-26 14:10:41 +01:00
userData.name = info.name;
userData.status = '';
userData.activity = '';
userData.id = info.userId;
// Firefox ignores \n in title text; Safari does a linebreak
2011-07-07 19:59:34 +02:00
userData.titleText = [info.userAgent || '', info.ip || ''].join(' \n');
2011-03-26 14:10:41 +01:00
var existingIndex = findExistingIndex(info.userId);
var numUsersBesides = otherUsersInfo.length;
2011-07-07 19:59:34 +02:00
if (existingIndex >= 0)
{
2011-03-26 14:10:41 +01:00
numUsersBesides--;
}
2011-07-07 19:59:34 +02:00
var newIndex = padutils.binarySearch(numUsersBesides, function(n)
{
if (existingIndex >= 0 && n >= existingIndex)
{
2011-03-26 14:10:41 +01:00
// pretend existingIndex isn't there
n++;
}
var infoN = otherUsersInfo[n];
2011-07-07 19:59:34 +02:00
var nameN = (infoN.name || '').toLowerCase();
var nameThis = (info.name || '').toLowerCase();
2011-03-26 14:10:41 +01:00
var idN = infoN.userId;
var idThis = info.userId;
2011-07-07 19:59:34 +02:00
return (nameN > nameThis) || (nameN == nameThis && idN > idThis);
2011-03-26 14:10:41 +01:00
});
2011-07-07 19:59:34 +02:00
if (existingIndex >= 0)
{
2011-03-26 14:10:41 +01:00
// update
2011-07-07 19:59:34 +02:00
if (existingIndex == newIndex)
{
2011-03-26 14:10:41 +01:00
otherUsersInfo[existingIndex] = info;
otherUsersData[existingIndex] = userData;
rowManager.updateRow(existingIndex, userData);
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
otherUsersInfo.splice(existingIndex, 1);
otherUsersData.splice(existingIndex, 1);
otherUsersInfo.splice(newIndex, 0, info);
otherUsersData.splice(newIndex, 0, userData);
rowManager.updateRow(existingIndex, userData);
rowManager.moveRow(existingIndex, newIndex);
}
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
otherUsersInfo.splice(newIndex, 0, info);
otherUsersData.splice(newIndex, 0, userData);
rowManager.insertRow(newIndex, userData);
}
2011-07-07 19:59:34 +02:00
updateInviteNotice();
2011-04-07 21:34:06 +02:00
self.updateNumberOfOnlineUsers();
2011-04-07 21:18:49 +02:00
},
2011-07-07 19:59:34 +02:00
updateNumberOfOnlineUsers: function()
{
2011-04-07 21:18:49 +02:00
var online = 1; // you are always online!
2011-07-07 19:59:34 +02:00
for (var i = 0; i < otherUsersData.length; i++)
{
if (otherUsersData[i].status == "")
2011-04-07 21:18:49 +02:00
{
online++;
}
}
$("#online_count").text(online);
2011-07-07 19:59:34 +02:00
2011-04-07 21:18:49 +02:00
return online;
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
userLeave: function(info)
{
2011-03-26 14:10:41 +01:00
var existingIndex = findExistingIndex(info.userId);
2011-07-07 19:59:34 +02:00
if (existingIndex >= 0)
{
2011-03-26 14:10:41 +01:00
var userData = otherUsersData[existingIndex];
userData.status = 'Disconnected';
rowManager.updateRow(existingIndex, userData);
2011-07-07 19:59:34 +02:00
if (userData.leaveTimer)
{
2011-03-26 14:10:41 +01:00
window.clearTimeout(userData.leaveTimer);
}
// set up a timer that will only fire if no leaves,
// joins, or updates happen for this user in the
// next N seconds, to remove the user from the list.
var thisUserId = info.userId;
2011-07-07 19:59:34 +02:00
var thisLeaveTimer = window.setTimeout(function()
{
2011-03-26 14:10:41 +01:00
var newExistingIndex = findExistingIndex(thisUserId);
2011-07-07 19:59:34 +02:00
if (newExistingIndex >= 0)
{
2011-03-26 14:10:41 +01:00
var newUserData = otherUsersData[newExistingIndex];
2011-07-07 19:59:34 +02:00
if (newUserData.status == 'Disconnected' && newUserData.leaveTimer == thisLeaveTimer)
{
2011-03-26 14:10:41 +01:00
otherUsersInfo.splice(newExistingIndex, 1);
otherUsersData.splice(newExistingIndex, 1);
rowManager.removeRow(newExistingIndex);
updateInviteNotice();
}
}
}, 8000); // how long to wait
userData.leaveTimer = thisLeaveTimer;
}
2011-07-07 19:59:34 +02:00
updateInviteNotice();
self.updateNumberOfOnlineUsers();
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
showGuestPrompt: function(userId, displayName)
{
if (knocksToIgnore[userId])
{
2011-03-26 14:10:41 +01:00
return;
}
var encodedUserId = padutils.encodeUserId(userId);
2011-07-07 19:59:34 +02:00
var actionName = 'hide-guest-prompt-' + encodedUserId;
2011-03-26 14:10:41 +01:00
padutils.cancelActions(actionName);
2011-07-07 19:59:34 +02:00
var box = $("#guestprompt-" + encodedUserId);
if (box.length == 0)
{
2011-03-26 14:10:41 +01:00
// make guest prompt box
box = $('<div id="'+padutils.escapeHtml('guestprompt-' + encodedUserId) + '" class="guestprompt"><div class="choices"><a href="' + padutils.escapeHtml('javascript:void(require('+JSON.stringify(module.id)+').paduserlist.answerGuestPrompt(' + JSON.stringify(encodedUserId) + ',false))')+'">'+_('pad_userlist.deny')+'</a> <a href="' + padutils.escapeHtml('javascript:void(require('+JSON.stringify(module.id)+').paduserlist.answerGuestPrompt(' + JSON.stringify(encodedUserId) + ',true))') + '">'+_('pad_userlist.approve')+'</a></div><div class="guestname"><strong>'+_('pad_userlist.guest')+':</strong> ' + padutils.escapeHtml(displayName) + '</div></div>');
2011-03-26 14:10:41 +01:00
$("#guestprompts").append(box);
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
// update display name
box.find(".guestname").html('<strong>'+_('pad_userlist.guest')+':</strong> ' + padutils.escapeHtml(displayName));
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
var hideLater = padutils.getCancellableAction(actionName, function()
{
2011-03-26 14:10:41 +01:00
self.removeGuestPrompt(userId);
});
window.setTimeout(hideLater, 15000); // time-out with no knock
guestPromptFlash.scheduleAnimation();
},
2011-07-07 19:59:34 +02:00
removeGuestPrompt: function(userId)
{
var box = $("#guestprompt-" + padutils.encodeUserId(userId));
2011-03-26 14:10:41 +01:00
// remove ID now so a new knock by same user gets new, unfaded box
2011-07-07 19:59:34 +02:00
box.removeAttr('id').fadeOut("fast", function()
{
2011-03-26 14:10:41 +01:00
box.remove();
});
knocksToIgnore[userId] = true;
2011-07-07 19:59:34 +02:00
window.setTimeout(function()
{
2011-03-26 14:10:41 +01:00
delete knocksToIgnore[userId];
}, 5000);
},
2011-07-07 19:59:34 +02:00
answerGuestPrompt: function(encodedUserId, approve)
{
2011-03-26 14:10:41 +01:00
var guestId = padutils.decodeUserId(encodedUserId);
var msg = {
type: 'guestanswer',
authId: pad.getUserId(),
guestId: guestId,
answer: (approve ? "approved" : "denied")
};
pad.sendClientMessage(msg);
self.removeGuestPrompt(guestId);
2011-04-07 20:45:28 +02:00
},
2011-07-07 19:59:34 +02:00
renderMyUserInfo: function()
{
if (myUserInfo.name)
{
2011-04-07 20:45:28 +02:00
$("#myusernameedit").removeClass("editempty").val(
2011-07-07 19:59:34 +02:00
myUserInfo.name);
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
else
{
$("#myusernameedit").addClass("editempty").val(_("pad_userlist.entername"));
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
if (colorPickerOpen)
{
$("#myswatchbox").addClass('myswatchboxunhoverable').removeClass('myswatchboxhoverable');
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
else
{
$("#myswatchbox").addClass('myswatchboxhoverable').removeClass('myswatchboxunhoverable');
2011-04-07 20:45:28 +02:00
}
2011-08-20 19:22:10 +02:00
$("#myswatch").css({'background-color': myUserInfo.colorId});
if ($.browser.msie && parseInt($.browser.version) <= 8) {
2012-03-01 00:29:08 +01:00
$("#usericon a").css({'box-shadow': 'inset 0 0 30px ' + myUserInfo.colorId,'background-color': myUserInfo.colorId});
}
else
{
2012-03-01 00:29:08 +01:00
$("#usericon a").css({'box-shadow': 'inset 0 0 30px ' + myUserInfo.colorId});
}
2011-03-26 14:10:41 +01:00
}
};
return self;
2011-04-07 20:45:28 +02:00
}());
2011-07-07 19:59:34 +02:00
function getColorPickerSwatchIndex(jnode)
{
// return Number(jnode.get(0).className.match(/\bn([0-9]+)\b/)[1])-1;
2011-04-07 20:45:28 +02:00
return $("#colorpickerswatches li").index(jnode);
}
2011-07-07 19:59:34 +02:00
function closeColorPicker(accept)
{
if (accept)
2011-08-20 19:22:10 +02:00
{
var newColor = $("#mycolorpickerpreview").css("background-color");
var parts = newColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
// parts now should be ["rgb(0, 70, 255", "0", "70", "255"]
if (parts) {
delete (parts[0]);
for (var i = 1; i <= 3; ++i) {
parts[i] = parseInt(parts[i]).toString(16);
if (parts[i].length == 1) parts[i] = '0' + parts[i];
}
var newColor = "#" +parts.join(''); // "0070ff"
2011-04-07 20:45:28 +02:00
}
2011-08-20 19:22:10 +02:00
myUserInfo.colorId = newColor;
pad.notifyChangeColor(newColor);
2011-04-07 20:45:28 +02:00
paduserlist.renderMyUserInfo();
2011-07-07 19:59:34 +02:00
}
else
{
2011-08-20 19:22:10 +02:00
//pad.notifyChangeColor(previousColorId);
//paduserlist.renderMyUserInfo();
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
colorPickerOpen = false;
2011-07-06 15:08:20 +02:00
$("#mycolorpicker").fadeOut("fast");
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
function showColorPicker()
{
previousColorId = myUserInfo.colorId;
2011-04-07 20:45:28 +02:00
2011-07-07 19:59:34 +02:00
if (!colorPickerOpen)
{
2011-04-07 20:45:28 +02:00
var palette = pad.getColorPalette();
2011-07-07 19:59:34 +02:00
if (!colorPickerSetup)
{
2011-04-07 20:45:28 +02:00
var colorsList = $("#colorpickerswatches")
2011-07-07 19:59:34 +02:00
for (var i = 0; i < palette.length; i++)
{
2011-04-07 20:45:28 +02:00
var li = $('<li>', {
2011-07-07 19:59:34 +02:00
style: 'background: ' + palette[i] + ';'
2011-04-07 20:45:28 +02:00
});
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
li.appendTo(colorsList);
2011-07-07 19:59:34 +02:00
li.bind('click', function(event)
{
2011-04-07 20:45:28 +02:00
$("#colorpickerswatches li").removeClass('picked');
$(event.target).addClass("picked");
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
var newColorId = getColorPickerSwatchIndex($("#colorpickerswatches .picked"));
pad.notifyChangeColor(newColorId);
});
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
}
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
colorPickerSetup = true;
}
2011-07-07 19:59:34 +02:00
2011-07-06 15:08:20 +02:00
$("#mycolorpicker").fadeIn();
2011-04-07 20:45:28 +02:00
colorPickerOpen = true;
2011-07-07 19:59:34 +02:00
2011-04-07 20:45:28 +02:00
$("#colorpickerswatches li").removeClass('picked');
$($("#colorpickerswatches li")[myUserInfo.colorId]).addClass("picked"); //seems weird
2011-07-07 19:59:34 +02:00
}
2011-07-06 15:08:20 +02:00
}
exports.paduserlist = paduserlist;