Merge branch 'master' into serverModule

This commit is contained in:
calcnerd256 2012-01-30 11:17:16 -06:00
commit 16735fe4fa
35 changed files with 935 additions and 904 deletions

View file

@ -58,7 +58,7 @@ Here is the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**
<ol> <ol>
<li>Install the dependencies. We need gzip, git, curl, libssl develop libraries, python and gcc. <br><i>For Debian/Ubuntu</i> <code>apt-get install gzip git-core curl python libssl-dev build-essential</code><br> <li>Install the dependencies. We need gzip, git, curl, libssl develop libraries, python and gcc. <br><i>For Debian/Ubuntu</i> <code>apt-get install gzip git-core curl python libssl-dev build-essential</code><br>
<i>For Fedora/CentOS</i> <code>yum install gzip git-core curl python openssl-dev && yum groupinstall "Development Tools"</code> <i>For Fedora/CentOS</i> <code>yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"</code>
</li><br> </li><br>
<li>Install node.js <li>Install node.js
<ol type="a"> <ol type="a">

View file

@ -4,6 +4,7 @@ var ueberDB = require("ueberDB");
var mysql = require("mysql"); var mysql = require("mysql");
var async = require("async"); var async = require("async");
var Changeset = require("../node/utils/Changeset"); var Changeset = require("../node/utils/Changeset");
var randomString = require("../node/utils/randomstring");
var AttributePoolFactory = require("../node/utils/AttributePoolFactory"); var AttributePoolFactory = require("../node/utils/AttributePoolFactory");
var settingsFile = process.argv[2]; var settingsFile = process.argv[2];
@ -450,18 +451,3 @@ function parsePage(array, pageStart, offsets, data, json)
start+=unitLength; start+=unitLength;
} }
} }
/**
* Generates a random String with the given length. Is needed to generate the Author Ids
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}

View file

@ -33,6 +33,13 @@ if [ ! $(echo $NPM_VERSION | cut -d "." -f 1) = "1" ]; then
exit 1 exit 1
fi fi
#check node version
NODE_VERSION=$(node --version)
if [ ! $(echo $NODE_VERSION | cut -d "." -f 1-2) = "v0.6" ]; then
echo "You're running a wrong version of node, you're using $NODE_VERSION, we need v0.6.x" >&2
exit 1
fi
#Does a settings.json exist? if no copy the template #Does a settings.json exist? if no copy the template
if [ ! -f "settings.json" ]; then if [ ! -f "settings.json" ]; then
echo "Copy the settings template to settings.json..." echo "Copy the settings template to settings.json..."

View file

@ -22,6 +22,8 @@ var ERR = require("async-stacktrace");
var db = require("./DB").db; var db = require("./DB").db;
var async = require("async"); var async = require("async");
var randomString = require("../utils/randomstring");
/** /**
* Checks if the author exists * Checks if the author exists
*/ */
@ -177,18 +179,3 @@ exports.setAuthorName = function (author, name, callback)
{ {
db.setSub("globalAuthor:" + author, ["name"], name, callback); db.setSub("globalAuthor:" + author, ["name"], name, callback);
} }
/**
* Generates a random String with the given length. Is needed to generate the Author Ids
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}

View file

@ -20,6 +20,7 @@
var ERR = require("async-stacktrace"); var ERR = require("async-stacktrace");
var customError = require("../utils/customError"); var customError = require("../utils/customError");
var randomString = require("../utils/randomstring");
var db = require("./DB").db; var db = require("./DB").db;
var async = require("async"); var async = require("async");
var padManager = require("./PadManager"); var padManager = require("./PadManager");
@ -255,18 +256,3 @@ exports.listPads = function(groupID, callback)
} }
}); });
} }
/**
* Generates a random String with the given length. Is needed to generate the Author Ids
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}

View file

@ -22,6 +22,8 @@ var ERR = require("async-stacktrace");
var db = require("./DB").db; var db = require("./DB").db;
var async = require("async"); var async = require("async");
var randomString = require("../utils/randomstring");
/** /**
* returns a read only id for a pad * returns a read only id for a pad
* @param {String} padId the id of the pad * @param {String} padId the id of the pad
@ -70,18 +72,3 @@ exports.getPadId = function(readOnlyId, callback)
{ {
db.get("readonly2pad:" + readOnlyId, callback); db.get("readonly2pad:" + readOnlyId, callback);
} }
/**
* Generates a random String with the given length. Is needed to generate the read only ids
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}

View file

@ -26,6 +26,8 @@ var padManager = require("./PadManager");
var sessionManager = require("./SessionManager"); var sessionManager = require("./SessionManager");
var settings = require("../utils/Settings") var settings = require("../utils/Settings")
var randomString = require("../utils/randomstring");
/** /**
* This function controlls the access to a pad, it checks if the user can access a pad. * This function controlls the access to a pad, it checks if the user can access a pad.
* @param padID the pad the user wants to access * @param padID the pad the user wants to access

View file

@ -20,6 +20,7 @@
var ERR = require("async-stacktrace"); var ERR = require("async-stacktrace");
var customError = require("../utils/customError"); var customError = require("../utils/customError");
var randomString = require("../utils/randomstring");
var db = require("./DB").db; var db = require("./DB").db;
var async = require("async"); var async = require("async");
var groupMangager = require("./GroupManager"); var groupMangager = require("./GroupManager");
@ -358,21 +359,6 @@ function listSessionsWithDBKey (dbkey, callback)
}); });
} }
/**
* Generates a random String with the given length. Is needed to generate the SessionIDs
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}
//checks if a number is an int //checks if a number is an int
function is_int(value) function is_int(value)
{ {

View file

@ -22,6 +22,7 @@ var ERR = require("async-stacktrace");
var fs = require("fs"); var fs = require("fs");
var api = require("../db/API"); var api = require("../db/API");
var padManager = require("../db/PadManager"); var padManager = require("../db/PadManager");
var randomString = require("../utils/randomstring");
//ensure we have an apikey //ensure we have an apikey
var apikey = null; var apikey = null;
@ -157,18 +158,3 @@ function callAPI(functionName, fields, req, res)
//call the api function //call the api function
api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]); api[functionName](functionParams[0],functionParams[1],functionParams[2],functionParams[3],functionParams[4]);
} }
/**
* Generates a random String with the given length. Is needed to generate the Author Ids
*/
function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
}

View file

@ -92,6 +92,33 @@ function init(additionalSetup){
next(); next();
}); });
//redirects browser to the pad's sanitized url if needed. otherwise, renders the html
app.param('pad', function (req, res, next, padId) {
//ensure the padname is valid and the url doesn't end with a /
if(!padManager.isValidPadId(padId) || /\/$/.test(req.url))
{
res.send('Such a padname is forbidden', 404);
}
else
{
padManager.sanitizePadId(padId, function(sanitizedPadId) {
//the pad id was sanitized, so we redirect to the sanitized version
if(sanitizedPadId != padId)
{
var real_path = req.path.replace(/^\/p\/[^\/]+/, '/p/' + sanitizedPadId);
res.header('Location', real_path);
res.send('You should be redirected to <a href="' + real_path + '">' + real_path + '</a>', 302);
}
//the pad id was fine, so just render it
else
{
next();
}
});
}
});
//load modules that needs a initalized db //load modules that needs a initalized db
readOnlyManager = require("./db/ReadOnlyManager"); readOnlyManager = require("./db/ReadOnlyManager");
exporthtml = require("./utils/ExportHtml"); exporthtml = require("./utils/ExportHtml");
@ -238,54 +265,23 @@ function init(additionalSetup){
}); });
}); });
//redirects browser to the pad's sanitized url if needed. otherwise, renders the html
function goToPad(req, res, render) {
//ensure the padname is valid and the url doesn't end with a /
if(!padManager.isValidPadId(req.params.pad) || /\/$/.test(req.url))
{
res.send('Such a padname is forbidden', 404);
}
else
{
padManager.sanitizePadId(req.params.pad, function(padId) {
//the pad id was sanitized, so we redirect to the sanitized version
if(padId != req.params.pad)
{
var real_path = req.path.replace(/^\/p\/[^\/]+/, '/p/' + padId);
res.header('Location', real_path);
res.send('You should be redirected to <a href="' + real_path + '">' + real_path + '</a>', 302);
}
//the pad id was fine, so just render it
else
{
render();
}
});
}
}
//serve pad.html under /p //serve pad.html under /p
app.get('/p/:pad', function(req, res, next) app.get('/p/:pad', function(req, res, next)
{ {
goToPad(req, res, function() {
var filePath = path.normalize(__dirname + "/../static/pad.html"); var filePath = path.normalize(__dirname + "/../static/pad.html");
res.sendfile(filePath, { maxAge: exports.maxAge }); res.sendfile(filePath, { maxAge: exports.maxAge });
}); });
});
//serve timeslider.html under /p/$padname/timeslider //serve timeslider.html under /p/$padname/timeslider
app.get('/p/:pad/timeslider', function(req, res, next) app.get('/p/:pad/timeslider', function(req, res, next)
{ {
goToPad(req, res, function() {
var filePath = path.normalize(__dirname + "/../static/timeslider.html"); var filePath = path.normalize(__dirname + "/../static/timeslider.html");
res.sendfile(filePath, { maxAge: exports.maxAge }); res.sendfile(filePath, { maxAge: exports.maxAge });
}); });
});
//serve timeslider.html under /p/$padname/timeslider //serve timeslider.html under /p/$padname/timeslider
app.get('/p/:pad/:rev?/export/:type', function(req, res, next) app.get('/p/:pad/:rev?/export/:type', function(req, res, next)
{ {
goToPad(req, res, function() {
var types = ["pdf", "doc", "txt", "html", "odt", "dokuwiki"]; var types = ["pdf", "doc", "txt", "html", "odt", "dokuwiki"];
//send a 404 if we don't support this filetype //send a 404 if we don't support this filetype
if(types.indexOf(req.params.type) == -1) if(types.indexOf(req.params.type) == -1)
@ -309,12 +305,10 @@ function init(additionalSetup){
exportHandler.doExport(req, res, req.params.pad, req.params.type); exportHandler.doExport(req, res, req.params.pad, req.params.type);
}); });
}); });
});
//handle import requests //handle import requests
app.post('/p/:pad/import', function(req, res, next) app.post('/p/:pad/import', function(req, res, next)
{ {
goToPad(req, res, function() {
//if abiword is disabled, skip handling this request //if abiword is disabled, skip handling this request
if(settings.abiword == null) if(settings.abiword == null)
{ {
@ -327,7 +321,6 @@ function init(additionalSetup){
importHandler.doImport(req, res, req.params.pad); importHandler.doImport(req, res, req.params.pad);
}); });
}); });
});
var apiLogger = log4js.getLogger("API"); var apiLogger = log4js.getLogger("API");

View file

@ -28,7 +28,7 @@ var jsp = require("uglify-js").parser;
var pro = require("uglify-js").uglify; var pro = require("uglify-js").uglify;
var path = require('path'); var path = require('path');
var Buffer = require('buffer').Buffer; var Buffer = require('buffer').Buffer;
var gzip = require('gzip'); var zlib = require('zlib');
var RequireKernel = require('require-kernel'); var RequireKernel = require('require-kernel');
var server = require('../server'); var server = require('../server');
var os = require('os'); var os = require('os');
@ -233,10 +233,7 @@ function _handle(req, res, jsFilename, jsFiles) {
//write the results compressed in a file //write the results compressed in a file
function(callback) function(callback)
{ {
//spawn a gzip process if we're on a unix system zlib.gzip(result, function(err, compressedResult){
if(os.type().indexOf("Windows") == -1)
{
gzip(result, 9, function(err, compressedResult){
//weird gzip bug that returns 0 instead of null if everything is ok //weird gzip bug that returns 0 instead of null if everything is ok
err = err === 0 ? null : err; err = err === 0 ? null : err;
@ -245,12 +242,6 @@ function _handle(req, res, jsFilename, jsFiles) {
fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback); fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback);
}); });
} }
//skip this step on windows
else
{
callback();
}
}
],callback); ],callback);
} }
], function(err) ], function(err)
@ -315,11 +306,6 @@ function tarCode(filesInOrder, files, write) {
write("\n\n\n/*** File: static/js/" + filename + " ***/\n\n\n"); write("\n\n\n/*** File: static/js/" + filename + " ***/\n\n\n");
write(isolateJS(files[filename], filename)); write(isolateJS(files[filename], filename));
} }
for(var i = 0, ii = filesInOrder.length; i < filesInOrder.length; i++) {
var filename = filesInOrder[i];
write('require(' + JSON.stringify('/' + filename.replace(/^\/+/, '')) + ');\n');
}
} }
// Wrap the following code in a self executing function and assign exports to // Wrap the following code in a self executing function and assign exports to

View file

@ -0,0 +1,16 @@
/**
* Generates a random String with the given length. Is needed to generate the Author, Group, readonly, session Ids
*/
var randomString = function randomString(len)
{
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var randomstring = '';
for (var i = 0; i < len; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return randomstring;
};
module.exports = randomString;

View file

@ -1,6 +1,8 @@
{ {
"pad.js": [ "pad.js": [
"jquery.js" "jquery.js"
, "pad.js"
, "ace2_common.js"
, "pad_utils.js" , "pad_utils.js"
, "plugins.js" , "plugins.js"
, "undo-xpopup.js" , "undo-xpopup.js"
@ -16,7 +18,6 @@
, "pad_impexp.js" , "pad_impexp.js"
, "pad_savedrevs.js" , "pad_savedrevs.js"
, "pad_connectionstatus.js" , "pad_connectionstatus.js"
, "pad2.js"
, "jquery-ui.js" , "jquery-ui.js"
, "chat.js" , "chat.js"
, "excanvas.js" , "excanvas.js"
@ -29,6 +30,7 @@
, "json2.js" , "json2.js"
, "colorutils.js" , "colorutils.js"
, "draggable.js" , "draggable.js"
, "ace2_common.js"
, "pad_utils.js" , "pad_utils.js"
, "pad_cookie.js" , "pad_cookie.js"
, "pad_editor.js" , "pad_editor.js"
@ -44,5 +46,6 @@
, "broadcast.js" , "broadcast.js"
, "broadcast_slider.js" , "broadcast_slider.js"
, "broadcast_revisions.js" , "broadcast_revisions.js"
, "timeslider.js"
] ]
} }

View file

@ -18,14 +18,16 @@
"express" : "2.5.0", "express" : "2.5.0",
"clean-css" : "0.2.4", "clean-css" : "0.2.4",
"uglify-js" : "1.1.1", "uglify-js" : "1.1.1",
"gzip" : "0.1.0",
"formidable" : "1.0.7", "formidable" : "1.0.7",
"log4js" : "0.3.9", "log4js" : "0.4.1",
"jsdom-nocontextifiy" : "0.2.10", "jsdom-nocontextifiy" : "0.2.10",
"async-stacktrace" : "0.0.2" "async-stacktrace" : "0.0.2"
}, },
"devDependencies": { "devDependencies": {
"jshint" : "*" "jshint" : "*"
}, },
"engines" : { "node" : ">=0.6.0",
"npm" : ">=1.0"
},
"version" : "1.0.0" "version" : "1.0.0"
} }

View file

@ -1,13 +1,13 @@
*,html,body,p{ margin: 0; padding: 0; } *,html,body,p{ margin: 0; padding: 0; }
.clear { clear: both; } .clear { clear: both; }
html { font-size: 62.5%; } html { font-size: 62.5%; width: 100%; }
body, textarea { font-family: Helvetica, Arial, sans-serif; } body, textarea { font-family: Helvetica, Arial, sans-serif; }
iframe {position:absolute;} iframe {position:absolute;}
#users #users
{ {
position: absolute; position: absolute;
z-index: 10; z-index:500;
background-color: #000; background-color: #000;
background-color: rgba(0,0,0,0.7); background-color: rgba(0,0,0,0.7);
width: 160px; width: 160px;
@ -560,28 +560,6 @@ table#otheruserstable { display: none; }
display: none; z-index: 55; } display: none; z-index: 55; }
#revision-notifier .label { color: #777; font-weight: bold; } #revision-notifier .label { color: #777; font-weight: bold; }
/* We don't ever actually hide the wrapper, even when the panel is
cloased, so that its contents can always be manipulated accurately. */
#padoptions { position: absolute; top: 0; left: 0; font-size: 1.2em;
color: #444; height: 100%; width: 100%; line-height: 15px; }
#options-viewhead { font-weight: bold; position: absolute; top: 10px; left: 15px;
width: auto; height: auto; }
#padoptions label { display: block; }
#padoptions input { padding: 0; margin: 0; }
#options-colorscheck { position: absolute; left: 15px; top: 34px; width: 15px; height: 15px; }
#options-colorslabel { position: absolute; left: 35px; top: 34px; }
#options-linenoscheck { position: absolute; left: 15px; top: 57px; width: 15px; height: 15px; }
#options-linenoslabel { position: absolute; left: 35px; top: 57px; }
#options-fontlabel { position: absolute; left: 15px; top: 82px; }
#viewfontmenu { position: absolute; top: 80px; left: 90px; width: 110px; }
#options-viewexplain { position: absolute; left: 215px; top: 15px; width: 100px; height: 70px; font-size: .7em;
padding-left: 10px; padding-top: 10px; border-left: 1px solid #ccc;
line-height: 20px; font-weight: bold; color: #999; }
#options-close { display: block; position: absolute; right: 7px; bottom: 8px;
width: auto; height: auto; font-size: 85%; color: #444; }
#mainmodals { z-index: 600; /* higher than the modals themselves #mainmodals { z-index: 600; /* higher than the modals themselves
so that modals are on top in IE */ } so that modals are on top in IE */ }
.modalfield { font-size: 1.2em; padding: 1px; border: 1px solid #bbb;} .modalfield { font-size: 1.2em; padding: 1px; border: 1px solid #bbb;}
@ -763,38 +741,8 @@ a#topbarmaximize {
width: 100%; width: 100%;
} }
#embed, #readonly {
display:none;
position:absolute;
top:40px;
font-size:14px;
width:400px;
right: 20px;
z-index: 500;
background-color: #000;
color: white;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.7);
padding: 10px;
-moz-border-radius: 6px;
border-radius: 6px;
} }
#embedreadonly {
float:right;
}
#embedcode, #readonlyUrl, #linkcode {
margin-left:10px;
}
#embedinput, #readonlyInput, #linkinput {
width:375px;
height:24px;
display:inline;
margin-top: 10px;
padding-left:4px;
}
ul#colorpickerswatches ul#colorpickerswatches
{ {
@ -850,6 +798,7 @@ ul#colorpickerswatches li:hover
left:0px; left:0px;
top:25px; top:25px;
bottom:25px; bottom:25px;
z-index:1002;
} }
#chattext p #chattext p
@ -986,40 +935,8 @@ position: relative;
top: -5px; top: -5px;
} }
#importexport{
position:absolute;
top:40px;
font-size:14px;
width:450px;
right: 20px;
z-index: 500;
background-color: #000;
color: white;
background-color: rgb(0,0,0);
background-color: rgba(0,0,0,0.7);
padding: 10px;
-moz-border-radius: 6px;
border-radius: 6px;
height:190px;
display:none;
}
#import{
position:absolute;
width:250px;
left:10px;
line-height:20px;
}
#export{
position:absolute;
width:180px;
right:10px;
line-height:20px;
}
.exporttype{ .exporttype{
line-height:20px; margin-top: 2px;
background-repeat:no-repeat; background-repeat:no-repeat;
padding-left:25px; padding-left:25px;
background-image: url("../../static/img/etherpad_lite_icons.png"); background-image: url("../../static/img/etherpad_lite_icons.png");
@ -1028,8 +945,8 @@ position: relative;
} }
#importexportline{ #importexportline{
border: dotted 1px; border-left: 1px solid #fff;
height: 185px; height: 190px;
position:absolute; position:absolute;
width:0px; width:0px;
left:260px; left:260px;
@ -1069,10 +986,6 @@ position: relative;
background-position: 0px -459px; background-position: 0px -459px;
} }
#export a{
text-decoration: none;
}
#importstatusball{ #importstatusball{
display:none; display:none;
} }
@ -1122,6 +1035,59 @@ background-repeat: no-repeat;
margin-left: 1px; margin-left: 1px;
margin-top: 1px; margin-top: 1px;
} }
.buttonicon-bold {
background-position: 0px -116px;
}
.buttonicon-italic {
background-position: 0px 0px;
}
.buttonicon-underline {
background-position: 0px -236px;
}
.buttonicon-strikethrough {
background-position: 0px -200px;
}
.buttonicon-insertorderedlist {
background-position: 0px -477px
}
.buttonicon-insertunorderedlist {
background-position: 0px -34px;
}
.buttonicon-indent {
background-position: 0px -52px;
}
.buttonicon-outdent {
background-position: 0px -134px;
}
.buttonicon-undo {
background-position: 0px -255px;
}
.buttonicon-redo {
background-position :0px -166px;
}
.buttonicon-clearauthorship {
background-position: 0px -86px;
}
.buttonicon-settings {
background-position: 0px -436px;
}
.buttonicon-import_export {
background-position: 0px -68px;
}
.buttonicon-embed {
background-position: 0px -18px;
}
.buttonicon-history {
background-position: 0px -218px;
}
.buttonicon-chat {
background-position: 0px -102px;
display: inline-block;
}
.buttonicon-showusers {
background-position: 0px -183px;
display: inline-block;
}
#usericon #usericon
{ {
@ -1145,18 +1111,22 @@ width:33px !important;
color: #999; color: #999;
} }
label[for=readonlyinput] {
margin: 0 10px 0 2px;
}
#qr_center { #qr_center {
margin: 10px 10px auto 0; margin: 10px 10px auto 0;
text-align: center; text-align: center;
} }
#qrcode{ #embedreadonlyqr {
margin-left:10px; box-shadow: 0 0 10px #000;
border-radius: 3px;
-webkit-transition: all .2s ease-in-out;
-moz-transition: all .2s ease-in-out;
}
#embedreadonlyqr:hover {
cursor: none;
-moz-transform: scale(1.5);
-webkit-transform: scale(1.5);
} }
@media screen and (max-width: 960px) { @media screen and (max-width: 960px) {
@ -1245,3 +1215,78 @@ label[for=readonlyinput] {
.rtl{ .rtl{
direction:RTL; direction:RTL;
} }
#chattext p {
word-wrap: break-word;
}
/* fix for misaligned labels */
label {
position: relative;
bottom: 1px;
}
.right {
float:right;
}
.popup {
font-size: 14px;
width: 450px;
z-index: 500;
padding: 10px;
border-radius: 6px;
background: #222;
background: rgba(0,0,0,.7);
background: -webkit-linear-gradient(rgba(0,0,0,.6), rgba(0,0,0,.7) 35px, rgba(0,0,0,.6));
background: -moz-linear-gradient(rgba(0,0,0,.6), rgba(0,0,0,.7) 35px, rgba(0,0,0,.6));
box-shadow: 0 0 8px #888;
color: #fff;
}
.popup input[type=text] {
width: 100%;
padding: 5px;
box-sizing: border-box;
-moz-box-sizing: border-box;
display:block;
margin-top: 10px;
}
.popup a {
text-decoration: none;
}
.popup h1 {
font-size: 18px;
}
.popup h2 {
font-size: 15px;
}
.popup p {
margin: 5px 0;
}
.left_popup {
float: left;
width: 50%;
}
.right_popup {
float: left;
width: 50%;
box-sizing: border-box;
}
#settingsmenu, #importexport, #embed {
position: absolute;
top: 55px;
right: 20px;
display: none;
}
.note {
color: #ddd;
font-size: 11px;
font-weight: bold;
}

View file

@ -195,10 +195,8 @@ float:right;
color: #222; color: #222;
} }
#importexport{ #importexport { top: 118px; }
top:103px; #importexport .popup { width: 185px; }
width:185px;
}
ul { margin-left: 1.5em; } ul { margin-left: 1.5em; }
ul ul { margin-left: 0 !important; } ul ul { margin-left: 0 !important; }

View file

@ -1,8 +1,11 @@
<!doctype html> <!doctype html>
<html> <html>
<title>Etherpad Lite</title> <title>Etherpad Lite</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<style> <style>
*{ margin:0;padding:0; } *{ margin:0;padding:0; }
body { body {
@ -108,15 +111,18 @@
} }
} }
</style> </style>
<link href="static/custom/index.css" rel="stylesheet"> <link href="static/custom/index.css" rel="stylesheet">
<script src="static/custom/index.js"></script> <script src="static/custom/index.js"></script>
<div id="container"> <div id="container">
<div id="button" onclick="go2Random()" class="translate">New Pad</div><br><div id="label" class="translate">or create/open a Pad with the name</div> <div id="button" onclick="go2Random()" class="translate">New Pad</div><br><div id="label" class="translate">or create/open a Pad with the name</div>
<form action="#" onsubmit="go2Name();return false;"> <form action="#" onsubmit="go2Name();return false;">
<input type="text" id="padname" autofocus> <input type="text" id="padname" autofocus x-webkit-speech>
<input type="submit" value="OK"> <input type="submit" value="OK">
</form> </form>
</div> </div>
<script> <script>
function go2Name() function go2Name()
{ {
@ -145,4 +151,5 @@
//start the costum js //start the costum js
if(typeof costumStart == "function") costumStart(); if(typeof costumStart == "function") costumStart();
</script> </script>
</html> </html>

View file

@ -237,11 +237,18 @@ function OUTER(gscope)
bgcolor = fadeColor(bgcolor, info.fade); bgcolor = fadeColor(bgcolor, info.fade);
} }
dynamicCSS.selectorStyle(getAuthorColorClassSelector( // Text color
getAuthorClassName(author))).backgroundColor = bgcolor; var txtcolor = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.45) ? '#ffffff' : '#000000';
dynamicCSSTop.selectorStyle(getAuthorColorClassSelector( var authorStyle = dynamicCSS.selectorStyle(getAuthorColorClassSelector(
getAuthorClassName(author))).backgroundColor = bgcolor; getAuthorClassName(author)));
authorStyle.backgroundColor = bgcolor;
authorStyle.color = txtcolor;
var authorStyleTop = dynamicCSSTop.selectorStyle(getAuthorColorClassSelector(
getAuthorClassName(author)));
authorStyleTop.backgroundColor = bgcolor;
authorStyleTop.color = txtcolor;
} }
} }
} }
@ -3138,11 +3145,12 @@ function OUTER(gscope)
// Such a div is what IE 6 creates naturally when you make a blank line // Such a div is what IE 6 creates naturally when you make a blank line
// in a document of divs. However, when copy-and-pasted the div will // in a document of divs. However, when copy-and-pasted the div will
// contain a space, so we note its emptiness with a property. // contain a space, so we note its emptiness with a property.
lineElem.innerHTML = ""; lineElem.innerHTML = " "; // Frist we set a value that isnt blank
// a primitive-valued property survives copy-and-paste // a primitive-valued property survives copy-and-paste
setAssoc(lineElem, "shouldBeEmpty", true); setAssoc(lineElem, "shouldBeEmpty", true);
// an object property doesn't // an object property doesn't
setAssoc(lineElem, "unpasted", {}); setAssoc(lineElem, "unpasted", {});
lineElem.innerHTML = ""; // Then we make it blank.. New line and no space = Awesome :)
}; };
var lineClass = 'ace-line'; var lineClass = 'ace-line';
result.appendSpan = function(txt, cls) result.appendSpan = function(txt, cls)

View file

@ -20,16 +20,17 @@
* limitations under the License. * limitations under the License.
*/ */
var global = this;
var makeCSSManager = require('/cssmanager_client').makeCSSManager; var makeCSSManager = require('/cssmanager_client').makeCSSManager;
var domline = require('/domline_client').domline; var domline = require('/domline_client').domline;
var Changeset = require('/easysync2_client').Changeset; var Changeset = require('/easysync2_client').Changeset;
var AttribPool = require('/easysync2_client').AttribPool; var AttribPool = require('/easysync2_client').AttribPool;
var linestylefilter = require('/linestylefilter_client').linestylefilter; var linestylefilter = require('/linestylefilter_client').linestylefilter;
function loadBroadcastJS() // These parameters were global, now they are injected. A reference to the
// Timeslider controller would probably be more appropriate.
function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider)
{ {
var changesetLoader = undefined;
// just in case... (todo: this must be somewhere else in the client code.) // just in case... (todo: this must be somewhere else in the client code.)
// Below Array#map code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_map.htm // Below Array#map code was direct pasted by AppJet/Etherpad, licence unknown. Possible source: http://www.tutorialspoint.com/javascript/array_map.htm
if (!Array.prototype.map) if (!Array.prototype.map)
@ -423,7 +424,7 @@ function loadBroadcastJS()
})); }));
} }
global.changesetLoader = { changesetLoader = {
running: false, running: false,
resolved: [], resolved: [],
requestQueue1: [], requestQueue1: [],
@ -763,6 +764,8 @@ function loadBroadcastJS()
} }
receiveAuthorData(clientVars.historicalAuthorData); receiveAuthorData(clientVars.historicalAuthorData);
return changesetLoader;
} }
exports.loadBroadcastJS = loadBroadcastJS; exports.loadBroadcastJS = loadBroadcastJS;

View file

@ -22,7 +22,6 @@
// revision info is a skip list whos entries represent a particular revision // revision info is a skip list whos entries represent a particular revision
// of the document. These revisions are connected together by various // of the document. These revisions are connected together by various
// changesets, or deltas, between any two revisions. // changesets, or deltas, between any two revisions.
var global = this;
function loadBroadcastRevisionsJS() function loadBroadcastRevisionsJS()
{ {

View file

@ -19,10 +19,12 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
var global = this;
function loadBroadcastSliderJS() // These parameters were global, now they are injected. A reference to the
// Timeslider controller would probably be more appropriate.
function loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded)
{ {
var BroadcastSlider;
(function() (function()
{ // wrap this code in its own namespace { // wrap this code in its own namespace
@ -203,7 +205,7 @@ function loadBroadcastSliderJS()
} }
} }
global.BroadcastSlider = { BroadcastSlider = {
onSlider: onSlider, onSlider: onSlider,
getSliderPosition: getSliderPosition, getSliderPosition: getSliderPosition,
setSliderPosition: setSliderPosition, setSliderPosition: setSliderPosition,
@ -495,6 +497,8 @@ function loadBroadcastSliderJS()
{ {
$("#viewlatest").html(loc == BroadcastSlider.getSliderLength() ? "Viewing latest content" : "View latest content"); $("#viewlatest").html(loc == BroadcastSlider.getSliderLength() ? "Viewing latest content" : "View latest content");
}) })
return BroadcastSlider;
} }
exports.loadBroadcastSliderJS = loadBroadcastSliderJS; exports.loadBroadcastSliderJS = loadBroadcastSliderJS;

View file

@ -21,17 +21,18 @@
*/ */
var padutils = require('/pad_utils').padutils; var padutils = require('/pad_utils').padutils;
var browser = require('/ace2_common').browser;
var padcookie = require('/pad_cookie').padcookie;
var chat = (function() var chat = (function()
{ {
var bottomMargin = "0px"; var isStuck = false;
var sDuration = 500; var sDuration = 500;
var hDuration = 750; var hDuration = 750;
var chatMentions = 0; var chatMentions = 0;
var title = document.title; var title = document.title;
if ($.browser.mobile){ if (browser.mobile){
sDuration = 0; sDuration = hDuration = 0;
hDuration = 0;
} }
var self = { var self = {
show: function () show: function ()
@ -56,10 +57,11 @@ var chat = (function()
{ {
$("#focusprotector").hide(); $("#focusprotector").hide();
if($.browser.mobile) if(browser.mobile) {
bottommargin = "32px"; $("#chatbox").css({right: "0px", bottom: "32px", left: "", top: ""});
} else {
$("#chatbox").css({right: "20px", bottom: bottomMargin, left: "", top: ""}); $("#chatbox").css({right: "20px", bottom: "0px", left: "", top: ""});
}
self.scrollDown(); self.scrollDown();
} }
@ -68,6 +70,23 @@ var chat = (function()
chatMentions = 0; chatMentions = 0;
document.title = title; document.title = title;
}, },
stickToScreen: function(fromInitialCall) // Make chat stick to right hand side of screen
{
chat.show();
if(!isStuck || fromInitialCall) { // Stick it to
padcookie.setPref("chatAlwaysVisible", true);
$('#chatbox').css({"right":"0px", "top":"36px", "border-radius":"0px", "height":"auto", "border-right":"none", "border-left":"1px solid #ccc", "border-top":"none", "background-color":"#f1f1f1", "width":"185px"});
$('#chattext').css({"top":"0px"});
$('#editorcontainer').css({"right":"192px", "width":"auto"});
isStuck = true;
} else { // Unstick it
padcookie.setPref("chatAlwaysVisible", false);
$('#chatbox').css({"right":"20px", "top":"auto", "border-top-left-radius":"5px", "border-top-right-radius":"5px", "border-right":"1px solid #999", "height":"200px", "border-top":"1px solid #999", "background-color":"#f7f7f7"});
$('#chattext').css({"top":"25px"});
$('#editorcontainer').css({"right":"0px", "width":"100%"});
isStuck = false;
}
},
hide: function () hide: function ()
{ {
$("#chatcounter").text("0"); $("#chatcounter").text("0");
@ -177,3 +196,4 @@ var chat = (function()
}()); }());
exports.chat = chat; exports.chat = chat;

View file

@ -24,13 +24,14 @@
var socket; var socket;
var settings = {}; // These jQuery things should create local references, but for now `require()`
settings.LineNumbersDisabled = false; // assigns to the global `$` and augments it with plugins.
settings.noColors = false; require('/jquery');
settings.useMonospaceFontGlobal = false; require('/jquery-ui');
settings.globalUserName = false; require('/farbtastic');
settings.hideQRCode = false; require('/excanvas');
settings.rtlIsTrue = false; require('/json2');
require('/undo-xpopup');
var chat = require('/chat').chat; var chat = require('/chat').chat;
var getCollabClient = require('/collab_client').getCollabClient; var getCollabClient = require('/collab_client').getCollabClient;
@ -45,19 +46,6 @@ var padsavedrevs = require('/pad_savedrevs').padsavedrevs;
var paduserlist = require('/pad_userlist').paduserlist; var paduserlist = require('/pad_userlist').paduserlist;
var padutils = require('/pad_utils').padutils; var padutils = require('/pad_utils').padutils;
$(document).ready(function()
{
//start the costum js
if(typeof costumStart == "function") costumStart();
getParams();
handshake();
});
$(window).unload(function()
{
pad.dispose();
});
function createCookie(name, value, days, path) function createCookie(name, value, days, path)
{ {
if (days) if (days)
@ -309,7 +297,7 @@ function handshake()
clientVars.collab_client_vars.clientAgent = "Anonymous"; clientVars.collab_client_vars.clientAgent = "Anonymous";
//initalize the pad //initalize the pad
pad.init(); pad._afterHandshake();
initalized = true; initalized = true;
// If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers // If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers
@ -358,7 +346,6 @@ function handshake()
} }
} }
}); });
// Bind the colorpicker // Bind the colorpicker
var fb = $('#colorpicker').farbtastic({ callback: '#mycolorpickerpreview', width: 220}); var fb = $('#colorpicker').farbtastic({ callback: '#mycolorpickerpreview', width: 220});
} }
@ -422,6 +409,23 @@ var pad = {
}, },
init: function() init: function()
{
padutils.setupGlobalExceptionHandler();
$(document).ready(function()
{
//start the costum js
if(typeof costumStart == "function") costumStart();
getParams();
handshake();
});
$(window).unload(function()
{
pad.dispose();
});
},
_afterHandshake: function()
{ {
pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp; pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp;
@ -447,10 +451,10 @@ var pad = {
} }
// order of inits is important here: // order of inits is important here:
padcookie.init(clientVars.cookiePrefsToSet); padcookie.init(clientVars.cookiePrefsToSet, this);
$("#widthprefcheck").click(pad.toggleWidthPref); $("#widthprefcheck").click(pad.toggleWidthPref);
$("#sidebarcheck").click(pad.toggleSidebar); // $("#sidebarcheck").click(pad.togglewSidebar);
pad.myUserInfo = { pad.myUserInfo = {
userId: clientVars.userId, userId: clientVars.userId,
@ -474,16 +478,16 @@ var pad = {
initialTitle: clientVars.initialTitle, initialTitle: clientVars.initialTitle,
initialPassword: clientVars.initialPassword, initialPassword: clientVars.initialPassword,
guestPolicy: pad.padOptions.guestPolicy guestPolicy: pad.padOptions.guestPolicy
}); }, this);
padimpexp.init(); padimpexp.init(this);
padsavedrevs.init(clientVars.initialRevisionList); padsavedrevs.init(clientVars.initialRevisionList, this);
padeditor.init(postAceInit, pad.padOptions.view || {}); padeditor.init(postAceInit, pad.padOptions.view || {}, this);
paduserlist.init(pad.myUserInfo); paduserlist.init(pad.myUserInfo, this);
// padchat.init(clientVars.chatHistory, pad.myUserInfo); // padchat.init(clientVars.chatHistory, pad.myUserInfo);
padconnectionstatus.init(); padconnectionstatus.init();
padmodals.init(); padmodals.init(this);
pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, { pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, {
colorPalette: pad.getColorPalette() colorPalette: pad.getColorPalette()
@ -775,15 +779,17 @@ var pad = {
padsavedrevs.handleIsFullyConnected(isConnected); padsavedrevs.handleIsFullyConnected(isConnected);
pad.determineSidebarVisibility(isConnected && !isInitialConnect); // pad.determineSidebarVisibility(isConnected && !isInitialConnect);
pad.determineChatVisibility(isConnected && !isInitialConnect);
}, },
determineSidebarVisibility: function(asNowConnectedFeedback) /* determineSidebarVisibility: function(asNowConnectedFeedback)
{ {
if (pad.isFullyConnected()) if (pad.isFullyConnected())
{ {
var setSidebarVisibility = padutils.getCancellableAction("set-sidebar-visibility", function() var setSidebarVisibility = padutils.getCancellableAction("set-sidebar-visibility", function()
{ {
$("body").toggleClass('hidesidebar', !! padcookie.getPref('hideSidebar')); // $("body").toggleClass('hidesidebar', !! padcookie.getPref('hideSidebar'));
}); });
window.setTimeout(setSidebarVisibility, asNowConnectedFeedback ? 3000 : 0); window.setTimeout(setSidebarVisibility, asNowConnectedFeedback ? 3000 : 0);
} }
@ -793,6 +799,17 @@ var pad = {
$("body").removeClass('hidesidebar'); $("body").removeClass('hidesidebar');
} }
}, },
*/
determineChatVisibility: function(asNowConnectedFeedback){
var chatVisCookie = padcookie.getPref('chatAlwaysVisible');
if(chatVisCookie){ // if the cookie is set for chat always visible
chat.stickToScreen(true); // stick it to the screen
$('#options-stickychat').prop("checked", true); // set the checkbox to on
}
else{
$('#options-stickychat').prop("checked", false); // set the checkbox for off
}
},
handleCollabAction: function(action) handleCollabAction: function(action)
{ {
if (action == "commitPerformed") if (action == "commitPerformed")
@ -841,6 +858,7 @@ var pad = {
$("#widthprefcheck").toggleClass('widthprefchecked', !! newValue).toggleClass('widthprefunchecked', !newValue); $("#widthprefcheck").toggleClass('widthprefchecked', !! newValue).toggleClass('widthprefunchecked', !newValue);
pad.handleWidthChange(); pad.handleWidthChange();
}, },
/*
toggleSidebar: function() toggleSidebar: function()
{ {
var newValue = !padcookie.getPref('hideSidebar'); var newValue = !padcookie.getPref('hideSidebar');
@ -848,6 +866,7 @@ var pad = {
$("#sidebarcheck").toggleClass('sidebarchecked', !newValue).toggleClass('sidebarunchecked', !! newValue); $("#sidebarcheck").toggleClass('sidebarchecked', !newValue).toggleClass('sidebarunchecked', !! newValue);
pad.determineSidebarVisibility(); pad.determineSidebarVisibility();
}, },
*/
handleWidthChange: function() handleWidthChange: function()
{ {
var isFullWidth = padcookie.getPref('fullWidth'); var isFullWidth = padcookie.getPref('fullWidth');
@ -967,6 +986,21 @@ var alertBar = (function()
return self; return self;
}()); }());
function init() {
return pad.init();
}
var settings = {
LineNumbersDisabled: false
, noColors: false
, useMonospaceFontGlobal: false
, globalUserName: false
, hideQRCode: false
, rtlIsTrue: false
};
pad.settings = settings;
exports.settings = settings; exports.settings = settings;
exports.createCookie = createCookie; exports.createCookie = createCookie;
exports.readCookie = readCookie; exports.readCookie = readCookie;
@ -976,4 +1010,5 @@ exports.getUrlVars = getUrlVars;
exports.savePassword = savePassword; exports.savePassword = savePassword;
exports.handshake = handshake; exports.handshake = handshake;
exports.pad = pad; exports.pad = pad;
exports.init = init;
exports.alertBar = alertBar; exports.alertBar = alertBar;

View file

@ -87,9 +87,9 @@ var padcookie = (function()
var pad = undefined; var pad = undefined;
var self = { var self = {
init: function(prefsToSet) init: function(prefsToSet, _pad)
{ {
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
var rawCookie = getRawCookie(); var rawCookie = getRawCookie();
if (rawCookie) if (rawCookie)

View file

@ -118,9 +118,9 @@ var paddocbar = (function()
var self = { var self = {
title: null, title: null,
password: null, password: null,
init: function(opts) init: function(opts, _pad)
{ {
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
panels = { panels = {
impexp: { impexp: {

View file

@ -108,17 +108,20 @@ var padeditbar = (function()
{ {
self.toogleDropDown("users"); self.toogleDropDown("users");
} }
else if (cmd == 'settings')
{
self.toogleDropDown("settingsmenu");
}
else if (cmd == 'embed') else if (cmd == 'embed')
{ {
self.setEmbedLinks(); self.setEmbedLinks();
$('#embedinput').focus().select(); $('#linkinput').focus().select();
self.toogleDropDown("embed"); self.toogleDropDown("embed");
} }
else if (cmd == 'import_export') else if (cmd == 'import_export')
{ {
self.toogleDropDown("importexport"); self.toogleDropDown("importexport");
} }
else if (cmd == 'save') else if (cmd == 'save')
{ {
padsavedrevs.saveNow(); padsavedrevs.saveNow();
@ -165,7 +168,7 @@ var padeditbar = (function()
}, },
toogleDropDown: function(moduleName) toogleDropDown: function(moduleName)
{ {
var modules = ["embed", "users", "readonly", "importexport"]; var modules = ["embed", "users", "readonly", "importexport", "settingsmenu"];
//hide all modules //hide all modules
if(moduleName == "none") if(moduleName == "none")

View file

@ -32,11 +32,11 @@ var padeditor = (function()
ace: null, ace: null,
// this is accessed directly from other files // this is accessed directly from other files
viewZoom: 100, viewZoom: 100,
init: function(readyFunc, initialViewOptions) init: function(readyFunc, initialViewOptions, _pad)
{ {
Ace2Editor = require('/ace').Ace2Editor; Ace2Editor = require('/ace').Ace2Editor;
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
settings = require('/pad2').settings; settings = pad.settings;
function aceReady() function aceReady()
{ {
@ -87,6 +87,11 @@ var padeditor = (function()
if (value == "false") return false; if (value == "false") return false;
return defaultValue; return defaultValue;
} }
self.ace.setProperty("showsauthorcolors", settings.noColors);
self.ace.setProperty("rtlIsTrue", settings.rtlIsTrue);
var v; var v;
v = getOption('showLineNumbers', true); v = getOption('showLineNumbers', true);
@ -100,10 +105,6 @@ var padeditor = (function()
v = getOption('useMonospaceFont', false); v = getOption('useMonospaceFont', false);
self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif")); self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif"));
$("#viewfontmenu").val(v ? "monospace" : "normal"); $("#viewfontmenu").val(v ? "monospace" : "normal");
self.ace.setProperty("showsauthorcolors", settings.noColors);
self.ace.setProperty("rtlIsTrue", settings.rtlIsTrue);
}, },
initViewZoom: function() initViewZoom: function()
{ {

View file

@ -236,13 +236,9 @@ var padimpexp = (function()
///// /////
var pad = undefined; var pad = undefined;
var self = { var self = {
init: function() init: function(_pad)
{ {
try { pad = _pad;
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected).
} catch (e) {
// skip (doesn't require pad when required by timeslider)
}
//get /p/padname //get /p/padname
var pad_root_path = new RegExp(/.*\/p\/[^\/]+/).exec(document.location.pathname) var pad_root_path = new RegExp(/.*\/p\/[^\/]+/).exec(document.location.pathname)

View file

@ -75,9 +75,9 @@ var padmodals = (function()
var pad = undefined; var pad = undefined;
var self = { var self = {
init: function() init: function(_pad)
{ {
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
self.initFeedback(); self.initFeedback();
self.initShareBox(); self.initShareBox();

View file

@ -349,9 +349,9 @@ var padsavedrevs = (function()
var pad = undefined; var pad = undefined;
var self = { var self = {
init: function(initialRevisions) init: function(initialRevisions, _pad)
{ {
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
self.newRevisionList(initialRevisions, true); self.newRevisionList(initialRevisions, true);
$("#savedrevs-savenow").click(function() $("#savedrevs-savenow").click(function()

View file

@ -464,9 +464,9 @@ var paduserlist = (function()
var pad = undefined; var pad = undefined;
var self = { var self = {
init: function(myInitialUserInfo) init: function(myInitialUserInfo, _pad)
{ {
pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). pad = _pad;
self.setMyUserInfo(myInitialUserInfo); self.setMyUserInfo(myInitialUserInfo);

View file

@ -34,7 +34,7 @@ var padutils = {
}, },
uniqueId: function() uniqueId: function()
{ {
var pad = require('/pad2').pad; // Sidestep circular dependency var pad = require('/pad').pad; // Sidestep circular dependency
function encodeNum(n, width) function encodeNum(n, width)
{ {
// returns string that is exactly 'width' chars, padding with zeros // returns string that is exactly 'width' chars, padding with zeros
@ -110,24 +110,6 @@ var padutils = {
var x = ua.split(' ')[0]; var x = ua.split(' ')[0];
return clean(x); return clean(x);
}, },
// "func" is a function over 0..(numItems-1) that is monotonically
// "increasing" with index (false, then true). Finds the boundary
// between false and true, a number between 0 and numItems inclusive.
binarySearch: function(numItems, func)
{
if (numItems < 1) return 0;
if (func(0)) return 0;
if (!func(numItems - 1)) return numItems;
var low = 0; // func(low) is always false
var high = numItems - 1; // func(high) is always true
while ((high - low) > 1)
{
var x = Math.floor((low + high) / 2); // x != low, x != high
if (func(x)) high = x;
else low = x;
}
return high;
},
// e.g. "Thu Jun 18 2009 13:09" // e.g. "Thu Jun 18 2009 13:09"
simpleDateTime: function(date) simpleDateTime: function(date)
{ {
@ -227,7 +209,7 @@ var padutils = {
}, },
timediff: function(d) timediff: function(d)
{ {
var pad = require('/pad2').pad; // Sidestep circular dependency var pad = require('/pad').pad; // Sidestep circular dependency
function format(n, word) function format(n, word)
{ {
n = Math.round(n); n = Math.round(n);
@ -477,8 +459,11 @@ var padutils = {
} }
}; };
var globalExceptionHandler = undefined;
function setupGlobalExceptionHandler() {
//send javascript errors to the server //send javascript errors to the server
window.onerror = function test (msg, url, linenumber) if (!globalExceptionHandler) {
globalExceptionHandler = function test (msg, url, linenumber)
{ {
var errObj = {errorInfo: JSON.stringify({msg: msg, url: url, linenumber: linenumber, userAgent: navigator.userAgent})}; var errObj = {errorInfo: JSON.stringify({msg: msg, url: url, linenumber: linenumber, userAgent: navigator.userAgent})};
var loc = document.location; var loc = document.location;
@ -488,5 +473,12 @@ window.onerror = function test (msg, url, linenumber)
return false; return false;
}; };
window.onerror = globalExceptionHandler;
}
}
padutils.setupGlobalExceptionHandler = setupGlobalExceptionHandler;
padutils.binarySearch = require('/ace2_common').binarySearch;
exports.padutils = padutils; exports.padutils = padutils;

184
static/js/timeslider.js Normal file
View file

@ -0,0 +1,184 @@
/**
* 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
*/
/**
* 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.
*/
// These jQuery things should create local references, but for now `require()`
// assigns to the global `$` and augments it with plugins.
require('/jquery');
require('/json2');
require('/undo-xpopup');
function createCookie(name,value,days)
{
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function randomString() {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var string_length = 20;
var randomstring = '';
for (var i=0; i<string_length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum,rnum+1);
}
return "t." + randomstring;
}
var socket, token, padId, export_links;
function init() {
$(document).ready(function ()
{
//start the costum js
if(typeof costumStart == "function") costumStart();
//get the padId out of the url
var urlParts= document.location.pathname.split("/");
padId = decodeURIComponent(urlParts[urlParts.length-2]);
//set the title
document.title = document.title + " | " + padId.replace(/_+/g, ' ');
//ensure we have a token
token = readCookie("token");
if(token == null)
{
token = randomString();
createCookie("token", token, 60);
}
var loc = document.location;
//get the correct port
var port = loc.port == "" ? (loc.protocol == "https:" ? 443 : 80) : loc.port;
//create the url
var url = loc.protocol + "//" + loc.hostname + ":" + port + "/";
//find out in which subfolder we are
var resource = loc.pathname.substr(1,loc.pathname.indexOf("/p/")) + "socket.io";
//build up the socket io connection
socket = io.connect(url, {resource: resource});
//send the ready message once we're connected
socket.on('connect', function()
{
sendSocketMsg("CLIENT_READY", {});
});
//route the incoming messages
socket.on('message', function(message)
{
if(window.console) console.log(message);
if(message.type == "CLIENT_VARS")
{
handleClientVars(message);
}
else if(message.type == "CHANGESET_REQ")
{
changesetLoader.handleSocketResponse(message);
}
else if(message.accessStatus)
{
$("body").html("<h2>You have no permission to access this pad</h2>")
}
});
//get all the export links
export_links = $('#export > .exportlink')
if(document.referrer.length > 0 && document.referrer.substring(document.referrer.lastIndexOf("/")-1,document.referrer.lastIndexOf("/")) === "p") {
$("#returnbutton").attr("href", document.referrer);
} else {
$("#returnbutton").attr("href", document.location.href.substring(0,document.location.href.lastIndexOf("/")));
}
});
}
//sends a message over the socket
function sendSocketMsg(type, data)
{
var sessionID = readCookie("sessionID");
var password = readCookie("password");
var msg = { "component" : "timeslider",
"type": type,
"data": data,
"padId": padId,
"token": token,
"sessionID": sessionID,
"password": password,
"protocolVersion": 2};
socket.json.send(msg);
}
var fireWhenAllScriptsAreLoaded = [];
var BroadcastSlider, changesetLoader;
function handleClientVars(message)
{
//save the client Vars
clientVars = message.data;
//load all script that doesn't work without the clientVars
BroadcastSlider = require('/broadcast_slider').loadBroadcastSliderJS(fireWhenAllScriptsAreLoaded);
require('/broadcast_revisions').loadBroadcastRevisionsJS();
changesetLoader = require('/broadcast').loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, BroadcastSlider);
//initialize export ui
require('/pad_impexp').padimpexp.init();
//change export urls when the slider moves
var export_rev_regex = /(\/\d+)?\/export/
BroadcastSlider.onSlider(function(revno)
{
export_links.each(function()
{
this.setAttribute('href', this.href.replace(export_rev_regex, '/' + revno + '/export'));
});
});
//fire all start functions of these scripts, formerly fired with window.load
for(var i=0;i < fireWhenAllScriptsAreLoaded.length;i++)
{
fireWhenAllScriptsAreLoaded[i]();
}
}
exports.init = init;

View file

@ -1,211 +1,196 @@
<!doctype html> <!doctype html>
<html lang="en"> <html>
<head>
<title>Etherpad Lite</title>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="robots" content="noindex, nofollow"> <meta name="robots" content="noindex, nofollow">
<title>Etherpad Lite</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<!-- CSS -->
<link href="../static/css/pad.css" rel="stylesheet"> <link href="../static/css/pad.css" rel="stylesheet">
<!-- javascript --> <link href="../static/custom/pad.css" rel="stylesheet">
<script type="text/javascript"> <style title="dynamicsyntax"></style>
// <![CDATA[
<script>
var clientVars = {}; var clientVars = {};
// ]]>
</script> </script>
<script src="../static/js/require-kernel.js"></script> <script src="../static/js/require-kernel.js"></script>
<script src="../socket.io/socket.io.js"></script> <script src="../socket.io/socket.io.js"></script>
<script src="../minified/pad.js"></script> <script src="../minified/pad.js"></script>
<link href="../static/custom/pad.css" rel="stylesheet">
<script src="../static/custom/pad.js"></script> <script src="../static/custom/pad.js"></script>
<style type="text/css" title="dynamicsyntax"></style>
</head>
<body>
<div id="editbar"> <div id="editbar">
<ul id="menu_left"> <ul id="menu_left">
<li onClick="window.pad&amp;&amp;pad.editbarClick('bold');return false" > <li onClick="window.pad&amp;&amp;pad.editbarClick('bold');return false" >
<a title="Bold (ctrl-B)"> <a title="Bold (ctrl-B)">
<div class="buttonicon" style="background-position:0px -116px"></div> <div class="buttonicon buttonicon-bold"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('italic'); return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('italic'); return false;" >
<a title="Italics (ctrl-I)"> <a title="Italics (ctrl-I)">
<div class="buttonicon" style="background-position:0px 0px"></div> <div class="buttonicon buttonicon-italic"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('underline');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('underline');return false;" >
<a title="Underline (ctrl-U)"> <a title="Underline (ctrl-U)">
<div class="buttonicon" style="background-position:0px -236px;margin-top:1px;"></div> <div class="buttonicon buttonicon-underline"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('strikethrough');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('strikethrough');return false;" >
<a title="Strikethrough"> <a title="Strikethrough">
<div class="buttonicon" style="background-position:0px -200px"></div> <div class="buttonicon buttonicon-strikethrough"></div>
</a> </a>
</li> </li>
<li class="separator"></li> <li class="separator"></li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('insertorderedlist');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('insertorderedlist');return false;" >
<a title="Toggle Ordered List"> <a title="Toggle Ordered List">
<div class="buttonicon" style="background-position:0px -477px"></div> <div class="buttonicon buttonicon-insertorderedlist"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('insertunorderedlist');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('insertunorderedlist');return false;" >
<a title="Toggle Bullet List"> <a title="Toggle Bullet List">
<div class="buttonicon" style="background-position:0px -34px"></div> <div class="buttonicon buttonicon-insertunorderedlist"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('indent');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('indent');return false;" >
<a title="Indent"> <a title="Indent">
<div class="buttonicon" style="background-position:0px -52px"></div> <div class="buttonicon buttonicon-indent"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('outdent');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('outdent');return false;" >
<a title="Unindent"> <a title="Unindent">
<div class="buttonicon" style="background-position:0px -134px"></div> <div class="buttonicon buttonicon-outdent"></div>
</a> </a>
</li> </li>
<li class="separator"></li> <li class="separator"></li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('undo');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('undo');return false;" >
<a title="Undo (ctrl-Z)"> <a title="Undo (ctrl-Z)">
<div class="buttonicon" style="background-position:0px -255px"></div> <div class="buttonicon buttonicon-undo"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('redo');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('redo');return false;" >
<a title="Redo (ctrl-Y)"> <a title="Redo (ctrl-Y)">
<div class="buttonicon" style="background-position:0px -166px"></div> <div class="buttonicon buttonicon-redo"></div>
</a> </a>
</li> </li>
<li class="separator"></li> <li class="separator"></li>
<li id="clearAuthorship" onClick="window.pad&amp;&amp;pad.editbarClick('clearauthorship');return false;" > <li id="clearAuthorship" onClick="window.pad&amp;&amp;pad.editbarClick('clearauthorship');return false;" >
<a title="Clear Authorship Colors"> <a title="Clear Authorship Colors">
<div class="buttonicon" style="background-position:0px -86px"></div> <div class="buttonicon buttonicon-clearauthorship"></div>
</a> </a>
</li> </li>
</ul> </ul>
<ul id="menu_right"> <ul id="menu_right">
<li onClick="window.pad&amp;&amp;pad.editbarClick('settings');return false;">
<a id="settingslink" title="Settings of this pad">
<div class="buttonicon buttonicon-settings"></div>
</a>
</li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('import_export');return false;"> <li onClick="window.pad&amp;&amp;pad.editbarClick('import_export');return false;">
<a id="exportlink" title="Import/Export from/to different document formats"> <a id="exportlink" title="Import/Export from/to different document formats">
<div class="buttonicon" style="background-position:0px -68px"></div> <div class="buttonicon buttonicon-import_export"></div>
</a> </a>
</li> </li>
<li onClick="window.pad&amp;&amp;pad.editbarClick('embed');return false;" > <li onClick="window.pad&amp;&amp;pad.editbarClick('embed');return false;" >
<a id="embedlink" title="Share and Embed this pad"> <a id="embedlink" title="Share and Embed this pad">
<div class="buttonicon" style="background-position:0px -18px"></div> <div class="buttonicon buttonicon-embed"></div>
</a> </a>
</li> </li>
<li class="separator"></li> <li class="separator"></li>
<li id="timesliderlink" onClick="document.location = document.location.pathname+ '/timeslider'"> <li id="timesliderlink" onClick="document.location = document.location.pathname+ '/timeslider'">
<a title="Show the history of this pad"> <a title="Show the history of this pad">
<div class="buttonicon" style="background-position:0px -218px"></div> <div class="buttonicon buttonicon-history"></div>
</a> </a>
</li> </li>
<li id="usericon" onClick="window.pad&amp;&amp;pad.editbarClick('showusers');return false;" > <li id="usericon" onClick="window.pad&amp;&amp;pad.editbarClick('showusers');return false;" >
<a title="Show connected users"> <a title="Show connected users">
<div class="buttonicon" id="usericonback" style="background-position:0px -183px;display:inline-block;"></div> <div class="buttonicon buttonicon-showusers" id="usericonback"></div>
<span id="online_count">1</span> <span id="online_count">1</span>
</a> </a>
</li> </li>
</ul> </ul>
</div> </div>
<div id="users"> <div id="users">
<div id="connectionstatus"> <div id="connectionstatus"></div>
<!-- -->
</div>
<div id="myuser"> <div id="myuser">
<div id="mycolorpicker"> <div id="mycolorpicker">
<div id="colorpicker"></div> <div id="colorpicker"></div>
<!-- <span id="mycolorpickersave"><a onclick="closeColorPicker()">Save</a></span>
<ul id="colorpickerswatches"> <span id="mycolorpickercancel"><a onclick="closeColorPicker()">Cancel</a></span>
</ul>
-->
<span id="mycolorpickersave">
<a onclick="closeColorPicker()">Save</a>
</span>
<span id="mycolorpickercancel">
<a onclick="closeColorPicker()">Cancel</a>
</span>
<span id="mycolorpickerpreview" class="myswatchboxhoverable"></span> <span id="mycolorpickerpreview" class="myswatchboxhoverable"></span>
</div> </div>
<div id="myswatchbox"><div id="myswatch"></div></div>
<div id="myswatchbox"><div id="myswatch"><!-- --></div></div> <div id="myusernameform"><input type="text" id="myusernameedit" disabled="disabled"></div>
<div id="myusernameform"><input type="text" id="myusernameedit" disabled="disabled" /></div> <div id="mystatusform"><input type="text" id="mystatusedit" disabled="disabled"></div>
<div id="mystatusform"><input type="text" id="mystatusedit" disabled="disabled" /></div>
</div> </div>
<div id="otherusers"> <div id="otherusers">
<div id="guestprompts"><!-- --></div> <div id="guestprompts"></div>
<table id="otheruserstable" cellspacing="0" cellpadding="0" border="0"> <table id="otheruserstable" cellspacing="0" cellpadding="0" border="0">
<tr> <tr><td></td></tr>
<td>
</td>
</tr>
</table> </table>
<div id="nootherusers"></div>
<div id="nootherusers">
</div> </div>
<div id="userlistbuttonarea"></div>
</div> </div>
<div id="userlistbuttonarea">
<!--<a href="javascript:void(0)" id="sharebutton">Share</a>-->
</div>
</div>
<!-- /padusers -->
<!--<div id="users">
<!-- some example code so I can make the css --*>
</div>-->
<div id="editorcontainerbox"> <div id="editorcontainerbox">
<div id="editorcontainer"></div>
<div id="editorcontainer"> <div id="editorloadingbox">Loading...</div>
<!-- -->
</div>
<div id="editorloadingbox">
Loading...
</div> </div>
<div id="settingsmenu" class="popup">
<h1>Pad settings</h1>
<div class="left_popup">
<h2>My view</h2>
<p>
<input type="checkbox" id="options-stickychat" onClick="chat.stickToScreen();">
<label for="options-stickychat">Chat always on screen</label>
</p>
<p>
<input type="checkbox" id="options-colorscheck" checked>
<label for="options-colorscheck">Authorship colors</label>
</p>
<p>
<input type="checkbox" id="options-linenoscheck" checked>
<label for="options-linenoscheck">Line numbers</label>
</p>
<p>
Font type:
<select id="viewfontmenu">
<option value="normal">Normal</option>
<option value="monospace">Monospaced</option>
</select>
</p>
</div>
<div class="right_popup">
<h2>Global view</h2>
<p>Currently nothing.</p>
<p class="note">These options affect everyone viewing this pad.</p>
</div>
</div> </div>
<!-- import export code --> <div id="importexport" class="popup">
<div id="importexport"> <div class="left_popup">
<h2>Import from text file, HTML, PDF, Word, ODT or RTF</h2><br>
<div id="import">
Import from text file, HTML, PDF, Word, ODT or RTF:<br/><br/>
<form id="importform" method="post" action="" target="importiframe" enctype="multipart/form-data"> <form id="importform" method="post" action="" target="importiframe" enctype="multipart/form-data">
<div class="importformdiv" id="importformfilediv"> <div class="importformdiv" id="importformfilediv">
<input type="file" name="file" size="15" id="importfileinput" /> <input type="file" name="file" size="15" id="importfileinput">
<div class="importmessage" id="importmessagefail"></div> <div class="importmessage" id="importmessagefail"></div>
</div> </div>
<div class="importmessage" id="importmessagesuccess">Successful!</div> <div class="importmessage" id="importmessagesuccess">Successful!</div>
<div class="importformdiv" id="importformsubmitdiv"> <div class="importformdiv" id="importformsubmitdiv">
<input type="hidden" name="padId" value="blpmaXT35R" /> <input type="hidden" name="padId" value="blpmaXT35R">
<span class="nowrap"> <span class="nowrap">
<input type="submit" name="submit" value="Import Now" disabled="disabled" id="importsubmitinput" /> <input type="submit" name="submit" value="Import Now" disabled="disabled" id="importsubmitinput">
<img alt="" id="importstatusball" src="../static/img/loading.gif" align="top" /> <img alt="" id="importstatusball" src="../static/img/loading.gif" align="top">
<img alt="" id="importarrow" src="../static/img/leftarrow.png" align="top" /> <img alt="" id="importarrow" src="../static/img/leftarrow.png" align="top">
</span> </span>
</div> </div>
</form> </form>
</div> </div>
<div class="right_popup">
<div id="importexportline"></div> <h2>Export current pad as</h2>
<div id="export">
Export current pad as:
<a id="exporthtmla" target="_blank" class="exportlink"><div class="exporttype" id="exporthtml">HTML</div></a> <a id="exporthtmla" target="_blank" class="exportlink"><div class="exporttype" id="exporthtml">HTML</div></a>
<a id="exportplaina" target="_blank" class="exportlink"><div class="exporttype" id="exportplain">Plain text</div></a> <a id="exportplaina" target="_blank" class="exportlink"><div class="exporttype" id="exportplain">Plain text</div></a>
<a id="exportworda" target="_blank" class="exportlink"><div class="exporttype" id="exportword">Microsoft Word</div></a> <a id="exportworda" target="_blank" class="exportlink"><div class="exporttype" id="exportword">Microsoft Word</div></a>
@ -213,40 +198,37 @@
<a id="exportopena" target="_blank" class="exportlink"><div class="exporttype" id="exportopen">OpenDocument</div></a> <a id="exportopena" target="_blank" class="exportlink"><div class="exporttype" id="exportopen">OpenDocument</div></a>
<a id="exportdokuwikia" target="_blank" class="exportlink"><div class="exporttype" id="exportdokuwiki">DokuWiki text</div></a> <a id="exportdokuwikia" target="_blank" class="exportlink"><div class="exporttype" id="exportdokuwiki">DokuWiki text</div></a>
<a id="exportwordlea" target="_blank" onClick="padimpexp.export2Wordle();return false;" class="exportlink"><div class="exporttype" id="exportwordle">Wordle</div></a> <a id="exportwordlea" target="_blank" onClick="padimpexp.export2Wordle();return false;" class="exportlink"><div class="exporttype" id="exportwordle">Wordle</div></a>
<form id="wordlepost" name="wall" action="http://wordle.net/advanced" method="POST" style="margin-left:0px;">
<div id="hidetext" style=""><textarea id="text" name="text" style="display:none;">Coming soon!</textarea></div>
</form>
</div> </div>
</div> </div>
<!-- the embed code --> <div id="embed" class="popup">
<div id="embed"> <div id="embedreadonly" class="right">
<div id="embedreadonly"> <input type="checkbox" id="readonlyinput" onClick="padeditbar.setEmbedLinks();">
<input type="checkbox" id="readonlyinput" onClick="padeditbar.setEmbedLinks();"/><label for="readonlyinput">Read only</label> <label for="readonlyinput">Read only</label>
</div> </div>
Share: <h1>Share this pad</h1>
<br/>
<div id="linkcode"> <div id="linkcode">
<label for="linkinput">Link:</label><input id="linkinput" type="text" value=""> <h2>Link</h2>
</div><br/> <input id="linkinput" type="text" value="">
</div>
<br>
<div id="embedcode"> <div id="embedcode">
<label for="embedinput">Embed code:</label><input id="embedinput" type="text" value=""> <h2>Embed URL</h2>
</div><br/> <input id="embedinput" type="text" value="">
</div>
<br>
<div id="qrcode"> <div id="qrcode">
<label for="embedreadonlyqr">QR code:</label><br/> <h2>QR code</h2>
<div id="qr_center"><img id="embedreadonlyqr"></div> <div id="qr_center"><img id="embedreadonlyqr"></div>
</div> </div>
</div> </div>
<div id="chatthrob"> <div id="chatthrob"></div>
</div>
<div id="chaticon"> <div id="chaticon">
<a onClick="chat.show();return false;" <a onClick="chat.show();return false;" title="Open the chat for this pad">
title="Open the chat for this pad">
<span id="chatlabel">Chat</span> <span id="chatlabel">Chat</span>
<div class="buttonicon" style="background-position:0px -102px;display:inline-block;"></div> <div class="buttonicon buttonicon-chat"></div>
</a> </a>
<span id="chatcounter">0</span> <span id="chatcounter">0</span>
</div> </div>
@ -256,95 +238,74 @@
<div id="chattext" class="authorColors"></div> <div id="chattext" class="authorColors"></div>
<div id="chatinputbox"> <div id="chatinputbox">
<form> <form>
<input id="chatinput" type="text" maxlength="140"/> <input id="chatinput" type="text" maxlength="140">
</form> </form>
</div> </div>
</div> </div>
<div id="focusprotector">&nbsp;</div> <div id="focusprotector">&nbsp;</div>
<!-- /padeditor -->
<div id="modaloverlay"> <div id="modaloverlay">
<div id="modaloverlay-inner"> <div id="modaloverlay-inner"></div>
<!-- --> </div>
</div>
</div>
<div id="mainmodals"> <div id="mainmodals">
<div id="connectionbox" class="modaldialog"> <div id="connectionbox" class="modaldialog">
<div id="connectionboxinner" class="modaldialog-inner"> <div id="connectionboxinner" class="modaldialog-inner">
<div class="connecting"> <div class="connecting">Connecting...</div>
Connecting... <div class="reconnecting">Reestablishing connection...</div>
</div>
<div class="reconnecting">
Reestablishing connection...
</div>
<div class="disconnected"> <div class="disconnected">
<h2 class="h2_disconnect">Disconnected.</h2> <h2 class="h2_disconnect">Disconnected.</h2>
<h2 class="h2_userdup">Opened in another window.</h2> <h2 class="h2_userdup">Opened in another window.</h2>
<h2 class="h2_unauth">No Authorization.</h2> <h2 class="h2_unauth">No Authorization.</h2>
<div id="disconnected_looping"> <div id="disconnected_looping">
<p> <p><b>We're having trouble talking to the EtherPad lite synchronization server.</b> You may be connecting through an incompatible firewall or proxy server.</p>
<b>We're having trouble talking to the EtherPad lite synchronization server.</b>
You may be connecting through an incompatible firewall or proxy server.
</p>
</div> </div>
<div id="disconnected_initsocketfail"> <div id="disconnected_initsocketfail">
<p> <p><b>We were unable to connect to the EtherPad lite synchronization server.</b> This may be due to an incompatibility with your web browser or internet connection.</p>
<b>We were unable to connect to the EtherPad lite synchronization server.</b>
This may be due to an incompatibility with your web browser or internet connection.
</p>
</div> </div>
<div id="disconnected_userdup"> <div id="disconnected_userdup">
<p> <p><b>You seem to have opened this pad in another browser window.</b> If you'd like to use this window instead, you can reconnect.</p>
<b>You seem to have opened this pad in another browser window.</b>
If you'd like to use this window instead, you can reconnect.
</p>
</div> </div>
<div id="disconnected_unknown"> <div id="disconnected_unknown">
<p> <p><b>Lost connection with the EtherPad lite synchronization server.</b> This may be due to a loss of network connectivity.</p>
<b>Lost connection with the EtherPad lite synchronization server.</b> This may be due to a loss of network connectivity.
</p>
</div> </div>
<div id="disconnected_slowcommit"> <div id="disconnected_slowcommit">
<p> <p><b>Server not responding.</b> This may be due to network connectivity issues or high load on the server.</p>
<b>Server not responding.</b> This may be due to network connectivity issues or high load on the server.
</p>
</div> </div>
<div id="disconnected_unauth"> <div id="disconnected_unauth">
<p> <p>Your browser's credentials or permissions have changed while viewing this pad. Try reconnecting.</p>
Your browser's credentials or permissions have changed while viewing this pad. Try reconnecting.
</p>
</div> </div>
<div id="disconnected_deleted"> <div id="disconnected_deleted">
<p> <p>This pad was deleted.</p>
This pad was deleted.
</p>
</div> </div>
<div id="reconnect_advise"> <div id="reconnect_advise">
<p> <p>If this continues to happen, please let us know</p>
If this continues to happen, please let us know
</p>
</div> </div>
<div id="reconnect_form"> <div id="reconnect_form">
<button id="forcereconnect">Reconnect Now</button> <button id="forcereconnect">Reconnect Now</button>
</div> </div>
</div> </div>
</div> </div>
<form id="reconnectform" method="post" action="/ep/pad/reconnect" accept-charset="UTF-8" style="display: none;"> <form id="reconnectform" method="post" action="/ep/pad/reconnect" accept-charset="UTF-8" style="display: none;">
<input type="hidden" class="padId" name="padId"/> <input type="hidden" class="padId" name="padId">
<input type="hidden" class="diagnosticInfo" name="diagnosticInfo"/> <input type="hidden" class="diagnosticInfo" name="diagnosticInfo">
<input type="hidden" class="missedChanges" name="missedChanges"/> <input type="hidden" class="missedChanges" name="missedChanges">
</form> </form>
</div>
</div>
<script> <script>
/* TODO: These globals shouldn't exist. */ /* TODO: These globals shouldn't exist. */
pad = require('/pad2').pad; pad = require('/pad').pad;
chat = require('/chat').chat; chat = require('/chat').chat;
padeditbar = require('/pad_editbar').padeditbar; padeditbar = require('/pad_editbar').padeditbar;
padimpexp = require('/pad_impexp').padimpexp; padimpexp = require('/pad_impexp').padimpexp;
(function () {
require('/pad').init();
}());
</script> </script>
</body>
</html> </html>

View file

@ -15,163 +15,6 @@
<link href="../../static/custom/timeslider.css" rel="stylesheet"> <link href="../../static/custom/timeslider.css" rel="stylesheet">
<script src="../../static/custom/timeslider.js"></script> <script src="../../static/custom/timeslider.js"></script>
<script>
// <![CDATA[
var clientVars = {};
/* TODO: These globals shouldn't exist. */
padeditbar = require('/pad_editbar').padeditbar;
padimpexp = require('/pad_impexp').padimpexp;
function createCookie(name,value,days)
{
if (days) {
var date = new Date();
date.setTime(date.getTime()+(days*24*60*60*1000));
var expires = "; expires="+date.toGMTString();
}
else var expires = "";
document.cookie = name+"="+value+expires+"; path=/";
}
function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for(var i=0;i < ca.length;i++) {
var c = ca[i];
while (c.charAt(0)==' ') c = c.substring(1,c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
}
return null;
}
function randomString() {
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
var string_length = 20;
var randomstring = '';
for (var i=0; i<string_length; i++) {
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum,rnum+1);
}
return "t." + randomstring;
}
var socket, token, padId, export_links;
$(document).ready(function ()
{
//start the costum js
if(typeof costumStart == "function") costumStart();
//get the padId out of the url
var urlParts= document.location.pathname.split("/");
padId = decodeURIComponent(urlParts[urlParts.length-2]);
//set the title
document.title = document.title + " | " + padId.replace(/_+/g, ' ');
//ensure we have a token
token = readCookie("token");
if(token == null)
{
token = randomString();
createCookie("token", token, 60);
}
var loc = document.location;
//get the correct port
var port = loc.port == "" ? (loc.protocol == "https:" ? 443 : 80) : loc.port;
//create the url
var url = loc.protocol + "//" + loc.hostname + ":" + port + "/";
//find out in which subfolder we are
var resource = loc.pathname.substr(1,loc.pathname.indexOf("/p/")) + "socket.io";
//build up the socket io connection
socket = io.connect(url, {resource: resource});
//send the ready message once we're connected
socket.on('connect', function()
{
sendSocketMsg("CLIENT_READY", {});
});
//route the incoming messages
socket.on('message', function(message)
{
if(window.console) console.log(message);
if(message.type == "CLIENT_VARS")
{
handleClientVars(message);
}
else if(message.type == "CHANGESET_REQ")
{
changesetLoader.handleSocketResponse(message);
}
else if(message.accessStatus)
{
$("body").html("<h2>You have no permission to access this pad</h2>")
}
});
//get all the export links
export_links = $('#export > .exportlink')
});
//sends a message over the socket
function sendSocketMsg(type, data)
{
var sessionID = readCookie("sessionID");
var password = readCookie("password");
var msg = { "component" : "timeslider",
"type": type,
"data": data,
"padId": padId,
"token": token,
"sessionID": sessionID,
"password": password,
"protocolVersion": 2};
socket.json.send(msg);
}
var fireWhenAllScriptsAreLoaded = [];
function handleClientVars(message)
{
//save the client Vars
clientVars = message.data;
//load all script that doesn't work without the clientVars
require('/broadcast_slider').loadBroadcastSliderJS();
require('/broadcast_revisions').loadBroadcastRevisionsJS();
require('/broadcast').loadBroadcastJS();
//initialize export ui
padimpexp.init();
//change export urls when the slider moves
var export_rev_regex = /(\/\d+)?\/export/
BroadcastSlider.onSlider(function(revno)
{
export_links.each(function()
{
this.setAttribute('href', this.href.replace(export_rev_regex, '/' + revno + '/export'));
});
});
//fire all start functions of these scripts, formerly fired with window.load
for(var i=0;i < fireWhenAllScriptsAreLoaded.length;i++)
{
fireWhenAllScriptsAreLoaded[i]();
}
}
// ]]>
</script>
</head> </head>
<body id="padbody" class="timeslider limwidth nonpropad nonprouser"> <body id="padbody" class="timeslider limwidth nonpropad nonprouser">
@ -293,18 +136,11 @@
<ul> <ul>
<li onClick="window.padeditbar.toolbarClick('import_export');return false;"> <li onClick="window.padeditbar.toolbarClick('import_export');return false;">
<a id="exportlink" title="Export to different document formats"> <a id="exportlink" title="Export to different document formats">
<div class="buttonicon" style="background-position:0px -68px"></div> <div class="buttonicon buttonicon-import_export"></div>
</a> </a>
</li> </li>
</ul> </ul>
<a id = "returnbutton">Return to pad</a> <a id = "returnbutton">Return to pad</a>
<script>
if(document.referrer.length > 0 && document.referrer.substring(document.referrer.lastIndexOf("/")-1,document.referrer.lastIndexOf("/")) === "p") {
$("#returnbutton").attr("href", document.referrer);
} else {
$("#returnbutton").attr("href", document.location.href.substring(0,document.location.href.lastIndexOf("/")));
}
</script>
</div> </div>
<div id="editbarinner" class="editbarinner"> <div id="editbarinner" class="editbarinner">
@ -352,7 +188,7 @@
<!-- export code --> <!-- export code -->
<div id="importexport"> <div id="importexport">
<div id="export"> <div id="export" class="popup">
Export current version as: Export current version as:
<a id="exporthtmla" target="_blank" class="exportlink"><div class="exporttype" id="exporthtml">HTML</div></a> <a id="exporthtmla" target="_blank" class="exportlink"><div class="exporttype" id="exporthtml">HTML</div></a>
<a id="exportplaina" target="_blank" class="exportlink"><div class="exporttype" id="exportplain">Plain text</div></a> <a id="exportplaina" target="_blank" class="exportlink"><div class="exporttype" id="exportplain">Plain text</div></a>
@ -366,6 +202,18 @@
</form> </form>
</div> </div>
</div> </div>
<script>
var clientVars = {};
/* TODO: These globals shouldn't exist. */
padeditbar = require('/pad_editbar').padeditbar;
padimpexp = require('/pad_impexp').padimpexp;
(function () {
var TimeSlider = require('/timeslider').init();
})();
</script>
</body> </body>
</html> </html>