Merge branch 'master' of git://github.com/Pita/etherpad-lite

This commit is contained in:
Eric Martindale 2011-11-27 22:24:35 +00:00
commit 464b70a066
31 changed files with 1264 additions and 330 deletions

View file

@ -469,7 +469,7 @@ table#otheruserstable { display: none; }
.modaldialog.cboxreconnecting .modaldialog-inner,
.modaldialog.cboxconnecting .modaldialog-inner {
background: url(static/img/connectingbar.gif) no-repeat center 60px;
background: url(../../static/img/connectingbar.gif) no-repeat center 60px;
height: 100px;
}
.modaldialog.cboxreconnecting {
@ -786,11 +786,15 @@ padding: 10px;
border-radius: 6px;
}
#embedcode, #readonlyUrl {
#embedreadonly {
float:right;
}
#embedcode, #readonlyUrl, #linkcode {
margin-left:10px;
}
#embedinput, #readonlyInput{
#embedinput, #readonlyInput, #linkinput {
width:375px;
height:24px;
display:inline;
@ -1146,4 +1150,13 @@ width:33px !important;
#editbar ul li {
padding: 4px 1px;
}
}
}
#embedreadonlyqr{
padding-top:20px;
margin-left:100px;
}
#qrcode{
margin-left:10px;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

View file

@ -74,8 +74,12 @@ function isArray(testObject)
return testObject && typeof testObject === 'object' && !(testObject.propertyIsEnumerable('length')) && typeof testObject.length === 'number';
}
if (typeof exports !== "undefined")
{
var navigator = {userAgent: "node-js"};
}
// Figure out what browser is being used (stolen from jquery 1.2.1)
var userAgent = navigator.userAgent.toLowerCase();
userAgent = navigator.userAgent.toLowerCase();
var browser = {
version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
safari: /webkit/.test(userAgent),
@ -85,6 +89,7 @@ var browser = {
windows: /windows/.test(userAgent) // dgreensp
};
function getAssoc(obj, name)
{
return obj["_magicdom_" + name];
@ -130,3 +135,8 @@ function htmlPrettyEscape(str)
{
return str.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\r?\n/g, '\\n');
}
if (typeof exports !== "undefined")
{
exports.map = map;
}

View file

@ -16,6 +16,8 @@
var chat = (function()
{
var chatMentions = 0;
var title = document.title;
var self = {
show: function ()
{
@ -43,6 +45,8 @@ var chat = (function()
}
});
});
chatMentions = 0;
document.title = title;
},
hide: function ()
{
@ -54,8 +58,6 @@ var chat = (function()
},
scrollDown: function()
{
//console.log($('#chatbox').css("display"));
if($('#chatbox').css("display") != "none")
$('#chattext').animate({scrollTop: $('#chattext')[0].scrollHeight}, "slow");
},
@ -87,6 +89,17 @@ var chat = (function()
});
var text = padutils.escapeHtmlWithClickableLinks(padutils.escapeHtml(msg.text), "_blank");
/* Performs an action if your name is mentioned */
var myName = $('#myusernameedit').val();
myName = myName.toLowerCase();
var chatText = text.toLowerCase();
var wasMentioned = false;
if (chatText.indexOf(myName) !== -1 && myName != "undefined"){
wasMentioned = true;
}
/* End of new action */
var authorName = msg.userName == null ? "unnamed" : padutils.escapeHtml(msg.userName);
var html = "<p class='" + authorClass + "'><b>" + authorName + ":</b><span class='time'>" + timeStr + "</span> " + text + "</p>";
@ -98,9 +111,22 @@ var chat = (function()
var count = Number($("#chatcounter").text());
count++;
$("#chatcounter").text(count);
// chat throb stuff -- Just make it throb in for ~2 secs then fadeotu
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text);
$('#chatthrob').effect("pulsate", {times:1,mode:"hide"},2000);
// chat throb stuff -- Just make it throw for twice as long
if(wasMentioned)
{ // If the user was mentioned show for twice as long and flash the browser window
if (chatMentions == 0){
title = document.title;
}
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text);
$('#chatthrob').effect("pulsate", {times:1,mode:"hide"},4000);
chatMentions++;
document.title = "("+chatMentions+") " + title;
}
else
{
$('#chatthrob').html("<b>"+authorName+"</b>" + ": " + text);
$('#chatthrob').effect("pulsate", {times:1,mode:"hide"},2000);
}
}
self.scrollDown();

View file

@ -77,10 +77,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
{
if (socket)
{
/*socket.onclosed = function() {};
socket.onhiccup = function() {};
socket.disconnect(true);*/
socket.disconnect();
setChannelState("DISCONNECTED", "unload");
}
});
if ($.browser.mozilla)
@ -100,18 +97,6 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
editor.setBaseAttributedText(serverVars.initialAttributedText, serverVars.apool);
editor.setUserChangeNotificationCallback(wrapRecordingErrors("handleUserChanges", handleUserChanges));
function abandonConnection(reason)
{
if (socket)
{
/*socket.onclosed = function() {};
socket.onhiccup = function() {};*/
socket.disconnect();
}
socket = null;
setChannelState("DISCONNECTED", reason);
}
function dmesg(str)
{
if (typeof window.ajlog == "string") window.ajlog += str + '\n';
@ -124,7 +109,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
{
if (channelState == "CONNECTING" && (((+new Date()) - initialStartConnectTime) > 20000))
{
abandonConnection("initsocketfail"); // give up
setChannelState("DISCONNECTED", "initsocketfail");
}
else
{
@ -141,8 +126,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
if (state == "COMMITTING" && (t - lastCommitTime) > 20000)
{
// a commit is taking too long
appLevelDisconnectReason = "slowcommit";
socket.disconnect();
setChannelState("DISCONNECTED", "slowcommit");
}
else if (state == "COMMITTING" && (t - lastCommitTime) > 5000)
{
@ -230,11 +214,6 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
handleMessageFromServer(obj);
});*/
socket.on('disconnect', function(obj)
{
handleSocketClosed(true);
});
/*var success = false;
callCatchingErrors("setUpSocket", function() {
appLevelDisconnectReason = null;
@ -366,7 +345,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
if (newRev != (rev + 1))
{
dmesg("bad message revision on NEW_CHANGES: " + newRev + " not " + (rev + 1));
socket.disconnect();
setChannelState("DISCONNECTED", "badmessage_newchanges");
return;
}
rev = newRev;
@ -378,7 +357,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
if (newRev != (rev + 1))
{
dmesg("bad message revision on ACCEPT_COMMIT: " + newRev + " not " + (rev + 1));
socket.disconnect();
setChannelState("DISCONNECTED", "badmessage_acceptcommit");
return;
}
rev = newRev;
@ -520,48 +499,6 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
//pad.dmesg($.map(getConnectedUsers(), function(u) { return u.userId.slice(-2); }).join(','));
}
function handleSocketClosed(params)
{
socket = null;
$.each(keys(userSet), function()
{
var uid = String(this);
if (uid != userId)
{
var userInfo = userSet[uid];
delete userSet[uid];
callbacks.onUserLeave(userInfo);
dmesgUsers();
}
});
var reason = appLevelDisconnectReason || params.reason;
var shouldReconnect = params.reconnect;
if (shouldReconnect)
{
// determine if this is a tight reconnect loop due to weird connectivity problems
reconnectTimes.push(+new Date());
var TOO_MANY_RECONNECTS = 8;
var TOO_SHORT_A_TIME_MS = 10000;
if (reconnectTimes.length >= TOO_MANY_RECONNECTS && ((+new Date()) - reconnectTimes[reconnectTimes.length - TOO_MANY_RECONNECTS]) < TOO_SHORT_A_TIME_MS)
{
setChannelState("DISCONNECTED", "looping");
}
else
{
setChannelState("RECONNECTING", reason);
setUpSocket();
}
}
else
{
setChannelState("DISCONNECTED", reason);
}
}
function setChannelState(newChannelState, moreInfo)
{
if (newChannelState != channelState)
@ -650,128 +587,6 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
return rev;
}
function getDiagnosticInfo()
{
var maxCaughtErrors = 3;
var maxAceErrors = 3;
var maxDebugMessages = 50;
var longStringCutoff = 500;
function trunc(str)
{
return String(str).substring(0, longStringCutoff);
}
var info = {
errors: {
length: 0
}
};
function addError(e, catcher, time)
{
var error = {
catcher: catcher
};
if (time) error.time = time;
// a little over-cautious?
try
{
if (e.description) error.description = e.description;
}
catch (x)
{}
try
{
if (e.fileName) error.fileName = e.fileName;
}
catch (x)
{}
try
{
if (e.lineNumber) error.lineNumber = e.lineNumber;
}
catch (x)
{}
try
{
if (e.message) error.message = e.message;
}
catch (x)
{}
try
{
if (e.name) error.name = e.name;
}
catch (x)
{}
try
{
if (e.number) error.number = e.number;
}
catch (x)
{}
try
{
if (e.stack) error.stack = trunc(e.stack);
}
catch (x)
{}
info.errors[info.errors.length] = error;
info.errors.length++;
}
for (var i = 0;
((i < caughtErrors.length) && (i < maxCaughtErrors)); i++)
{
addError(caughtErrors[i], caughtErrorCatchers[i], caughtErrorTimes[i]);
}
if (editor)
{
var aceErrors = editor.getUnhandledErrors();
for (var i = 0;
((i < aceErrors.length) && (i < maxAceErrors)); i++)
{
var errorRecord = aceErrors[i];
addError(errorRecord.error, "ACE", errorRecord.time);
}
}
info.time = +new Date();
info.collabState = state;
info.channelState = channelState;
info.lastCommitTime = lastCommitTime;
info.numSocketReconnects = reconnectTimes.length;
info.userId = userId;
info.currentRev = rev;
info.participants = (function()
{
var pp = [];
for (var u in userSet)
{
pp.push(u);
}
return pp.join(',');
})();
if (debugMessages.length > maxDebugMessages)
{
debugMessages = debugMessages.slice(debugMessages.length - maxDebugMessages, debugMessages.length);
}
info.debugMessages = {
length: 0
};
for (var i = 0; i < debugMessages.length; i++)
{
info.debugMessages[i] = trunc(debugMessages[i]);
info.debugMessages.length++;
}
return info;
}
function getMissedChanges()
{
var obj = {};
@ -863,10 +678,10 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options)
sendClientMessage: sendClientMessage,
sendMessage: sendMessage,
getCurrentRevisionNumber: getCurrentRevisionNumber,
getDiagnosticInfo: getDiagnosticInfo,
getMissedChanges: getMissedChanges,
callWhenNotCommitting: callWhenNotCommitting,
addHistoricalAuthors: tellAceAboutHistoricalAuthors
addHistoricalAuthors: tellAceAboutHistoricalAuthors,
setChannelState: setChannelState
});
}

View file

@ -152,6 +152,10 @@ domline.createDomLine = function(nonEmpty, doesWrap, optBrowser, optDocument)
{
if (href)
{
if(!~href.indexOf("http")) // if the url doesn't include http or https etc prefix it.
{
href = "http://"+href;
}
extraOpenTags = extraOpenTags + '<a href="' + href.replace(/\"/g, '&quot;') + '">';
extraCloseTags = '</a>' + extraCloseTags;
}

View file

@ -237,7 +237,7 @@ linestylefilter.getRegexpFilter = function(regExp, tag)
linestylefilter.REGEX_WORDCHAR = /[\u0030-\u0039\u0041-\u005A\u0061-\u007A\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0100-\u1FFF\u3040-\u9FFF\uF900-\uFDFF\uFE70-\uFEFE\uFF10-\uFF19\uFF21-\uFF3A\uFF41-\uFF5A\uFF66-\uFFDC]/;
linestylefilter.REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source + '|' + linestylefilter.REGEX_WORDCHAR.source + ')');
linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source + linestylefilter.REGEX_URLCHAR.source + '*(?![:.,;])' + linestylefilter.REGEX_URLCHAR.source, 'g');
linestylefilter.REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:|www\.)/.source + linestylefilter.REGEX_URLCHAR.source + '*(?![:.,;])' + linestylefilter.REGEX_URLCHAR.source, 'g');
linestylefilter.getURLFilter = linestylefilter.getRegexpFilter(
linestylefilter.REGEX_URL, 'url');

View file

@ -79,12 +79,13 @@ function randomString()
function getParams()
{
var showControls = getUrlVars()["showControls"];
var showChat = getUrlVars()["showChat"];
var userName = unescape(getUrlVars()["userName"]);
var showLineNumbers = getUrlVars()["showLineNumbers"];
var useMonospaceFont = getUrlVars()["useMonospaceFont"];
var IsnoColors = getUrlVars()["noColors"];
var params = getUrlVars()
var showControls = params["showControls"];
var showChat = params["showChat"];
var userName = params["userName"];
var showLineNumbers = params["showLineNumbers"];
var useMonospaceFont = params["useMonospaceFont"];
var IsnoColors = params["noColors"];
if(IsnoColors)
{
@ -130,7 +131,7 @@ function getParams()
if(userName)
{
// If the username is set as a parameter we should set a global value that we can call once we have initiated the pad.
globalUserName = userName;
globalUserName = unescape(userName);
}
}
@ -166,15 +167,17 @@ function handshake()
var resource = loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "socket.io";
//connect
socket = io.connect(url, {
resource: resource
resource: resource,
'max reconnection attempts': 3
});
socket.once('connect', function()
function sendClientReady(isReconnect)
{
var padId = document.location.pathname.substring(document.location.pathname.lastIndexOf("/") + 1);
padId = unescape(padId); // unescape neccesary due to Safari and Opera interpretation of spaces
document.title = document.title + " | " + padId;
if(!isReconnect)
document.title = document.title + " | " + padId;
var token = readCookie("token");
if (token == null)
@ -195,7 +198,43 @@ function handshake()
"token": token,
"protocolVersion": 2
};
//this is a reconnect, lets tell the server our revisionnumber
if(isReconnect == true)
{
msg.client_rev=pad.collabClient.getCurrentRevisionNumber();
msg.reconnect=true;
}
socket.json.send(msg);
};
var disconnectTimeout;
socket.once('connect', function () {
sendClientReady(false);
});
socket.on('reconnect', function () {
//reconnect is before the timeout, lets stop the timeout
if(disconnectTimeout)
{
clearTimeout(disconnectTimeout);
}
pad.collabClient.setChannelState("CONNECTED");
sendClientReady(true);
});
socket.on('disconnect', function () {
function disconnectEvent()
{
pad.collabClient.setChannelState("DISCONNECTED", "reconnect_timeout");
}
pad.collabClient.setChannelState("RECONNECTING");
disconnectTimeout = setTimeout(disconnectEvent, 10000);
});
var receivedClientVars = false;
@ -351,7 +390,6 @@ var pad = {
//initialize the chat
chat.init();
pad.diagnosticInfo.uniqueId = padutils.uniqueId();
pad.initTime = +(new Date());
pad.padOptions = clientVars.initialOptions;
@ -648,7 +686,22 @@ var pad = {
else if (newState == "DISCONNECTED")
{
pad.diagnosticInfo.disconnectedMessage = message;
pad.diagnosticInfo.padInitTime = pad.initTime;
pad.diagnosticInfo.padId = pad.getPadId();
pad.diagnosticInfo.socket = {};
//we filter non objects from the socket object and put them in the diagnosticInfo
//this ensures we have no cyclic data - this allows us to stringify the data
for(var i in socket.socket)
{
var value = socket.socket[i];
var type = typeof value;
if(type == "string" || type == "number")
{
pad.diagnosticInfo.socket[i] = value;
}
}
pad.asyncSendDiagnosticInfo();
if (typeof window.ajlog == "string")
{
@ -720,7 +773,6 @@ var pad = {
},
asyncSendDiagnosticInfo: function()
{
pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo();
window.setTimeout(function()
{
$.ajax(
@ -728,7 +780,6 @@ var pad = {
type: 'post',
url: '/ep/pad/connection-diagnostic-info',
data: {
padId: pad.getPadId(),
diagnosticInfo: JSON.stringify(pad.diagnosticInfo)
},
success: function()
@ -808,7 +859,7 @@ var pad = {
},
preloadImages: function()
{
var images = []; // Removed as we now use CSS and JS for colorpicker
var images = ["../static/img/connectingbar.gif"];
function loadNextImage()
{

View file

@ -99,26 +99,16 @@ var padeditbar = (function()
self.toogleDropDown("users");
}
else if (cmd == 'embed')
{
var padurl = window.location.href.split("?")[0];
$('#embedinput').val("<iframe src='" + padurl + "?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false' width=600 height=400>");
self.toogleDropDown("embed");
{
self.setEmbedLinks();
$('#embedinput').focus().select();
self.toogleDropDown("embed");
}
else if (cmd == 'import_export')
{
self.toogleDropDown("importexport");
}
else if (cmd == 'readonly')
{
var basePath = document.location.href.substring(0, document.location.href.indexOf("/p/"));
var readonlyLink = basePath + "/ro/" + clientVars.readOnlyId;
$('#readonlyImage').attr("src","https://chart.googleapis.com/chart?chs=200x200&cht=qr&chld=H|0&chl=" + readonlyLink);
$('#readonlyInput').val(readonlyLink);
self.toogleDropDown("readonly");
$('#readonlyInput').focus().select();
}
else if (cmd == 'save')
{
padsavedrevs.saveNow();
@ -211,6 +201,25 @@ var padeditbar = (function()
{
syncAnimation.done();
}
},
setEmbedLinks: function()
{
if ($('#readonlyinput').is(':checked'))
{
$('#qrcode').show();
var basePath = document.location.href.substring(0, document.location.href.indexOf("/p/"));
var readonlyLink = basePath + "/ro/" + clientVars.readOnlyId;
$('#embedinput').val("<iframe src='" + readonlyLink + "?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false' width=600 height=400>");
$('#linkinput').val(readonlyLink);
}
else
{
$('#qrcode').hide();
var padurl = window.location.href.split("?")[0];
$('#embedinput').val("<iframe src='" + padurl + "?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false' width=600 height=400>");
$('#linkinput').val(padurl);
$('#embedreadonlyqr').attr("src","https://chart.googleapis.com/chart?chs=200x200&cht=qr&chld=H|0&chl=" + padurl);
}
}
};
return self;

View file

@ -711,6 +711,7 @@ var paduserlist = (function()
}
$("#myswatch").css({'background-color': myUserInfo.colorId});
$("#usericon").css({'box-shadow': 'inset 0 0 30px ' + myUserInfo.colorId});
}
};
return self;

View file

@ -80,11 +80,6 @@
<ul id="menu_right">
<li onClick="window.pad&&pad.editbarClick('readonly');return false;" >
<a id="readonlylink" title="Create a readonly link for this pad">
<div class="buttonicon" style="background-position:0px -150px"></div>
</a>
</li>
<li onClick="window.pad&&pad.editbarClick('import_export');return false;">
<a id="exportlink" title="Import/Export from/to different document formats">
<div class="buttonicon" style="background-position:0px -68px"></div>
@ -103,7 +98,7 @@
</li>
<li id="usericon" onClick="window.pad&&pad.editbarClick('showusers');return false;" >
<a title="Show connected users">
<div class="buttonicon" style="background-position:0px -184px;display:inline-block;"></div>
<div class="buttonicon" id="usericonback" style="background-position:0px -184px;display:inline-block;"></div>
<span id="online_count">1</span>
</a>
</li>
@ -217,17 +212,21 @@
<!-- the embed code -->
<div id="embed">
<div id="embedcode">
Embed code:<input id="embedinput" type="text" value="">
</div>
</div>
<!-- the embed code -->
<div id="readonly">
<div id="readonlyUrl">
Use this link to share a read-only version of your pad:<input id="readonlyInput" type="text" value="">
<img id="readonlyImage" src="" alt="" style="margin: 10px 90px">
</div>
<div id="embedreadonly">
<input type="checkbox" id="readonlyinput" onClick="padeditbar.setEmbedLinks();"/><label for="readonlyinput">Read only</label>
</div>
Share:
<br/>
<div id="linkcode">
<label for="linkinput">Link:</label><input id="linkinput" type="text" value="">
</div><br/>
<div id="embedcode">
<label for="embedinput">Embed code:</label><input id="embedinput" type="text" value="">
</div><br/>
<div id="qrcode">
<label for="embedreadonlyqr">QR code:</label><br/>
<img id="embedreadonlyqr">
</div>
</div>
<div id="chatthrob">