lint: pad prefix files (#4577)

* lint: pad_connectionstatus

* lint: pad_utils

* lint: pad_userlist.js -- still WIP

* shift underscore not to be in require but to be used from window

* lint: pad_modals

* pad_impexp.js

* lint: more errors done

* lint: auto reconn

* lint: pad_editor

* lint: finish auto reconn

* lint: imp exp rework

* lint: import

* lint: pad.js nearly done but pizza here...

* lint: clientVars global query

* put clientVars in window

* Revert incorrect lint fixes

* Properly fix guard-for-in lint errors

* Properly fix no-unused-vars error regarding `gritter`

* Refine lint fixes

Co-authored-by: Richard Hansen <rhansen@rhansen.org>
This commit is contained in:
John McLear 2020-12-20 07:15:58 +00:00 committed by GitHub
parent 34ee77993f
commit 0362d3b05d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 512 additions and 459 deletions

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -20,8 +22,6 @@
* limitations under the License. * limitations under the License.
*/ */
/* global $, window */
let socket; let socket;
// These jQuery things should create local references, but for now `require()` // These jQuery things should create local references, but for now `require()`
@ -43,24 +43,13 @@ const padsavedrevs = require('./pad_savedrevs');
const paduserlist = require('./pad_userlist').paduserlist; const paduserlist = require('./pad_userlist').paduserlist;
const padutils = require('./pad_utils').padutils; const padutils = require('./pad_utils').padutils;
const colorutils = require('./colorutils').colorutils; const colorutils = require('./colorutils').colorutils;
var randomString = require('./pad_utils').randomString; const randomString = require('./pad_utils').randomString;
const gritter = require('./gritter').gritter; require('./gritter'); // Mutates the jQuery object to make $.gritter available.
const hooks = require('./pluginfw/hooks'); const hooks = require('./pluginfw/hooks');
let receivedClientVars = false; let receivedClientVars = false;
function randomString() {
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
const string_length = 20;
let randomstring = '';
for (let i = 0; i < string_length; i++) {
const rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return `t.${randomstring}`;
}
// This array represents all GET-parameters which can be used to change a setting. // This array represents all GET-parameters which can be used to change a setting.
// name: the parameter-name, eg `?noColors=true` => `noColors` // name: the parameter-name, eg `?noColors=true` => `noColors`
// checkVal: the callback is only executed when // checkVal: the callback is only executed when
@ -68,26 +57,101 @@ function randomString() {
// * the parameter was supplied and checkVal is null // * the parameter was supplied and checkVal is null
// callback: the function to call when all above succeeds, `val` is the value supplied by the user // callback: the function to call when all above succeeds, `val` is the value supplied by the user
const getParameters = [ const getParameters = [
{name: 'noColors', checkVal: 'true', callback(val) { settings.noColors = true; $('#clearAuthorship').hide(); }}, {
{name: 'showControls', checkVal: 'true', callback(val) { $('#editbar').css('display', 'flex'); }}, name: 'noColors',
{name: 'showChat', checkVal: null, callback(val) { if (val === 'false') { settings.hideChat = true; chat.hide(); $('#chaticon').hide(); } }}, checkVal: 'true',
{name: 'showLineNumbers', checkVal: 'false', callback(val) { settings.LineNumbersDisabled = true; }}, callback: (val) => {
{name: 'useMonospaceFont', checkVal: 'true', callback(val) { settings.useMonospaceFontGlobal = true; }}, settings.noColors = true;
// If the username is set as a parameter we should set a global value that we can call once we have initiated the pad. $('#clearAuthorship').hide();
{name: 'userName', checkVal: null, callback(val) { settings.globalUserName = decodeURIComponent(val); clientVars.userName = decodeURIComponent(val); }}, },
// If the userColor is set as a parameter, set a global value to use once we have initiated the pad. },
{name: 'userColor', checkVal: null, callback(val) { settings.globalUserColor = decodeURIComponent(val); clientVars.userColor = decodeURIComponent(val); }}, {
{name: 'rtl', checkVal: 'true', callback(val) { settings.rtlIsTrue = true; }}, name: 'showControls',
{name: 'alwaysShowChat', checkVal: 'true', callback(val) { if (!settings.hideChat) chat.stickToScreen(); }}, checkVal: 'true',
{name: 'chatAndUsers', checkVal: 'true', callback(val) { chat.chatAndUsers(); }}, callback: (val) => {
{name: 'lang', checkVal: null, callback(val) { window.html10n.localize([val, 'en']); Cookies.set('language', val); }}, $('#editbar').css('display', 'flex');
},
},
{
name: 'showChat',
checkVal: null,
callback: (val) => {
if (val === 'false') {
settings.hideChat = true;
chat.hide();
$('#chaticon').hide();
}
},
},
{
name: 'showLineNumbers',
checkVal: 'false',
callback: (val) => {
settings.LineNumbersDisabled = true;
},
},
{
name: 'useMonospaceFont',
checkVal: 'true',
callback: (val) => {
settings.useMonospaceFontGlobal = true;
},
},
// If the username is set as a parameter we should set a global value that we can call once we
// have initiated the pad.
{
name: 'userName',
checkVal: null,
callback: (val) => {
settings.globalUserName = decodeURIComponent(val);
clientVars.userName = decodeURIComponent(val);
},
},
// If the userColor is set as a parameter, set a global value to use once we have initiated the
// pad.
{
name: 'userColor',
checkVal: null,
callback: (val) => {
settings.globalUserColor = decodeURIComponent(val);
clientVars.userColor = decodeURIComponent(val);
},
},
{
name: 'rtl',
checkVal: 'true',
callback: (val) => {
settings.rtlIsTrue = true;
},
},
{
name: 'alwaysShowChat',
checkVal: 'true',
callback: (val) => {
if (!settings.hideChat) chat.stickToScreen();
},
},
{
name: 'chatAndUsers',
checkVal: 'true',
callback: (val) => {
chat.chatAndUsers();
},
},
{
name: 'lang',
checkVal: null,
callback: (val) => {
window.html10n.localize([val, 'en']);
Cookies.set('language', val);
},
},
]; ];
function getParams() { const getParams = () => {
// Tries server enforced options first.. // Tries server enforced options first..
for (var i = 0; i < getParameters.length; i++) { for (const setting of getParameters) {
var setting = getParameters[i]; const value = clientVars.padOptions[setting.name];
var value = clientVars.padOptions[setting.name];
if (value.toString() === setting.checkVal) { if (value.toString() === setting.checkVal) {
setting.callback(value); setting.callback(value);
} }
@ -96,19 +160,18 @@ function getParams() {
// Then URL applied stuff // Then URL applied stuff
const params = getUrlVars(); const params = getUrlVars();
for (var i = 0; i < getParameters.length; i++) { for (const setting of getParameters) {
var setting = getParameters[i]; const value = params[setting.name];
var value = params[setting.name];
if (value && (value == setting.checkVal || setting.checkVal == null)) { if (value && (value === setting.checkVal || setting.checkVal == null)) {
setting.callback(value); setting.callback(value);
} }
} }
} };
function getUrlVars() { const getUrlVars = () => {
const vars = []; let const vars = [];
hash; let hash;
const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for (let i = 0; i < hashes.length; i++) { for (let i = 0; i < hashes.length; i++) {
hash = hashes[i].split('='); hash = hashes[i].split('=');
@ -116,12 +179,13 @@ function getUrlVars() {
vars[hash[0]] = hash[1]; vars[hash[0]] = hash[1];
} }
return vars; return vars;
} };
function sendClientReady(isReconnect, messageType) { const sendClientReady = (isReconnect, messageType) => {
messageType = typeof messageType !== 'undefined' ? messageType : 'CLIENT_READY'; messageType = typeof messageType !== 'undefined' ? messageType : 'CLIENT_READY';
let padId = document.location.pathname.substring(document.location.pathname.lastIndexOf('/') + 1); let padId = document.location.pathname.substring(document.location.pathname.lastIndexOf('/') + 1);
padId = decodeURIComponent(padId); // unescape neccesary due to Safari and Opera interpretation of spaces // unescape neccesary due to Safari and Opera interpretation of spaces
padId = decodeURIComponent(padId);
if (!isReconnect) { if (!isReconnect) {
const titleArray = document.title.split('|'); const titleArray = document.title.split('|');
@ -151,12 +215,12 @@ function sendClientReady(isReconnect, messageType) {
} }
socket.json.send(msg); socket.json.send(msg);
} };
function handshake() { const handshake = () => {
const loc = document.location; const loc = document.location;
// get the correct port // get the correct port
const port = loc.port == '' ? (loc.protocol == 'https:' ? 443 : 80) : loc.port; const port = loc.port === '' ? (loc.protocol === 'https:' ? 443 : 80) : loc.port;
// create the url // create the url
const url = `${loc.protocol}//${loc.hostname}:${port}/`; const url = `${loc.protocol}//${loc.hostname}:${port}/`;
// find out in which subfolder we are // find out in which subfolder we are
@ -211,12 +275,10 @@ function handshake() {
throw new Error(`socket.io connection error: ${JSON.stringify(error)}`); throw new Error(`socket.io connection error: ${JSON.stringify(error)}`);
}); });
let initalized = false;
socket.on('message', (obj) => { socket.on('message', (obj) => {
// the access was not granted, give the user a message // the access was not granted, give the user a message
if (obj.accessStatus) { if (obj.accessStatus) {
if (obj.accessStatus == 'deny') { if (obj.accessStatus === 'deny') {
$('#loading').hide(); $('#loading').hide();
$('#permissionDenied').show(); $('#permissionDenied').show();
@ -226,18 +288,15 @@ function handshake() {
$('#editorloadingbox').show(); $('#editorloadingbox').show();
} }
} }
} } else if (!receivedClientVars && obj.type === 'CLIENT_VARS') {
// if we haven't recieved the clientVars yet, then this message should it be
// if we haven't recieved the clientVars yet, then this message should it be
else if (!receivedClientVars && obj.type == 'CLIENT_VARS') {
receivedClientVars = true; receivedClientVars = true;
// set some client vars // set some client vars
clientVars = obj.data; window.clientVars = obj.data;
// initalize the pad // initalize the pad
pad._afterHandshake(); pad._afterHandshake();
initalized = true;
if (clientVars.readonly) { if (clientVars.readonly) {
chat.hide(); chat.hide();
@ -255,63 +314,61 @@ function handshake() {
}); });
// If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers // If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers
if (settings.LineNumbersDisabled == true) { if (settings.LineNumbersDisabled === true) {
pad.changeViewOption('showLineNumbers', false); pad.changeViewOption('showLineNumbers', false);
} }
// If the noColors value is set to true then we need to hide the background colors on the ace spans // If the noColors value is set to true then we need to
if (settings.noColors == true) { // hide the background colors on the ace spans
if (settings.noColors === true) {
pad.changeViewOption('noColors', true); pad.changeViewOption('noColors', true);
} }
if (settings.rtlIsTrue == true) { if (settings.rtlIsTrue === true) {
pad.changeViewOption('rtlIsTrue', true); pad.changeViewOption('rtlIsTrue', true);
} }
// If the Monospacefont value is set to true then change it to monospace. // If the Monospacefont value is set to true then change it to monospace.
if (settings.useMonospaceFontGlobal == true) { if (settings.useMonospaceFontGlobal === true) {
pad.changeViewOption('padFontFamily', 'monospace'); pad.changeViewOption('padFontFamily', 'monospace');
} }
// if the globalUserName value is set we need to tell the server and the client about the new authorname // if the globalUserName value is set we need to tell the server and
// the client about the new authorname
if (settings.globalUserName !== false) { if (settings.globalUserName !== false) {
pad.notifyChangeName(settings.globalUserName); // Notifies the server pad.notifyChangeName(settings.globalUserName); // Notifies the server
pad.myUserInfo.name = settings.globalUserName; pad.myUserInfo.name = settings.globalUserName;
$('#myusernameedit').val(settings.globalUserName); // Updates the current users UI $('#myusernameedit').val(settings.globalUserName); // Updates the current users UI
} }
if (settings.globalUserColor !== false && colorutils.isCssHex(settings.globalUserColor)) { if (settings.globalUserColor !== false && colorutils.isCssHex(settings.globalUserColor)) {
// Add a 'globalUserColor' property to myUserInfo, so collabClient knows we have a query parameter. // Add a 'globalUserColor' property to myUserInfo,
// so collabClient knows we have a query parameter.
pad.myUserInfo.globalUserColor = settings.globalUserColor; pad.myUserInfo.globalUserColor = settings.globalUserColor;
pad.notifyChangeColor(settings.globalUserColor); // Updates pad.myUserInfo.colorId pad.notifyChangeColor(settings.globalUserColor); // Updates pad.myUserInfo.colorId
paduserlist.setMyUserInfo(pad.myUserInfo); paduserlist.setMyUserInfo(pad.myUserInfo);
} }
} } else if (obj.disconnect) {
// This handles every Message after the clientVars padconnectionstatus.disconnected(obj.disconnect);
else { socket.disconnect();
// this message advices the client to disconnect
if (obj.disconnect) {
padconnectionstatus.disconnected(obj.disconnect);
socket.disconnect();
// block user from making any change to the pad // block user from making any change to the pad
padeditor.disable(); padeditor.disable();
padeditbar.disable(); padeditbar.disable();
padimpexp.disable(); padimpexp.disable();
return; return;
} else { } else {
pad.collabClient.handleMessageFromServer(obj); pad.collabClient.handleMessageFromServer(obj);
}
} }
}); });
// Bind the colorpicker // Bind the colorpicker
const fb = $('#colorpicker').farbtastic({callback: '#mycolorpickerpreview', width: 220}); $('#colorpicker').farbtastic({callback: '#mycolorpickerpreview', width: 220});
// Bind the read only button // Bind the read only button
$('#readonlyinput').on('click', () => { $('#readonlyinput').on('click', () => {
padeditbar.setEmbedLinks(); padeditbar.setEmbedLinks();
}); });
} };
var pad = { const pad = {
// don't access these directly from outside this file, except // don't access these directly from outside this file, except
// for debugging // for debugging
collabClient: null, collabClient: null,
@ -322,44 +379,28 @@ var pad = {
padOptions: {}, padOptions: {},
// these don't require init; clientVars should all go through here // these don't require init; clientVars should all go through here
getPadId() { getPadId: () => clientVars.padId,
return clientVars.padId; getClientIp: () => clientVars.clientIp,
}, getColorPalette: () => clientVars.colorPalette,
getClientIp() { getIsDebugEnabled: () => clientVars.debugEnabled,
return clientVars.clientIp; getPrivilege: (name) => clientVars.accountPrivs[name],
}, getUserId: () => pad.myUserInfo.userId,
getColorPalette() { getUserName: () => pad.myUserInfo.name,
return clientVars.colorPalette; userList: () => paduserlist.users(),
}, switchToPad: (padId) => {
getIsDebugEnabled() { let newHref = new RegExp(/.*\/p\/[^/]+/).exec(document.location.pathname) || clientVars.padId;
return clientVars.debugEnabled;
},
getPrivilege(name) {
return clientVars.accountPrivs[name];
},
getUserId() {
return pad.myUserInfo.userId;
},
getUserName() {
return pad.myUserInfo.name;
},
userList() {
return paduserlist.users();
},
switchToPad(padId) {
let newHref = new RegExp(/.*\/p\/[^\/]+/).exec(document.location.pathname) || clientVars.padId;
newHref = newHref[0]; newHref = newHref[0];
const options = clientVars.padOptions; const options = clientVars.padOptions;
if (typeof options !== 'undefined' && options != null) { if (typeof options !== 'undefined' && options != null) {
var option_str = []; const optionArr = [];
$.each(options, (k, v) => { $.each(options, (k, v) => {
const str = `${k}=${v}`; const str = `${k}=${v}`;
option_str.push(str); optionArr.push(str);
}); });
var option_str = option_str.join('&'); const optionStr = optionArr.join('&');
newHref = `${newHref}?${option_str}`; newHref = `${newHref}?${optionStr}`;
} }
// destroy old pad from DOM // destroy old pad from DOM
@ -373,21 +414,21 @@ var pad = {
window.history.pushState('', '', newHref); window.history.pushState('', '', newHref);
receivedClientVars = false; receivedClientVars = false;
sendClientReady(false, 'SWITCH_TO_PAD'); sendClientReady(false, 'SWITCH_TO_PAD');
} else // fallback } else {
{ // fallback
window.location.href = newHref; window.location.href = newHref;
} }
}, },
sendClientMessage(msg) { sendClientMessage: (msg) => {
pad.collabClient.sendClientMessage(msg); pad.collabClient.sendClientMessage(msg);
}, },
init() { init: () => {
padutils.setupGlobalExceptionHandler(); padutils.setupGlobalExceptionHandler();
$(document).ready(() => { $(document).ready(() => {
// start the custom js // start the custom js
if (typeof customStart === 'function') customStart(); if (typeof customStart === 'function') customStart(); // eslint-disable-line no-undef
handshake(); handshake();
// To use etherpad you have to allow cookies. // To use etherpad you have to allow cookies.
@ -406,7 +447,6 @@ var pad = {
pad.initTime = +(new Date()); pad.initTime = +(new Date());
pad.padOptions = clientVars.initialOptions; pad.padOptions = clientVars.initialOptions;
// order of inits is important here:
pad.myUserInfo = { pad.myUserInfo = {
userId: clientVars.userId, userId: clientVars.userId,
name: clientVars.userName, name: clientVars.userName,
@ -414,18 +454,60 @@ var pad = {
colorId: clientVars.userColor, colorId: clientVars.userColor,
}; };
const postAceInit = () => {
padeditbar.init();
setTimeout(() => {
padeditor.ace.focus();
}, 0);
// if we have a cookie for always showing chat then show it
if (padcookie.getPref('chatAlwaysVisible')) {
chat.stickToScreen(true); // stick it to the screen
$('#options-stickychat').prop('checked', true); // set the checkbox to on
}
// if we have a cookie for always showing chat then show it
if (padcookie.getPref('chatAndUsers')) {
chat.chatAndUsers(true); // stick it to the screen
$('#options-chatandusers').prop('checked', true); // set the checkbox to on
}
if (padcookie.getPref('showAuthorshipColors') === false) {
pad.changeViewOption('showAuthorColors', false);
}
if (padcookie.getPref('showLineNumbers') === false) {
pad.changeViewOption('showLineNumbers', false);
}
if (padcookie.getPref('rtlIsTrue') === true) {
pad.changeViewOption('rtlIsTrue', true);
}
pad.changeViewOption('padFontFamily', padcookie.getPref('padFontFamily'));
$('#viewfontmenu').val(padcookie.getPref('padFontFamily')).niceSelect('update');
// Prevent sticky chat or chat and users to be checked for mobiles
const checkChatAndUsersVisibility = (x) => {
if (x.matches) { // If media query matches
$('#options-chatandusers:checked').click();
$('#options-stickychat:checked').click();
}
};
const mobileMatch = window.matchMedia('(max-width: 800px)');
mobileMatch.addListener(checkChatAndUsersVisibility); // check if window resized
setTimeout(() => { checkChatAndUsersVisibility(mobileMatch); }, 0); // check now after load
$('#editorcontainer').addClass('initialized');
hooks.aCallAll('postAceInit', {ace: padeditor.ace, pad});
};
// order of inits is important here:
padimpexp.init(this); padimpexp.init(this);
padsavedrevs.init(this); padsavedrevs.init(this);
padeditor.init(postAceInit, pad.padOptions.view || {}, this); padeditor.init(postAceInit, pad.padOptions.view || {}, this);
paduserlist.init(pad.myUserInfo, this); paduserlist.init(pad.myUserInfo, this);
padconnectionstatus.init(); padconnectionstatus.init();
padmodals.init(this); padmodals.init(this);
pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, { pad.collabClient = getCollabClient(
colorPalette: pad.getColorPalette(), padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo,
}, pad); {colorPalette: pad.getColorPalette()}, pad);
pad.collabClient.setOnUserJoin(pad.handleUserJoin); pad.collabClient.setOnUserJoin(pad.handleUserJoin);
pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate); pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate);
pad.collabClient.setOnUserLeave(pad.handleUserLeave); pad.collabClient.setOnUserLeave(pad.handleUserLeave);
@ -434,68 +516,27 @@ var pad = {
pad.collabClient.setOnInternalAction(pad.handleCollabAction); pad.collabClient.setOnInternalAction(pad.handleCollabAction);
// load initial chat-messages // load initial chat-messages
if (clientVars.chatHead != -1) { if (clientVars.chatHead !== -1) {
const chatHead = clientVars.chatHead; const chatHead = clientVars.chatHead;
const start = Math.max(chatHead - 100, 0); const start = Math.max(chatHead - 100, 0);
pad.collabClient.sendMessage({type: 'GET_CHAT_MESSAGES', start, end: chatHead}); pad.collabClient.sendMessage({type: 'GET_CHAT_MESSAGES', start, end: chatHead});
} else // there are no messages } else {
{ // there are no messages
$('#chatloadmessagesbutton').css('display', 'none'); $('#chatloadmessagesbutton').css('display', 'none');
} }
function postAceInit() {
padeditbar.init();
setTimeout(() => {
padeditor.ace.focus();
}, 0);
if (padcookie.getPref('chatAlwaysVisible')) { // if we have a cookie for always showing chat then show it
chat.stickToScreen(true); // stick it to the screen
$('#options-stickychat').prop('checked', true); // set the checkbox to on
}
if (padcookie.getPref('chatAndUsers')) { // if we have a cookie for always showing chat then show it
chat.chatAndUsers(true); // stick it to the screen
$('#options-chatandusers').prop('checked', true); // set the checkbox to on
}
if (padcookie.getPref('showAuthorshipColors') == false) {
pad.changeViewOption('showAuthorColors', false);
}
if (padcookie.getPref('showLineNumbers') == false) {
pad.changeViewOption('showLineNumbers', false);
}
if (padcookie.getPref('rtlIsTrue') == true) {
pad.changeViewOption('rtlIsTrue', true);
}
pad.changeViewOption('padFontFamily', padcookie.getPref('padFontFamily'));
$('#viewfontmenu').val(padcookie.getPref('padFontFamily')).niceSelect('update');
// Prevent sticky chat or chat and users to be checked for mobiles
function checkChatAndUsersVisibility(x) {
if (x.matches) { // If media query matches
$('#options-chatandusers:checked').click();
$('#options-stickychat:checked').click();
}
}
const mobileMatch = window.matchMedia('(max-width: 800px)');
mobileMatch.addListener(checkChatAndUsersVisibility); // check if window resized
setTimeout(() => { checkChatAndUsersVisibility(mobileMatch); }, 0); // check now after load
$('#editorcontainer').addClass('initialized');
hooks.aCallAll('postAceInit', {ace: padeditor.ace, pad});
}
}, },
dispose() { dispose: () => {
padeditor.dispose(); padeditor.dispose();
}, },
notifyChangeName(newName) { notifyChangeName: (newName) => {
pad.myUserInfo.name = newName; pad.myUserInfo.name = newName;
pad.collabClient.updateUserInfo(pad.myUserInfo); pad.collabClient.updateUserInfo(pad.myUserInfo);
}, },
notifyChangeColor(newColorId) { notifyChangeColor: (newColorId) => {
pad.myUserInfo.colorId = newColorId; pad.myUserInfo.colorId = newColorId;
pad.collabClient.updateUserInfo(pad.myUserInfo); pad.collabClient.updateUserInfo(pad.myUserInfo);
}, },
changePadOption(key, value) { changePadOption: (key, value) => {
const options = {}; const options = {};
options[key] = value; options[key] = value;
pad.handleOptionsChange(options); pad.handleOptionsChange(options);
@ -506,32 +547,30 @@ var pad = {
changedBy: pad.myUserInfo.name || 'unnamed', changedBy: pad.myUserInfo.name || 'unnamed',
}); });
}, },
changeViewOption(key, value) { changeViewOption: (key, value) => {
const options = { const options = {
view: {}, view: {},
}; };
options.view[key] = value; options.view[key] = value;
pad.handleOptionsChange(options); pad.handleOptionsChange(options);
}, },
handleOptionsChange(opts) { handleOptionsChange: (opts) => {
// opts object is a full set of options or just // opts object is a full set of options or just
// some options to change // some options to change
if (opts.view) { if (opts.view) {
if (!pad.padOptions.view) { if (!pad.padOptions.view) {
pad.padOptions.view = {}; pad.padOptions.view = {};
} }
for (const k in opts.view) { for (const [k, v] of Object.entries(opts.view)) {
pad.padOptions.view[k] = opts.view[k]; pad.padOptions.view[k] = v;
padcookie.setPref(k, opts.view[k]); padcookie.setPref(k, v);
} }
padeditor.setViewOptions(pad.padOptions.view); padeditor.setViewOptions(pad.padOptions.view);
} }
}, },
getPadOptions() { // caller shouldn't mutate the object
// caller shouldn't mutate the object getPadOptions: () => pad.padOptions,
return pad.padOptions; suggestUserName: (userId, name) => {
},
suggestUserName(userId, name) {
pad.collabClient.sendClientMessage( pad.collabClient.sendClientMessage(
{ {
type: 'suggestUserName', type: 'suggestUserName',
@ -539,31 +578,31 @@ var pad = {
newName: name, newName: name,
}); });
}, },
handleUserJoin(userInfo) { handleUserJoin: (userInfo) => {
paduserlist.userJoinOrUpdate(userInfo); paduserlist.userJoinOrUpdate(userInfo);
}, },
handleUserUpdate(userInfo) { handleUserUpdate: (userInfo) => {
paduserlist.userJoinOrUpdate(userInfo); paduserlist.userJoinOrUpdate(userInfo);
}, },
handleUserLeave(userInfo) { handleUserLeave: (userInfo) => {
paduserlist.userLeave(userInfo); paduserlist.userLeave(userInfo);
}, },
handleClientMessage(msg) { handleClientMessage: (msg) => {
if (msg.type == 'suggestUserName') { if (msg.type === 'suggestUserName') {
if (msg.unnamedId == pad.myUserInfo.userId && msg.newName && !pad.myUserInfo.name) { if (msg.unnamedId === pad.myUserInfo.userId && msg.newName && !pad.myUserInfo.name) {
pad.notifyChangeName(msg.newName); pad.notifyChangeName(msg.newName);
paduserlist.setMyUserInfo(pad.myUserInfo); paduserlist.setMyUserInfo(pad.myUserInfo);
} }
} else if (msg.type == 'newRevisionList') { } else if (msg.type === 'newRevisionList') {
padsavedrevs.newRevisionList(msg.revisionList); padsavedrevs.newRevisionList(msg.revisionList);
} else if (msg.type == 'revisionLabel') { } else if (msg.type === 'revisionLabel') {
padsavedrevs.newRevisionList(msg.revisionList); padsavedrevs.newRevisionList(msg.revisionList);
} else if (msg.type == 'padoptions') { } else if (msg.type === 'padoptions') {
const opts = msg.options; const opts = msg.options;
pad.handleOptionsChange(opts); pad.handleOptionsChange(opts);
} }
}, },
dmesg(m) { dmesg: (m) => {
if (pad.getIsDebugEnabled()) { if (pad.getIsDebugEnabled()) {
const djs = $('#djs').get(0); const djs = $('#djs').get(0);
const wasAtBottom = (djs.scrollTop - (djs.scrollHeight - $(djs).height()) >= -20); const wasAtBottom = (djs.scrollTop - (djs.scrollHeight - $(djs).height()) >= -20);
@ -573,31 +612,30 @@ var pad = {
} }
} }
}, },
handleChannelStateChange(newState, message) { handleChannelStateChange: (newState, message) => {
const oldFullyConnected = !!padconnectionstatus.isFullyConnected(); const oldFullyConnected = !!padconnectionstatus.isFullyConnected();
const wasConnecting = (padconnectionstatus.getStatus().what == 'connecting'); const wasConnecting = (padconnectionstatus.getStatus().what === 'connecting');
if (newState == 'CONNECTED') { if (newState === 'CONNECTED') {
padeditor.enable(); padeditor.enable();
padeditbar.enable(); padeditbar.enable();
padimpexp.enable(); padimpexp.enable();
padconnectionstatus.connected(); padconnectionstatus.connected();
} else if (newState == 'RECONNECTING') { } else if (newState === 'RECONNECTING') {
padeditor.disable(); padeditor.disable();
padeditbar.disable(); padeditbar.disable();
padimpexp.disable(); padimpexp.disable();
padconnectionstatus.reconnecting(); padconnectionstatus.reconnecting();
} else if (newState == 'DISCONNECTED') { } else if (newState === 'DISCONNECTED') {
pad.diagnosticInfo.disconnectedMessage = message; pad.diagnosticInfo.disconnectedMessage = message;
pad.diagnosticInfo.padId = pad.getPadId(); pad.diagnosticInfo.padId = pad.getPadId();
pad.diagnosticInfo.socket = {}; pad.diagnosticInfo.socket = {};
// we filter non objects from the socket object and put them in the diagnosticInfo // we filter non objects from the socket object and put them in the diagnosticInfo
// this ensures we have no cyclic data - this allows us to stringify the data // this ensures we have no cyclic data - this allows us to stringify the data
for (const i in socket.socket) { for (const [i, value] of Object.entries(socket.socket || {})) {
const value = socket.socket[i];
const type = typeof value; const type = typeof value;
if (type == 'string' || type == 'number') { if (type === 'string' || type === 'number') {
pad.diagnosticInfo.socket[i] = value; pad.diagnosticInfo.socket[i] = value;
} }
} }
@ -613,11 +651,11 @@ var pad = {
padconnectionstatus.disconnected(message); padconnectionstatus.disconnected(message);
} }
const newFullyConnected = !!padconnectionstatus.isFullyConnected(); const newFullyConnected = !!padconnectionstatus.isFullyConnected();
if (newFullyConnected != oldFullyConnected) { if (newFullyConnected !== oldFullyConnected) {
pad.handleIsFullyConnected(newFullyConnected, wasConnecting); pad.handleIsFullyConnected(newFullyConnected, wasConnecting);
} }
}, },
handleIsFullyConnected(isConnected, isInitialConnect) { handleIsFullyConnected: (isConnected, isInitialConnect) => {
pad.determineChatVisibility(isConnected && !isInitialConnect); pad.determineChatVisibility(isConnected && !isInitialConnect);
pad.determineChatAndUsersVisibility(isConnected && !isInitialConnect); pad.determineChatAndUsersVisibility(isConnected && !isInitialConnect);
pad.determineAuthorshipColorsVisibility(); pad.determineAuthorshipColorsVisibility();
@ -625,7 +663,7 @@ var pad = {
padeditbar.toggleDropDown('none'); padeditbar.toggleDropDown('none');
}, 1000); }, 1000);
}, },
determineChatVisibility(asNowConnectedFeedback) { determineChatVisibility: (asNowConnectedFeedback) => {
const chatVisCookie = padcookie.getPref('chatAlwaysVisible'); const chatVisCookie = padcookie.getPref('chatAlwaysVisible');
if (chatVisCookie) { // if the cookie is set for chat always visible if (chatVisCookie) { // if the cookie is set for chat always visible
chat.stickToScreen(true); // stick it to the screen chat.stickToScreen(true); // stick it to the screen
@ -634,7 +672,7 @@ var pad = {
$('#options-stickychat').prop('checked', false); // set the checkbox for off $('#options-stickychat').prop('checked', false); // set the checkbox for off
} }
}, },
determineChatAndUsersVisibility(asNowConnectedFeedback) { determineChatAndUsersVisibility: (asNowConnectedFeedback) => {
const chatAUVisCookie = padcookie.getPref('chatAndUsersVisible'); const chatAUVisCookie = padcookie.getPref('chatAndUsersVisible');
if (chatAUVisCookie) { // if the cookie is set for chat always visible if (chatAUVisCookie) { // if the cookie is set for chat always visible
chat.chatAndUsers(true); // stick it to the screen chat.chatAndUsers(true); // stick it to the screen
@ -643,7 +681,7 @@ var pad = {
$('#options-chatandusers').prop('checked', false); // set the checkbox for off $('#options-chatandusers').prop('checked', false); // set the checkbox for off
} }
}, },
determineAuthorshipColorsVisibility() { determineAuthorshipColorsVisibility: () => {
const authColCookie = padcookie.getPref('showAuthorshipColors'); const authColCookie = padcookie.getPref('showAuthorshipColors');
if (authColCookie) { if (authColCookie) {
pad.changeViewOption('showAuthorColors', true); pad.changeViewOption('showAuthorColors', true);
@ -652,14 +690,14 @@ var pad = {
$('#options-colorscheck').prop('checked', false); $('#options-colorscheck').prop('checked', false);
} }
}, },
handleCollabAction(action) { handleCollabAction: (action) => {
if (action == 'commitPerformed') { if (action === 'commitPerformed') {
padeditbar.setSyncStatus('syncing'); padeditbar.setSyncStatus('syncing');
} else if (action == 'newlyIdle') { } else if (action === 'newlyIdle') {
padeditbar.setSyncStatus('done'); padeditbar.setSyncStatus('done');
} }
}, },
asyncSendDiagnosticInfo() { asyncSendDiagnosticInfo: () => {
window.setTimeout(() => { window.setTimeout(() => {
$.ajax( $.ajax(
{ {
@ -668,32 +706,29 @@ var pad = {
data: { data: {
diagnosticInfo: JSON.stringify(pad.diagnosticInfo), diagnosticInfo: JSON.stringify(pad.diagnosticInfo),
}, },
success() {}, success: () => {},
error() {}, error: () => {},
}); });
}, 0); }, 0);
}, },
forceReconnect() { forceReconnect: () => {
$('form#reconnectform input.padId').val(pad.getPadId()); $('form#reconnectform input.padId').val(pad.getPadId());
pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo(); pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo();
$('form#reconnectform input.diagnosticInfo').val(JSON.stringify(pad.diagnosticInfo)); $('form#reconnectform input.diagnosticInfo').val(JSON.stringify(pad.diagnosticInfo));
$('form#reconnectform input.missedChanges').val(JSON.stringify(pad.collabClient.getMissedChanges())); $('form#reconnectform input.missedChanges')
.val(JSON.stringify(pad.collabClient.getMissedChanges()));
$('form#reconnectform').submit(); $('form#reconnectform').submit();
}, },
// this is called from code put into a frame from the server: // this is called from code put into a frame from the server:
handleImportExportFrameCall(callName, varargs) { handleImportExportFrameCall: (callName, varargs) => {
padimpexp.handleFrameCall.call(padimpexp, callName, Array.prototype.slice.call(arguments, 1)); padimpexp.handleFrameCall.call(padimpexp, callName, Array.prototype.slice.call(arguments, 1));
}, },
callWhenNotCommitting(f) { callWhenNotCommitting: (f) => {
pad.collabClient.callWhenNotCommitting(f); pad.collabClient.callWhenNotCommitting(f);
}, },
getCollabRevisionNumber() { getCollabRevisionNumber: () => pad.collabClient.getCurrentRevisionNumber(),
return pad.collabClient.getCurrentRevisionNumber(); isFullyConnected: () => padconnectionstatus.isFullyConnected(),
}, addHistoricalAuthors: (data) => {
isFullyConnected() {
return padconnectionstatus.isFullyConnected();
},
addHistoricalAuthors(data) {
if (!pad.collabClient) { if (!pad.collabClient) {
window.setTimeout(() => { window.setTimeout(() => {
pad.addHistoricalAuthors(data); pad.addHistoricalAuthors(data);
@ -704,11 +739,9 @@ var pad = {
}, },
}; };
function init() { const init = () => pad.init();
return pad.init();
}
var settings = { const settings = {
LineNumbersDisabled: false, LineNumbersDisabled: false,
noColors: false, noColors: false,
useMonospaceFontGlobal: false, useMonospaceFontGlobal: false,
@ -718,6 +751,7 @@ var settings = {
}; };
pad.settings = settings; pad.settings = settings;
exports.baseURL = ''; exports.baseURL = '';
exports.settings = settings; exports.settings = settings;
exports.randomString = randomString; exports.randomString = randomString;

View file

@ -1,4 +1,6 @@
exports.showCountDownTimerToReconnectOnModal = function ($modal, pad) { 'use strict';
exports.showCountDownTimerToReconnectOnModal = ($modal, pad) => {
if (clientVars.automaticReconnectionTimeout && $modal.is('.with_reconnect_timer')) { if (clientVars.automaticReconnectionTimeout && $modal.is('.with_reconnect_timer')) {
createCountDownElementsIfNecessary($modal); createCountDownElementsIfNecessary($modal);
@ -13,7 +15,7 @@ exports.showCountDownTimerToReconnectOnModal = function ($modal, pad) {
} }
}; };
var createCountDownElementsIfNecessary = function ($modal) { const createCountDownElementsIfNecessary = ($modal) => {
const elementsDoNotExist = $modal.find('#cancelreconnect').length === 0; const elementsDoNotExist = $modal.find('#cancelreconnect').length === 0;
if (elementsDoNotExist) { if (elementsDoNotExist) {
const $defaultMessage = $modal.find('#defaulttext'); const $defaultMessage = $modal.find('#defaulttext');
@ -45,12 +47,13 @@ var createCountDownElementsIfNecessary = function ($modal) {
} }
}; };
var localize = function ($element) { const localize = ($element) => {
html10n.translateElement(html10n.translations, $element.get(0)); html10n.translateElement(html10n.translations, $element.get(0));
}; };
var createTimerForModal = function ($modal, pad) { const createTimerForModal = ($modal, pad) => {
const timeUntilReconnection = clientVars.automaticReconnectionTimeout * reconnectionTries.nextTry(); const timeUntilReconnection =
clientVars.automaticReconnectionTimeout * reconnectionTries.nextTry();
const timer = new CountDownTimer(timeUntilReconnection); const timer = new CountDownTimer(timeUntilReconnection);
timer.onTick((minutes, seconds) => { timer.onTick((minutes, seconds) => {
@ -68,23 +71,23 @@ var createTimerForModal = function ($modal, pad) {
return timer; return timer;
}; };
var disableAutomaticReconnection = function ($modal) { const disableAutomaticReconnection = ($modal) => {
toggleAutomaticReconnectionOption($modal, true); toggleAutomaticReconnectionOption($modal, true);
}; };
var enableAutomaticReconnection = function ($modal) { const enableAutomaticReconnection = ($modal) => {
toggleAutomaticReconnectionOption($modal, false); toggleAutomaticReconnectionOption($modal, false);
}; };
var toggleAutomaticReconnectionOption = function ($modal, disableAutomaticReconnect) { const toggleAutomaticReconnectionOption = ($modal, disableAutomaticReconnect) => {
$modal.find('#cancelreconnect, .reconnecttimer').toggleClass('hidden', disableAutomaticReconnect); $modal.find('#cancelreconnect, .reconnecttimer').toggleClass('hidden', disableAutomaticReconnect);
$modal.find('#defaulttext').toggleClass('hidden', !disableAutomaticReconnect); $modal.find('#defaulttext').toggleClass('hidden', !disableAutomaticReconnect);
}; };
var waitUntilClientCanConnectToServerAndThen = function (callback, pad) { const waitUntilClientCanConnectToServerAndThen = (callback, pad) => {
whenConnectionIsRestablishedWithServer(callback, pad); whenConnectionIsRestablishedWithServer(callback, pad);
pad.socket.connect(); pad.socket.connect();
}; };
var whenConnectionIsRestablishedWithServer = function (callback, pad) { const whenConnectionIsRestablishedWithServer = (callback, pad) => {
// only add listener for the first try, don't need to add another listener // only add listener for the first try, don't need to add another listener
// on every unsuccessful try // on every unsuccessful try
if (reconnectionTries.counter === 1) { if (reconnectionTries.counter === 1) {
@ -92,11 +95,11 @@ var whenConnectionIsRestablishedWithServer = function (callback, pad) {
} }
}; };
var forceReconnection = function ($modal) { const forceReconnection = ($modal) => {
$modal.find('#forcereconnect').click(); $modal.find('#forcereconnect').click();
}; };
var updateCountDownTimerMessage = function ($modal, minutes, seconds) { const updateCountDownTimerMessage = ($modal, minutes, seconds) => {
minutes = minutes < 10 ? `0${minutes}` : minutes; minutes = minutes < 10 ? `0${minutes}` : minutes;
seconds = seconds < 10 ? `0${seconds}` : seconds; seconds = seconds < 10 ? `0${seconds}` : seconds;
@ -105,7 +108,7 @@ var updateCountDownTimerMessage = function ($modal, minutes, seconds) {
// store number of tries to reconnect to server, in order to increase time to wait // store number of tries to reconnect to server, in order to increase time to wait
// until next try // until next try
var reconnectionTries = { const reconnectionTries = {
counter: 0, counter: 0,
nextTry() { nextTry() {
@ -119,8 +122,9 @@ var reconnectionTries = {
// Timer based on http://stackoverflow.com/a/20618517. // Timer based on http://stackoverflow.com/a/20618517.
// duration: how many **seconds** until the timer ends // duration: how many **seconds** until the timer ends
// granularity (optional): how many **milliseconds** between each 'tick' of timer. Default: 1000ms (1s) // granularity (optional): how many **milliseconds**
var CountDownTimer = function (duration, granularity) { // between each 'tick' of timer. Default: 1000ms (1s)
const CountDownTimer = function (duration, granularity) {
this.duration = duration; this.duration = duration;
this.granularity = granularity || 1000; this.granularity = granularity || 1000;
this.running = false; this.running = false;
@ -137,8 +141,7 @@ CountDownTimer.prototype.start = function () {
const start = Date.now(); const start = Date.now();
const that = this; const that = this;
let diff; let diff;
const timer = () => {
(function timer() {
diff = that.duration - Math.floor((Date.now() - start) / 1000); diff = that.duration - Math.floor((Date.now() - start) / 1000);
if (diff > 0) { if (diff > 0) {
@ -149,7 +152,8 @@ CountDownTimer.prototype.start = function () {
that.tick(0); that.tick(0);
that.expire(); that.expire();
} }
}()); };
timer();
}; };
CountDownTimer.prototype.tick = function (diff) { CountDownTimer.prototype.tick = function (diff) {
@ -184,9 +188,7 @@ CountDownTimer.prototype.cancel = function () {
return this; return this;
}; };
CountDownTimer.parse = function (seconds) { CountDownTimer.parse = (seconds) => ({
return { minutes: (seconds / 60) | 0,
minutes: (seconds / 60) | 0, seconds: (seconds % 60) | 0,
seconds: (seconds % 60) | 0, });
};
};

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -22,25 +24,25 @@
const padmodals = require('./pad_modals').padmodals; const padmodals = require('./pad_modals').padmodals;
const padconnectionstatus = (function () { const padconnectionstatus = (() => {
let status = { let status = {
what: 'connecting', what: 'connecting',
}; };
const self = { const self = {
init() { init: () => {
$('button#forcereconnect').click(() => { $('button#forcereconnect').click(() => {
window.location.reload(); window.location.reload();
}); });
}, },
connected() { connected: () => {
status = { status = {
what: 'connected', what: 'connected',
}; };
padmodals.showModal('connected'); padmodals.showModal('connected');
padmodals.hideOverlay(); padmodals.hideOverlay();
}, },
reconnecting() { reconnecting: () => {
status = { status = {
what: 'reconnecting', what: 'reconnecting',
}; };
@ -48,8 +50,8 @@ const padconnectionstatus = (function () {
padmodals.showModal('reconnecting'); padmodals.showModal('reconnecting');
padmodals.showOverlay(); padmodals.showOverlay();
}, },
disconnected(msg) { disconnected: (msg) => {
if (status.what == 'disconnected') return; if (status.what === 'disconnected') return;
status = { status = {
what: 'disconnected', what: 'disconnected',
@ -81,14 +83,10 @@ const padconnectionstatus = (function () {
padmodals.showModal(k); padmodals.showModal(k);
padmodals.showOverlay(); padmodals.showOverlay();
}, },
isFullyConnected() { isFullyConnected: () => status.what === 'connected',
return status.what == 'connected'; getStatus: () => status,
},
getStatus() {
return status;
},
}; };
return self; return self;
}()); })();
exports.padconnectionstatus = padconnectionstatus; exports.padconnectionstatus = padconnectionstatus;

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* Copyright 2009 Google Inc. * Copyright 2009 Google Inc.
* *

View file

@ -1,4 +1,5 @@
'use strict'; 'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -24,26 +26,26 @@ const Cookies = require('./pad_utils').Cookies;
const padcookie = require('./pad_cookie').padcookie; const padcookie = require('./pad_cookie').padcookie;
const padutils = require('./pad_utils').padutils; const padutils = require('./pad_utils').padutils;
const padeditor = (function () { const padeditor = (() => {
let Ace2Editor = undefined; let Ace2Editor = undefined;
let pad = undefined; let pad = undefined;
let settings = undefined; let settings = undefined;
var self = { const self = {
ace: null, ace: null,
// this is accessed directly from other files // this is accessed directly from other files
viewZoom: 100, viewZoom: 100,
init(readyFunc, initialViewOptions, _pad) { init: (readyFunc, initialViewOptions, _pad) => {
Ace2Editor = require('./ace').Ace2Editor; Ace2Editor = require('./ace').Ace2Editor;
pad = _pad; pad = _pad;
settings = pad.settings; settings = pad.settings;
function aceReady() { const aceReady = () => {
$('#editorloadingbox').hide(); $('#editorloadingbox').hide();
if (readyFunc) { if (readyFunc) {
readyFunc(); readyFunc();
} }
} };
self.ace = new Ace2Editor(); self.ace = new Ace2Editor();
self.ace.init('editorcontainer', '', aceReady); self.ace.init('editorcontainer', '', aceReady);
@ -57,7 +59,7 @@ const padeditor = (function () {
// view bar // view bar
$('#viewbarcontents').show(); $('#viewbarcontents').show();
}, },
initViewOptions() { initViewOptions: () => {
// Line numbers // Line numbers
padutils.bindCheckboxChange($('#options-linenoscheck'), () => { padutils.bindCheckboxChange($('#options-linenoscheck'), () => {
pad.changeViewOption('showLineNumbers', padutils.getCheckbox($('#options-linenoscheck'))); pad.changeViewOption('showLineNumbers', padutils.getCheckbox($('#options-linenoscheck')));
@ -74,8 +76,8 @@ const padeditor = (function () {
pad.changeViewOption('rtlIsTrue', padutils.getCheckbox($('#options-rtlcheck'))); pad.changeViewOption('rtlIsTrue', padutils.getCheckbox($('#options-rtlcheck')));
}); });
html10n.bind('localized', () => { html10n.bind('localized', () => {
pad.changeViewOption('rtlIsTrue', ('rtl' == html10n.getDirection())); pad.changeViewOption('rtlIsTrue', ('rtl' === html10n.getDirection()));
padutils.setCheckbox($('#options-rtlcheck'), ('rtl' == html10n.getDirection())); padutils.setCheckbox($('#options-rtlcheck'), ('rtl' === html10n.getDirection()));
}); });
// font family change // font family change
@ -87,9 +89,10 @@ const padeditor = (function () {
html10n.bind('localized', () => { html10n.bind('localized', () => {
$('#languagemenu').val(html10n.getLanguage()); $('#languagemenu').val(html10n.getLanguage());
// translate the value of 'unnamed' and 'Enter your name' textboxes in the userlist // translate the value of 'unnamed' and 'Enter your name' textboxes in the userlist
// this does not interfere with html10n's normal value-setting because html10n just ingores <input>s // this does not interfere with html10n's normal value-setting because
// also, a value which has been set by the user will be not overwritten since a user-edited <input> // html10n just ingores <input>s
// does *not* have the editempty-class // also, a value which has been set by the user will be not overwritten
// since a user-edited <input> does *not* have the editempty-class
$('input[data-l10n-id]').each((key, input) => { $('input[data-l10n-id]').each((key, input) => {
input = $(input); input = $(input);
if (input.hasClass('editempty')) { if (input.hasClass('editempty')) {
@ -106,17 +109,17 @@ const padeditor = (function () {
} }
}); });
}, },
setViewOptions(newOptions) { setViewOptions: (newOptions) => {
function getOption(key, defaultValue) { const getOption = (key, defaultValue) => {
const value = String(newOptions[key]); const value = String(newOptions[key]);
if (value == 'true') return true; if (value === 'true') return true;
if (value == 'false') return false; if (value === 'false') return false;
return defaultValue; return defaultValue;
} };
let v; let v;
v = getOption('rtlIsTrue', ('rtl' == html10n.getDirection())); v = getOption('rtlIsTrue', ('rtl' === html10n.getDirection()));
self.ace.setProperty('rtlIsTrue', v); self.ace.setProperty('rtlIsTrue', v);
padutils.setCheckbox($('#options-rtlcheck'), v); padutils.setCheckbox($('#options-rtlcheck'), v);
@ -137,29 +140,29 @@ const padeditor = (function () {
self.ace.setProperty('textface', newOptions.padFontFamily || ''); self.ace.setProperty('textface', newOptions.padFontFamily || '');
}, },
dispose() { dispose: () => {
if (self.ace) { if (self.ace) {
self.ace.destroy(); self.ace.destroy();
self.ace = null; self.ace = null;
} }
}, },
enable() { enable: () => {
if (self.ace) { if (self.ace) {
self.ace.setEditable(true); self.ace.setEditable(true);
} }
}, },
disable() { disable: () => {
if (self.ace) { if (self.ace) {
self.ace.setProperty('grayedOut', true); self.ace.setProperty('grayedOut', true);
self.ace.setEditable(false); self.ace.setEditable(false);
} }
}, },
restoreRevisionText(dataFromServer) { restoreRevisionText: (dataFromServer) => {
pad.addHistoricalAuthors(dataFromServer.historicalAuthorData); pad.addHistoricalAuthors(dataFromServer.historicalAuthorData);
self.ace.importAText(dataFromServer.atext, dataFromServer.apool, true); self.ace.importAText(dataFromServer.atext, dataFromServer.apool, true);
}, },
}; };
return self; return self;
}()); })();
exports.padeditor = padeditor; exports.padeditor = padeditor;

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -20,24 +22,27 @@
* limitations under the License. * limitations under the License.
*/ */
const padimpexp = (function () { const padimpexp = (() => {
// /// import // /// import
let currentImportTimer = null; let currentImportTimer = null;
function addImportFrames() { const addImportFrames = () => {
$('#import .importframe').remove(); $('#import .importframe').remove();
const iframe = $('<iframe style="display: none;" name="importiframe" class="importframe"></iframe>'); const iframe = $('<iframe>')
.css('display', 'none')
.attr('name', 'importiframe')
.addClass('importframe');
$('#import').append(iframe); $('#import').append(iframe);
} };
function fileInputUpdated() { const fileInputUpdated = () => {
$('#importsubmitinput').addClass('throbbold'); $('#importsubmitinput').addClass('throbbold');
$('#importformfilediv').addClass('importformenabled'); $('#importformfilediv').addClass('importformenabled');
$('#importsubmitinput').removeAttr('disabled'); $('#importsubmitinput').removeAttr('disabled');
$('#importmessagefail').fadeOut('fast'); $('#importmessagefail').fadeOut('fast');
} };
function fileInputSubmit() { const fileInputSubmit = () => {
$('#importmessagefail').fadeOut('fast'); $('#importmessagefail').fadeOut('fast');
const ret = window.confirm(html10n.get('pad.impexp.confirmimport')); const ret = window.confirm(html10n.get('pad.impexp.confirmimport'));
if (ret) { if (ret) {
@ -64,13 +69,13 @@ const padimpexp = (function () {
$('#importstatusball').show(); $('#importstatusball').show();
} }
return ret; return ret;
} };
function importFailed(msg) { const importFailed = (msg) => {
importErrorMessage(msg); importErrorMessage(msg);
} };
function importDone() { const importDone = () => {
$('#importsubmitinput').removeAttr('disabled').val(html10n.get('pad.impexp.importbutton')); $('#importsubmitinput').removeAttr('disabled').val(html10n.get('pad.impexp.importbutton'));
window.setTimeout(() => { window.setTimeout(() => {
$('#importfileinput').removeAttr('disabled'); $('#importfileinput').removeAttr('disabled');
@ -78,16 +83,16 @@ const padimpexp = (function () {
$('#importstatusball').hide(); $('#importstatusball').hide();
importClearTimeout(); importClearTimeout();
addImportFrames(); addImportFrames();
} };
function importClearTimeout() { const importClearTimeout = () => {
if (currentImportTimer) { if (currentImportTimer) {
window.clearTimeout(currentImportTimer); window.clearTimeout(currentImportTimer);
currentImportTimer = null; currentImportTimer = null;
} }
} };
function importErrorMessage(status) { const importErrorMessage = (status) => {
let msg = ''; let msg = '';
if (status === 'convertFailed') { if (status === 'convertFailed') {
@ -102,9 +107,11 @@ const padimpexp = (function () {
msg = html10n.get('pad.impexp.permission'); msg = html10n.get('pad.impexp.permission');
} }
function showError(fade) { const showError = (fade) => {
$('#importmessagefail').html(`<strong style="color: red">${html10n.get('pad.impexp.importfailed')}:</strong> ${msg || html10n.get('pad.impexp.copypaste', '')}`)[(fade ? 'fadeIn' : 'show')](); $('#importmessagefail').html(
} `<strong style="color: red">${html10n.get('pad.impexp.importfailed')}:</strong> ` +
`${msg || html10n.get('pad.impexp.copypaste', '')}`)[(fade ? 'fadeIn' : 'show')]();
};
if ($('#importexport .importmessage').is(':visible')) { if ($('#importexport .importmessage').is(':visible')) {
$('#importmessagesuccess').fadeOut('fast'); $('#importmessagesuccess').fadeOut('fast');
@ -114,7 +121,7 @@ const padimpexp = (function () {
} else { } else {
showError(); showError();
} }
} };
// /// export // /// export
@ -134,16 +141,17 @@ const padimpexp = (function () {
} }
// /// // ///
var pad = undefined; let pad = undefined;
const self = { const self = {
init(_pad) { init: (_pad) => {
pad = _pad; pad = _pad;
// get /p/padname // get /p/padname
// if /p/ isn't available due to a rewrite we use the clientVars padId // if /p/ isn't available due to a rewrite we use the clientVars padId
const pad_root_path = new RegExp(/.*\/p\/[^\/]+/).exec(document.location.pathname) || clientVars.padId; const padRootPath = /.*\/p\/[^/]+/.exec(document.location.pathname) || clientVars.padId;
// get http://example.com/p/padname without Params // get http://example.com/p/padname without Params
const pad_root_url = `${document.location.protocol}//${document.location.host}${document.location.pathname}`; const dl = document.location;
const padRootUrl = `${dl.protocol}//${dl.host}${dl.pathname}`;
// i10l buttom import // i10l buttom import
$('#importsubmitinput').val(html10n.get('pad.impexp.importbutton')); $('#importsubmitinput').val(html10n.get('pad.impexp.importbutton'));
@ -152,32 +160,32 @@ const padimpexp = (function () {
}); });
// build the export links // build the export links
$('#exporthtmla').attr('href', `${pad_root_path}/export/html`); $('#exporthtmla').attr('href', `${padRootPath}/export/html`);
$('#exportetherpada').attr('href', `${pad_root_path}/export/etherpad`); $('#exportetherpada').attr('href', `${padRootPath}/export/etherpad`);
$('#exportplaina').attr('href', `${pad_root_path}/export/txt`); $('#exportplaina').attr('href', `${padRootPath}/export/txt`);
// activate action to import in the form // activate action to import in the form
$('#importform').attr('action', `${pad_root_url}/import`); $('#importform').attr('action', `${padRootUrl}/import`);
// hide stuff thats not avaible if abiword/soffice is disabled // hide stuff thats not avaible if abiword/soffice is disabled
if (clientVars.exportAvailable == 'no') { if (clientVars.exportAvailable === 'no') {
$('#exportworda').remove(); $('#exportworda').remove();
$('#exportpdfa').remove(); $('#exportpdfa').remove();
$('#exportopena').remove(); $('#exportopena').remove();
$('#importmessageabiword').show(); $('#importmessageabiword').show();
} else if (clientVars.exportAvailable == 'withoutPDF') { } else if (clientVars.exportAvailable === 'withoutPDF') {
$('#exportpdfa').remove(); $('#exportpdfa').remove();
$('#exportworda').attr('href', `${pad_root_path}/export/doc`); $('#exportworda').attr('href', `${padRootPath}/export/doc`);
$('#exportopena').attr('href', `${pad_root_path}/export/odt`); $('#exportopena').attr('href', `${padRootPath}/export/odt`);
$('#importexport').css({height: '142px'}); $('#importexport').css({height: '142px'});
$('#importexportline').css({height: '142px'}); $('#importexportline').css({height: '142px'});
} else { } else {
$('#exportworda').attr('href', `${pad_root_path}/export/doc`); $('#exportworda').attr('href', `${padRootPath}/export/doc`);
$('#exportpdfa').attr('href', `${pad_root_path}/export/pdf`); $('#exportpdfa').attr('href', `${padRootPath}/export/pdf`);
$('#exportopena').attr('href', `${pad_root_path}/export/odt`); $('#exportopena').attr('href', `${padRootPath}/export/odt`);
} }
addImportFrames(); addImportFrames();
@ -185,7 +193,7 @@ const padimpexp = (function () {
$('#importform').unbind('submit').submit(fileInputSubmit); $('#importform').unbind('submit').submit(fileInputSubmit);
$('.disabledexport').click(cantExport); $('.disabledexport').click(cantExport);
}, },
handleFrameCall(directDatabaseAccess, status) { handleFrameCall: (directDatabaseAccess, status) => {
if (directDatabaseAccess === 'undefined') directDatabaseAccess = false; if (directDatabaseAccess === 'undefined') directDatabaseAccess = false;
if (status !== 'ok') { if (status !== 'ok') {
importFailed(status); importFailed(status);
@ -201,18 +209,18 @@ const padimpexp = (function () {
importDone(); importDone();
}, },
disable() { disable: () => {
$('#impexp-disabled-clickcatcher').show(); $('#impexp-disabled-clickcatcher').show();
$('#import').css('opacity', 0.5); $('#import').css('opacity', 0.5);
$('#impexp-export').css('opacity', 0.5); $('#impexp-export').css('opacity', 0.5);
}, },
enable() { enable: () => {
$('#impexp-disabled-clickcatcher').hide(); $('#impexp-disabled-clickcatcher').hide();
$('#import').css('opacity', 1); $('#import').css('opacity', 1);
$('#impexp-export').css('opacity', 1); $('#impexp-export').css('opacity', 1);
}, },
}; };
return self; return self;
}()); })();
exports.padimpexp = padimpexp; exports.padimpexp = padimpexp;

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -23,13 +25,13 @@
const padeditbar = require('./pad_editbar').padeditbar; const padeditbar = require('./pad_editbar').padeditbar;
const automaticReconnect = require('./pad_automatic_reconnect'); const automaticReconnect = require('./pad_automatic_reconnect');
const padmodals = (function () { const padmodals = (() => {
let pad = undefined; let pad = undefined;
const self = { const self = {
init(_pad) { init: (_pad) => {
pad = _pad; pad = _pad;
}, },
showModal(messageId) { showModal: (messageId) => {
padeditbar.toggleDropDown('none', () => { padeditbar.toggleDropDown('none', () => {
$('#connectivity .visible').removeClass('visible'); $('#connectivity .visible').removeClass('visible');
$(`#connectivity .${messageId}`).addClass('visible'); $(`#connectivity .${messageId}`).addClass('visible');
@ -40,15 +42,15 @@ const padmodals = (function () {
padeditbar.toggleDropDown('connectivity'); padeditbar.toggleDropDown('connectivity');
}); });
}, },
showOverlay() { showOverlay: () => {
// Prevent the user to interact with the toolbar. Useful when user is disconnected for example // Prevent the user to interact with the toolbar. Useful when user is disconnected for example
$('#toolbar-overlay').show(); $('#toolbar-overlay').show();
}, },
hideOverlay() { hideOverlay: () => {
$('#toolbar-overlay').hide(); $('#toolbar-overlay').hide();
}, },
}; };
return self; return self;
}()); })();
exports.padmodals = padmodals; exports.padmodals = padmodals;

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* Copyright 2012 Peter 'Pita' Martischka * Copyright 2012 Peter 'Pita' Martischka
* *
@ -16,13 +18,14 @@
let pad; let pad;
exports.saveNow = function () { exports.saveNow = () => {
pad.collabClient.sendMessage({type: 'SAVE_REVISION'}); pad.collabClient.sendMessage({type: 'SAVE_REVISION'});
$.gritter.add({ $.gritter.add({
// (string | mandatory) the heading of the notification // (string | mandatory) the heading of the notification
title: _('pad.savedrevs.marked'), title: html10n.get('pad.savedrevs.marked'),
// (string | mandatory) the text inside the notification // (string | mandatory) the text inside the notification
text: _('pad.savedrevs.timeslider') || 'You can view saved revisions in the timeslider', text: html10n.get('pad.savedrevs.timeslider') ||
'You can view saved revisions in the timeslider',
// (bool | optional) if you want it to fade out on its own or just sit there // (bool | optional) if you want it to fade out on its own or just sit there
sticky: false, sticky: false,
time: 3000, time: 3000,
@ -30,6 +33,6 @@ exports.saveNow = function () {
}); });
}; };
exports.init = function (_pad) { exports.init = (_pad) => {
pad = _pad; pad = _pad;
}; };

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -22,13 +24,12 @@
const padutils = require('./pad_utils').padutils; const padutils = require('./pad_utils').padutils;
const hooks = require('./pluginfw/hooks'); const hooks = require('./pluginfw/hooks');
const browser = require('./browser');
let myUserInfo = {}; let myUserInfo = {};
let colorPickerOpen = false; let colorPickerOpen = false;
let colorPickerSetup = false; let colorPickerSetup = false;
let previousColorId = 0;
const paduserlist = (function () { const paduserlist = (function () {
const rowManager = (function () { const rowManager = (function () {
@ -36,9 +37,7 @@ const paduserlist = (function () {
// their insertion, removal, and reordering. It manipulates TD height // their insertion, removal, and reordering. It manipulates TD height
// and TD opacity. // and TD opacity.
function nextRowId() { const nextRowId = () => `usertr${nextRowId.counter++}`;
return `usertr${nextRowId.counter++}`;
}
nextRowId.counter = 1; nextRowId.counter = 1;
// objects are shared; fields are "domId","data","animationStep" // objects are shared; fields are "domId","data","animationStep"
const rowsFadingOut = []; // unordered set const rowsFadingOut = []; // unordered set
@ -47,20 +46,67 @@ const paduserlist = (function () {
const ANIMATION_START = -12; // just starting to fade in const ANIMATION_START = -12; // just starting to fade in
const ANIMATION_END = 12; // just finishing fading out 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();
}
}
function getAnimationHeight(step, power) { handleOtherUserInputs();
return (rowsFadingIn.length > 0) || (rowsFadingOut.length > 0); // is more to do
};
const getAnimationHeight = (step, power) => {
let a = Math.abs(step / 12); let a = Math.abs(step / 12);
if (power == 2) a *= a; if (power === 2) a **= 2;
else if (power == 3) a = a * a * a; else if (power === 3) a **= 3;
else if (power == 4) a = a * a * a * a; else if (power === 4) a **= 4;
else if (power >= 5) a = a * a * a * a * a; else if (power >= 5) a **= 5;
return Math.round(26 * (1 - a)); return Math.round(26 * (1 - a));
} };
const OPACITY_STEPS = 6; const OPACITY_STEPS = 6;
const ANIMATION_STEP_TIME = 20; const ANIMATION_STEP_TIME = 20;
const LOWER_FRAMERATE_FACTOR = 2; const LOWER_FRAMERATE_FACTOR = 2;
const scheduleAnimation = padutils.makeAnimationScheduler(animateStep, ANIMATION_STEP_TIME, LOWER_FRAMERATE_FACTOR).scheduleAnimation; const {scheduleAnimation} =
padutils.makeAnimationScheduler(animateStep, ANIMATION_STEP_TIME, LOWER_FRAMERATE_FACTOR);
const NUMCOLS = 4; const NUMCOLS = 4;
@ -72,11 +118,9 @@ const paduserlist = (function () {
.css('border', 0) .css('border', 0)
.css('height', `${height}px`); .css('height', `${height}px`);
function isNameEditable(data) { const isNameEditable = (data) => (!data.name) && (data.status !== 'Disconnected');
return (!data.name) && (data.status != 'Disconnected');
}
function replaceUserRowContents(tr, height, data) { const replaceUserRowContents = (tr, height, data) => {
const tds = createUserRowTds(height, data); const tds = createUserRowTds(height, data);
if (isNameEditable(data) && tr.find('td.usertdname input:enabled').length > 0) { if (isNameEditable(data) && tr.find('td.usertdname input:enabled').length > 0) {
// preserve input field node // preserve input field node
@ -93,7 +137,7 @@ const paduserlist = (function () {
tr.empty().append(tds); tr.empty().append(tds);
} }
return tr; return tr;
} };
const createUserRowTds = (height, data) => { const createUserRowTds = (height, data) => {
let name; let name;
@ -105,7 +149,7 @@ const paduserlist = (function () {
.attr('type', 'text') .attr('type', 'text')
.addClass('editempty') .addClass('editempty')
.addClass('newinput') .addClass('newinput')
.attr('value', _('pad.userlist.unnamed')); .attr('value', html10n.get('pad.userlist.unnamed'));
if (isNameEditable(data)) name.attr('disabled', 'disabled'); if (isNameEditable(data)) name.attr('disabled', 'disabled');
} }
return $() return $()
@ -131,19 +175,17 @@ const paduserlist = (function () {
.attr('id', id) .attr('id', id)
.append(contents); .append(contents);
function rowNode(row) { const rowNode = (row) => $(`#${row.domId}`);
return $(`#${row.domId}`);
}
function handleRowData(row) { const handleRowData = (row) => {
if (row.data && row.data.status == 'Disconnected') { if (row.data && row.data.status === 'Disconnected') {
row.opacity = 0.5; row.opacity = 0.5;
} else { } else {
delete row.opacity; delete row.opacity;
} }
} };
function handleOtherUserInputs() { const handleOtherUserInputs = () => {
// handle 'INPUT' elements for naming other unnamed users // handle 'INPUT' elements for naming other unnamed users
$('#otheruserstable input.newinput').each(function () { $('#otheruserstable input.newinput').each(function () {
const input = $(this); const input = $(this);
@ -156,12 +198,12 @@ const paduserlist = (function () {
} }
} }
}).removeClass('newinput'); }).removeClass('newinput');
} };
// animationPower is 0 to skip animation, 1 for linear, 2 for quadratic, etc. // animationPower is 0 to skip animation, 1 for linear, 2 for quadratic, etc.
function insertRow(position, data, animationPower) { const insertRow = (position, data, animationPower) => {
position = Math.max(0, Math.min(rowsPresent.length, position)); position = Math.max(0, Math.min(rowsPresent.length, position));
animationPower = (animationPower === undefined ? 4 : animationPower); animationPower = (animationPower === undefined ? 4 : animationPower);
@ -177,7 +219,7 @@ const paduserlist = (function () {
handleRowData(row); handleRowData(row);
rowsPresent.splice(position, 0, row); rowsPresent.splice(position, 0, row);
let tr; let tr;
if (animationPower == 0) { if (animationPower === 0) {
tr = createRow(domId, createUserRowTds(getAnimationHeight(0), data), authorId); tr = createRow(domId, createUserRowTds(getAnimationHeight(0), data), authorId);
row.animationStep = 0; row.animationStep = 0;
} else { } else {
@ -185,41 +227,43 @@ const paduserlist = (function () {
tr = createRow(domId, createEmptyRowTds(getAnimationHeight(ANIMATION_START)), authorId); tr = createRow(domId, createEmptyRowTds(getAnimationHeight(ANIMATION_START)), authorId);
} }
$('table#otheruserstable').show(); $('table#otheruserstable').show();
if (position == 0) { if (position === 0) {
$('table#otheruserstable').prepend(tr); $('table#otheruserstable').prepend(tr);
} else { } else {
rowNode(rowsPresent[position - 1]).after(tr); rowNode(rowsPresent[position - 1]).after(tr);
} }
if (animationPower != 0) { if (animationPower !== 0) {
scheduleAnimation(); scheduleAnimation();
} }
handleOtherUserInputs(); handleOtherUserInputs();
return row; return row;
} };
function updateRow(position, data) { const updateRow = (position, data) => {
const row = rowsPresent[position]; const row = rowsPresent[position];
if (row) { if (row) {
row.data = data; row.data = data;
handleRowData(row); handleRowData(row);
if (row.animationStep == 0) { if (row.animationStep === 0) {
// not currently animating // not currently animating
const tr = rowNode(row); const tr = rowNode(row);
replaceUserRowContents(tr, getAnimationHeight(0), row.data).find('td').css('opacity', (row.opacity === undefined ? 1 : row.opacity)); replaceUserRowContents(tr, getAnimationHeight(0), row.data)
.find('td')
.css('opacity', (row.opacity === undefined ? 1 : row.opacity));
handleOtherUserInputs(); handleOtherUserInputs();
} }
} }
} };
function removeRow(position, animationPower) { const removeRow = (position, animationPower) => {
animationPower = (animationPower === undefined ? 4 : animationPower); animationPower = (animationPower === undefined ? 4 : animationPower);
const row = rowsPresent[position]; const row = rowsPresent[position];
if (row) { if (row) {
rowsPresent.splice(position, 1); // remove rowsPresent.splice(position, 1); // remove
if (animationPower == 0) { if (animationPower === 0) {
rowNode(row).remove(); rowNode(row).remove();
} else { } else {
row.animationStep = -row.animationStep; // use symmetry row.animationStep = -row.animationStep; // use symmetry
@ -231,65 +275,20 @@ const paduserlist = (function () {
if (rowsPresent.length === 0) { if (rowsPresent.length === 0) {
$('table#otheruserstable').hide(); $('table#otheruserstable').hide();
} }
} };
// newPosition is position after the row has been removed // newPosition is position after the row has been removed
function moveRow(oldPosition, newPosition, animationPower) { const moveRow = (oldPosition, newPosition, animationPower) => {
animationPower = (animationPower === undefined ? 1 : animationPower); // linear is best animationPower = (animationPower === undefined ? 1 : animationPower); // linear is best
const row = rowsPresent[oldPosition]; const row = rowsPresent[oldPosition];
if (row && oldPosition != newPosition) { if (row && oldPosition !== newPosition) {
const rowData = row.data; const rowData = row.data;
removeRow(oldPosition, animationPower); removeRow(oldPosition, animationPower);
insertRow(newPosition, rowData, animationPower); insertRow(newPosition, rowData, animationPower);
} }
} };
function animateStep() {
// animation must be symmetrical
for (var i = rowsFadingIn.length - 1; i >= 0; i--) { // backwards to allow removal
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);
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 (var i = rowsFadingOut.length - 1; i >= 0; i--) { // backwards to allow removal
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);
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 self = { const self = {
insertRow, insertRow,
@ -302,7 +301,7 @@ const paduserlist = (function () {
const otherUsersInfo = []; const otherUsersInfo = [];
const otherUsersData = []; const otherUsersData = [];
function rowManagerMakeNameEditor(jnode, userId) { const rowManagerMakeNameEditor = (jnode, userId) => {
setUpEditable(jnode, () => { setUpEditable(jnode, () => {
const existingIndex = findExistingIndex(userId); const existingIndex = findExistingIndex(userId);
if (existingIndex >= 0) { if (existingIndex >= 0) {
@ -313,26 +312,26 @@ const paduserlist = (function () {
}, (newName) => { }, (newName) => {
if (!newName) { if (!newName) {
jnode.addClass('editempty'); jnode.addClass('editempty');
jnode.val(_('pad.userlist.unnamed')); jnode.val(html10n.get('pad.userlist.unnamed'));
} else { } else {
jnode.attr('disabled', 'disabled'); jnode.attr('disabled', 'disabled');
pad.suggestUserName(userId, newName); pad.suggestUserName(userId, newName);
} }
}); });
} };
function findExistingIndex(userId) { const findExistingIndex = (userId) => {
let existingIndex = -1; let existingIndex = -1;
for (let i = 0; i < otherUsersInfo.length; i++) { for (let i = 0; i < otherUsersInfo.length; i++) {
if (otherUsersInfo[i].userId == userId) { if (otherUsersInfo[i].userId === userId) {
existingIndex = i; existingIndex = i;
break; break;
} }
} }
return existingIndex; return existingIndex;
} };
function setUpEditable(jqueryNode, valueGetter, valueSetter) { const setUpEditable = (jqueryNode, valueGetter, valueSetter) => {
jqueryNode.bind('focus', (evt) => { jqueryNode.bind('focus', (evt) => {
const oldValue = valueGetter(); const oldValue = valueGetter();
if (jqueryNode.val() !== oldValue) { if (jqueryNode.val() !== oldValue) {
@ -350,16 +349,18 @@ const paduserlist = (function () {
jqueryNode.val(valueGetter()).blur(); jqueryNode.val(valueGetter()).blur();
}); });
jqueryNode.removeAttr('disabled').addClass('editable'); jqueryNode.removeAttr('disabled').addClass('editable');
} };
var pad = undefined; let pad = undefined;
var self = { const self = {
init(myInitialUserInfo, _pad) { init(myInitialUserInfo, _pad) {
pad = _pad; pad = _pad;
self.setMyUserInfo(myInitialUserInfo); self.setMyUserInfo(myInitialUserInfo);
if ($('#online_count').length === 0) $('#editbar [data-key=showusers] > a').append('<span id="online_count">1</span>'); if ($('#online_count').length === 0) {
$('#editbar [data-key=showusers] > a').append('<span id="online_count">1</span>');
}
$('#otheruserstable tr').remove(); $('#otheruserstable tr').remove();
@ -388,23 +389,24 @@ const paduserlist = (function () {
}); });
// //
}, },
usersOnline() { usersOnline: () => {
// Returns an object of users who are currently online on this pad // Returns an object of users who are currently online on this pad
const userList = [].concat(otherUsersInfo); // Make a copy of the otherUsersInfo, otherwise every call to users modifies the referenced array // Make a copy of the otherUsersInfo, otherwise every call to users
// modifies the referenced array
const userList = [].concat(otherUsersInfo);
// Now we need to add ourselves.. // Now we need to add ourselves..
userList.push(myUserInfo); userList.push(myUserInfo);
return userList; return userList;
}, },
users() { users: () => {
// Returns an object of users who have been on this pad // Returns an object of users who have been on this pad
const userList = self.usersOnline(); const userList = self.usersOnline();
// Now we add historical authors // Now we add historical authors
const historical = clientVars.collab_client_vars.historicalAuthorData; const historical = clientVars.collab_client_vars.historicalAuthorData;
for (const key in historical) { for (const [key, {userId}] of Object.entries(historical)) {
var userId = historical[key].userId;
// Check we don't already have this author in our array // Check we don't already have this author in our array
var exists = false; let exists = false;
userList.forEach((user) => { userList.forEach((user) => {
if (user.userId === userId) exists = true; if (user.userId === userId) exists = true;
@ -416,7 +418,7 @@ const paduserlist = (function () {
} }
return userList; return userList;
}, },
setMyUserInfo(info) { setMyUserInfo: (info) => {
// translate the colorId // translate the colorId
if (typeof info.colorId === 'number') { if (typeof info.colorId === 'number') {
info.colorId = clientVars.colorPalette[info.colorId]; info.colorId = clientVars.colorPalette[info.colorId];
@ -427,8 +429,8 @@ const paduserlist = (function () {
self.renderMyUserInfo(); self.renderMyUserInfo();
}, },
userJoinOrUpdate(info) { userJoinOrUpdate: (info) => {
if ((!info.userId) || (info.userId == myUserInfo.userId)) { if ((!info.userId) || (info.userId === myUserInfo.userId)) {
// not sure how this would happen // not sure how this would happen
return; return;
} }
@ -438,7 +440,8 @@ const paduserlist = (function () {
}); });
const userData = {}; const userData = {};
userData.color = typeof info.colorId === 'number' ? clientVars.colorPalette[info.colorId] : info.colorId; userData.color = typeof info.colorId === 'number'
? clientVars.colorPalette[info.colorId] : info.colorId;
userData.name = info.name; userData.name = info.name;
userData.status = ''; userData.status = '';
userData.activity = ''; userData.activity = '';
@ -460,12 +463,12 @@ const paduserlist = (function () {
const nameThis = (info.name || '').toLowerCase(); const nameThis = (info.name || '').toLowerCase();
const idN = infoN.userId; const idN = infoN.userId;
const idThis = info.userId; const idThis = info.userId;
return (nameN > nameThis) || (nameN == nameThis && idN > idThis); return (nameN > nameThis) || (nameN === nameThis && idN > idThis);
}); });
if (existingIndex >= 0) { if (existingIndex >= 0) {
// update // update
if (existingIndex == newIndex) { if (existingIndex === newIndex) {
otherUsersInfo[existingIndex] = info; otherUsersInfo[existingIndex] = info;
otherUsersData[existingIndex] = userData; otherUsersData[existingIndex] = userData;
rowManager.updateRow(existingIndex, userData); rowManager.updateRow(existingIndex, userData);
@ -485,10 +488,10 @@ const paduserlist = (function () {
self.updateNumberOfOnlineUsers(); self.updateNumberOfOnlineUsers();
}, },
updateNumberOfOnlineUsers() { updateNumberOfOnlineUsers: () => {
let online = 1; // you are always online! let online = 1; // you are always online!
for (let i = 0; i < otherUsersData.length; i++) { for (let i = 0; i < otherUsersData.length; i++) {
if (otherUsersData[i].status == '') { if (otherUsersData[i].status === '') {
online++; online++;
} }
} }
@ -497,7 +500,7 @@ const paduserlist = (function () {
return online; return online;
}, },
userLeave(info) { userLeave: (info) => {
const existingIndex = findExistingIndex(info.userId); const existingIndex = findExistingIndex(info.userId);
if (existingIndex >= 0) { if (existingIndex >= 0) {
const userData = otherUsersData[existingIndex]; const userData = otherUsersData[existingIndex];
@ -510,11 +513,12 @@ const paduserlist = (function () {
// joins, or updates happen for this user in the // joins, or updates happen for this user in the
// next N seconds, to remove the user from the list. // next N seconds, to remove the user from the list.
const thisUserId = info.userId; const thisUserId = info.userId;
var thisLeaveTimer = window.setTimeout(() => { const thisLeaveTimer = window.setTimeout(() => {
const newExistingIndex = findExistingIndex(thisUserId); const newExistingIndex = findExistingIndex(thisUserId);
if (newExistingIndex >= 0) { if (newExistingIndex >= 0) {
const newUserData = otherUsersData[newExistingIndex]; const newUserData = otherUsersData[newExistingIndex];
if (newUserData.status == 'Disconnected' && newUserData.leaveTimer == thisLeaveTimer) { if (newUserData.status === 'Disconnected' &&
newUserData.leaveTimer === thisLeaveTimer) {
otherUsersInfo.splice(newExistingIndex, 1); otherUsersInfo.splice(newExistingIndex, 1);
otherUsersData.splice(newExistingIndex, 1); otherUsersData.splice(newExistingIndex, 1);
rowManager.removeRow(newExistingIndex); rowManager.removeRow(newExistingIndex);
@ -529,7 +533,7 @@ const paduserlist = (function () {
self.updateNumberOfOnlineUsers(); self.updateNumberOfOnlineUsers();
}, },
renderMyUserInfo() { renderMyUserInfo: () => {
if (myUserInfo.name) { if (myUserInfo.name) {
$('#myusernameedit').removeClass('editempty').val(myUserInfo.name); $('#myusernameedit').removeClass('editempty').val(myUserInfo.name);
} else { } else {
@ -549,23 +553,20 @@ const paduserlist = (function () {
return self; return self;
}()); }());
function getColorPickerSwatchIndex(jnode) { const getColorPickerSwatchIndex = (jnode) => $('#colorpickerswatches li').index(jnode);
// return Number(jnode.get(0).className.match(/\bn([0-9]+)\b/)[1])-1;
return $('#colorpickerswatches li').index(jnode);
}
function closeColorPicker(accept) { const closeColorPicker = (accept) => {
if (accept) { if (accept) {
var newColor = $('#mycolorpickerpreview').css('background-color'); let newColor = $('#mycolorpickerpreview').css('background-color');
const parts = newColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/); const parts = newColor.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
// parts now should be ["rgb(0, 70, 255", "0", "70", "255"] // parts now should be ["rgb(0, 70, 255", "0", "70", "255"]
if (parts) { if (parts) {
delete (parts[0]); delete (parts[0]);
for (let i = 1; i <= 3; ++i) { for (let i = 1; i <= 3; ++i) {
parts[i] = parseInt(parts[i]).toString(16); parts[i] = parseInt(parts[i]).toString(16);
if (parts[i].length == 1) parts[i] = `0${parts[i]}`; if (parts[i].length === 1) parts[i] = `0${parts[i]}`;
} }
var newColor = `#${parts.join('')}`; // "0070ff" newColor = `#${parts.join('')}`; // "0070ff"
} }
myUserInfo.colorId = newColor; myUserInfo.colorId = newColor;
pad.notifyChangeColor(newColor); pad.notifyChangeColor(newColor);
@ -577,10 +578,9 @@ function closeColorPicker(accept) {
colorPickerOpen = false; colorPickerOpen = false;
$('#mycolorpicker').removeClass('popup-show'); $('#mycolorpicker').removeClass('popup-show');
} };
function showColorPicker() { const showColorPicker = () => {
previousColorId = myUserInfo.colorId;
$.farbtastic('#colorpicker').setColor(myUserInfo.colorId); $.farbtastic('#colorpicker').setColor(myUserInfo.colorId);
if (!colorPickerOpen) { if (!colorPickerOpen) {
@ -613,6 +613,6 @@ function showColorPicker() {
$('#colorpickerswatches li').removeClass('picked'); $('#colorpickerswatches li').removeClass('picked');
$($('#colorpickerswatches li')[myUserInfo.colorId]).addClass('picked'); // seems weird $($('#colorpickerswatches li')[myUserInfo.colorId]).addClass('picked'); // seems weird
} }
} };
exports.paduserlist = paduserlist; exports.paduserlist = paduserlist;

View file

@ -1,3 +1,5 @@
'use strict';
/** /**
* This code is mostly from the old Etherpad. Please help us to comment this code. * 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. * This helps other people to understand this code better and helps them to improve it.
@ -20,8 +22,6 @@
* limitations under the License. * limitations under the License.
*/ */
'use strict';
const Security = require('./security'); const Security = require('./security');
/** /**