diff --git a/src/static/js/broadcast.js b/src/static/js/broadcast.js index d9f759752..e785d5648 100644 --- a/src/static/js/broadcast.js +++ b/src/static/js/broadcast.js @@ -1,3 +1,5 @@ +'use strict'; + /** * 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. @@ -32,51 +34,33 @@ const hooks = require('./pluginfw/hooks'); // These parameters were global, now they are injected. A reference to the // Timeslider controller would probably be more appropriate. function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider) { + let goToRevisionIfEnabledCount = 0; let changesetLoader = undefined; - // Below Array#indexOf code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_indexof.htm - if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (elt /* , from*/) { - const len = this.length >>> 0; - - let from = Number(arguments[1]) || 0; - from = (from < 0) ? Math.ceil(from) : Math.floor(from); - if (from < 0) from += len; - - for (; from < len; from++) { - if (from in this && this[from] === elt) return from; - } - return -1; - }; - } - - function debugLog() { + const debugLog = (...args) => { try { - if (window.console) console.log.apply(console, arguments); + if (window.console) console.log(...args); } catch (e) { if (window.console) console.log('error printing: ', e); } - } - - // var socket; - const channelState = 'DISCONNECTED'; - - const appLevelDisconnectReason = null; + }; const padContents = { currentRevision: clientVars.collab_client_vars.rev, currentTime: clientVars.collab_client_vars.time, - currentLines: Changeset.splitTextLines(clientVars.collab_client_vars.initialAttributedText.text), + currentLines: + Changeset.splitTextLines(clientVars.collab_client_vars.initialAttributedText.text), currentDivs: null, // to be filled in once the dom loads apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool), alines: Changeset.splitAttributionLines( - clientVars.collab_client_vars.initialAttributedText.attribs, clientVars.collab_client_vars.initialAttributedText.text), + clientVars.collab_client_vars.initialAttributedText.attribs, + clientVars.collab_client_vars.initialAttributedText.text), // generates a jquery element containing HTML for a line lineToElement(line, aline) { const element = document.createElement('div'); - const emptyLine = (line == '\n'); + const emptyLine = (line === '\n'); const domInfo = domline.createDomLine(!emptyLine, true); linestylefilter.populateDomLine(line, aline, this.apool, domInfo); domInfo.prepareForAdd(); @@ -86,9 +70,10 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro return $(element); }, - applySpliceToDivs(start, numRemoved, newLines) { + // splice the lines + splice(start, numRemoved, ...newLines) { // remove spliced-out lines from DOM - for (var i = start; i < start + numRemoved && i < this.currentDivs.length; i++) { + for (let i = start; i < start + numRemoved && i < this.currentDivs.length; i++) { this.currentDivs[i].remove(); } @@ -96,7 +81,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro this.currentDivs.splice(start, numRemoved); const newDivs = []; - for (var i = 0; i < newLines.length; i++) { + for (let i = 0; i < newLines.length; i++) { newDivs.push(this.lineToElement(newLines[i], this.alines[start + i])); } @@ -104,7 +89,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro let startDiv = this.currentDivs[start - 1] || null; // insert the div elements into the correct place, in the correct order - for (var i = 0; i < newDivs.length; i++) { + for (let i = 0; i < newDivs.length; i++) { if (startDiv) { startDiv.after(newDivs[i]); } else { @@ -114,23 +99,10 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro } // insert new divs into currentDivs array - newDivs.unshift(0); // remove 0 elements - newDivs.unshift(start); - this.currentDivs.splice.apply(this.currentDivs, newDivs); - return this; - }, - - // splice the lines - splice(start, numRemoved, newLinesVA) { - const newLines = _.map(Array.prototype.slice.call(arguments, 2), (s) => s); - - // apply this splice to the divs - this.applySpliceToDivs(start, numRemoved, newLines); + this.currentDivs.splice(start, 0, ...newDivs); // call currentLines.splice, to keep the currentLines array up to date - newLines.unshift(numRemoved); - newLines.unshift(start); - this.currentLines.splice.apply(this.currentLines, arguments); + this.currentLines.splice(start, numRemoved, ...newLines); }, // returns the contents of the specified line I get(i) { @@ -142,16 +114,15 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro }, getActiveAuthors() { - const self = this; const authors = []; const seenNums = {}; - const alines = self.alines; + const alines = this.alines; for (let i = 0; i < alines.length; i++) { Changeset.eachAttribNumber(alines[i], (n) => { if (!seenNums[n]) { seenNums[n] = true; - if (self.apool.getAttribKey(n) == 'author') { - const a = self.apool.getAttribValue(n); + if (this.apool.getAttribKey(n) === 'author') { + const a = this.apool.getAttribValue(n); if (a) { authors.push(a); } @@ -164,42 +135,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro }, }; - function callCatchingErrors(catcher, func) { - try { - wrapRecordingErrors(catcher, func)(); - } catch (e) { /* absorb*/ - } - } - - function wrapRecordingErrors(catcher, func) { - return function () { - try { - return func.apply(this, Array.prototype.slice.call(arguments)); - } catch (e) { - // caughtErrors.push(e); - // caughtErrorCatchers.push(catcher); - // caughtErrorTimes.push(+new Date()); - // console.dir({catcher: catcher, e: e}); - debugLog(e); // TODO(kroo): added temporary, to catch errors - throw e; - } - }; - } - - function loadedNewChangeset(changesetForward, changesetBackward, revision, timeDelta) { - const broadcasting = (BroadcastSlider.getSliderPosition() == revisionInfo.latest); - revisionInfo.addChangeset(revision, revision + 1, changesetForward, changesetBackward, timeDelta); - BroadcastSlider.setSliderLength(revisionInfo.latest); - if (broadcasting) applyChangeset(changesetForward, revision + 1, false, timeDelta); - } - - /* - At this point, we must be certain that the changeset really does map from - the current revision to the specified revision. Any mistakes here will - cause the whole slider to get out of sync. - */ - - function applyChangeset(changeset, revision, preventSliderMovement, timeDelta) { + const applyChangeset = (changeset, revision, preventSliderMovement, timeDelta) => { // disable the next 'gotorevision' call handled by a timeslider update if (!preventSliderMovement) { goToRevisionIfEnabledCount++; @@ -215,7 +151,8 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro } // scroll to the area that is changed before the lines are mutated - if ($('#options-followContents').is(':checked') || $('#options-followContents').prop('checked')) { + if ($('#options-followContents').is(':checked') || + $('#options-followContents').prop('checked')) { // get the index of the first line that has mutated attributes // the last line in `oldAlines` should always equal to "|1+1", ie newline without attributes // so it should be safe to assume this line has changed attributes when inserting content at @@ -227,11 +164,25 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro return true; // break } }); - // deal with someone is the author of a line and changes one character, so the alines won't change + // deal with someone is the author of a line and changes one character, + // so the alines won't change if (lineChanged === undefined) { lineChanged = Changeset.opIterator(Changeset.unpack(changeset).ops).next().lines; } + const goToLineNumber = (lineNumber) => { + // Sets the Y scrolling of the browser to go to this line + const line = $('#innerdocbody').find(`div:nth-child(${lineNumber + 1})`); + const newY = $(line)[0].offsetTop; + const ecb = document.getElementById('editorcontainerbox'); + // Chrome 55 - 59 bugfix + if (ecb.scrollTo) { + ecb.scrollTo({top: newY, behavior: 'smooth'}); + } else { + $('#editorcontainerbox').scrollTop(newY); + } + }; + goToLineNumber(lineChanged); } @@ -244,17 +195,32 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]); BroadcastSlider.setAuthors(authors); - } + }; - function updateTimer() { - const zpad = function (str, length) { + const loadedNewChangeset = (changesetForward, changesetBackward, revision, timeDelta) => { + const revisionInfo = window.revisionInfo; + const broadcasting = (BroadcastSlider.getSliderPosition() === revisionInfo.latest); + revisionInfo.addChangeset( + revision, revision + 1, changesetForward, changesetBackward, timeDelta); + BroadcastSlider.setSliderLength(revisionInfo.latest); + if (broadcasting) applyChangeset(changesetForward, revision + 1, false, timeDelta); + }; + + /* + At this point, we must be certain that the changeset really does map from + the current revision to the specified revision. Any mistakes here will + cause the whole slider to get out of sync. + */ + + const updateTimer = () => { + const zpad = (str, length) => { str = `${str}`; while (str.length < length) str = `0${str}`; return str; }; const date = new Date(padContents.currentTime); - const dateFormat = function () { + const dateFormat = () => { const month = zpad(date.getMonth() + 1, 2); const day = zpad(date.getDate(), 2); const year = (date.getFullYear()); @@ -292,43 +258,41 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro year: date.getFullYear(), }); $('#revision_date').html(revisionDate); - } + }; updateTimer(); - function goToRevision(newRevision) { + const goToRevision = (newRevision) => { padContents.targetRevision = newRevision; - const self = this; - const path = revisionInfo.getPath(padContents.currentRevision, newRevision); + const path = window.revisionInfo.getPath(padContents.currentRevision, newRevision); hooks.aCallAll('goToRevisionEvent', { rev: newRevision, }); - if (path.status == 'complete') { - var cs = path.changesets; - var changeset = cs[0]; - var timeDelta = path.times[0]; - for (var i = 1; i < cs.length; i++) { + if (path.status === 'complete') { + const cs = path.changesets; + let changeset = cs[0]; + let timeDelta = path.times[0]; + for (let i = 1; i < cs.length; i++) { changeset = Changeset.compose(changeset, cs[i], padContents.apool); timeDelta += path.times[i]; } if (changeset) applyChangeset(changeset, path.rev, true, timeDelta); - } else if (path.status == 'partial') { - const sliderLocation = padContents.currentRevision; + } else if (path.status === 'partial') { // callback is called after changeset information is pulled from server // this may never get called, if the changeset has already been loaded - const update = function (start, end) { + const update = (start, end) => { // if we've called goToRevision in the time since, don't goToRevision goToRevision(padContents.targetRevision); }; // do our best with what we have... - var cs = path.changesets; + const cs = path.changesets; - var changeset = cs[0]; - var timeDelta = path.times[0]; - for (var i = 1; i < cs.length; i++) { + let changeset = cs[0]; + let timeDelta = path.times[0]; + for (let i = 1; i < cs.length; i++) { changeset = Changeset.compose(changeset, cs[i], padContents.apool); timeDelta += path.times[i]; } @@ -342,23 +306,23 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]); BroadcastSlider.setAuthors(authors); - } + }; - function loadChangesetsForRevision(revision, callback) { + const loadChangesetsForRevision = (revision, callback) => { if (BroadcastSlider.getSliderLength() > 10000) { - var start = (Math.floor((revision) / 10000) * 10000); // revision 0 to 10 + const start = (Math.floor((revision) / 10000) * 10000); // revision 0 to 10 changesetLoader.queueUp(start, 100); } if (BroadcastSlider.getSliderLength() > 1000) { - var start = (Math.floor((revision) / 1000) * 1000); // (start from -1, go to 19) + 1 + const start = (Math.floor((revision) / 1000) * 1000); // (start from -1, go to 19) + 1 changesetLoader.queueUp(start, 10); } - start = (Math.floor((revision) / 100) * 100); + const start = (Math.floor((revision) / 100) * 100); changesetLoader.queueUp(start, 1, callback); - } + }; changesetLoader = { running: false, @@ -369,29 +333,38 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro reqCallbacks: [], queueUp(revision, width, callback) { if (revision < 0) revision = 0; - // if(changesetLoader.requestQueue.indexOf(revision) != -1) + // if(this.requestQueue.indexOf(revision) != -1) // return; // already in the queue. - if (changesetLoader.resolved.indexOf(`${revision}_${width}`) != -1) return; // already loaded from the server - changesetLoader.resolved.push(`${revision}_${width}`); + if (this.resolved.indexOf(`${revision}_${width}`) !== -1) { + // already loaded from the server + return; + } + this.resolved.push(`${revision}_${width}`); - const requestQueue = width == 1 ? changesetLoader.requestQueue3 : width == 10 ? changesetLoader.requestQueue2 : changesetLoader.requestQueue1; + const requestQueue = + width === 1 ? this.requestQueue3 + : width === 10 ? this.requestQueue2 + : this.requestQueue1; requestQueue.push( { rev: revision, res: width, callback, }); - if (!changesetLoader.running) { - changesetLoader.running = true; - setTimeout(changesetLoader.loadFromQueue, 10); + if (!this.running) { + this.running = true; + setTimeout(() => this.loadFromQueue(), 10); } }, loadFromQueue() { - const self = changesetLoader; - const requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 : self.requestQueue2.length > 0 ? self.requestQueue2 : self.requestQueue3.length > 0 ? self.requestQueue3 : null; + const requestQueue = + this.requestQueue1.length > 0 ? this.requestQueue1 + : this.requestQueue2.length > 0 ? this.requestQueue2 + : this.requestQueue3.length > 0 ? this.requestQueue3 + : null; if (!requestQueue) { - self.running = false; + this.running = false; return; } @@ -407,48 +380,48 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro requestID, }); - self.reqCallbacks[requestID] = callback; + this.reqCallbacks[requestID] = callback; }, handleSocketResponse(message) { - const self = changesetLoader; - const start = message.data.start; const granularity = message.data.granularity; - const callback = self.reqCallbacks[message.data.requestID]; - delete self.reqCallbacks[message.data.requestID]; + const callback = this.reqCallbacks[message.data.requestID]; + delete this.reqCallbacks[message.data.requestID]; - self.handleResponse(message.data, start, granularity, callback); - setTimeout(self.loadFromQueue, 10); + this.handleResponse(message.data, start, granularity, callback); + setTimeout(() => this.loadFromQueue(), 10); }, - handleResponse(data, start, granularity, callback) { + handleResponse: (data, start, granularity, callback) => { const pool = (new AttribPool()).fromJsonable(data.apool); for (let i = 0; i < data.forwardsChangesets.length; i++) { const astart = start + i * granularity - 1; // rev -1 is a blank single line let aend = start + (i + 1) * granularity - 1; // totalRevs is the most recent revision if (aend > data.actualEndNum - 1) aend = data.actualEndNum - 1; // debugLog("adding changeset:", astart, aend); - const forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool); - const backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool); - revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]); + const forwardcs = + Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool); + const backwardcs = + Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool); + window.revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]); } if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1); }, handleMessageFromServer(obj) { - if (obj.type == 'COLLABROOM') { + if (obj.type === 'COLLABROOM') { obj = obj.data; - if (obj.type == 'NEW_CHANGES') { + if (obj.type === 'NEW_CHANGES') { const changeset = Changeset.moveOpsToNewPool( obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); - var changesetBack = Changeset.inverse( + let changesetBack = Changeset.inverse( obj.changeset, padContents.currentLines, padContents.alines, padContents.apool); - var changesetBack = Changeset.moveOpsToNewPool( + changesetBack = Changeset.moveOpsToNewPool( changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool); loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta); - } else if (obj.type == 'NEW_AUTHORDATA') { + } else if (obj.type === 'NEW_AUTHORDATA') { const authorMap = {}; authorMap[obj.author] = obj.data; receiveAuthorData(authorMap); @@ -456,13 +429,13 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]); BroadcastSlider.setAuthors(authors); - } else if (obj.type == 'NEW_SAVEDREV') { + } else if (obj.type === 'NEW_SAVEDREV') { const savedRev = obj.savedRev; BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev); } hooks.callAll(`handleClientTimesliderMessage_${obj.type}`, {payload: obj}); - } else if (obj.type == 'CHANGESET_REQ') { - changesetLoader.handleSocketResponse(obj); + } else if (obj.type === 'CHANGESET_REQ') { + this.handleSocketResponse(obj); } else { debugLog(`Unknown message type: ${obj.type}`); } @@ -485,49 +458,36 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro // this is necessary to keep infinite loops of events firing, // since goToRevision changes the slider position - var goToRevisionIfEnabledCount = 0; - const goToRevisionIfEnabled = function () { + const goToRevisionIfEnabled = (...args) => { if (goToRevisionIfEnabledCount > 0) { goToRevisionIfEnabledCount--; } else { - goToRevision.apply(goToRevision, arguments); + goToRevision(...args); } }; BroadcastSlider.onSlider(goToRevisionIfEnabled); const dynamicCSS = makeCSSManager('dynamicsyntax'); - var authorData = {}; + const authorData = {}; - function receiveAuthorData(newAuthorData) { - for (const author in newAuthorData) { - const data = newAuthorData[author]; - const bgcolor = typeof data.colorId === 'number' ? clientVars.colorPalette[data.colorId] : data.colorId; + const receiveAuthorData = (newAuthorData) => { + for (const [author, data] of Object.entries(newAuthorData)) { + const bgcolor = typeof data.colorId === 'number' + ? clientVars.colorPalette[data.colorId] : data.colorId; if (bgcolor && dynamicCSS) { const selector = dynamicCSS.selectorStyle(`.${linestylefilter.getAuthorClassName(author)}`); selector.backgroundColor = bgcolor; - selector.color = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5) ? '#ffffff' : '#000000'; // see ace2_inner.js for the other part + selector.color = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5) + ? '#ffffff' : '#000000'; // see ace2_inner.js for the other part } authorData[author] = data; } - } + }; receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData); return changesetLoader; - - function goToLineNumber(lineNumber) { - // Sets the Y scrolling of the browser to go to this line - const line = $('#innerdocbody').find(`div:nth-child(${lineNumber + 1})`); - const newY = $(line)[0].offsetTop; - const ecb = document.getElementById('editorcontainerbox'); - // Chrome 55 - 59 bugfix - if (ecb.scrollTo) { - ecb.scrollTo({top: newY, behavior: 'smooth'}); - } else { - $('#editorcontainerbox').scrollTop(newY); - } - } } exports.loadBroadcastJS = loadBroadcastJS; diff --git a/src/static/js/broadcast_revisions.js b/src/static/js/broadcast_revisions.js index 619ede137..8a9eb2e6c 100644 --- a/src/static/js/broadcast_revisions.js +++ b/src/static/js/broadcast_revisions.js @@ -1,3 +1,5 @@ +'use strict'; + /** * 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. @@ -23,7 +25,7 @@ // of the document. These revisions are connected together by various // changesets, or deltas, between any two revisions. -function loadBroadcastRevisionsJS() { +const loadBroadcastRevisionsJS = () => { function Revision(revNum) { this.rev = revNum; this.changesets = []; @@ -33,18 +35,16 @@ function loadBroadcastRevisionsJS() { const changesetWrapper = { deltaRev: destIndex - this.rev, deltaTime: timeDelta, - getValue() { - return changeset; - }, + getValue: () => changeset, }; this.changesets.push(changesetWrapper); this.changesets.sort((a, b) => (b.deltaRev - a.deltaRev)); }; - revisionInfo = {}; + const revisionInfo = {}; revisionInfo.addChangeset = function (fromIndex, toIndex, changeset, backChangeset, timeDelta) { - const startRevision = revisionInfo[fromIndex] || revisionInfo.createNew(fromIndex); - const endRevision = revisionInfo[toIndex] || revisionInfo.createNew(toIndex); + const startRevision = this[fromIndex] || this.createNew(fromIndex); + const endRevision = this[toIndex] || this.createNew(toIndex); startRevision.addChangeset(toIndex, changeset, timeDelta); endRevision.addChangeset(fromIndex, backChangeset, -1 * timeDelta); }; @@ -52,12 +52,12 @@ function loadBroadcastRevisionsJS() { revisionInfo.latest = clientVars.collab_client_vars.rev || -1; revisionInfo.createNew = function (index) { - revisionInfo[index] = new Revision(index); - if (index > revisionInfo.latest) { - revisionInfo.latest = index; + this[index] = new Revision(index); + if (index > this.latest) { + this.latest = index; } - return revisionInfo[index]; + return this[index]; }; // assuming that there is a path from fromIndex to toIndex, and that the links @@ -66,8 +66,8 @@ function loadBroadcastRevisionsJS() { const changesets = []; const spans = []; const times = []; - let elem = revisionInfo[fromIndex] || revisionInfo.createNew(fromIndex); - if (elem.changesets.length != 0 && fromIndex != toIndex) { + let elem = this[fromIndex] || this.createNew(fromIndex); + if (elem.changesets.length !== 0 && fromIndex !== toIndex) { const reverse = !(fromIndex < toIndex); while (((elem.rev < toIndex) && !reverse) || ((elem.rev > toIndex) && reverse)) { let couldNotContinue = false; @@ -76,27 +76,29 @@ function loadBroadcastRevisionsJS() { for (let i = reverse ? elem.changesets.length - 1 : 0; reverse ? i >= 0 : i < elem.changesets.length; i += reverse ? -1 : 1) { - if (((elem.changesets[i].deltaRev < 0) && !reverse) || ((elem.changesets[i].deltaRev > 0) && reverse)) { + if (((elem.changesets[i].deltaRev < 0) && !reverse) || + ((elem.changesets[i].deltaRev > 0) && reverse)) { couldNotContinue = true; break; } - if (((elem.rev + elem.changesets[i].deltaRev <= toIndex) && !reverse) || ((elem.rev + elem.changesets[i].deltaRev >= toIndex) && reverse)) { + if (((elem.rev + elem.changesets[i].deltaRev <= toIndex) && !reverse) || + ((elem.rev + elem.changesets[i].deltaRev >= toIndex) && reverse)) { const topush = elem.changesets[i]; changesets.push(topush.getValue()); spans.push(elem.changesets[i].deltaRev); times.push(topush.deltaTime); - elem = revisionInfo[elem.rev + elem.changesets[i].deltaRev]; + elem = this[elem.rev + elem.changesets[i].deltaRev]; break; } } - if (couldNotContinue || oldRev == elem.rev) break; + if (couldNotContinue || oldRev === elem.rev) break; } } let status = 'partial'; - if (elem.rev == toIndex) status = 'complete'; + if (elem.rev === toIndex) status = 'complete'; return { fromRev: fromIndex, @@ -107,6 +109,7 @@ function loadBroadcastRevisionsJS() { times, }; }; -} + window.revisionInfo = revisionInfo; +}; exports.loadBroadcastRevisionsJS = loadBroadcastRevisionsJS; diff --git a/src/static/js/broadcast_slider.js b/src/static/js/broadcast_slider.js index 430cebf75..f03a22836 100644 --- a/src/static/js/broadcast_slider.js +++ b/src/static/js/broadcast_slider.js @@ -1,3 +1,4 @@ +'use strict'; /** * 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. @@ -26,13 +27,14 @@ const _ = require('./underscore'); const padmodals = require('./pad_modals').padmodals; const colorutils = require('./colorutils').colorutils; -function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { +const loadBroadcastSliderJS = (fireWhenAllScriptsAreLoaded) => { let BroadcastSlider; // Hack to ensure timeslider i18n values are in - $("[data-key='timeslider_returnToPad'] > a > span").html(html10n.get('timeslider.toolbar.returnbutton')); + $("[data-key='timeslider_returnToPad'] > a > span").html( + html10n.get('timeslider.toolbar.returnbutton')); - (function () { // wrap this code in its own namespace + (() => { // wrap this code in its own namespace let sliderLength = 1000; let sliderPos = 0; let sliderActive = false; @@ -40,27 +42,30 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { const savedRevisions = []; let sliderPlaying = false; - const _callSliderCallbacks = function (newval) { + const _callSliderCallbacks = (newval) => { sliderPos = newval; for (let i = 0; i < slidercallbacks.length; i++) { slidercallbacks[i](newval); } }; - const updateSliderElements = function () { + const updateSliderElements = () => { for (let i = 0; i < savedRevisions.length; i++) { const position = parseInt(savedRevisions[i].attr('pos')); - savedRevisions[i].css('left', (position * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)) - 1); + savedRevisions[i].css( + 'left', (position * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)) - 1); } - $('#ui-slider-handle').css('left', sliderPos * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)); + $('#ui-slider-handle').css( + 'left', sliderPos * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)); }; - const addSavedRevision = function (position, info) { + const addSavedRevision = (position, info) => { const newSavedRevision = $('
'); newSavedRevision.addClass('star'); newSavedRevision.attr('pos', position); - newSavedRevision.css('left', (position * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)) - 1); + newSavedRevision.css( + 'left', (position * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)) - 1); $('#ui-slider-bar').append(newSavedRevision); newSavedRevision.mouseup((evt) => { BroadcastSlider.setSliderPosition(position); @@ -68,60 +73,50 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { savedRevisions.push(newSavedRevision); }; - const removeSavedRevision = function (position) { - const element = $(`div.star [pos=${position}]`); - savedRevisions.remove(element); - element.remove(); - return element; - }; - /* Begin small 'API' */ - function onSlider(callback) { + const onSlider = (callback) => { slidercallbacks.push(callback); - } + }; - function getSliderPosition() { - return sliderPos; - } + const getSliderPosition = () => sliderPos; - function setSliderPosition(newpos) { + const setSliderPosition = (newpos) => { newpos = Number(newpos); if (newpos < 0 || newpos > sliderLength) return; if (!newpos) { newpos = 0; // stops it from displaying NaN if newpos isn't set } window.location.hash = `#${newpos}`; - $('#ui-slider-handle').css('left', newpos * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)); + $('#ui-slider-handle').css( + 'left', newpos * ($('#ui-slider-bar').width() - 2) / (sliderLength * 1.0)); $('a.tlink').map(function () { $(this).attr('href', $(this).attr('thref').replace('%revision%', newpos)); }); $('#revision_label').html(html10n.get('timeslider.version', {version: newpos})); - $('#leftstar, #leftstep').toggleClass('disabled', newpos == 0); - $('#rightstar, #rightstep').toggleClass('disabled', newpos == sliderLength); + $('#leftstar, #leftstep').toggleClass('disabled', newpos === 0); + $('#rightstar, #rightstep').toggleClass('disabled', newpos === sliderLength); sliderPos = newpos; _callSliderCallbacks(newpos); - } + }; - function getSliderLength() { - return sliderLength; - } + const getSliderLength = () => sliderLength; - function setSliderLength(newlength) { + const setSliderLength = (newlength) => { sliderLength = newlength; updateSliderElements(); - } + }; // just take over the whole slider screen with a reconnect message - function showReconnectUI() { + const showReconnectUI = () => { padmodals.showModal('disconnected'); - } + }; - function setAuthors(authors) { + const setAuthors = (authors) => { const authorsList = $('#authorsList'); authorsList.empty(); let numAnonymous = 0; @@ -132,7 +127,8 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { const authorColor = clientVars.colorPalette[author.colorId] || author.colorId; if (author.name) { if (numNamed !== 0) authorsList.append(', '); - const textColor = colorutils.textColorFromBackgroundColor(authorColor, clientVars.skinName); + const textColor = + colorutils.textColorFromBackgroundColor(authorColor, clientVars.skinName); $('') .text(author.name || 'unnamed') .css('background-color', authorColor) @@ -168,27 +164,12 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { authorsList.append(')'); } } - if (authors.length == 0) { + if (authors.length === 0) { authorsList.append(html10n.get('timeslider.toolbar.authorsList')); } - } - - BroadcastSlider = { - onSlider, - getSliderPosition, - setSliderPosition, - getSliderLength, - setSliderLength, - isSliderActive() { - return sliderActive; - }, - playpause, - addSavedRevision, - showReconnectUI, - setAuthors, }; - function playButtonUpdater() { + const playButtonUpdater = () => { if (sliderPlaying) { if (getSliderPosition() + 1 > sliderLength) { $('#playpause_button_icon').toggleClass('pause'); @@ -199,39 +180,52 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { setTimeout(playButtonUpdater, 100); } - } + }; - function playpause() { + const playpause = () => { $('#playpause_button_icon').toggleClass('pause'); if (!sliderPlaying) { - if (getSliderPosition() == sliderLength) setSliderPosition(0); + if (getSliderPosition() === sliderLength) setSliderPosition(0); sliderPlaying = true; playButtonUpdater(); } else { sliderPlaying = false; } - } + }; + + BroadcastSlider = { + onSlider, + getSliderPosition, + setSliderPosition, + getSliderLength, + setSliderLength, + isSliderActive: () => sliderActive, + playpause, + addSavedRevision, + showReconnectUI, + setAuthors, + }; // assign event handlers to html UI elements after page load fireWhenAllScriptsAreLoaded.push(() => { $(document).keyup((e) => { - if (!e) var e = window.event; + if (!e) e = window.event; const code = e.keyCode || e.which; - if (code == 37) { // left + if (code === 37) { // left if (e.shiftKey) { $('#leftstar').click(); } else { $('#leftstep').click(); } - } else if (code == 39) { // right + } else if (code === 39) { // right if (e.shiftKey) { $('#rightstar').click(); } else { $('#rightstep').click(); } - } else if (code == 32) { // spacebar + } else if (code === 32) { // spacebar $('#playpause_button_icon').trigger('click'); } }); @@ -251,31 +245,32 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { $('#ui-slider-handle').mousedown(function (evt) { this.startLoc = evt.clientX; this.currentLoc = parseInt($(this).css('left')); - const self = this; sliderActive = true; $(document).mousemove((evt2) => { - $(self).css('pointer', 'move'); - let newloc = self.currentLoc + (evt2.clientX - self.startLoc); + $(this).css('pointer', 'move'); + let newloc = this.currentLoc + (evt2.clientX - this.startLoc); if (newloc < 0) newloc = 0; - if (newloc > ($('#ui-slider-bar').width() - 2)) newloc = ($('#ui-slider-bar').width() - 2); - $('#revision_label').html(html10n.get('timeslider.version', {version: Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))})); - $(self).css('left', newloc); - if (getSliderPosition() != Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))) _callSliderCallbacks(Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))); + const maxPos = $('#ui-slider-bar').width() - 2; + if (newloc > maxPos) newloc = maxPos; + const version = Math.floor(newloc * sliderLength / maxPos); + $('#revision_label').html(html10n.get('timeslider.version', {version})); + $(this).css('left', newloc); + if (getSliderPosition() !== version) _callSliderCallbacks(version); }); $(document).mouseup((evt2) => { $(document).unbind('mousemove'); $(document).unbind('mouseup'); sliderActive = false; - let newloc = self.currentLoc + (evt2.clientX - self.startLoc); + let newloc = this.currentLoc + (evt2.clientX - this.startLoc); if (newloc < 0) newloc = 0; - if (newloc > ($('#ui-slider-bar').width() - 2)) newloc = ($('#ui-slider-bar').width() - 2); - $(self).css('left', newloc); - // if(getSliderPosition() != Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2))) - setSliderPosition(Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))); - if (parseInt($(self).css('left')) < 2) { - $(self).css('left', '2px'); + const maxPos = $('#ui-slider-bar').width() - 2; + if (newloc > maxPos) newloc = maxPos; + $(this).css('left', newloc); + setSliderPosition(Math.floor(newloc * sliderLength / maxPos)); + if (parseInt($(this).css('left')) < 2) { + $(this).css('left', '2px'); } else { - self.currentLoc = parseInt($(self).css('left')); + this.currentLoc = parseInt($(this).css('left')); } }); }); @@ -294,29 +289,30 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { case 'rightstep': setSliderPosition(getSliderPosition() + 1); break; - case 'leftstar': - var nextStar = 0; // default to first revision in document - for (var i = 0; i < savedRevisions.length; i++) { - var pos = parseInt(savedRevisions[i].attr('pos')); + case 'leftstar': { + let nextStar = 0; // default to first revision in document + for (let i = 0; i < savedRevisions.length; i++) { + const pos = parseInt(savedRevisions[i].attr('pos')); if (pos < getSliderPosition() && nextStar < pos) nextStar = pos; } setSliderPosition(nextStar); break; - case 'rightstar': - var nextStar = sliderLength; // default to last revision in document - for (var i = 0; i < savedRevisions.length; i++) { - var pos = parseInt(savedRevisions[i].attr('pos')); + } + case 'rightstar': { + let nextStar = sliderLength; // default to last revision in document + for (let i = 0; i < savedRevisions.length; i++) { + const pos = parseInt(savedRevisions[i].attr('pos')); if (pos > getSliderPosition() && nextStar > pos) nextStar = pos; } setSliderPosition(nextStar); break; + } } }); if (clientVars) { $('#timeslider-wrapper').show(); - const startPos = clientVars.collab_client_vars.rev; if (window.location.hash.length > 1) { const hashRev = Number(window.location.hash.substr(1)); if (!isNaN(hashRev)) { @@ -336,10 +332,11 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) { })(); BroadcastSlider.onSlider((loc) => { - $('#viewlatest').html(loc == BroadcastSlider.getSliderLength() ? 'Viewing latest content' : 'View latest content'); + $('#viewlatest').html( + `${loc === BroadcastSlider.getSliderLength() ? 'Viewing' : 'View'} latest content`); }); return BroadcastSlider; -} +}; exports.loadBroadcastSliderJS = loadBroadcastSliderJS;