pad: Fix initialization race condition

Ensure that `padeditbar.init()` is called before setting up
`pad.collabClient` to avoid the following exception when there is an
error connecting:

    TypeError: Cannot read property 'length' of undefined
        at Object.toggleDropDown
        at Object.showModal
        at Object.disconnected
        at r.<anonymous>
        at r.emit
        at r.onevent
        at r.onpacket
        at r.<anonymous>
        at r.emit
        at r.ondecoded
rhansen-collab_client
Richard Hansen 2021-03-30 19:55:35 -04:00
parent a18f5de0fc
commit 8ef84e5350
1 changed files with 47 additions and 48 deletions

View File

@ -283,7 +283,7 @@ const handshake = () => {
// just annoys users and fills logs.
});
socket.on('message', (obj) => {
socket.on('message', async (obj) => {
// the access was not granted, give the user a message
if (obj.accessStatus) {
if (obj.accessStatus === 'deny') {
@ -304,7 +304,7 @@ const handshake = () => {
window.clientVars = obj.data;
// initialize the pad
pad._afterHandshake();
await pad._afterHandshake();
if (clientVars.readonly) {
chat.hide();
@ -444,7 +444,7 @@ const pad = {
padcookie.init();
});
},
_afterHandshake() {
async _afterHandshake() {
pad.clientTimeOffset = Date.now() - clientVars.serverTimestamp;
// initialize the chat
chat.init(this);
@ -461,8 +461,37 @@ const pad = {
colorId: clientVars.userColor,
};
const postAceInit = () => {
padimpexp.init(this);
padsavedrevs.init(this);
paduserlist.init(pad.myUserInfo, this);
padconnectionstatus.init();
padmodals.init(this);
// padeditor.init() should be called late because it hides #editorloadingbox, which tests use as
// a signal that the pad is ready.
await padeditor.init(pad.padOptions.view || {}, this);
padeditbar.init();
pad.collabClient = getCollabClient(
padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo,
{colorPalette: pad.getColorPalette()}, pad);
pad.collabClient.setOnUserJoin(pad.handleUserJoin);
pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate);
pad.collabClient.setOnUserLeave(pad.handleUserLeave);
pad.collabClient.setOnClientMessage(pad.handleClientMessage);
pad.collabClient.setOnChannelStateChange(pad.handleChannelStateChange);
pad.collabClient.setOnInternalAction(pad.handleCollabAction);
pad.collabClient.setChannelState('CONNECTED');
// load initial chat-messages
if (clientVars.chatHead !== -1) {
const chatHead = clientVars.chatHead;
const start = Math.max(chatHead - 100, 0);
pad.collabClient.sendMessage({type: 'GET_CHAT_MESSAGES', start, end: chatHead});
} else {
// there are no messages
$('#chatloadmessagesbutton').css('display', 'none');
}
setTimeout(() => {
padeditor.ace.focus();
}, 0);
@ -501,37 +530,7 @@ const pad = {
$('#editorcontainer').addClass('initialized');
hooks.aCallAll('postAceInit', {ace: padeditor.ace, clientVars, pad});
};
// order of inits is important here:
padimpexp.init(this);
padsavedrevs.init(this);
padeditor.init(pad.padOptions.view || {}, this).then(postAceInit);
paduserlist.init(pad.myUserInfo, this);
padconnectionstatus.init();
padmodals.init(this);
pad.collabClient = getCollabClient(
padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo,
{colorPalette: pad.getColorPalette()}, pad);
pad.collabClient.setOnUserJoin(pad.handleUserJoin);
pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate);
pad.collabClient.setOnUserLeave(pad.handleUserLeave);
pad.collabClient.setOnClientMessage(pad.handleClientMessage);
pad.collabClient.setOnChannelStateChange(pad.handleChannelStateChange);
pad.collabClient.setOnInternalAction(pad.handleCollabAction);
pad.collabClient.setChannelState('CONNECTED');
// load initial chat-messages
if (clientVars.chatHead !== -1) {
const chatHead = clientVars.chatHead;
const start = Math.max(chatHead - 100, 0);
pad.collabClient.sendMessage({type: 'GET_CHAT_MESSAGES', start, end: chatHead});
} else {
// there are no messages
$('#chatloadmessagesbutton').css('display', 'none');
}
await hooks.aCallAll('postAceInit', {ace: padeditor.ace, clientVars, pad});
},
dispose: () => {
padeditor.dispose();