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

This commit is contained in:
Peter 'Pita' Martischka 2011-08-10 22:47:50 +01:00
commit 9cc3b543cc
28 changed files with 348 additions and 213 deletions

View File

@ -1,7 +1,7 @@
# About
Etherpad lite is a really-real time collaborative editor spawned from the Hell fire of Etherpad.
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 ligther and more stable than the original Etherpad. Our hope
is based on node.js what makes it much lighter 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. Etherpad Lite is optimized
to be easy embeddable. Look at our [FAQ Page](https://github.com/Pita/etherpad-lite/wiki/FAQ)
@ -32,7 +32,7 @@ Visit <http://pitapoison.de:9001> to test it live. <br>You can find the same ins
**As root:**
<ol>
<li>Install all dependencies. We need the sqlite develob libraries, gzip, git, curl, libssl develop libraries and python <br><code>apt-get install libsqlite3-dev gzip git-core curl python libssl-dev</code></li><br>
<li>Install all dependencies. We need the sqlite development libraries, gzip, git, curl, libssl develop libraries and python <br><code>apt-get install libsqlite3-dev gzip git-core curl python libssl-dev</code></li><br>
<li>Install node.js
<ol type="a">
<li>Download the latest <b>0.4.x</b> node.js release from <a href="http://nodejs.org/#download">http://nodejs.org/#download</a></li>
@ -43,7 +43,7 @@ Visit <http://pitapoison.de:9001> to test it live. <br>You can find the same ins
<li>Install npm <code>curl http://npmjs.org/install.sh | sh</code></li>
</ol>
**As any user (we recommend creating a seperate user called etherpad-lite):**
**As any user (we recommend creating a separate user called etherpad-lite):**
<ol start="4">
<li> Clone the git repository <code>git clone 'git://github.com/Pita/etherpad-lite.git'</code><br>&nbsp;</li>
@ -55,7 +55,7 @@ Visit <http://pitapoison.de:9001> to test it live. <br>You can find the same ins
## Troubleshooting
### It fails while installing the sqlite dependency
The sqlite package of some linux versions (including debian lenny) is too old. We need sqlite >=3.6. You have to use a PPA or debian backports. You find sqlite packages for Ubuntu Hardy [here](https://launchpad.net/~mirabilos/+archive/ppa/+sourcepub/1304941/+listing-archive-extra), Debian Backports can be found [here](http://backports-master.debian.org/Instructions/#index1h2)
The sqlite package of some Linux versions (including debian lenny) is too old. We need sqlite >=3.6. You have to use a PPA or debian backports. You find sqlite packages for Ubuntu Hardy [here](https://launchpad.net/~mirabilos/+archive/ppa/+sourcepub/1304941/+listing-archive-extra), Debian Backports can be found [here](http://backports-master.debian.org/Instructions/#index1h2)
### It fails while installing the express dependency, it says my node version is wrong
You might have installed node.js version 0.5. You can check that with `node --version`. Please reinstall node 0.4.x
@ -93,7 +93,7 @@ You also help the project, if you only host a Etherpad Lite instance and share y
# Modules created for this project
* [ueberDB](https://github.com/Pita/ueberDB) "transforms every database into a object key value store" - manages all database access
* [doc.md](https://github.com/Pita/doc.md) "A simple JSDoc documenation tool that creates markdown for node.js modules exports" - is used to generate the docs
* [doc.md](https://github.com/Pita/doc.md) "A simple JSDoc documentation tool that creates markdown for node.js modules exports" - is used to generate the docs
* [channels](https://github.com/Pita/channels) "Event channels in node.js" - ensures that ueberDB operations are atomic and in series for each key
# License

View File

@ -13,27 +13,30 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var async = require("async");
var Changeset = require("./Changeset");
var padManager = require("../db/PadManager");
function getPadPlainText(pad, revNum) {
var atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) :
pad.atext());
var textLines = atext.text.slice(0,-1).split('\n');
function getPadPlainText(pad, revNum)
{
var atext = ((revNum !== undefined) ? pad.getInternalRevisionAText(revNum) : pad.atext());
var textLines = atext.text.slice(0, -1).split('\n');
var attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
var apool = pad.pool();
var pieces = [];
for(var i=0;i<textLines.length;i++) {
for (var i = 0; i < textLines.length; i++)
{
var line = _analyzeLine(textLines[i], attribLines[i], apool);
if (line.listLevel) {
var numSpaces = line.listLevel*2-1;
if (line.listLevel)
{
var numSpaces = line.listLevel * 2 - 1;
var bullet = '*';
pieces.push(new Array(numSpaces+1).join(' '), bullet, ' ', line.text, '\n');
pieces.push(new Array(numSpaces + 1).join(' '), bullet, ' ', line.text, '\n');
}
else {
else
{
pieces.push(line.text, '\n');
}
}
@ -41,52 +44,68 @@ function getPadPlainText(pad, revNum) {
return pieces.join('');
}
function getPadHTML(pad, revNum, callback) {
function getPadHTML(pad, revNum, callback)
{
var atext = pad.atext;
var html;
async.waterfall([
// fetch revision atext
function (callback) {
if (revNum != undefined) {
pad.getInternalRevisionAText(revNum, function (err, revisionAtext) {
atext = revisionAtext;
callback(err);
});
} else {
callback(null);
}
},
// convert atext to html
function (callback) {
html = getHTMLFromAtext(pad, atext);
// fetch revision atext
function (callback)
{
if (revNum != undefined)
{
pad.getInternalRevisionAText(revNum, function (err, revisionAtext)
{
atext = revisionAtext;
callback(err);
});
}
else
{
callback(null);
}
],
// run final callback
function (err) {
callback(err, html);
}
);
},
// convert atext to html
function (callback)
{
html = getHTMLFromAtext(pad, atext);
callback(null);
}],
// run final callback
function (err)
{
callback(err, html);
});
}
function getHTMLFromAtext(pad, atext) {
function getHTMLFromAtext(pad, atext)
{
var apool = pad.apool();
var textLines = atext.text.slice(0,-1).split('\n');
var textLines = atext.text.slice(0, -1).split('\n');
var attribLines = Changeset.splitAttributionLines(atext.attribs, atext.text);
var tags = ['h1', 'h2', 'strong','em','u','s'];
var props = ['heading1', 'heading2', 'bold','italic','underline','strikethrough'];
var tags = ['h1', 'h2', 'strong', 'em', 'u', 's'];
var props = ['heading1', 'heading2', 'bold', 'italic', 'underline', 'strikethrough'];
var anumMap = {};
props.forEach(function(propName, i) {
var propTrueNum = apool.putAttrib([propName,true], true);
if (propTrueNum >= 0) {
props.forEach(function (propName, i)
{
var propTrueNum = apool.putAttrib([propName, true], true);
if (propTrueNum >= 0)
{
anumMap[propTrueNum] = i;
}
});
function getLineHTML(text, attribs) {
function getLineHTML(text, attribs)
{
var propVals = [false, false, false];
var ENTER = 1;
var STAY = 2;
@ -97,16 +116,18 @@ function getHTMLFromAtext(pad, atext) {
// <b>Just bold<b> <b><i>Bold and italics</i></b> <i>Just italics</i>
// becomes
// <b>Just bold <i>Bold and italics</i></b> <i>Just italics</i>
var taker = Changeset.stringIterator(text);
var assem = Changeset.stringAssembler();
function emitOpenTag(i) {
function emitOpenTag(i)
{
assem.append('<');
assem.append(tags[i]);
assem.append('>');
}
function emitCloseTag(i) {
function emitCloseTag(i)
{
assem.append('</');
assem.append(tags[i]);
assem.append('>');
@ -115,101 +136,123 @@ function getHTMLFromAtext(pad, atext) {
var urls = _findURLs(text);
var idx = 0;
function processNextChars(numChars) {
if (numChars <= 0) {
function processNextChars(numChars)
{
if (numChars <= 0)
{
return;
}
var iter = Changeset.opIterator(Changeset.subattribution(attribs,
idx, idx+numChars));
var iter = Changeset.opIterator(Changeset.subattribution(attribs, idx, idx + numChars));
idx += numChars;
while (iter.hasNext()) {
while (iter.hasNext())
{
var o = iter.next();
var propChanged = false;
Changeset.eachAttribNumber(o.attribs, function(a) {
if (a in anumMap) {
Changeset.eachAttribNumber(o.attribs, function (a)
{
if (a in anumMap)
{
var i = anumMap[a]; // i = 0 => bold, etc.
if (! propVals[i]) {
if (!propVals[i])
{
propVals[i] = ENTER;
propChanged = true;
}
else {
else
{
propVals[i] = STAY;
}
}
});
for(var i=0;i<propVals.length;i++) {
if (propVals[i] === true) {
for (var i = 0; i < propVals.length; i++)
{
if (propVals[i] === true)
{
propVals[i] = LEAVE;
propChanged = true;
}
else if (propVals[i] === STAY) {
else if (propVals[i] === STAY)
{
propVals[i] = true; // set it back
}
}
// now each member of propVal is in {false,LEAVE,ENTER,true}
// according to what happens at start of span
if (propChanged) {
if (propChanged)
{
// leaving bold (e.g.) also leaves italics, etc.
var left = false;
for(var i=0;i<propVals.length;i++) {
for (var i = 0; i < propVals.length; i++)
{
var v = propVals[i];
if (! left) {
if (v === LEAVE) {
if (!left)
{
if (v === LEAVE)
{
left = true;
}
}
else {
if (v === true) {
else
{
if (v === true)
{
propVals[i] = STAY; // tag will be closed and re-opened
}
}
}
for(var i=propVals.length-1; i>=0; i--) {
if (propVals[i] === LEAVE) {
for (var i = propVals.length - 1; i >= 0; i--)
{
if (propVals[i] === LEAVE)
{
emitCloseTag(i);
propVals[i] = false;
}
else if (propVals[i] === STAY) {
else if (propVals[i] === STAY)
{
emitCloseTag(i);
}
}
for(var i=0; i<propVals.length; i++) {
if (propVals[i] === ENTER || propVals[i] === STAY) {
for (var i = 0; i < propVals.length; i++)
{
if (propVals[i] === ENTER || propVals[i] === STAY)
{
emitOpenTag(i);
propVals[i] = true;
}
}
// propVals is now all {true,false} again
} // end if (propChanged)
var chars = o.chars;
if (o.lines) {
if (o.lines)
{
chars--; // exclude newline at end of line, if present
}
var s = taker.take(chars);
assem.append(_escapeHTML(s));
} // end iteration over spans in line
for(var i=propVals.length-1; i>=0; i--) {
if (propVals[i]) {
for (var i = propVals.length - 1; i >= 0; i--)
{
if (propVals[i])
{
emitCloseTag(i);
propVals[i] = false;
}
}
} // end processNextChars
if (urls) {
urls.forEach(function(urlData) {
if (urls)
{
urls.forEach(function (urlData)
{
var startIndex = urlData[0];
var url = urlData[1];
var urlLength = url.length;
processNextChars(startIndex - idx);
assem.append('<a href="'+url.replace(/\"/g, '&quot;')+'">');
assem.append('<a href="' + url.replace(/\"/g, '&quot;') + '">');
processNextChars(urlLength);
assem.append('</a>');
});
@ -218,7 +261,6 @@ function getHTMLFromAtext(pad, atext) {
return _processSpaces(assem.toString());
} // end getLineHTML
var pieces = [];
// Need to deal with constraints imposed on HTML lists; can
@ -228,79 +270,98 @@ function getHTMLFromAtext(pad, atext) {
// so we want to do something reasonable there. We also
// want to deal gracefully with blank lines.
var lists = []; // e.g. [[1,'bullet'], [3,'bullet'], ...]
for(var i=0;i<textLines.length;i++) {
for (var i = 0; i < textLines.length; i++)
{
var line = _analyzeLine(textLines[i], attribLines[i], apool);
var lineContent = getLineHTML(line.text, line.aline);
if (line.listLevel || lists.length > 0) {
if (line.listLevel || lists.length > 0)
{
// do list stuff
var whichList = -1; // index into lists or -1
if (line.listLevel) {
if (line.listLevel)
{
whichList = lists.length;
for(var j=lists.length-1;j>=0;j--) {
if (line.listLevel <= lists[j][0]) {
for (var j = lists.length - 1; j >= 0; j--)
{
if (line.listLevel <= lists[j][0])
{
whichList = j;
}
}
}
if (whichList >= lists.length) {
if (whichList >= lists.length)
{
lists.push([line.listLevel, line.listTypeName]);
pieces.push('<ul><li>', lineContent || '<br>');
}
else if (whichList == -1) {
if (line.text) {
else if (whichList == -1)
{
if (line.text)
{
// non-blank line, end all lists
pieces.push(new Array(lists.length+1).join('</li></ul\n>'));
pieces.push(new Array(lists.length + 1).join('</li></ul\n>'));
lists.length = 0;
pieces.push(lineContent, '<br>');
}
else {
else
{
pieces.push('<br><br>');
}
}
else {
while (whichList < lists.length-1) {
else
{
while (whichList < lists.length - 1)
{
pieces.push('</li></ul>');
lists.length--;
}
pieces.push('</li><li>', lineContent || '<br>');
}
}
else {
else
{
pieces.push(lineContent, '<br>');
}
}
pieces.push(new Array(lists.length+1).join('</li></ul>'));
pieces.push(new Array(lists.length + 1).join('</li></ul>'));
return pieces.join('');
}
function _analyzeLine(text, aline, apool) {
function _analyzeLine(text, aline, apool)
{
var line = {};
// identify list
var lineMarker = 0;
line.listLevel = 0;
if (aline) {
if (aline)
{
var opIter = Changeset.opIterator(aline);
if (opIter.hasNext()) {
if (opIter.hasNext())
{
var listType = Changeset.opAttributeValue(opIter.next(), 'list', apool);
if (listType) {
if (listType)
{
lineMarker = 1;
listType = /([a-z]+)([12345678])/.exec(listType);
if (listType) {
if (listType)
{
line.listTypeName = listType[1];
line.listLevel = Number(listType[2]);
}
}
}
}
if (lineMarker) {
if (lineMarker)
{
line.text = text.substring(1);
line.aline = Changeset.subattribution(aline, 1);
}
else {
else
{
line.text = text;
line.aline = aline;
}
@ -308,37 +369,32 @@ function _analyzeLine(text, aline, apool) {
return line;
}
exports.getPadHTMLDocument = function(padId, revNum, noDocType, callback) {
padManager.getPad(padId, function(err, pad)
exports.getPadHTMLDocument = function (padId, revNum, noDocType, callback)
{
padManager.getPad(padId, function (err, pad)
{
if(err)
if (err)
{
callback(err);
return;
}
var head = (noDocType?'':'<!doctype html>\n')+
'<html lang="en">\n'+
(noDocType?'':
'<head>\n'+
'<meta charset="utf-8">\n'+
'<style> * { font-family: arial, sans-serif;\n'+
'font-size: 13px;\n'+
'line-height: 17px; }</style>\n' +
'</head>\n')+
'<body>';
var head = (noDocType ? '' : '<!doctype html>\n') + '<html lang="en">\n' + (noDocType ? '' : '<head>\n' + '<meta charset="utf-8">\n' + '<style> * { font-family: arial, sans-serif;\n' + 'font-size: 13px;\n' + 'line-height: 17px; }</style>\n' + '</head>\n') + '<body>';
var foot = '</body>\n</html>\n';
getPadHTML(pad, revNum, function (err, html) {
getPadHTML(pad, revNum, function (err, html)
{
callback(err, head + html + foot);
});
});
}
function _escapeHTML(s) {
function _escapeHTML(s)
{
var re = /[&<>]/g;
if (! re.MAP) {
if (!re.MAP)
{
// persisted across function calls!
re.MAP = {
'&': '&amp;',
@ -346,53 +402,78 @@ function _escapeHTML(s) {
'>': '&gt;',
};
}
return s.replace(re, function(c) { return re.MAP[c]; });
s = s.replace(re, function (c)
{
return re.MAP[c];
});
return s.replace(/[^\x21-\x7E\s\t\n\r]/g, function(c)
{
return "&#" +c.charCodeAt(0) + ";"
});
}
// copied from ACE
function _processSpaces(s) {
function _processSpaces(s)
{
var doesWrap = true;
if (s.indexOf("<") < 0 && ! doesWrap) {
if (s.indexOf("<") < 0 && !doesWrap)
{
// short-cut
return s.replace(/ /g, '&nbsp;');
}
var parts = [];
s.replace(/<[^>]*>?| |[^ <]+/g, function(m) { parts.push(m); });
if (doesWrap) {
s.replace(/<[^>]*>?| |[^ <]+/g, function (m)
{
parts.push(m);
});
if (doesWrap)
{
var endOfLine = true;
var beforeSpace = false;
// last space in a run is normal, others are nbsp,
// end of line is nbsp
for(var i=parts.length-1;i>=0;i--) {
for (var i = parts.length - 1; i >= 0; i--)
{
var p = parts[i];
if (p == " ") {
if (endOfLine || beforeSpace)
parts[i] = '&nbsp;';
endOfLine = false;
beforeSpace = true;
if (p == " ")
{
if (endOfLine || beforeSpace) parts[i] = '&nbsp;';
endOfLine = false;
beforeSpace = true;
}
else if (p.charAt(0) != "<") {
endOfLine = false;
beforeSpace = false;
else if (p.charAt(0) != "<")
{
endOfLine = false;
beforeSpace = false;
}
}
// beginning of line is nbsp
for(var i=0;i<parts.length;i++) {
for (var i = 0; i < parts.length; i++)
{
var p = parts[i];
if (p == " ") {
parts[i] = '&nbsp;';
break;
if (p == " ")
{
parts[i] = '&nbsp;';
break;
}
else if (p.charAt(0) != "<") {
break;
else if (p.charAt(0) != "<")
{
break;
}
}
}
else {
for(var i=0;i<parts.length;i++) {
else
{
for (var i = 0; i < parts.length; i++)
{
var p = parts[i];
if (p == " ") {
parts[i] = '&nbsp;';
if (p == " ")
{
parts[i] = '&nbsp;';
}
}
}
@ -403,15 +484,19 @@ function _processSpaces(s) {
// copied from ACE
var _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]/;
var _REGEX_SPACE = /\s/;
var _REGEX_URLCHAR = new RegExp('('+/[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source+'|'+_REGEX_WORDCHAR.source+')');
var _REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source+_REGEX_URLCHAR.source+'*(?![:.,;])'+_REGEX_URLCHAR.source, 'g');
var _REGEX_URLCHAR = new RegExp('(' + /[-:@a-zA-Z0-9_.,~%+\/\\?=&#;()$]/.source + '|' + _REGEX_WORDCHAR.source + ')');
var _REGEX_URL = new RegExp(/(?:(?:https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man|gopher|txmt):\/\/|mailto:)/.source + _REGEX_URLCHAR.source + '*(?![:.,;])' + _REGEX_URLCHAR.source, 'g');
// returns null if no URLs, or [[startIndex1, url1], [startIndex2, url2], ...]
function _findURLs(text) {
function _findURLs(text)
{
_REGEX_URL.lastIndex = 0;
var urls = null;
var execResult;
while ((execResult = _REGEX_URL.exec(text))) {
while ((execResult = _REGEX_URL.exec(text)))
{
urls = (urls || []);
var startIndex = execResult.index;
var url = execResult[0];

View File

@ -61,6 +61,7 @@ a img
padding: 4px 5px;
height: 18px;
width: 18px;
cursor: pointer;
@ -94,6 +95,7 @@ a img
border: inherit;
background: inherit;
visibility:hidden;
width: 0px;
}
#editbar ul li a
{
@ -308,7 +310,13 @@ a#hidetopmsg { position: absolute; right: 5px; bottom: 5px; }
.hidesidebar #padeditor { right: 0; }
#vdraggie {
background: url(static/img/vdraggie.gif) no-repeat top center;
/* background: url(static/img/vdraggie.gif) no-repeat top center;*/
width:16px;
height:16px;
background-image:url('../../static/img/etherpad_lite_icons.gif');
background-repeat: no-repeat;
background-position: 0px -300px;
cursor: W-resize;
bottom:0;
position:absolute;
@ -812,7 +820,6 @@ ul#colorpickerswatches li:hover
#chatlabel
{
cursor: default;
font-size:13px;
line-height:16px;
font-weight:bold;
@ -842,6 +849,7 @@ ul#colorpickerswatches li:hover
border-top-left-radius: 5px;
border-top-right-radius: 5px;
background-color:#fff;
cursor: pointer;
}
#chaticon a
@ -876,10 +884,11 @@ ul#colorpickerswatches li:hover
#titlecross
{
font-size:16px;
font-size:25px;
float:right;
text-align: right;
text-decoration: none;
cursor: pointer;
color:#555;
}
@ -906,22 +915,26 @@ position: relative;
display: block;
}
/*
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable- autohide .ui-resizable-handle { display: none; }
*/
.ui-resizable-nw {
cursor: nw-resize;
width: 22px;
height: 22px;
left: 0px; top: 0px;
background-size: 100% auto;
background-image: url("../img/nw-resize.png");
background-repeat: no-repeat;
/* background-position: -5px -5px;*/
background-size: 100% auto;
cursor: nw-resize;
height: 22px;
left: 0;
top: 0;
width: 22px;
}
.ui-resizable-ne
{
cursor: ne-resize;
width: 9px;
height: 9px;
right: -5px;
top: -5px;
}
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right:
-5px; top: -5px;}
#importexport{
position:absolute;
@ -1046,3 +1059,30 @@ padding: 10px;
border-radius: 6px;
opacity:.8;
}
.buttonicon{
width:16px;
height:16px;
background-image:url('../../static/img/etherpad_lite_icons.gif');
background-repeat: no-repeat;
margin-left: 1px;
margin-top: 1px;
}
#usericon
{
width:27px !important;
}
#focusprotector
{
z-index: 100;
position: absolute;
bottom: 0px;
top: 0px;
left: 0px;
right: 0px;
background-color: white;
opacity:0.01;
display:none;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 867 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 147 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 336 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 230 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 372 B

View File

@ -3,16 +3,29 @@ var chat = (function()
var self = {
show: function ()
{
$("#chaticon").hide("slide", { direction: "down" }, 500, function()
$("#chaticon").hide("slide", {
direction: "down"
}, 500, function ()
{
$("#chatbox").show("slide", { direction: "down" }, 750, self.scrollDown);
$("#chatbox").resizable({ handles: 'nw', start: function(event,ui){
$("#editorcontainer").hide();
}, stop: function(event,ui){
$("#editorcontainer").show();
self.scrollDown();
}});
$("#chatbox").show("slide", {
direction: "down"
}, 750, self.scrollDown);
$("#chatbox").resizable(
{
handles: 'nw',
start: function (event, ui)
{
$("#focusprotector").show();
},
stop: function (event, ui)
{
$("#focusprotector").hide();
$("#chatbox").css({right: "20px", bottom: "0px", left: "", top: ""});
self.scrollDown();
}
});
});
},
hide: function ()

View File

@ -25,76 +25,75 @@
<ul id="menu_left">
<li>
<a onClick="window.pad&&pad.editbarClick('bold');return false" title="Bold (ctrl-B)">
<img src="../static/img/editbar_bold.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -116px"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('italic'); return false;" title="Italics (ctrl-I)">
<img src="../static/img/editbar_italic.gif" width="16" height="16" />
</a>
<a onClick="window.pad&&pad.editbarClick('italic'); return false;" title="Italics (ctrl-I)">
<div class="buttonicon" style="background-position:0px 0px"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('underline');return false;" title="Underline (ctrl-U)">
<img src="../static/img/editbar_underline.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -236px;margin-top:1px;"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('strikethrough');return false;" title="Strikethrough">
<img src="../static/img/editbar_strikethrough.gif" width="16" height="16" />
</a>
<a onClick="window.pad&&pad.editbarClick('strikethrough');return false;" title="Strikethrough">
<div class="buttonicon" style="background-position:0px -200px"></div>
</a>
</li>
<li class="separator"></li>
<li>
<a onClick="window.pad&&pad.editbarClick('insertunorderedlist');return false;" title="Toggle Bullet List">
<img src="../static/img/editbar_insertunorderedlist.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -34px"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('indent');return false;" title="Indent List">
<img src="../static/img/editbar_indent.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -52px"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('outdent');return false;" title="Unindent List">
<img src="../static/img/editbar_outdent.gif" width="16" height="16" />
<a onClick="window.pad&&pad.editbarClick('outdent');return false;" title="Unindent List">
<div class="buttonicon" style="background-position:0px -134px"></div>
</a>
</li>
<li class="separator"></li>
<li>
<a onClick="window.pad&&pad.editbarClick('undo');return false;" title="Undo (ctrl-Z)">
<img src="../static/img/editbar_undo.gif" width="16" height="16" />
</a>
<a onClick="window.pad&&pad.editbarClick('undo');return false;" title="Undo (ctrl-Z)">
<div class="buttonicon" style="background-position:0px -255px"></div>
</a>
</li>
<li>
<a onClick="window.pad&&pad.editbarClick('redo');return false;" title="Redo (ctrl-Y)">
<img src="../static/img/editbar_redo.gif" width="16" height="16" />
</a>
<div class="buttonicon" style="background-position:0px -166px"></div>
</a>
</li>
<li class="separator"></li>
<li>
<a onClick="window.pad&&pad.editbarClick('clearauthorship');return false;" title="Clear Authorship Colors">
<img src="../static/img/editbar_clearauthorship.gif" width="16" height="16" />
</a>
<a onClick="window.pad&&pad.editbarClick('clearauthorship');return false;" title="Clear Authorship Colors">
<div class="buttonicon" style="background-position:0px -86px"></div>
</a>
</li>
</ul>
<ul id="menu_right">
<li>
<a id="readonlylink" onClick="window.pad&&pad.editbarClick('readonly');return false;" title="Create a readonly link for this pad">
<img src="../static/img/editbar_readonly.gif" width="16" height="16" />
</a>
<a id="readonlylink" onClick="window.pad&&pad.editbarClick('readonly');return false;" title="Create a readonly link for this pad">
<div class="buttonicon" style="background-position:0px -150px"></div>
</a>
</li>
<li>
<a id="exportlink" onClick="window.pad&&pad.editbarClick('import_export');return false;"
title="Import/Export from/to different document formats">
<img src="../static/img/editbar_import_export.gif" width="16" height="16" />
</a>
<a id="exportlink" onClick="window.pad&&pad.editbarClick('import_export');return false;" title="Import/Export from/to different document formats">
<div class="buttonicon" style="background-position:0px -68px"></div>
</a>
</li>
<li>
<a id="embedlink" onClick="window.pad&&pad.editbarClick('embed');return false;" title="Embed this pad">
<img src="../static/img/editbar_embed.gif" width="16" height="16" />
</a>
<a id="embedlink" onClick="window.pad&&pad.editbarClick('embed');return false;" title="Embed this pad">
<div class="buttonicon" style="background-position:0px -18px"></div>
</a>
</li>
<!--
We removed this feature cause its not worth the space it needs in the editbar
@ -109,23 +108,18 @@ We removed this feature cause its not worth the space it needs in the editbar
</select>
</li>-->
<li class="separator"></li>
<!--<li>
<a onClick="window.pad&&pad.editbarClick('chat'); return false;"
title="(Placeholder, not implemented so far) Open the chat for this pad">
<img src="../static/img/editbar_chat.gif" width="16" height="16" />
</a>
</li>-->
<li>
<a id="timesliderlink" title="Show the history of this pad">
<script>
document.getElementById('timesliderlink').href = document.location+ '/timeslider';
</script>
<img src="../static/img/editbar_timeslider.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -218px"></div>
</a>
</li>
<li>
<li id="usericon">
<a onClick="window.pad&&pad.editbarClick('showusers');return false;" title="Show connected users">
<img id="showusersicon" src="../static/img/editbar_showusers.gif" width="16" height="16" /> <span id="online_count">1</span>
<div class="buttonicon" style="background-position:0px -184px;display:inline-block;"></div>
<span id="online_count">1</span>
</a>
</li>
</ul>
@ -256,13 +250,13 @@ Use this link to share a read-only version of your pad:<input id="readonlyInput"
<a onClick="chat.show();return false;"
title="Open the chat for this pad">
<span id="chatlabel">Chat</span>
<img src="../static/img/editbar_chat.gif" width="16" height="16" />
<div class="buttonicon" style="background-position:0px -102px;display:inline-block;"></div>
</a>
<span id="chatcounter">0</span>
</div>
<div id="chatbox">
<div id="titlebar"><span id ="titlelabel">Chat</span><a id="titlecross" onClick="chat.hide();return false;">x&nbsp;</a></div>
<div id="titlebar"><span id ="titlelabel">Chat</span><a id="titlecross" onClick="chat.hide();return false;">-&nbsp;</a></div>
<div id="chattext" class="authorColors"></div>
<div id="chatinputbox">
<form>
@ -271,10 +265,13 @@ Use this link to share a read-only version of your pad:<input id="readonlyInput"
</div>
</div>
<div id="focusprotector">&nbsp;</div>
<!-- /padeditor -->
<div id="modaloverlay">
<div id="modaloverlay-inner">
<!-- -->
</div>
</div>
<div id="mainmodals">