etherpad-lite/static/js/pad_savedrevs.js

527 lines
14 KiB
JavaScript
Raw Normal View History

/**
* This code is mostly from the old Etherpad. Please help us to comment this code.
* This helps other people to understand this code better and helps them to improve it.
* TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
*/
2011-03-26 14:10:41 +01:00
/**
* Copyright 2009 Google Inc.
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* http://www.apache.org/licenses/LICENSE-2.0
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var padutils = require('/pad_utils').padutils;
var paddocbar = require('/pad_docbar').paddocbar;
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
var padsavedrevs = (function()
{
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
function reversedCopy(L)
{
2011-03-26 14:10:41 +01:00
var L2 = L.slice();
L2.reverse();
return L2;
}
2011-07-07 19:59:34 +02:00
function makeRevisionBox(revisionInfo, rnum)
{
var box = $('<div class="srouterbox">' + '<div class="srinnerbox">' + '<a href="javascript:void(0)" class="srname"><!-- --></a>' + '<div class="sractions"><a class="srview" href="javascript:void(0)" target="_blank">view</a> | <a class="srrestore" href="javascript:void(0)">restore</a></div>' + '<div class="srtime"><!-- --></div>' + '<div class="srauthor"><!-- --></div>' + '<img class="srtwirly" src="static/img/misc/status-ball.gif">' + '</div></div>');
2011-03-26 14:10:41 +01:00
setBoxLabel(box, revisionInfo.label);
setBoxTimestamp(box, revisionInfo.timestamp);
2011-07-07 19:59:34 +02:00
box.find(".srauthor").html("by " + padutils.escapeHtml(revisionInfo.savedBy));
var viewLink = '/ep/pad/view/' + pad.getPadId() + '/' + revisionInfo.id;
2011-03-26 14:10:41 +01:00
box.find(".srview").attr('href', viewLink);
var restoreLink = 'javascript:void(require('+JSON.stringify(module.id)+').padsavedrevs.restoreRevision(' + JSON.stringify(rnum) + ');';
2011-03-26 14:10:41 +01:00
box.find(".srrestore").attr('href', restoreLink);
2011-07-07 19:59:34 +02:00
box.find(".srname").click(function(evt)
{
2011-03-26 14:10:41 +01:00
editRevisionLabel(rnum, box);
});
return box;
}
2011-07-07 19:59:34 +02:00
function setBoxLabel(box, label)
{
2011-03-26 14:10:41 +01:00
box.find(".srname").html(padutils.escapeHtml(label)).attr('title', label);
}
2011-07-07 19:59:34 +02:00
function setBoxTimestamp(box, timestamp)
{
2011-03-26 14:10:41 +01:00
box.find(".srtime").html(padutils.escapeHtml(
2011-07-07 19:59:34 +02:00
padutils.timediff(new Date(timestamp))));
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function getNthBox(n)
{
2011-03-26 14:10:41 +01:00
return $("#savedrevisions .srouterbox").eq(n);
}
2011-07-07 19:59:34 +02:00
function editRevisionLabel(rnum, box)
{
2011-03-26 14:10:41 +01:00
var input = $('<input type="text" class="srnameedit"/>');
box.find(".srnameedit").remove(); // just in case
var label = box.find(".srname");
input.width(label.width());
input.height(label.height());
input.css('top', label.position().top);
input.css('left', label.position().left);
label.after(input);
label.css('opacity', 0);
2011-07-07 19:59:34 +02:00
function endEdit()
{
2011-03-26 14:10:41 +01:00
input.remove();
label.css('opacity', 1);
}
var rev = currentRevisionList[rnum];
var oldLabel = rev.label;
2011-07-07 19:59:34 +02:00
input.blur(function()
{
2011-03-26 14:10:41 +01:00
var newLabel = input.val();
2011-07-07 19:59:34 +02:00
if (newLabel && newLabel != oldLabel)
{
2011-03-26 14:10:41 +01:00
relabelRevision(rnum, newLabel);
}
endEdit();
});
input.val(rev.label).focus().select();
2011-07-07 19:59:34 +02:00
padutils.bindEnterAndEscape(input, function onEnter()
{
2011-03-26 14:10:41 +01:00
input.blur();
2011-07-07 19:59:34 +02:00
}, function onEscape()
{
2011-03-26 14:10:41 +01:00
input.val('').blur();
});
}
2011-07-07 19:59:34 +02:00
function relabelRevision(rnum, newLabel)
{
2011-03-26 14:10:41 +01:00
var rev = currentRevisionList[rnum];
2011-07-07 19:59:34 +02:00
$.ajax(
{
2011-03-26 14:10:41 +01:00
type: 'post',
url: '/ep/pad/saverevisionlabel',
2011-07-07 19:59:34 +02:00
data: {
userId: pad.getUserId(),
padId: pad.getPadId(),
revId: rev.id,
newLabel: newLabel
},
2011-03-26 14:10:41 +01:00
success: success,
error: error
});
2011-07-07 19:59:34 +02:00
function success(text)
{
2011-03-26 14:10:41 +01:00
var newRevisionList = JSON.parse(text);
self.newRevisionList(newRevisionList);
2011-07-07 19:59:34 +02:00
pad.sendClientMessage(
{
2011-03-26 14:10:41 +01:00
type: 'revisionLabel',
revisionList: reversedCopy(currentRevisionList),
savedBy: pad.getUserName(),
newLabel: newLabel
});
}
2011-07-07 19:59:34 +02:00
function error(e)
{
2011-03-26 14:10:41 +01:00
alert("Oops! There was an error saving that revision label. Please try again later.");
}
}
var currentRevisionList = [];
2011-07-07 19:59:34 +02:00
function setRevisionList(newRevisionList, noAnimation)
{
2011-03-26 14:10:41 +01:00
// deals with changed labels and new added revisions
2011-07-07 19:59:34 +02:00
for (var i = 0; i < currentRevisionList.length; i++)
{
2011-03-26 14:10:41 +01:00
var a = currentRevisionList[i];
var b = newRevisionList[i];
2011-07-07 19:59:34 +02:00
if (b.label != a.label)
{
2011-03-26 14:10:41 +01:00
setBoxLabel(getNthBox(i), b.label);
}
}
2011-07-07 19:59:34 +02:00
for (var j = currentRevisionList.length; j < newRevisionList.length; j++)
{
2011-03-26 14:10:41 +01:00
var newBox = makeRevisionBox(newRevisionList[j], j);
$("#savedrevs-scrollinner").append(newBox);
newBox.css('left', j * REVISION_BOX_WIDTH);
}
var newOnes = (newRevisionList.length > currentRevisionList.length);
currentRevisionList = newRevisionList;
2011-07-07 19:59:34 +02:00
if (newOnes)
{
2011-03-26 14:10:41 +01:00
setDesiredScroll(getMaxScroll());
2011-07-07 19:59:34 +02:00
if (noAnimation)
{
2011-03-26 14:10:41 +01:00
setScroll(desiredScroll);
}
2011-07-07 19:59:34 +02:00
if (!noAnimation)
{
var nameOfLast = currentRevisionList[currentRevisionList.length - 1].label;
2011-03-26 14:10:41 +01:00
displaySavedTip(nameOfLast);
}
}
}
2011-07-07 19:59:34 +02:00
function refreshRevisionList()
{
for (var i = 0; i < currentRevisionList.length; i++)
{
2011-03-26 14:10:41 +01:00
var r = currentRevisionList[i];
var box = getNthBox(i);
setBoxTimestamp(box, r.timestamp);
}
}
2011-07-07 19:59:34 +02:00
var savedTipAnimator = padutils.makeShowHideAnimator(function(state)
{
if (state == -1)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier").css('opacity', 0).css('display', 'block');
}
2011-07-07 19:59:34 +02:00
else if (state == 0)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier").css('opacity', 1);
}
2011-07-07 19:59:34 +02:00
else if (state == 1)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier").css('opacity', 0).css('display', 'none');
}
2011-07-07 19:59:34 +02:00
else if (state < 0)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier").css('opacity', 1);
}
2011-07-07 19:59:34 +02:00
else if (state > 0)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier").css('opacity', 1 - state);
}
}, false, 25, 300);
2011-07-07 19:59:34 +02:00
function displaySavedTip(text)
{
2011-03-26 14:10:41 +01:00
$("#revision-notifier .name").html(padutils.escapeHtml(text));
savedTipAnimator.show();
padutils.cancelActions("hide-revision-notifier");
2011-07-07 19:59:34 +02:00
var hideLater = padutils.getCancellableAction("hide-revision-notifier", function()
{
savedTipAnimator.hide();
});
2011-03-26 14:10:41 +01:00
window.setTimeout(hideLater, 3000);
}
var REVISION_BOX_WIDTH = 120;
var curScroll = 0; // distance between left of revisions and right of view
var desiredScroll = 0;
2011-07-07 19:59:34 +02:00
function getScrollWidth()
{
2011-03-26 14:10:41 +01:00
return REVISION_BOX_WIDTH * currentRevisionList.length;
}
2011-07-07 19:59:34 +02:00
function getViewportWidth()
{
2011-03-26 14:10:41 +01:00
return $("#savedrevs-scrollouter").width();
}
2011-07-07 19:59:34 +02:00
function getMinScroll()
{
2011-03-26 14:10:41 +01:00
return Math.min(getViewportWidth(), getScrollWidth());
}
2011-07-07 19:59:34 +02:00
function getMaxScroll()
{
2011-03-26 14:10:41 +01:00
return getScrollWidth();
}
2011-07-07 19:59:34 +02:00
function setScroll(newScroll)
{
2011-03-26 14:10:41 +01:00
curScroll = newScroll;
$("#savedrevs-scrollinner").css('right', newScroll);
updateScrollArrows();
}
2011-07-07 19:59:34 +02:00
function setDesiredScroll(newDesiredScroll, dontUpdate)
{
desiredScroll = Math.min(getMaxScroll(), Math.max(getMinScroll(), newDesiredScroll));
if (!dontUpdate)
{
2011-03-26 14:10:41 +01:00
updateScroll();
}
}
2011-07-07 19:59:34 +02:00
function updateScroll()
{
2011-03-26 14:10:41 +01:00
updateScrollArrows();
scrollAnimator.scheduleAnimation();
}
2011-07-07 19:59:34 +02:00
function updateScrollArrows()
{
$("#savedrevs-scrollleft").toggleClass("disabledscrollleft", desiredScroll <= getMinScroll());
$("#savedrevs-scrollright").toggleClass("disabledscrollright", desiredScroll >= getMaxScroll());
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
var scrollAnimator = padutils.makeAnimationScheduler(function()
{
2011-03-26 14:10:41 +01:00
setDesiredScroll(desiredScroll, true); // re-clamp
2011-07-07 19:59:34 +02:00
if (Math.abs(desiredScroll - curScroll) < 1)
{
2011-03-26 14:10:41 +01:00
setScroll(desiredScroll);
return false;
}
2011-07-07 19:59:34 +02:00
else
{
setScroll(curScroll + (desiredScroll - curScroll) * 0.5);
2011-03-26 14:10:41 +01:00
return true;
}
}, 50, 2);
var isSaving = false;
2011-07-07 19:59:34 +02:00
function setIsSaving(v)
{
2011-03-26 14:10:41 +01:00
isSaving = v;
rerenderButton();
}
2011-07-07 19:59:34 +02:00
function haveReachedRevLimit()
{
2011-03-26 14:10:41 +01:00
var mv = pad.getPrivilege('maxRevisions');
return (!(mv < 0 || mv > currentRevisionList.length));
}
2011-07-07 19:59:34 +02:00
function rerenderButton()
{
if (isSaving || (!pad.isFullyConnected()) || haveReachedRevLimit())
{
2011-03-26 14:10:41 +01:00
$("#savedrevs-savenow").css('opacity', 0.75);
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
$("#savedrevs-savenow").css('opacity', 1);
}
}
var scrollRepeatTimer = null;
var scrollStartTime = 0;
2011-07-07 19:59:34 +02:00
function setScrollRepeatTimer(dir)
{
2011-03-26 14:10:41 +01:00
clearScrollRepeatTimer();
scrollStartTime = +new Date;
2011-07-07 19:59:34 +02:00
scrollRepeatTimer = window.setTimeout(function f()
{
if (!scrollRepeatTimer)
{
2011-03-26 14:10:41 +01:00
return;
}
self.scroll(dir);
var scrollTime = (+new Date) - scrollStartTime;
var delay = (scrollTime > 2000 ? 50 : 300);
scrollRepeatTimer = window.setTimeout(f, delay);
}, 300);
$(document).bind('mouseup', clearScrollRepeatTimer);
}
2011-07-07 19:59:34 +02:00
function clearScrollRepeatTimer()
{
if (scrollRepeatTimer)
{
2011-03-26 14:10:41 +01:00
window.clearTimeout(scrollRepeatTimer);
scrollRepeatTimer = null;
}
$(document).unbind('mouseup', clearScrollRepeatTimer);
}
var pad = undefined;
2011-03-26 14:10:41 +01:00
var self = {
init: function(initialRevisions, _pad)
2011-07-07 19:59:34 +02:00
{
pad = _pad;
2011-03-26 14:10:41 +01:00
self.newRevisionList(initialRevisions, true);
2011-07-07 19:59:34 +02:00
$("#savedrevs-savenow").click(function()
{
self.saveNow();
});
$("#savedrevs-scrollleft").mousedown(function()
{
2011-03-26 14:10:41 +01:00
self.scroll('left');
setScrollRepeatTimer('left');
});
2011-07-07 19:59:34 +02:00
$("#savedrevs-scrollright").mousedown(function()
{
2011-03-26 14:10:41 +01:00
self.scroll('right');
setScrollRepeatTimer('right');
});
2011-07-07 19:59:34 +02:00
$("#savedrevs-close").click(function()
{
paddocbar.setShownPanel(null);
});
2011-03-26 14:10:41 +01:00
// update "saved n minutes ago" times
2011-07-07 19:59:34 +02:00
window.setInterval(function()
{
2011-03-26 14:10:41 +01:00
refreshRevisionList();
2011-07-07 19:59:34 +02:00
}, 60 * 1000);
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
restoreRevision: function(rnum)
{
2011-03-26 14:10:41 +01:00
var rev = currentRevisionList[rnum];
2011-07-07 19:59:34 +02:00
var warning = ("Restoring this revision will overwrite the current" + " text of the pad. " + "Are you sure you want to continue?");
2011-03-26 14:10:41 +01:00
var hidePanel = paddocbar.hideLaterIfNoOtherInteraction();
var box = getNthBox(rnum);
2011-07-07 19:59:34 +02:00
if (confirm(warning))
{
2011-03-26 14:10:41 +01:00
box.find(".srtwirly").show();
2011-07-07 19:59:34 +02:00
$.ajax(
{
2011-03-26 14:10:41 +01:00
type: 'get',
url: '/ep/pad/getrevisionatext',
2011-07-07 19:59:34 +02:00
data: {
padId: pad.getPadId(),
revId: rev.id
},
2011-03-26 14:10:41 +01:00
success: success,
error: error
});
}
2011-07-07 19:59:34 +02:00
function success(resultJson)
{
2011-03-26 14:10:41 +01:00
untwirl();
var result = JSON.parse(resultJson);
padeditor.restoreRevisionText(result);
2011-07-07 19:59:34 +02:00
window.setTimeout(function()
{
2011-03-26 14:10:41 +01:00
hidePanel();
}, 0);
}
2011-07-07 19:59:34 +02:00
function error(e)
{
2011-03-26 14:10:41 +01:00
untwirl();
2011-07-07 19:59:34 +02:00
alert("Oops! There was an error retreiving the text (revNum= " + rev.revNum + "; padId=" + pad.getPadId());
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function untwirl()
{
2011-03-26 14:10:41 +01:00
box.find(".srtwirly").hide();
}
},
2011-07-07 19:59:34 +02:00
showReachedLimit: function()
{
alert("Sorry, you do not have privileges to save more than " + pad.getPrivilege('maxRevisions') + " revisions.");
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
newRevisionList: function(lst, noAnimation)
{
2011-03-26 14:10:41 +01:00
// server gives us list with newest first;
// we want chronological order
var L = reversedCopy(lst);
setRevisionList(L, noAnimation);
rerenderButton();
},
2011-07-07 19:59:34 +02:00
saveNow: function()
{
if (isSaving)
{
2011-03-26 14:10:41 +01:00
return;
}
2011-07-07 19:59:34 +02:00
if (!pad.isFullyConnected())
{
2011-03-26 14:10:41 +01:00
return;
}
2011-07-07 19:59:34 +02:00
if (haveReachedRevLimit())
{
2011-03-26 14:10:41 +01:00
self.showReachedLimit();
return;
}
setIsSaving(true);
var savedBy = pad.getUserName() || "unnamed";
pad.callWhenNotCommitting(submitSave);
2011-07-07 19:59:34 +02:00
function submitSave()
{
$.ajax(
{
2011-03-26 14:10:41 +01:00
type: 'post',
url: '/ep/pad/saverevision',
data: {
2011-07-07 19:59:34 +02:00
padId: pad.getPadId(),
savedBy: savedBy,
savedById: pad.getUserId(),
revNum: pad.getCollabRevisionNumber()
2011-03-26 14:10:41 +01:00
},
success: success,
error: error
});
}
2011-07-07 19:59:34 +02:00
function success(text)
{
2011-03-26 14:10:41 +01:00
setIsSaving(false);
var newRevisionList = JSON.parse(text);
self.newRevisionList(newRevisionList);
2011-07-07 19:59:34 +02:00
pad.sendClientMessage(
{
2011-03-26 14:10:41 +01:00
type: 'newRevisionList',
revisionList: newRevisionList,
savedBy: savedBy
});
}
2011-07-07 19:59:34 +02:00
function error(e)
{
2011-03-26 14:10:41 +01:00
setIsSaving(false);
alert("Oops! The server failed to save the revision. Please try again later.");
}
},
2011-07-07 19:59:34 +02:00
handleResizePage: function()
{
2011-03-26 14:10:41 +01:00
updateScrollArrows();
},
2011-07-07 19:59:34 +02:00
handleIsFullyConnected: function(isConnected)
{
2011-03-26 14:10:41 +01:00
rerenderButton();
},
2011-07-07 19:59:34 +02:00
scroll: function(dir)
{
2011-03-26 14:10:41 +01:00
var minScroll = getMinScroll();
var maxScroll = getMaxScroll();
2011-07-07 19:59:34 +02:00
if (dir == 'left')
{
if (desiredScroll > minScroll)
{
var n = Math.floor((desiredScroll - 1 - minScroll) / REVISION_BOX_WIDTH);
setDesiredScroll(Math.max(0, n) * REVISION_BOX_WIDTH + minScroll);
2011-03-26 14:10:41 +01:00
}
}
2011-07-07 19:59:34 +02:00
else if (dir == 'right')
{
if (desiredScroll < maxScroll)
{
var n = Math.floor((maxScroll - desiredScroll - 1) / REVISION_BOX_WIDTH);
setDesiredScroll(maxScroll - Math.max(0, n) * REVISION_BOX_WIDTH);
2011-03-26 14:10:41 +01:00
}
}
}
};
return self;
2011-07-07 19:59:34 +02:00
}());
exports.padsavedrevs = padsavedrevs;