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

This commit is contained in:
Pita Poison 2011-07-05 16:51:29 +02:00
commit 7a10e1783a
11 changed files with 209 additions and 92 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
node_modules
settings.json
settings.json
static/js/jquery.min.js

View file

@ -3,17 +3,30 @@ Etherpad lite is a really-real time collaborative editor spawned from the Hell f
We're reusing the well tested Etherpad easysync library to make it really realtime. Etherpad Lite
is based on node.js what makes it much leigther and more stable than the original Etherpad. Our hope
is that this will encourage more users to install a realtime collaborative editor. A smaller and well
documented codebase makes it easier for developers to improve the code
documented codebase makes it easier for developers to improve the code. Etherpad Lite is optimized
to be easy embeddable
**Online demo**<br>
Visit <http://pitapoison.de:9001> to test it live
# Why use Etherpad Lite?
* Tiny server hardware footprint
* Pure Javascript client and server side
* Simplfied interface
* Easy to embed
* Well documented
# Etherpad vs Etherpad Lite
<table>
<tr>
<td>&nbsp;</td><td>&nbsp;</td><td><b>Etherpad</b></td><td>&nbsp;</td><td><b>Etherpad Lite</b></td>
</tr>
<tr>
<td align="right">Size of the folder (without git history)</td><td>&nbsp;</td><td>30 MB</td><td>&nbsp;</td><td>1.5 MB</td>
</tr>
<tr>
<td align="right">Languages used server side</td><td>&nbsp;</td><td>Javascript (Rhino), Java, Scala</td><td>&nbsp;</td><td>Javascript (node.js)</td>
</tr>
<tr>
<td align="right">Lines of server side Javascript code</td><td>&nbsp;</td><td>101410</td><td>&nbsp;</td><td>5330</td>
</tr>
<tr>
<td align="right">RAM Usage immediately after start</td><td>&nbsp;</td><td>257 MB</td><td>&nbsp;</td><td>16 MB</td>
</tr>
</table>
# Installation
1. Download latest node.js version from <http://nodejs.org/> and build it with this instructions <https://github.com/joyent/node/wiki/Installation>. <br>THE NODE.JS VERSION OF YOUR LINUX REPOSITORY MAY BE TOO OLD. PLEASE COMPILE FROM THE SOURCE TO GET SURE YOU HAVE THE LATEST VERSION.

View file

@ -37,6 +37,21 @@ fi
echo "Ensure that all dependencies are up to date..."
npm install
echo "Ensure jQuery is downloaded and up to date..."
DOWNLOAD_JQUERY="true"
NEEDED_VERSION="1.6.1"
if [ -f "static/js/jquery.min.js" ]; then
VERSION=$(cat static/js/jquery.min.js | head -n 2 | tail -n 1 | grep -o "v[0-9]*\.[0-9]*\.[0-9]*");
if [[ ${VERSION:1} = $NEEDED_VERSION ]]; then
DOWNLOAD_JQUERY="false"
fi
fi
if [[ $DOWNLOAD_JQUERY = "true" ]]; then
wget -O static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js
fi
#Remove all minified data to force node creating it new
echo "Clear minfified cache..."
rm var/minified* 2> /dev/null

View file

@ -145,7 +145,7 @@ exports.handleMessage = function(client, message)
}
if(!message.type)
{
throw "Message have no type attribute!";
throw "Message has no type attribute!";
}
//Check what type of message we get and delegate to the other methodes
@ -163,6 +163,12 @@ exports.handleMessage = function(client, message)
{
handleUserInfoUpdate(client, message);
}
else if(message.type == "COLLABROOM" &&
message.data.type == "CLIENT_MESSAGE" &&
message.data.payload.type == "suggestUserName")
{
handleSuggestUserName(client, message);
}
//if the message type is unkown, throw an exception
else
{
@ -170,6 +176,36 @@ exports.handleMessage = function(client, message)
}
}
/**
* Handles a handleSuggestUserName, that means a user have suggest a userName for a other user
* @param client the client that send this message
* @param message the message from the client
*/
function handleSuggestUserName(client, message)
{
//check if all ok
if(message.data.payload.newName == null)
{
throw "suggestUserName Message has no newName!";
}
if(message.data.payload.unnamedId == null)
{
throw "suggestUserName Message has no unnamedId!";
}
var padId = session2pad[client.sessionId];
//search the author and send him this message
for(var i in pad2sessions[padId])
{
if(sessioninfos[pad2sessions[padId][i]].author == message.data.payload.unnamedId)
{
socketio.clients[pad2sessions[padId][i]].send(message);
break;
}
}
}
/**
* Handles a USERINFO_UPDATE, that means that a user have changed his color or name. Anyway, we get both informations
* @param client the client that send this message
@ -180,7 +216,7 @@ function handleUserInfoUpdate(client, message)
//check if all ok
if(message.data.userInfo.colorId == null)
{
throw "USERINFO_UPDATE Message have no colorId!";
throw "USERINFO_UPDATE Message has no colorId!";
}
//Find out the author name of this session
@ -202,7 +238,7 @@ function handleUserInfoUpdate(client, message)
message.data.type = "USER_NEWINFO";
//Send the other clients on the pad the update message
for(i in pad2sessions[padId])
for(var i in pad2sessions[padId])
{
if(pad2sessions[padId][i] != client.id)
{
@ -228,15 +264,15 @@ function handleUserChanges(client, message)
//check if all ok
if(message.data.baseRev == null)
{
throw "USER_CHANGES Message have no baseRev!";
throw "USER_CHANGES Message has no baseRev!";
}
if(message.data.apool == null)
{
throw "USER_CHANGES Message have no apool!";
throw "USER_CHANGES Message has no apool!";
}
if(message.data.changeset == null)
{
throw "USER_CHANGES Message have no changeset!";
throw "USER_CHANGES Message has no changeset!";
}
//get all Vars we need
@ -451,25 +487,26 @@ function handleClientReady(client, message)
//check if all ok
if(!message.token)
{
throw "CLIENT_READY Message have no token!";
throw "CLIENT_READY Message has no token!";
}
if(!message.padId)
{
throw "CLIENT_READY Message have no padId!";
throw "CLIENT_READY Message has no padId!";
}
if(!message.protocolVersion)
{
throw "CLIENT_READY Message have no protocolVersion!";
throw "CLIENT_READY Message has no protocolVersion!";
}
if(message.protocolVersion != 2)
{
throw "CLIENT_READY Message have a unkown protocolVersion '" + message.protocolVersion + "'!";
throw "CLIENT_READY Message has a unkown protocolVersion '" + message.protocolVersion + "'!";
}
var author;
var authorName;
var authorColorId;
var pad;
var historicalAuthorData = {};
async.series([
//get all authordata of this new user
@ -511,6 +548,20 @@ function handleClientReady(client, message)
});
},
function(callback)
{
var authors = pad.getAllAuthors();
//get all author data out of the database
async.forEach(authors, function(authorId, callback)
{
authorManager.getAuthor(authorId, function(err, author)
{
historicalAuthorData[authorId] = author;
callback(err);
});
}, callback);
},
function(callback)
{
//Check if this author is already on the pad, if yes, kick the other sessions!
if(pad2sessions[message.padId])
@ -556,7 +607,7 @@ function handleClientReady(client, message)
"clientIp": (client.request && client.request.connection) ? client.request.connection.remoteAddress : "127.0.0.1",
//"clientAgent": "Anonymous Agent",
"padId": message.padId,
"historicalAuthorData": {},
"historicalAuthorData": historicalAuthorData,
"apool": apool,
"rev": pad.getHeadRevisionNumber(),
"globalPadId": message.padId
@ -570,7 +621,7 @@ function handleClientReady(client, message)
"opts": {},
"chatHistory": {
"start": 0,
"historicalAuthorData": {},
"historicalAuthorData": historicalAuthorData,
"end": 0,
"lines": []
},
@ -592,16 +643,6 @@ function handleClientReady(client, message)
clientVars.userName = authorName;
}
//Add all authors that worked on this pad, to the historicalAuthorData on clientVars
var allAuthors = pad.getAllAuthors();
for(i in allAuthors)
{
clientVars.collab_client_vars.historicalAuthorData[allAuthors[i]] = {};
if(authorName != null)
clientVars.collab_client_vars.historicalAuthorData[allAuthors[i]].name = authorName;
clientVars.collab_client_vars.historicalAuthorData[allAuthors[i]].colorId = authorColorId;
}
//Send the clientVars to the Client
client.json.send(clientVars);

View file

@ -58,6 +58,12 @@ exports.setSocketIO = function(_socket)
client.on('message', function(message)
{
if(message.protocolVersion && message.protocolVersion != 2)
{
console.error("Protocolversion header is not correct:" + JSON.stringify(message));
return;
}
//route this message to the correct component, if possible
if(message.component && components[message.component])
{
@ -71,7 +77,7 @@ exports.setSocketIO = function(_socket)
}
else
{
throw "Can't route the message:" + JSON.stringify(message);
console.error("Can't route the message:" + JSON.stringify(message));
}
});

View file

@ -39,7 +39,7 @@ exports.padJS = function(req, res)
{
res.header("Content-Type","text/javascript");
var jsFiles = ["plugins.js", "undo-xpopup.js", "json2.js", "pad_utils.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js"];
var jsFiles = ["jquery.min.js", "plugins.js", "undo-xpopup.js", "json2.js", "pad_utils.js", "pad_cookie.js", "pad_editor.js", "pad_editbar.js", "pad_docbar.js", "pad_modals.js", "ace.js", "collab_client.js", "pad_userlist.js", "pad_impexp.js", "pad_savedrevs.js", "pad_connectionstatus.js", "pad2.js"];
//minifying is enabled
if(settings.minify)
@ -182,9 +182,9 @@ exports.padJS = function(req, res)
{
//put all javascript files in an array
var values = [];
for(var i in fileValues)
for(var i in jsFiles)
{
values.push(fileValues[i]);
values.push(fileValues[jsFiles[i]]);
}
//minify all javascript files to one

View file

@ -23,6 +23,7 @@
require('joose');
var socketio = require('socket.io');
var fs = require('fs');
var settings = require('./settings');
var socketIORouter = require("./SocketIORouter");
var db = require('./db');
@ -31,9 +32,24 @@ var express = require('express');
var path = require('path');
var minify = require('./minify');
var serverName = "Etherpad-Lite ( http://j.mp/ep-lite )";
//try to get the git version
var version = "";
try
{
var ref = fs.readFileSync("../.git/HEAD", "utf-8");
var refPath = "../.git/" + ref.substring(5, ref.indexOf("\n"));
version = fs.readFileSync(refPath, "utf-8");
version = version.substring(0, 8);
}
catch(e)
{
console.error("Can't get git version for server header\n" + e.message)
}
var serverName = "Etherpad-Lite " + version + " (http://j.mp/ep-lite)";
//cache a week
exports.maxAge = 1000*60*60*24*1;
exports.maxAge = 1000*60*60*6;
async.waterfall([
//initalize the database
@ -77,16 +93,30 @@ async.waterfall([
});
//serve pad.html under /p
app.get('/p/:pad', function(req, res)
app.get('/p/:pad', function(req, res, next)
{
//ensure the padname is valid and the url doesn't end with a /
if(!isValidPadname(req.params.pad) || /\/$/.test(req.url))
{
next();
return;
}
res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/pad.html");
res.sendfile(filePath, { maxAge: exports.maxAge });
});
//serve timeslider.html under /p/$padname/timeslider
app.get('/p/:pad/timeslider', function(req, res)
app.get('/p/:pad/timeslider', function(req, res, next)
{
//ensure the padname is valid and the url doesn't end with a /
if(!isValidPadname(req.params.pad) || /\/$/.test(req.url))
{
next();
return;
}
res.header("Server", serverName);
var filePath = path.normalize(__dirname + "/../static/timeslider.html");
res.sendfile(filePath, { maxAge: exports.maxAge });
@ -134,3 +164,12 @@ async.waterfall([
callback(null);
}
]);
function isValidPadname(padname)
{
//ensure there is no dollar sign in the pad name
if(padname.indexOf("$")!=-1)
return false;
return true;
}

View file

@ -171,7 +171,7 @@ div #timeslider div#steppers div#rightstep {
#rightbars {
/*#rightbars {
margin-left: 730px;
margin-top: 5px;
margin-bottom: 5px;
@ -220,10 +220,10 @@ div #timeslider div#steppers div#rightstep {
color: rgb(50, 132, 213);
text-decoration: none;
}
*/
#legend {
/*#legend {
width: 143px;
background-color: white;
border: 1px solid rgb(194, 194, 194);
@ -249,7 +249,7 @@ div #timeslider div#steppers div#rightstep {
margin-top:3px;
margin-right: 14px;
border: rgb(149, 149, 149) 1px solid;
}
}*/
.topbarcenter{
display:none;

View file

@ -22,7 +22,7 @@ body, textarea { font-family: Helvetica, Arial, sans-serif; }
border-radius: 6px;
}
#sharebutton {
/*#sharebutton {
background: url(static/img/inviteshare2.gif) no-repeat 0 -31px;
position: relative;
display: block;
@ -31,7 +31,7 @@ body, textarea { font-family: Helvetica, Arial, sans-serif; }
height: 0; overflow: hidden; width: 96px;
left:50%;
margin-left: -48px;
}
}*/
a img
@ -193,20 +193,17 @@ a#backtoprosite { padding-left: 20px; left: 6px;
background: url(static/img/protop.gif) no-repeat -5px -6px; }
#accountnav { right: 30px; color: #fff; }
#topbarcenter { margin-left: 150px; margin-right: 150px; text-align:center;}
/*#topbarcenter { margin-left: 150px; margin-right: 150px; text-align:center;}
a#topbaretherpad { margin-left: auto; margin-right: auto; display: block; width: 103px;
position: relative; top: 3px; height: 0; padding-top: 20px;
/* background: url(static/img/padtop5.gif) no-repeat -397px -3px; overflow: hidden; */
}
#topbarBrand {font-size:2.1em; color: white; font-weight: bold; text-decoration: none; text-align: center;}
}*/
/*#topbarBrand {font-size:2.1em; color: white; font-weight: bold; text-decoration: none; text-align: center;}
#EtherpadLink {font-size: 1.2em; color: white;float:left;margin-left:-140px;margin-top:4px; text-decoration: none; }
#Licensing {font-size: 1.2em; color: white;float:left;margin-top:4px;margin-left:-75px; text-decoration: none; }
#fullscreen {font-size: 1.2em; color: white;float:right;margin-top:4px;margin-right:-120px; text-decoration: none; }
#fullscreen {font-size: 1.2em; color: white;float:right;margin-top:4px;margin-right:-120px; text-decoration: none; }*/
.propad a#topbaretherpad { background: url(static/img/protop.gif) no-repeat -397px -3px; }
@ -361,7 +358,7 @@ a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
white-space: nowrap;
}
.editbarbutton
/*.editbarbutton
{
border-top: 1px solid #8b9eba;
border-bottom: 1px solid #8b9eba;
@ -386,21 +383,21 @@ a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
position: relative;
top: 1px;
left: 1px;
}
}*/
.editbargroupsfirst
/*.editbargroupsfirst
{
border-left-width: 0px !important;
}
}*/
#editbar #syncstatussyncing { position: absolute; height: 26px; width: 26px;
/*#editbar #syncstatussyncing { position: absolute; height: 26px; width: 26px;
background: url(static/img/syncing2.gif) no-repeat center center;
right: 38px; top: 5px; display: none; }
#editbar #syncstatusdone { position: absolute; height: 26px; width: 26px;
background: url(static/img/syncdone.gif) no-repeat center center;
right: 38px; top: 5px; display: none; }
right: 38px; top: 5px; display: none; }*/
#padsidebar {
/*#padsidebar {
bottom: 0px;
position: absolute;
right: 0;
@ -409,7 +406,7 @@ a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
overflow: hidden;
z-index: 11;
}
.hidesidebar #padsidebar { width: 0; overflow: hidden; }
.hidesidebar #padsidebar { width: 0; overflow: hidden; }*/
#myswatchbox { position: absolute; left: 5px; top: 5px; width: 22px; height: 22px;
/*border-top: 1px solid #c3cfe0; border-left: 1px solid #c3cfe0;
@ -504,12 +501,12 @@ table#otheruserstable { display: none; }
top: 5px; width: 95px; }
.guestpolicystuff { display: none; }*/
.guestprompt { border: 1px solid #ccc; font-size: 1.2em;
/*.guestprompt { border: 1px solid #ccc; font-size: 1.2em;
padding: 5px; color: #222; background: #ffc; }
.guestprompt .choices { float: right; }
.guestprompt a { margin: 0 0.5em; }
.guestprompt a { margin: 0 0.5em; }*/
#chattop { background: #ecf2fa; padding: 5px; font-size: 1.2em; border-bottom: 1px solid #ddd; }
/*#chattop { background: #ecf2fa; padding: 5px; font-size: 1.2em; border-bottom: 1px solid #ddd; }
#chattop a { color: #36b; }
#chatlines .chatline { color: #444; padding-left: 5px; padding-top: 2px; padding-bottom: 2px;
background: #ddd; overflow: hidden; }
@ -527,13 +524,13 @@ table#otheruserstable { display: none; }
#padchat a#chatloadmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic; }
#padchat #chatloadingmore { display: none; font-size: 1.2em; padding: 2px 5px; font-style: italic;
color: #999; }
#padchat a#chatloadmore:focus { outline: 0; }
#padchat a#chatloadmore:focus { outline: 0; }*/
#djs { font-family: monospace; font-size: 10pt;
/*#djs { font-family: monospace; font-size: 10pt;
height: 200px; overflow: auto; border: 1px solid #ccc;
background: #fee; margin: 0; padding: 6px;
}
#djs p { margin: 0; padding: 0; display: block; }
#djs p { margin: 0; padding: 0; display: block; }*/
.modaldialog.cboxreconnecting .modaldialog-inner,
.modaldialog.cboxconnecting .modaldialog-inner {
@ -635,14 +632,14 @@ table#otheruserstable { display: none; }
/* We don't ever actually hide the wrapper, even when the panel is
cloased, so that its contents can always be manipulated accurately. */
.dbpanel-wrapper { position: absolute;
overflow: hidden; /* animated: */ height: 0; top: 25px; /* /animated */
/*.dbpanel-wrapper { position: absolute;
overflow: hidden; height: 0; top: 25px;
z-index: 51; zoom: 1; }
.dbpanel-panel { position: absolute; bottom: 0; width: 100%; }
.dbpanel-middle { margin-left: 7px; margin-right: 7px;
position: relative; height: 100%; overflow: hidden; zoom: 1; }
.dbpanel-inner { background: #f7f7f7 /* covered up by images */;
.dbpanel-inner { background: #f7f7f7 ;
width: 100%; height: 100%; position: absolute; overflow: hidden; top: -10px; }
.dbpanel-top { position: absolute; top: 0; width: 100%;
@ -655,10 +652,10 @@ table#otheruserstable { display: none; }
background-position: left top;
}
* html .dbpanel-top, * html .dbpanel-bottom { /* for IE 6+ */
* html .dbpanel-top, * html .dbpanel-bottom {
background-color: transparent;
background-image: url(static/img/apr09/blank.gif);
/* scale the image instead of repeating, but it amounts to the same */
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="static/img/docpanelmiddle2.png", sizingMethod="scale");
}
@ -681,12 +678,12 @@ table#otheruserstable { display: none; }
* html .dbpanel-leftedge, * html .dbpanel-rightedge, * html .dbpanel-botleftcorner, * html .dbpanel-botrightcorner {
background-color: transparent;
background-image: url(static/img/apr09/blank.gif);
/* crop the image */
filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(src="static/img/docpaneledge2.png", sizingMethod="crop");
}
* html .dbpanel-leftedge, * html .dbpanel-botleftcorner { left: -7px; width: 14px; }
#impexp-importlabel { position: absolute; top: 5px; left: 10px; width: 300px; }
*/
/*#impexp-importlabel { position: absolute; top: 5px; left: 10px; width: 300px; }
#importform { position: absolute; top: 24px; left: 5px; width: 300px; height: 60px; }
#importformsubmitdiv, #importformfilediv { padding: 5px 5px; }
@ -703,7 +700,7 @@ table#otheruserstable { display: none; }
#importexport #importmessagesuccess { margin: 0 20px; }
#importexport a.disabledexport {
color: #333; text-decoration: none;
opacity: 0.5; filter: alpha(opacity = 50) /*IE*/;
opacity: 0.5; filter: alpha(opacity = 50) ;
}
#importexport #importfileinput { padding: 2px 0; }
#importexport #importsubmitinput { padding: 2px; }
@ -712,7 +709,7 @@ table#otheruserstable { display: none; }
background: #ddd; }
#impexp-close { display: block; position: absolute; right: 2px; bottom: 15px;
width: auto; height: auto; font-size: 85%; color: #444;
z-index: 61 /* > clickcatcher */}
z-index: 61}
#impexp-disabled-clickcatcher {
display: none;
position: absolute; width: 100%; height: 100%;
@ -721,7 +718,7 @@ table#otheruserstable { display: none; }
#impexp-exportlabel { position: absolute; top: 5px; left: 350px;
width: 300px; }
#exportlinks .exportlink {
#exportlinks .exportlink {
display: block; position: absolute; height: 22px; width: auto;
background-repeat: no-repeat;
background-image: url(static/img/fileicons.gif);
@ -759,7 +756,7 @@ table#otheruserstable { display: none; }
width: auto; height: 100%; overflow: hidden; position: relative;
}
#savedrevs-scrollinner { position: absolute; width: 1px; height: 100%;
overflow: visible; right: 0/*...initially*/; top: 0; }
overflow: visible; right: 0; top: 0; }
#savedrevisions .srouterbox { width: 120px; height: 100%;
position: absolute; top: 0;
}
@ -767,10 +764,10 @@ table#otheruserstable { display: none; }
height: 59px; width: auto; border-left: 1px solid #ddd;
padding: 0 8px 0 8px; }
#savedrevisions a.srname { display: block; white-space: nowrap;
text-overflow: ellipsis /*no FF support*/; overflow: hidden;
text-overflow: ellipsis ; overflow: hidden;
text-decoration: none; color: #444; cursor: text;
padding: 1px; height: 14px; position: relative; left: -1px;
width: 100px /*specify for proper overflow in IE*/;
width: 100px ;
}
#savedrevisions a.srname:hover { text-decoration: none; color: #444;
border: 1px solid #ccc; padding: 0; }
@ -782,7 +779,7 @@ table#otheruserstable { display: none; }
#savedrevisions .srtime { color: #666; font-size: 90%;
white-space: nowrap; margin-top: 3px; }
#savedrevisions .srauthor { color: #666; font-size: 90%;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis /*no FF*/;
white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
#savedrevisions .srtwirly { position: absolute; display: block;
bottom: 0; right: 10px; display: none; }
@ -797,7 +794,7 @@ table#otheruserstable { display: none; }
#savedrevs-savenow:active { background-position: 0 -24px; }
#savedrevs-close { display: block; position: absolute; right: 7px; bottom: 8px;
width: auto; height: auto; font-size: 85%; color: #444; }
form#reconnectform { display: none; }
form#reconnectform { display: none; }*/
#padoptions { position: absolute; top: 0; left: 0; font-size: 1.2em;
color: #444; height: 100%; width: 100%; line-height: 15px; }
@ -817,7 +814,7 @@ form#reconnectform { display: none; }
#options-close { display: block; position: absolute; right: 7px; bottom: 8px;
width: auto; height: auto; font-size: 85%; color: #444; }
#padsecurity { position: absolute; top: 0; left: 0; font-size: 1.1em;
/*#padsecurity { position: absolute; top: 0; left: 0; font-size: 1.1em;
color: #444; height: 100%; width: 100%; line-height: 15px; }
#security-close { display: block; position: absolute; right: 7px; bottom: 8px;
width: auto; height: auto; font-size: 85%; color: #444; }
@ -856,7 +853,7 @@ form#reconnectform { display: none; }
#access-public, #access-public-label { top: 60px; }
#security-access label { color: #999; }
#security-access label strong { font-weight: normal; padding-right: 10px;
color: #444; }
color: #444; }*/
#mainmodals { z-index: 600; /* higher than the modals themselves
so that modals are on top in IE */ }
@ -865,10 +862,10 @@ form#reconnectform { display: none; }
#mainmodals .editempty { color: #aaa; }
#feedbackbox {
/*#feedbackbox {
position: absolute; display: none;
width: 400px; height: 270px;
left: 100px/*set in code*/; bottom: 50px;
left: 100px ; bottom: 50px;
z-index: 501; zoom: 1;
}
#feedbackbox-tl, #feedbackbox-tr, #feedbackbox-bl, #feedbackbox-br,
@ -914,7 +911,7 @@ form#reconnectform { display: none; }
#feedbackbox li a:hover { background: #ffe; }
#feedbackbox a, #feedbackbox li a:visited { color: #47b; }
#feedbackbox tt { font-size: 110%; }
*/
.expand-collapse {
height: 22px;
background-image: url(static/img/sharedistri.gif);
@ -1142,7 +1139,7 @@ ul#colorpickerswatches li:hover
cursor: pointer;
}
.user{
/*.user{
border: 1px solid #BBBBBB;
padding-left:2px;
padding-right:2px;
@ -1182,4 +1179,4 @@ color:#000;
padding-left:4px;
padding-right:4px;
padding-top:2px;
}
}*/

View file

@ -19,7 +19,6 @@
var clientVars = {}; // ]]>
</script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="/socket.io/socket.io.js"></script>
<!--<script type="text/javascript" src="/static/js/plugins.js"></script>
@ -100,7 +99,10 @@ var clientVars = {}; // ]]>
</li>
<li>
<a href="javascript:document.location = document.location+ '/timeslider'" title="Show the history of this pad">
<a id="timesliderlink" title="Show the history of this pad">
<script>
$("#timesliderlink").attr("href", document.location+ '/timeslider');
</script>
<img src="/static/img/editbar_timeslider.gif" />
</a>
</li>

View file

@ -11,7 +11,7 @@
<link href="/static/css/pad_lite.css" rel="stylesheet" type="text/css" />
<link href="/static/css/broadcast.css" rel="stylesheet" type="text/css" />
<style type="text/css" title="dynamicsyntax"></style>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="/static/js/jquery.min.js"></script>
<script type="text/javascript">
// <![CDATA[
var clientVars = {};
@ -274,7 +274,10 @@
<div id="editbarright" class="editbarright">
<!-- termporary place holder-->
<a id = "returnbutton" href="javascript:document.location=document.location.href.substring(0,document.location.href.lastIndexOf('/timeslider'))">Return to pad</a>
<a id = "returnbutton">Return to pad</a>
<script>
$("#returnbutton").attr("href", document.location.href.substring(0,document.location.href.lastIndexOf('/timeslider')));
</script>
</div>
<div id="editbarinner" class="editbarinner">