diff options
Diffstat (limited to 'trunk/etherpad/src/etherpad/control/pad/pad_view_control.js')
-rw-r--r-- | trunk/etherpad/src/etherpad/control/pad/pad_view_control.js | 287 |
1 files changed, 287 insertions, 0 deletions
diff --git a/trunk/etherpad/src/etherpad/control/pad/pad_view_control.js b/trunk/etherpad/src/etherpad/control/pad/pad_view_control.js new file mode 100644 index 0000000..0606d2c --- /dev/null +++ b/trunk/etherpad/src/etherpad/control/pad/pad_view_control.js @@ -0,0 +1,287 @@ +/** + * Copyright 2009 Google Inc. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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. + */ + +import("etherpad.helpers"); +import("etherpad.pad.model"); +import("etherpad.pad.padusers"); +import("etherpad.pad.padutils"); +import("etherpad.pad.exporthtml"); +import("etherpad.pro.pro_accounts"); +import("etherpad.pro.pro_padmeta"); +import("etherpad.utils.*"); +import("etherpad.pad.revisions"); +import("stringutils.toHTML"); +import("etherpad.collab.server_utils.*"); +import("etherpad.collab.collab_server.buildHistoricalAuthorDataMapForPadHistory"); +import("etherpad.collab.collab_server.getATextForWire"); +import("etherpad.control.pad.pad_changeset_control.getChangesetInfo"); +import("etherpad.globals"); +import("fastJSON"); +import("etherpad.collab.ace.easysync2.Changeset"); +import("etherpad.collab.ace.linestylefilter.linestylefilter"); +import("etherpad.collab.ace.domline.domline"); + +//---------------------------------------------------------------- +// view (viewing a static revision of a pad) +//---------------------------------------------------------------- + +function onRequest() { + var parts = request.path.split('/'); + // TODO(kroo): create a mapping between padId and read-only id + var readOnlyIdOrLocalPadId = parts[4]; + var parseResult = parseUrlId(readOnlyIdOrLocalPadId); + var isReadOnly = parseResult.isReadOnly; + var viewId = parseResult.viewId; + var localPadId = parseResult.localPadId; + var globalPadId = parseResult.globalPadId; + var roPadId = parseResult.roPadId; + var revisionId = parts[5]; + + var rev = getRevisionInfo(localPadId, revisionId); + if (! rev) { + return false; + } + + if (request.params.pt == 1) { + var padText = padutils.accessPadLocal(localPadId, function(pad) { + return pad.getRevisionText(rev.revNum); + }, 'r'); + + response.setContentType('text/plain; charset=utf-8'); + response.write(padText); + } else { + var padContents, totalRevs, atextForWire, savedRevisions; + var supportsSlider; + padutils.accessPadLocal(localPadId, function(pad) { + padContents = [_getPadHTML(pad, rev.revNum), + pad.getRevisionText(rev.revNum)]; + totalRevs = pad.getHeadRevisionNumber(); + atextForWire = getATextForWire(pad, rev.revNum); + savedRevisions = revisions.getRevisionList(pad); + supportsSlider = pad.getSupportsTimeSlider(); + }, 'r'); + + var _add = function(dict, anotherdict) { + for(var key in anotherdict) { + dict[key] = anotherdict[key]; + } + return dict; + } + + var getAdaptiveChangesetsArray = function(array, start, granularity) { + array = array || []; + start = start || 0; + granularity = granularity || Math.pow(10, Math.floor(Math.log(totalRevs+1) / Math.log(10))); + var changeset = _add(getChangesetInfo(localPadId, start, totalRevs+1, granularity), { + start: start, + granularity: Math.floor(granularity) + }); + array.push(changeset); + if(changeset.actualEndNum != totalRevs+1 && granularity > 1) + getAdaptiveChangesetsArray(array, changeset.actualEndNum, Math.floor(granularity / 10)); + return array; + } + var initialChangesets = []; + if (supportsSlider) { + initialChangesets = getAdaptiveChangesetsArray( + [ + _add(getChangesetInfo(localPadId, Math.floor(rev.revNum / 1000)*1000, Math.floor(rev.revNum / 1000)*1000+1000, 100), { + start: Math.floor(rev.revNum / 1000)*1000, + granularity: 100 + }), + _add(getChangesetInfo(localPadId, Math.floor(rev.revNum / 100)*100, Math.floor(rev.revNum / 100)*100+100, 10), { + start: Math.floor(rev.revNum / 100)*100, + granularity: 10 + }), + _add(getChangesetInfo(localPadId, Math.floor(rev.revNum / 10)*10, Math.floor(rev.revNum / 10)*10+10, 1), { + start: Math.floor(rev.revNum / 10)*10, + granularity: 1 + })] + ); + } + + var zpad = function(str, length) { + str = str+""; + while(str.length < length) + str = '0'+str; + return str; + }; + var dateFormat = function(savedWhen) { + var date = new Date(savedWhen); + var month = zpad(date.getMonth()+1,2); + var day = zpad(date.getDate(),2); + var year = (date.getFullYear()); + var hours = zpad(date.getHours(),2); + var minutes = zpad(date.getMinutes(),2); + var seconds = zpad(date.getSeconds(),2); + return ([month,'/',day,'/',year,' ',hours,':',minutes,':',seconds].join("")); + }; + + var proTitle = null; + var initialPassword = null; + if (isProDomainRequest()) { + pro_padmeta.accessProPadLocal(localPadId, function(propad) { + proTitle = propad.getDisplayTitle(); + initialPassword = propad.getPassword(); + }); + } + var documentBarTitle = (proTitle || "Public Pad"); + + var padHTML = padContents[0]; + var padText = padContents[1]; + + var historicalAuthorData = padutils.accessPadLocal(localPadId, function(pad) { + return buildHistoricalAuthorDataMapForPadHistory(pad); + }, 'r'); + + helpers.addClientVars({ + viewId: viewId, + initialPadContents: padText, + revNum: rev.revNum, + totalRevs: totalRevs, + initialChangesets: initialChangesets, + initialStyledContents: atextForWire, + savedRevisions: savedRevisions, + currentTime: rev.timestamp, + sliderEnabled: (!appjet.cache.killSlider) && request.params.slider != 0, + supportsSlider: supportsSlider, + historicalAuthorData: historicalAuthorData, + colorPalette: globals.COLOR_PALETTE, + padIdForUrl: readOnlyIdOrLocalPadId, + fullWidth: request.params.fullScreen == 1, + disableRightBar: request.params.sidebar == 0, + }); + + var userId = padusers.getUserId(); + var isPro = isProDomainRequest(); + var isProUser = (isPro && ! padusers.isGuest(userId)); + + var bodyClass = ["limwidth", + (isPro ? "propad" : "nonpropad"), + (isProUser ? "prouser" : "nonprouser")].join(" "); + + renderHtml("pad/padview_body.ejs", { + bodyClass: bodyClass, + isPro: isPro, + isProAccountHolder: isProUser, + account: pro_accounts.getSessionProAccount(), + signinUrl: '/ep/account/sign-in?cont='+ + encodeURIComponent(request.url), + padId: readOnlyIdOrLocalPadId, + padTitle: documentBarTitle, + rlabel: rev.label, + padHTML: padHTML, + padText: padText, + savedBy: rev.savedBy, + savedIp: rev.ip, + savedWhen: rev.timestamp, + toHTML: toHTML, + revisionId: revisionId, + dateFormat: dateFormat(rev.timestamp), + readOnly: isReadOnly, + roPadId: roPadId, + hasOffice: hasOffice() + }); + } + + return true; +} + +function getRevisionInfo(localPadId, revisionId) { + var rev = padutils.accessPadLocal(localPadId, function(pad) { + if (!pad.exists()) { + return null; + } + var r; + if (revisionId == "latest") { + // a "fake" revision for HEAD + var headRevNum = pad.getHeadRevisionNumber(); + r = { + revNum: headRevNum, + label: "Latest text of pad "+localPadId, + savedBy: null, + savedIp: null, + timestamp: +pad.getRevisionDate(headRevNum) + }; + } else if (revisionId == "autorecover") { + var revNum = _findLastGoodRevisionInPad(pad); + r = { + revNum: revNum, + label: "Auto-recovered text of pad "+localPadId, + savedBy: null, + savedIp: null, + timestamp: +pad.getRevisionDate(revNum) + }; + } else if(revisionId.indexOf("rev.") === 0) { + var revNum = parseInt(revisionId.split(".")[1]); + var latest = pad.getHeadRevisionNumber(); + if(revNum > latest) + revNum = latest; + r = { + revNum: revNum, + label: "Version " + revNum, + savedBy: null, + savedIp: null, + timestamp: +pad.getRevisionDate(revNum) + } + + } else { + r = revisions.getStoredRevision(pad, revisionId); + } + if (!r) { + return null; + } + return r; + }, "r"); + return rev; +} + +function _findLastGoodRevisionInPad(pad) { + var revNum = pad.getHeadRevisionNumber(); + function valueOrNullOnError(f) { + try { return f(); } catch (e) { return null; } + } + function isAcceptable(strOrNull) { + return (strOrNull && strOrNull.length > 20); + } + while (revNum > 0 && + ! isAcceptable(valueOrNullOnError(function() { return pad.getRevisionText(revNum); }))) { + revNum--; + } + return revNum; +} + +function _getPadHTML(pad, revNum) { + var atext = pad.getInternalRevisionAText(revNum); + var textlines = Changeset.splitTextLines(atext.text); + var alines = Changeset.splitAttributionLines(atext.attribs, + atext.text); + + var pieces = []; + var apool = pad.pool(); + for(var i=0;i<textlines.length;i++) { + var line = textlines[i]; + var aline = alines[i]; + var emptyLine = (line == '\n'); + var domInfo = domline.createDomLine(! emptyLine, true); + linestylefilter.populateDomLine(line, aline, apool, domInfo); + domInfo.prepareForAdd(); + var node = domInfo.node; + pieces.push('<div class="', node.className, '">', + node.innerHTML, '</div>\n'); + } + return pieces.join(''); +}
\ No newline at end of file |