mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-02-01 03:12:42 +01:00
lint: broadcast_revisions (#4571)
Co-authored-by: Richard Hansen <rhansen@rhansen.org>
This commit is contained in:
parent
4aef15cb11
commit
8bf463fb00
3 changed files with 231 additions and 271 deletions
|
@ -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.
|
||||||
|
@ -32,51 +34,33 @@ const hooks = require('./pluginfw/hooks');
|
||||||
// These parameters were global, now they are injected. A reference to the
|
// These parameters were global, now they are injected. A reference to the
|
||||||
// Timeslider controller would probably be more appropriate.
|
// Timeslider controller would probably be more appropriate.
|
||||||
function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider) {
|
function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider) {
|
||||||
|
let goToRevisionIfEnabledCount = 0;
|
||||||
let changesetLoader = undefined;
|
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
|
const debugLog = (...args) => {
|
||||||
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() {
|
|
||||||
try {
|
try {
|
||||||
if (window.console) console.log.apply(console, arguments);
|
if (window.console) console.log(...args);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (window.console) console.log('error printing: ', e);
|
if (window.console) console.log('error printing: ', e);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
// var socket;
|
|
||||||
const channelState = 'DISCONNECTED';
|
|
||||||
|
|
||||||
const appLevelDisconnectReason = null;
|
|
||||||
|
|
||||||
const padContents = {
|
const padContents = {
|
||||||
currentRevision: clientVars.collab_client_vars.rev,
|
currentRevision: clientVars.collab_client_vars.rev,
|
||||||
currentTime: clientVars.collab_client_vars.time,
|
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,
|
currentDivs: null,
|
||||||
// to be filled in once the dom loads
|
// to be filled in once the dom loads
|
||||||
apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool),
|
apool: (new AttribPool()).fromJsonable(clientVars.collab_client_vars.apool),
|
||||||
alines: Changeset.splitAttributionLines(
|
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
|
// generates a jquery element containing HTML for a line
|
||||||
lineToElement(line, aline) {
|
lineToElement(line, aline) {
|
||||||
const element = document.createElement('div');
|
const element = document.createElement('div');
|
||||||
const emptyLine = (line == '\n');
|
const emptyLine = (line === '\n');
|
||||||
const domInfo = domline.createDomLine(!emptyLine, true);
|
const domInfo = domline.createDomLine(!emptyLine, true);
|
||||||
linestylefilter.populateDomLine(line, aline, this.apool, domInfo);
|
linestylefilter.populateDomLine(line, aline, this.apool, domInfo);
|
||||||
domInfo.prepareForAdd();
|
domInfo.prepareForAdd();
|
||||||
|
@ -86,9 +70,10 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
return $(element);
|
return $(element);
|
||||||
},
|
},
|
||||||
|
|
||||||
applySpliceToDivs(start, numRemoved, newLines) {
|
// splice the lines
|
||||||
|
splice(start, numRemoved, ...newLines) {
|
||||||
// remove spliced-out lines from DOM
|
// 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();
|
this.currentDivs[i].remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +81,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
this.currentDivs.splice(start, numRemoved);
|
this.currentDivs.splice(start, numRemoved);
|
||||||
|
|
||||||
const newDivs = [];
|
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]));
|
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;
|
let startDiv = this.currentDivs[start - 1] || null;
|
||||||
|
|
||||||
// insert the div elements into the correct place, in the correct order
|
// 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) {
|
if (startDiv) {
|
||||||
startDiv.after(newDivs[i]);
|
startDiv.after(newDivs[i]);
|
||||||
} else {
|
} else {
|
||||||
|
@ -114,23 +99,10 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert new divs into currentDivs array
|
// insert new divs into currentDivs array
|
||||||
newDivs.unshift(0); // remove 0 elements
|
this.currentDivs.splice(start, 0, ...newDivs);
|
||||||
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);
|
|
||||||
|
|
||||||
// call currentLines.splice, to keep the currentLines array up to date
|
// call currentLines.splice, to keep the currentLines array up to date
|
||||||
newLines.unshift(numRemoved);
|
this.currentLines.splice(start, numRemoved, ...newLines);
|
||||||
newLines.unshift(start);
|
|
||||||
this.currentLines.splice.apply(this.currentLines, arguments);
|
|
||||||
},
|
},
|
||||||
// returns the contents of the specified line I
|
// returns the contents of the specified line I
|
||||||
get(i) {
|
get(i) {
|
||||||
|
@ -142,16 +114,15 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
},
|
},
|
||||||
|
|
||||||
getActiveAuthors() {
|
getActiveAuthors() {
|
||||||
const self = this;
|
|
||||||
const authors = [];
|
const authors = [];
|
||||||
const seenNums = {};
|
const seenNums = {};
|
||||||
const alines = self.alines;
|
const alines = this.alines;
|
||||||
for (let i = 0; i < alines.length; i++) {
|
for (let i = 0; i < alines.length; i++) {
|
||||||
Changeset.eachAttribNumber(alines[i], (n) => {
|
Changeset.eachAttribNumber(alines[i], (n) => {
|
||||||
if (!seenNums[n]) {
|
if (!seenNums[n]) {
|
||||||
seenNums[n] = true;
|
seenNums[n] = true;
|
||||||
if (self.apool.getAttribKey(n) == 'author') {
|
if (this.apool.getAttribKey(n) === 'author') {
|
||||||
const a = self.apool.getAttribValue(n);
|
const a = this.apool.getAttribValue(n);
|
||||||
if (a) {
|
if (a) {
|
||||||
authors.push(a);
|
authors.push(a);
|
||||||
}
|
}
|
||||||
|
@ -164,42 +135,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function callCatchingErrors(catcher, func) {
|
const applyChangeset = (changeset, revision, preventSliderMovement, timeDelta) => {
|
||||||
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) {
|
|
||||||
// disable the next 'gotorevision' call handled by a timeslider update
|
// disable the next 'gotorevision' call handled by a timeslider update
|
||||||
if (!preventSliderMovement) {
|
if (!preventSliderMovement) {
|
||||||
goToRevisionIfEnabledCount++;
|
goToRevisionIfEnabledCount++;
|
||||||
|
@ -215,7 +151,8 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
}
|
}
|
||||||
|
|
||||||
// scroll to the area that is changed before the lines are mutated
|
// 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
|
// 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
|
// 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
|
// 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
|
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) {
|
if (lineChanged === undefined) {
|
||||||
lineChanged = Changeset.opIterator(Changeset.unpack(changeset).ops).next().lines;
|
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);
|
goToLineNumber(lineChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,17 +195,32 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
||||||
|
|
||||||
BroadcastSlider.setAuthors(authors);
|
BroadcastSlider.setAuthors(authors);
|
||||||
}
|
};
|
||||||
|
|
||||||
function updateTimer() {
|
const loadedNewChangeset = (changesetForward, changesetBackward, revision, timeDelta) => {
|
||||||
const zpad = function (str, length) {
|
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}`;
|
str = `${str}`;
|
||||||
while (str.length < length) str = `0${str}`;
|
while (str.length < length) str = `0${str}`;
|
||||||
return str;
|
return str;
|
||||||
};
|
};
|
||||||
|
|
||||||
const date = new Date(padContents.currentTime);
|
const date = new Date(padContents.currentTime);
|
||||||
const dateFormat = function () {
|
const dateFormat = () => {
|
||||||
const month = zpad(date.getMonth() + 1, 2);
|
const month = zpad(date.getMonth() + 1, 2);
|
||||||
const day = zpad(date.getDate(), 2);
|
const day = zpad(date.getDate(), 2);
|
||||||
const year = (date.getFullYear());
|
const year = (date.getFullYear());
|
||||||
|
@ -292,43 +258,41 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
year: date.getFullYear(),
|
year: date.getFullYear(),
|
||||||
});
|
});
|
||||||
$('#revision_date').html(revisionDate);
|
$('#revision_date').html(revisionDate);
|
||||||
}
|
};
|
||||||
|
|
||||||
updateTimer();
|
updateTimer();
|
||||||
|
|
||||||
function goToRevision(newRevision) {
|
const goToRevision = (newRevision) => {
|
||||||
padContents.targetRevision = newRevision;
|
padContents.targetRevision = newRevision;
|
||||||
const self = this;
|
const path = window.revisionInfo.getPath(padContents.currentRevision, newRevision);
|
||||||
const path = revisionInfo.getPath(padContents.currentRevision, newRevision);
|
|
||||||
|
|
||||||
hooks.aCallAll('goToRevisionEvent', {
|
hooks.aCallAll('goToRevisionEvent', {
|
||||||
rev: newRevision,
|
rev: newRevision,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (path.status == 'complete') {
|
if (path.status === 'complete') {
|
||||||
var cs = path.changesets;
|
const cs = path.changesets;
|
||||||
var changeset = cs[0];
|
let changeset = cs[0];
|
||||||
var timeDelta = path.times[0];
|
let timeDelta = path.times[0];
|
||||||
for (var i = 1; i < cs.length; i++) {
|
for (let i = 1; i < cs.length; i++) {
|
||||||
changeset = Changeset.compose(changeset, cs[i], padContents.apool);
|
changeset = Changeset.compose(changeset, cs[i], padContents.apool);
|
||||||
timeDelta += path.times[i];
|
timeDelta += path.times[i];
|
||||||
}
|
}
|
||||||
if (changeset) applyChangeset(changeset, path.rev, true, timeDelta);
|
if (changeset) applyChangeset(changeset, path.rev, true, timeDelta);
|
||||||
} else if (path.status == 'partial') {
|
} else if (path.status === 'partial') {
|
||||||
const sliderLocation = padContents.currentRevision;
|
|
||||||
// callback is called after changeset information is pulled from server
|
// callback is called after changeset information is pulled from server
|
||||||
// this may never get called, if the changeset has already been loaded
|
// 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
|
// if we've called goToRevision in the time since, don't goToRevision
|
||||||
goToRevision(padContents.targetRevision);
|
goToRevision(padContents.targetRevision);
|
||||||
};
|
};
|
||||||
|
|
||||||
// do our best with what we have...
|
// do our best with what we have...
|
||||||
var cs = path.changesets;
|
const cs = path.changesets;
|
||||||
|
|
||||||
var changeset = cs[0];
|
let changeset = cs[0];
|
||||||
var timeDelta = path.times[0];
|
let timeDelta = path.times[0];
|
||||||
for (var i = 1; i < cs.length; i++) {
|
for (let i = 1; i < cs.length; i++) {
|
||||||
changeset = Changeset.compose(changeset, cs[i], padContents.apool);
|
changeset = Changeset.compose(changeset, cs[i], padContents.apool);
|
||||||
timeDelta += path.times[i];
|
timeDelta += path.times[i];
|
||||||
}
|
}
|
||||||
|
@ -342,23 +306,23 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
|
|
||||||
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
||||||
BroadcastSlider.setAuthors(authors);
|
BroadcastSlider.setAuthors(authors);
|
||||||
}
|
};
|
||||||
|
|
||||||
function loadChangesetsForRevision(revision, callback) {
|
const loadChangesetsForRevision = (revision, callback) => {
|
||||||
if (BroadcastSlider.getSliderLength() > 10000) {
|
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);
|
changesetLoader.queueUp(start, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BroadcastSlider.getSliderLength() > 1000) {
|
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);
|
changesetLoader.queueUp(start, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
start = (Math.floor((revision) / 100) * 100);
|
const start = (Math.floor((revision) / 100) * 100);
|
||||||
|
|
||||||
changesetLoader.queueUp(start, 1, callback);
|
changesetLoader.queueUp(start, 1, callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
changesetLoader = {
|
changesetLoader = {
|
||||||
running: false,
|
running: false,
|
||||||
|
@ -369,29 +333,38 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
reqCallbacks: [],
|
reqCallbacks: [],
|
||||||
queueUp(revision, width, callback) {
|
queueUp(revision, width, callback) {
|
||||||
if (revision < 0) revision = 0;
|
if (revision < 0) revision = 0;
|
||||||
// if(changesetLoader.requestQueue.indexOf(revision) != -1)
|
// if(this.requestQueue.indexOf(revision) != -1)
|
||||||
// return; // already in the queue.
|
// return; // already in the queue.
|
||||||
if (changesetLoader.resolved.indexOf(`${revision}_${width}`) != -1) return; // already loaded from the server
|
if (this.resolved.indexOf(`${revision}_${width}`) !== -1) {
|
||||||
changesetLoader.resolved.push(`${revision}_${width}`);
|
// 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(
|
requestQueue.push(
|
||||||
{
|
{
|
||||||
rev: revision,
|
rev: revision,
|
||||||
res: width,
|
res: width,
|
||||||
callback,
|
callback,
|
||||||
});
|
});
|
||||||
if (!changesetLoader.running) {
|
if (!this.running) {
|
||||||
changesetLoader.running = true;
|
this.running = true;
|
||||||
setTimeout(changesetLoader.loadFromQueue, 10);
|
setTimeout(() => this.loadFromQueue(), 10);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
loadFromQueue() {
|
loadFromQueue() {
|
||||||
const self = changesetLoader;
|
const requestQueue =
|
||||||
const requestQueue = self.requestQueue1.length > 0 ? self.requestQueue1 : self.requestQueue2.length > 0 ? self.requestQueue2 : self.requestQueue3.length > 0 ? self.requestQueue3 : null;
|
this.requestQueue1.length > 0 ? this.requestQueue1
|
||||||
|
: this.requestQueue2.length > 0 ? this.requestQueue2
|
||||||
|
: this.requestQueue3.length > 0 ? this.requestQueue3
|
||||||
|
: null;
|
||||||
|
|
||||||
if (!requestQueue) {
|
if (!requestQueue) {
|
||||||
self.running = false;
|
this.running = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -407,48 +380,48 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
requestID,
|
requestID,
|
||||||
});
|
});
|
||||||
|
|
||||||
self.reqCallbacks[requestID] = callback;
|
this.reqCallbacks[requestID] = callback;
|
||||||
},
|
},
|
||||||
handleSocketResponse(message) {
|
handleSocketResponse(message) {
|
||||||
const self = changesetLoader;
|
|
||||||
|
|
||||||
const start = message.data.start;
|
const start = message.data.start;
|
||||||
const granularity = message.data.granularity;
|
const granularity = message.data.granularity;
|
||||||
const callback = self.reqCallbacks[message.data.requestID];
|
const callback = this.reqCallbacks[message.data.requestID];
|
||||||
delete self.reqCallbacks[message.data.requestID];
|
delete this.reqCallbacks[message.data.requestID];
|
||||||
|
|
||||||
self.handleResponse(message.data, start, granularity, callback);
|
this.handleResponse(message.data, start, granularity, callback);
|
||||||
setTimeout(self.loadFromQueue, 10);
|
setTimeout(() => this.loadFromQueue(), 10);
|
||||||
},
|
},
|
||||||
handleResponse(data, start, granularity, callback) {
|
handleResponse: (data, start, granularity, callback) => {
|
||||||
const pool = (new AttribPool()).fromJsonable(data.apool);
|
const pool = (new AttribPool()).fromJsonable(data.apool);
|
||||||
for (let i = 0; i < data.forwardsChangesets.length; i++) {
|
for (let i = 0; i < data.forwardsChangesets.length; i++) {
|
||||||
const astart = start + i * granularity - 1; // rev -1 is a blank single line
|
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
|
let aend = start + (i + 1) * granularity - 1; // totalRevs is the most recent revision
|
||||||
if (aend > data.actualEndNum - 1) aend = data.actualEndNum - 1;
|
if (aend > data.actualEndNum - 1) aend = data.actualEndNum - 1;
|
||||||
// debugLog("adding changeset:", astart, aend);
|
// debugLog("adding changeset:", astart, aend);
|
||||||
const forwardcs = Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool);
|
const forwardcs =
|
||||||
const backwardcs = Changeset.moveOpsToNewPool(data.backwardsChangesets[i], pool, padContents.apool);
|
Changeset.moveOpsToNewPool(data.forwardsChangesets[i], pool, padContents.apool);
|
||||||
revisionInfo.addChangeset(astart, aend, forwardcs, backwardcs, data.timeDeltas[i]);
|
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);
|
if (callback) callback(start - 1, start + data.forwardsChangesets.length * granularity - 1);
|
||||||
},
|
},
|
||||||
handleMessageFromServer(obj) {
|
handleMessageFromServer(obj) {
|
||||||
if (obj.type == 'COLLABROOM') {
|
if (obj.type === 'COLLABROOM') {
|
||||||
obj = obj.data;
|
obj = obj.data;
|
||||||
|
|
||||||
if (obj.type == 'NEW_CHANGES') {
|
if (obj.type === 'NEW_CHANGES') {
|
||||||
const changeset = Changeset.moveOpsToNewPool(
|
const changeset = Changeset.moveOpsToNewPool(
|
||||||
obj.changeset, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
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);
|
obj.changeset, padContents.currentLines, padContents.alines, padContents.apool);
|
||||||
|
|
||||||
var changesetBack = Changeset.moveOpsToNewPool(
|
changesetBack = Changeset.moveOpsToNewPool(
|
||||||
changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
changesetBack, (new AttribPool()).fromJsonable(obj.apool), padContents.apool);
|
||||||
|
|
||||||
loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta);
|
loadedNewChangeset(changeset, changesetBack, obj.newRev - 1, obj.timeDelta);
|
||||||
} else if (obj.type == 'NEW_AUTHORDATA') {
|
} else if (obj.type === 'NEW_AUTHORDATA') {
|
||||||
const authorMap = {};
|
const authorMap = {};
|
||||||
authorMap[obj.author] = obj.data;
|
authorMap[obj.author] = obj.data;
|
||||||
receiveAuthorData(authorMap);
|
receiveAuthorData(authorMap);
|
||||||
|
@ -456,13 +429,13 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
|
||||||
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
const authors = _.map(padContents.getActiveAuthors(), (name) => authorData[name]);
|
||||||
|
|
||||||
BroadcastSlider.setAuthors(authors);
|
BroadcastSlider.setAuthors(authors);
|
||||||
} else if (obj.type == 'NEW_SAVEDREV') {
|
} else if (obj.type === 'NEW_SAVEDREV') {
|
||||||
const savedRev = obj.savedRev;
|
const savedRev = obj.savedRev;
|
||||||
BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
|
BroadcastSlider.addSavedRevision(savedRev.revNum, savedRev);
|
||||||
}
|
}
|
||||||
hooks.callAll(`handleClientTimesliderMessage_${obj.type}`, {payload: obj});
|
hooks.callAll(`handleClientTimesliderMessage_${obj.type}`, {payload: obj});
|
||||||
} else if (obj.type == 'CHANGESET_REQ') {
|
} else if (obj.type === 'CHANGESET_REQ') {
|
||||||
changesetLoader.handleSocketResponse(obj);
|
this.handleSocketResponse(obj);
|
||||||
} else {
|
} else {
|
||||||
debugLog(`Unknown message type: ${obj.type}`);
|
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,
|
// this is necessary to keep infinite loops of events firing,
|
||||||
// since goToRevision changes the slider position
|
// since goToRevision changes the slider position
|
||||||
var goToRevisionIfEnabledCount = 0;
|
const goToRevisionIfEnabled = (...args) => {
|
||||||
const goToRevisionIfEnabled = function () {
|
|
||||||
if (goToRevisionIfEnabledCount > 0) {
|
if (goToRevisionIfEnabledCount > 0) {
|
||||||
goToRevisionIfEnabledCount--;
|
goToRevisionIfEnabledCount--;
|
||||||
} else {
|
} else {
|
||||||
goToRevision.apply(goToRevision, arguments);
|
goToRevision(...args);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BroadcastSlider.onSlider(goToRevisionIfEnabled);
|
BroadcastSlider.onSlider(goToRevisionIfEnabled);
|
||||||
|
|
||||||
const dynamicCSS = makeCSSManager('dynamicsyntax');
|
const dynamicCSS = makeCSSManager('dynamicsyntax');
|
||||||
var authorData = {};
|
const authorData = {};
|
||||||
|
|
||||||
function receiveAuthorData(newAuthorData) {
|
const receiveAuthorData = (newAuthorData) => {
|
||||||
for (const author in newAuthorData) {
|
for (const [author, data] of Object.entries(newAuthorData)) {
|
||||||
const data = newAuthorData[author];
|
const bgcolor = typeof data.colorId === 'number'
|
||||||
const bgcolor = typeof data.colorId === 'number' ? clientVars.colorPalette[data.colorId] : data.colorId;
|
? clientVars.colorPalette[data.colorId] : data.colorId;
|
||||||
if (bgcolor && dynamicCSS) {
|
if (bgcolor && dynamicCSS) {
|
||||||
const selector = dynamicCSS.selectorStyle(`.${linestylefilter.getAuthorClassName(author)}`);
|
const selector = dynamicCSS.selectorStyle(`.${linestylefilter.getAuthorClassName(author)}`);
|
||||||
selector.backgroundColor = bgcolor;
|
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;
|
authorData[author] = data;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData);
|
receiveAuthorData(clientVars.collab_client_vars.historicalAuthorData);
|
||||||
|
|
||||||
return changesetLoader;
|
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;
|
exports.loadBroadcastJS = loadBroadcastJS;
|
||||||
|
|
|
@ -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,7 +25,7 @@
|
||||||
// of the document. These revisions are connected together by various
|
// of the document. These revisions are connected together by various
|
||||||
// changesets, or deltas, between any two revisions.
|
// changesets, or deltas, between any two revisions.
|
||||||
|
|
||||||
function loadBroadcastRevisionsJS() {
|
const loadBroadcastRevisionsJS = () => {
|
||||||
function Revision(revNum) {
|
function Revision(revNum) {
|
||||||
this.rev = revNum;
|
this.rev = revNum;
|
||||||
this.changesets = [];
|
this.changesets = [];
|
||||||
|
@ -33,18 +35,16 @@ function loadBroadcastRevisionsJS() {
|
||||||
const changesetWrapper = {
|
const changesetWrapper = {
|
||||||
deltaRev: destIndex - this.rev,
|
deltaRev: destIndex - this.rev,
|
||||||
deltaTime: timeDelta,
|
deltaTime: timeDelta,
|
||||||
getValue() {
|
getValue: () => changeset,
|
||||||
return changeset;
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
this.changesets.push(changesetWrapper);
|
this.changesets.push(changesetWrapper);
|
||||||
this.changesets.sort((a, b) => (b.deltaRev - a.deltaRev));
|
this.changesets.sort((a, b) => (b.deltaRev - a.deltaRev));
|
||||||
};
|
};
|
||||||
|
|
||||||
revisionInfo = {};
|
const revisionInfo = {};
|
||||||
revisionInfo.addChangeset = function (fromIndex, toIndex, changeset, backChangeset, timeDelta) {
|
revisionInfo.addChangeset = function (fromIndex, toIndex, changeset, backChangeset, timeDelta) {
|
||||||
const startRevision = revisionInfo[fromIndex] || revisionInfo.createNew(fromIndex);
|
const startRevision = this[fromIndex] || this.createNew(fromIndex);
|
||||||
const endRevision = revisionInfo[toIndex] || revisionInfo.createNew(toIndex);
|
const endRevision = this[toIndex] || this.createNew(toIndex);
|
||||||
startRevision.addChangeset(toIndex, changeset, timeDelta);
|
startRevision.addChangeset(toIndex, changeset, timeDelta);
|
||||||
endRevision.addChangeset(fromIndex, backChangeset, -1 * timeDelta);
|
endRevision.addChangeset(fromIndex, backChangeset, -1 * timeDelta);
|
||||||
};
|
};
|
||||||
|
@ -52,12 +52,12 @@ function loadBroadcastRevisionsJS() {
|
||||||
revisionInfo.latest = clientVars.collab_client_vars.rev || -1;
|
revisionInfo.latest = clientVars.collab_client_vars.rev || -1;
|
||||||
|
|
||||||
revisionInfo.createNew = function (index) {
|
revisionInfo.createNew = function (index) {
|
||||||
revisionInfo[index] = new Revision(index);
|
this[index] = new Revision(index);
|
||||||
if (index > revisionInfo.latest) {
|
if (index > this.latest) {
|
||||||
revisionInfo.latest = index;
|
this.latest = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
return revisionInfo[index];
|
return this[index];
|
||||||
};
|
};
|
||||||
|
|
||||||
// assuming that there is a path from fromIndex to toIndex, and that the links
|
// assuming that there is a path from fromIndex to toIndex, and that the links
|
||||||
|
@ -66,8 +66,8 @@ function loadBroadcastRevisionsJS() {
|
||||||
const changesets = [];
|
const changesets = [];
|
||||||
const spans = [];
|
const spans = [];
|
||||||
const times = [];
|
const times = [];
|
||||||
let elem = revisionInfo[fromIndex] || revisionInfo.createNew(fromIndex);
|
let elem = this[fromIndex] || this.createNew(fromIndex);
|
||||||
if (elem.changesets.length != 0 && fromIndex != toIndex) {
|
if (elem.changesets.length !== 0 && fromIndex !== toIndex) {
|
||||||
const reverse = !(fromIndex < toIndex);
|
const reverse = !(fromIndex < toIndex);
|
||||||
while (((elem.rev < toIndex) && !reverse) || ((elem.rev > toIndex) && reverse)) {
|
while (((elem.rev < toIndex) && !reverse) || ((elem.rev > toIndex) && reverse)) {
|
||||||
let couldNotContinue = false;
|
let couldNotContinue = false;
|
||||||
|
@ -76,27 +76,29 @@ function loadBroadcastRevisionsJS() {
|
||||||
for (let i = reverse ? elem.changesets.length - 1 : 0;
|
for (let i = reverse ? elem.changesets.length - 1 : 0;
|
||||||
reverse ? i >= 0 : i < elem.changesets.length;
|
reverse ? i >= 0 : i < elem.changesets.length;
|
||||||
i += reverse ? -1 : 1) {
|
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;
|
couldNotContinue = true;
|
||||||
break;
|
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];
|
const topush = elem.changesets[i];
|
||||||
changesets.push(topush.getValue());
|
changesets.push(topush.getValue());
|
||||||
spans.push(elem.changesets[i].deltaRev);
|
spans.push(elem.changesets[i].deltaRev);
|
||||||
times.push(topush.deltaTime);
|
times.push(topush.deltaTime);
|
||||||
elem = revisionInfo[elem.rev + elem.changesets[i].deltaRev];
|
elem = this[elem.rev + elem.changesets[i].deltaRev];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (couldNotContinue || oldRev == elem.rev) break;
|
if (couldNotContinue || oldRev === elem.rev) break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let status = 'partial';
|
let status = 'partial';
|
||||||
if (elem.rev == toIndex) status = 'complete';
|
if (elem.rev === toIndex) status = 'complete';
|
||||||
|
|
||||||
return {
|
return {
|
||||||
fromRev: fromIndex,
|
fromRev: fromIndex,
|
||||||
|
@ -107,6 +109,7 @@ function loadBroadcastRevisionsJS() {
|
||||||
times,
|
times,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
window.revisionInfo = revisionInfo;
|
||||||
|
};
|
||||||
|
|
||||||
exports.loadBroadcastRevisionsJS = loadBroadcastRevisionsJS;
|
exports.loadBroadcastRevisionsJS = loadBroadcastRevisionsJS;
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
'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.
|
||||||
|
@ -26,13 +27,14 @@ const _ = require('./underscore');
|
||||||
const padmodals = require('./pad_modals').padmodals;
|
const padmodals = require('./pad_modals').padmodals;
|
||||||
const colorutils = require('./colorutils').colorutils;
|
const colorutils = require('./colorutils').colorutils;
|
||||||
|
|
||||||
function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
const loadBroadcastSliderJS = (fireWhenAllScriptsAreLoaded) => {
|
||||||
let BroadcastSlider;
|
let BroadcastSlider;
|
||||||
|
|
||||||
// Hack to ensure timeslider i18n values are in
|
// 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 sliderLength = 1000;
|
||||||
let sliderPos = 0;
|
let sliderPos = 0;
|
||||||
let sliderActive = false;
|
let sliderActive = false;
|
||||||
|
@ -40,27 +42,30 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
const savedRevisions = [];
|
const savedRevisions = [];
|
||||||
let sliderPlaying = false;
|
let sliderPlaying = false;
|
||||||
|
|
||||||
const _callSliderCallbacks = function (newval) {
|
const _callSliderCallbacks = (newval) => {
|
||||||
sliderPos = newval;
|
sliderPos = newval;
|
||||||
for (let i = 0; i < slidercallbacks.length; i++) {
|
for (let i = 0; i < slidercallbacks.length; i++) {
|
||||||
slidercallbacks[i](newval);
|
slidercallbacks[i](newval);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const updateSliderElements = function () {
|
const updateSliderElements = () => {
|
||||||
for (let i = 0; i < savedRevisions.length; i++) {
|
for (let i = 0; i < savedRevisions.length; i++) {
|
||||||
const position = parseInt(savedRevisions[i].attr('pos'));
|
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 = $('<div></div>');
|
const newSavedRevision = $('<div></div>');
|
||||||
newSavedRevision.addClass('star');
|
newSavedRevision.addClass('star');
|
||||||
|
|
||||||
newSavedRevision.attr('pos', position);
|
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);
|
$('#ui-slider-bar').append(newSavedRevision);
|
||||||
newSavedRevision.mouseup((evt) => {
|
newSavedRevision.mouseup((evt) => {
|
||||||
BroadcastSlider.setSliderPosition(position);
|
BroadcastSlider.setSliderPosition(position);
|
||||||
|
@ -68,60 +73,50 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
savedRevisions.push(newSavedRevision);
|
savedRevisions.push(newSavedRevision);
|
||||||
};
|
};
|
||||||
|
|
||||||
const removeSavedRevision = function (position) {
|
|
||||||
const element = $(`div.star [pos=${position}]`);
|
|
||||||
savedRevisions.remove(element);
|
|
||||||
element.remove();
|
|
||||||
return element;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Begin small 'API' */
|
/* Begin small 'API' */
|
||||||
|
|
||||||
function onSlider(callback) {
|
const onSlider = (callback) => {
|
||||||
slidercallbacks.push(callback);
|
slidercallbacks.push(callback);
|
||||||
}
|
};
|
||||||
|
|
||||||
function getSliderPosition() {
|
const getSliderPosition = () => sliderPos;
|
||||||
return sliderPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSliderPosition(newpos) {
|
const setSliderPosition = (newpos) => {
|
||||||
newpos = Number(newpos);
|
newpos = Number(newpos);
|
||||||
if (newpos < 0 || newpos > sliderLength) return;
|
if (newpos < 0 || newpos > sliderLength) return;
|
||||||
if (!newpos) {
|
if (!newpos) {
|
||||||
newpos = 0; // stops it from displaying NaN if newpos isn't set
|
newpos = 0; // stops it from displaying NaN if newpos isn't set
|
||||||
}
|
}
|
||||||
window.location.hash = `#${newpos}`;
|
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 () {
|
$('a.tlink').map(function () {
|
||||||
$(this).attr('href', $(this).attr('thref').replace('%revision%', newpos));
|
$(this).attr('href', $(this).attr('thref').replace('%revision%', newpos));
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#revision_label').html(html10n.get('timeslider.version', {version: newpos}));
|
$('#revision_label').html(html10n.get('timeslider.version', {version: newpos}));
|
||||||
|
|
||||||
$('#leftstar, #leftstep').toggleClass('disabled', newpos == 0);
|
$('#leftstar, #leftstep').toggleClass('disabled', newpos === 0);
|
||||||
$('#rightstar, #rightstep').toggleClass('disabled', newpos == sliderLength);
|
$('#rightstar, #rightstep').toggleClass('disabled', newpos === sliderLength);
|
||||||
|
|
||||||
sliderPos = newpos;
|
sliderPos = newpos;
|
||||||
_callSliderCallbacks(newpos);
|
_callSliderCallbacks(newpos);
|
||||||
}
|
};
|
||||||
|
|
||||||
function getSliderLength() {
|
const getSliderLength = () => sliderLength;
|
||||||
return sliderLength;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setSliderLength(newlength) {
|
const setSliderLength = (newlength) => {
|
||||||
sliderLength = newlength;
|
sliderLength = newlength;
|
||||||
updateSliderElements();
|
updateSliderElements();
|
||||||
}
|
};
|
||||||
|
|
||||||
// just take over the whole slider screen with a reconnect message
|
// just take over the whole slider screen with a reconnect message
|
||||||
|
|
||||||
function showReconnectUI() {
|
const showReconnectUI = () => {
|
||||||
padmodals.showModal('disconnected');
|
padmodals.showModal('disconnected');
|
||||||
}
|
};
|
||||||
|
|
||||||
function setAuthors(authors) {
|
const setAuthors = (authors) => {
|
||||||
const authorsList = $('#authorsList');
|
const authorsList = $('#authorsList');
|
||||||
authorsList.empty();
|
authorsList.empty();
|
||||||
let numAnonymous = 0;
|
let numAnonymous = 0;
|
||||||
|
@ -132,7 +127,8 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
const authorColor = clientVars.colorPalette[author.colorId] || author.colorId;
|
const authorColor = clientVars.colorPalette[author.colorId] || author.colorId;
|
||||||
if (author.name) {
|
if (author.name) {
|
||||||
if (numNamed !== 0) authorsList.append(', ');
|
if (numNamed !== 0) authorsList.append(', ');
|
||||||
const textColor = colorutils.textColorFromBackgroundColor(authorColor, clientVars.skinName);
|
const textColor =
|
||||||
|
colorutils.textColorFromBackgroundColor(authorColor, clientVars.skinName);
|
||||||
$('<span />')
|
$('<span />')
|
||||||
.text(author.name || 'unnamed')
|
.text(author.name || 'unnamed')
|
||||||
.css('background-color', authorColor)
|
.css('background-color', authorColor)
|
||||||
|
@ -168,27 +164,12 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
authorsList.append(')');
|
authorsList.append(')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (authors.length == 0) {
|
if (authors.length === 0) {
|
||||||
authorsList.append(html10n.get('timeslider.toolbar.authorsList'));
|
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 (sliderPlaying) {
|
||||||
if (getSliderPosition() + 1 > sliderLength) {
|
if (getSliderPosition() + 1 > sliderLength) {
|
||||||
$('#playpause_button_icon').toggleClass('pause');
|
$('#playpause_button_icon').toggleClass('pause');
|
||||||
|
@ -199,39 +180,52 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
|
|
||||||
setTimeout(playButtonUpdater, 100);
|
setTimeout(playButtonUpdater, 100);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function playpause() {
|
const playpause = () => {
|
||||||
$('#playpause_button_icon').toggleClass('pause');
|
$('#playpause_button_icon').toggleClass('pause');
|
||||||
|
|
||||||
if (!sliderPlaying) {
|
if (!sliderPlaying) {
|
||||||
if (getSliderPosition() == sliderLength) setSliderPosition(0);
|
if (getSliderPosition() === sliderLength) setSliderPosition(0);
|
||||||
sliderPlaying = true;
|
sliderPlaying = true;
|
||||||
playButtonUpdater();
|
playButtonUpdater();
|
||||||
} else {
|
} else {
|
||||||
sliderPlaying = false;
|
sliderPlaying = false;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
BroadcastSlider = {
|
||||||
|
onSlider,
|
||||||
|
getSliderPosition,
|
||||||
|
setSliderPosition,
|
||||||
|
getSliderLength,
|
||||||
|
setSliderLength,
|
||||||
|
isSliderActive: () => sliderActive,
|
||||||
|
playpause,
|
||||||
|
addSavedRevision,
|
||||||
|
showReconnectUI,
|
||||||
|
setAuthors,
|
||||||
|
};
|
||||||
|
|
||||||
// assign event handlers to html UI elements after page load
|
// assign event handlers to html UI elements after page load
|
||||||
fireWhenAllScriptsAreLoaded.push(() => {
|
fireWhenAllScriptsAreLoaded.push(() => {
|
||||||
$(document).keyup((e) => {
|
$(document).keyup((e) => {
|
||||||
if (!e) var e = window.event;
|
if (!e) e = window.event;
|
||||||
const code = e.keyCode || e.which;
|
const code = e.keyCode || e.which;
|
||||||
|
|
||||||
if (code == 37) { // left
|
if (code === 37) { // left
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
$('#leftstar').click();
|
$('#leftstar').click();
|
||||||
} else {
|
} else {
|
||||||
$('#leftstep').click();
|
$('#leftstep').click();
|
||||||
}
|
}
|
||||||
} else if (code == 39) { // right
|
} else if (code === 39) { // right
|
||||||
if (e.shiftKey) {
|
if (e.shiftKey) {
|
||||||
$('#rightstar').click();
|
$('#rightstar').click();
|
||||||
} else {
|
} else {
|
||||||
$('#rightstep').click();
|
$('#rightstep').click();
|
||||||
}
|
}
|
||||||
} else if (code == 32) { // spacebar
|
} else if (code === 32) { // spacebar
|
||||||
$('#playpause_button_icon').trigger('click');
|
$('#playpause_button_icon').trigger('click');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -251,31 +245,32 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
$('#ui-slider-handle').mousedown(function (evt) {
|
$('#ui-slider-handle').mousedown(function (evt) {
|
||||||
this.startLoc = evt.clientX;
|
this.startLoc = evt.clientX;
|
||||||
this.currentLoc = parseInt($(this).css('left'));
|
this.currentLoc = parseInt($(this).css('left'));
|
||||||
const self = this;
|
|
||||||
sliderActive = true;
|
sliderActive = true;
|
||||||
$(document).mousemove((evt2) => {
|
$(document).mousemove((evt2) => {
|
||||||
$(self).css('pointer', 'move');
|
$(this).css('pointer', 'move');
|
||||||
let newloc = self.currentLoc + (evt2.clientX - self.startLoc);
|
let newloc = this.currentLoc + (evt2.clientX - this.startLoc);
|
||||||
if (newloc < 0) newloc = 0;
|
if (newloc < 0) newloc = 0;
|
||||||
if (newloc > ($('#ui-slider-bar').width() - 2)) newloc = ($('#ui-slider-bar').width() - 2);
|
const maxPos = $('#ui-slider-bar').width() - 2;
|
||||||
$('#revision_label').html(html10n.get('timeslider.version', {version: Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))}));
|
if (newloc > maxPos) newloc = maxPos;
|
||||||
$(self).css('left', newloc);
|
const version = Math.floor(newloc * sliderLength / maxPos);
|
||||||
if (getSliderPosition() != Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2))) _callSliderCallbacks(Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2)));
|
$('#revision_label').html(html10n.get('timeslider.version', {version}));
|
||||||
|
$(this).css('left', newloc);
|
||||||
|
if (getSliderPosition() !== version) _callSliderCallbacks(version);
|
||||||
});
|
});
|
||||||
$(document).mouseup((evt2) => {
|
$(document).mouseup((evt2) => {
|
||||||
$(document).unbind('mousemove');
|
$(document).unbind('mousemove');
|
||||||
$(document).unbind('mouseup');
|
$(document).unbind('mouseup');
|
||||||
sliderActive = false;
|
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 < 0) newloc = 0;
|
||||||
if (newloc > ($('#ui-slider-bar').width() - 2)) newloc = ($('#ui-slider-bar').width() - 2);
|
const maxPos = $('#ui-slider-bar').width() - 2;
|
||||||
$(self).css('left', newloc);
|
if (newloc > maxPos) newloc = maxPos;
|
||||||
// if(getSliderPosition() != Math.floor(newloc * sliderLength / ($("#ui-slider-bar").width()-2)))
|
$(this).css('left', newloc);
|
||||||
setSliderPosition(Math.floor(newloc * sliderLength / ($('#ui-slider-bar').width() - 2)));
|
setSliderPosition(Math.floor(newloc * sliderLength / maxPos));
|
||||||
if (parseInt($(self).css('left')) < 2) {
|
if (parseInt($(this).css('left')) < 2) {
|
||||||
$(self).css('left', '2px');
|
$(this).css('left', '2px');
|
||||||
} else {
|
} else {
|
||||||
self.currentLoc = parseInt($(self).css('left'));
|
this.currentLoc = parseInt($(this).css('left'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -294,29 +289,30 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
case 'rightstep':
|
case 'rightstep':
|
||||||
setSliderPosition(getSliderPosition() + 1);
|
setSliderPosition(getSliderPosition() + 1);
|
||||||
break;
|
break;
|
||||||
case 'leftstar':
|
case 'leftstar': {
|
||||||
var nextStar = 0; // default to first revision in document
|
let nextStar = 0; // default to first revision in document
|
||||||
for (var i = 0; i < savedRevisions.length; i++) {
|
for (let i = 0; i < savedRevisions.length; i++) {
|
||||||
var pos = parseInt(savedRevisions[i].attr('pos'));
|
const pos = parseInt(savedRevisions[i].attr('pos'));
|
||||||
if (pos < getSliderPosition() && nextStar < pos) nextStar = pos;
|
if (pos < getSliderPosition() && nextStar < pos) nextStar = pos;
|
||||||
}
|
}
|
||||||
setSliderPosition(nextStar);
|
setSliderPosition(nextStar);
|
||||||
break;
|
break;
|
||||||
case 'rightstar':
|
}
|
||||||
var nextStar = sliderLength; // default to last revision in document
|
case 'rightstar': {
|
||||||
for (var i = 0; i < savedRevisions.length; i++) {
|
let nextStar = sliderLength; // default to last revision in document
|
||||||
var pos = parseInt(savedRevisions[i].attr('pos'));
|
for (let i = 0; i < savedRevisions.length; i++) {
|
||||||
|
const pos = parseInt(savedRevisions[i].attr('pos'));
|
||||||
if (pos > getSliderPosition() && nextStar > pos) nextStar = pos;
|
if (pos > getSliderPosition() && nextStar > pos) nextStar = pos;
|
||||||
}
|
}
|
||||||
setSliderPosition(nextStar);
|
setSliderPosition(nextStar);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (clientVars) {
|
if (clientVars) {
|
||||||
$('#timeslider-wrapper').show();
|
$('#timeslider-wrapper').show();
|
||||||
|
|
||||||
const startPos = clientVars.collab_client_vars.rev;
|
|
||||||
if (window.location.hash.length > 1) {
|
if (window.location.hash.length > 1) {
|
||||||
const hashRev = Number(window.location.hash.substr(1));
|
const hashRev = Number(window.location.hash.substr(1));
|
||||||
if (!isNaN(hashRev)) {
|
if (!isNaN(hashRev)) {
|
||||||
|
@ -336,10 +332,11 @@ function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded) {
|
||||||
})();
|
})();
|
||||||
|
|
||||||
BroadcastSlider.onSlider((loc) => {
|
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;
|
return BroadcastSlider;
|
||||||
}
|
};
|
||||||
|
|
||||||
exports.loadBroadcastSliderJS = loadBroadcastSliderJS;
|
exports.loadBroadcastSliderJS = loadBroadcastSliderJS;
|
||||||
|
|
Loading…
Reference in a new issue