diff --git a/README.md b/README.md index b2f85fcff..4995e852a 100644 --- a/README.md +++ b/README.md @@ -58,7 +58,7 @@ Here is the **[FAQ](https://github.com/Pita/etherpad-lite/wiki/FAQ)**
  1. Install the dependencies. We need gzip, git, curl, libssl develop libraries, python and gcc.
    For Debian/Ubuntu apt-get install gzip git-core curl python libssl-dev build-essential
    - For Fedora/CentOS yum install gzip git-core curl python openssl-dev && yum groupinstall "Development Tools" + For Fedora/CentOS yum install gzip git-core curl python openssl-devel && yum groupinstall "Development Tools"

  2. Install node.js
      diff --git a/bin/convert.js b/bin/convert.js index d410f7a4a..4302114c6 100644 --- a/bin/convert.js +++ b/bin/convert.js @@ -4,6 +4,7 @@ var ueberDB = require("ueberDB"); var mysql = require("mysql"); var async = require("async"); var Changeset = require("../node/utils/Changeset"); +var randomString = require("../node/utils/randomstring"); var AttributePoolFactory = require("../node/utils/AttributePoolFactory"); var settingsFile = process.argv[2]; @@ -450,18 +451,3 @@ function parsePage(array, pageStart, offsets, data, json) 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; -} diff --git a/bin/installDeps.sh b/bin/installDeps.sh index a3f767a24..8580387db 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -33,6 +33,13 @@ if [ ! $(echo $NPM_VERSION | cut -d "." -f 1) = "1" ]; then exit 1 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 if [ ! -f "settings.json" ]; then echo "Copy the settings template to settings.json..." diff --git a/node/db/AuthorManager.js b/node/db/AuthorManager.js index f4f42d112..7c054a56f 100644 --- a/node/db/AuthorManager.js +++ b/node/db/AuthorManager.js @@ -22,6 +22,8 @@ var ERR = require("async-stacktrace"); var db = require("./DB").db; var async = require("async"); +var randomString = require("../utils/randomstring"); + /** * Checks if the author exists */ @@ -177,18 +179,3 @@ exports.setAuthorName = function (author, 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; -} diff --git a/node/db/GroupManager.js b/node/db/GroupManager.js index 473ea9b77..7e3b7d6d1 100644 --- a/node/db/GroupManager.js +++ b/node/db/GroupManager.js @@ -20,6 +20,7 @@ var ERR = require("async-stacktrace"); var customError = require("../utils/customError"); +var randomString = require("../utils/randomstring"); var db = require("./DB").db; var async = require("async"); 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; -} diff --git a/node/db/ReadOnlyManager.js b/node/db/ReadOnlyManager.js index 73b3be9ec..1e5079c52 100644 --- a/node/db/ReadOnlyManager.js +++ b/node/db/ReadOnlyManager.js @@ -22,6 +22,8 @@ var ERR = require("async-stacktrace"); var db = require("./DB").db; var async = require("async"); +var randomString = require("../utils/randomstring"); + /** * returns a read only id for a pad * @param {String} padId the id of the pad @@ -70,18 +72,3 @@ exports.getPadId = function(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; -} diff --git a/node/db/SecurityManager.js b/node/db/SecurityManager.js index 52d5afcbe..4b86d868a 100644 --- a/node/db/SecurityManager.js +++ b/node/db/SecurityManager.js @@ -26,6 +26,8 @@ var padManager = require("./PadManager"); var sessionManager = require("./SessionManager"); 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. * @param padID the pad the user wants to access diff --git a/node/db/SessionManager.js b/node/db/SessionManager.js index a394f5442..084d4a695 100644 --- a/node/db/SessionManager.js +++ b/node/db/SessionManager.js @@ -20,6 +20,7 @@ var ERR = require("async-stacktrace"); var customError = require("../utils/customError"); +var randomString = require("../utils/randomstring"); var db = require("./DB").db; var async = require("async"); 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 function is_int(value) { diff --git a/node/handler/APIHandler.js b/node/handler/APIHandler.js index 0cd9cb58e..ca45e1f8f 100644 --- a/node/handler/APIHandler.js +++ b/node/handler/APIHandler.js @@ -22,6 +22,7 @@ var ERR = require("async-stacktrace"); var fs = require("fs"); var api = require("../db/API"); var padManager = require("../db/PadManager"); +var randomString = require("../utils/randomstring"); //ensure we have an apikey var apikey = null; @@ -157,18 +158,3 @@ function callAPI(functionName, fields, req, res) //call the api function 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; -} diff --git a/node/server.js b/node/server.js index 4f3ef9bad..37503cbf2 100644 --- a/node/server.js +++ b/node/server.js @@ -92,6 +92,33 @@ function init(additionalSetup){ 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 ' + real_path + '', 302); + } + //the pad id was fine, so just render it + else + { + next(); + } + }); + } + }); + //load modules that needs a initalized db readOnlyManager = require("./db/ReadOnlyManager"); exporthtml = require("./utils/ExportHtml"); @@ -238,94 +265,60 @@ 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 ' + real_path + '', 302); - } - //the pad id was fine, so just render it - else - { - render(); - } - }); - } - } - //serve pad.html under /p app.get('/p/:pad', function(req, res, next) { - goToPad(req, res, function() { - var filePath = path.normalize(__dirname + "/../static/pad.html"); - res.sendfile(filePath, { maxAge: exports.maxAge }); - }); + var filePath = path.normalize(__dirname + "/../static/pad.html"); + res.sendfile(filePath, { maxAge: exports.maxAge }); }); //serve timeslider.html under /p/$padname/timeslider app.get('/p/:pad/timeslider', function(req, res, next) { - goToPad(req, res, function() { - var filePath = path.normalize(__dirname + "/../static/timeslider.html"); - res.sendfile(filePath, { maxAge: exports.maxAge }); - }); + var filePath = path.normalize(__dirname + "/../static/timeslider.html"); + res.sendfile(filePath, { maxAge: exports.maxAge }); }); //serve timeslider.html under /p/$padname/timeslider app.get('/p/:pad/:rev?/export/:type', function(req, res, next) { - goToPad(req, res, function() { - var types = ["pdf", "doc", "txt", "html", "odt", "dokuwiki"]; - //send a 404 if we don't support this filetype - if(types.indexOf(req.params.type) == -1) - { - next(); - return; - } - - //if abiword is disabled, and this is a format we only support with abiword, output a message - if(settings.abiword == null && - ["odt", "pdf", "doc"].indexOf(req.params.type) !== -1) - { - res.send("Abiword is not enabled at this Etherpad Lite instance. Set the path to Abiword in settings.json to enable this feature"); - return; - } - - res.header("Access-Control-Allow-Origin", "*"); - - hasPadAccess(req, res, function() - { - exportHandler.doExport(req, res, req.params.pad, req.params.type); - }); + var types = ["pdf", "doc", "txt", "html", "odt", "dokuwiki"]; + //send a 404 if we don't support this filetype + if(types.indexOf(req.params.type) == -1) + { + next(); + return; + } + + //if abiword is disabled, and this is a format we only support with abiword, output a message + if(settings.abiword == null && + ["odt", "pdf", "doc"].indexOf(req.params.type) !== -1) + { + res.send("Abiword is not enabled at this Etherpad Lite instance. Set the path to Abiword in settings.json to enable this feature"); + return; + } + + res.header("Access-Control-Allow-Origin", "*"); + + hasPadAccess(req, res, function() + { + exportHandler.doExport(req, res, req.params.pad, req.params.type); }); }); //handle import requests app.post('/p/:pad/import', function(req, res, next) { - goToPad(req, res, function() { - //if abiword is disabled, skip handling this request - if(settings.abiword == null) - { - next(); - return; - } - - hasPadAccess(req, res, function() - { - importHandler.doImport(req, res, req.params.pad); - }); + //if abiword is disabled, skip handling this request + if(settings.abiword == null) + { + next(); + return; + } + + hasPadAccess(req, res, function() + { + importHandler.doImport(req, res, req.params.pad); }); }); diff --git a/node/utils/Minify.js b/node/utils/Minify.js index 348f25373..98774d195 100644 --- a/node/utils/Minify.js +++ b/node/utils/Minify.js @@ -28,7 +28,7 @@ var jsp = require("uglify-js").parser; var pro = require("uglify-js").uglify; var path = require('path'); var Buffer = require('buffer').Buffer; -var gzip = require('gzip'); +var zlib = require('zlib'); var RequireKernel = require('require-kernel'); var server = require('../server'); var os = require('os'); @@ -233,23 +233,14 @@ function _handle(req, res, jsFilename, jsFiles) { //write the results compressed in a file function(callback) { - //spawn a gzip process if we're on a unix system - 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 - err = err === 0 ? null : err; + zlib.gzip(result, function(err, compressedResult){ + //weird gzip bug that returns 0 instead of null if everything is ok + err = err === 0 ? null : err; + + if(ERR(err, callback)) return; - if(ERR(err, callback)) return; - - fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback); - }); - } - //skip this step on windows - else - { - callback(); - } + fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback); + }); } ],callback); } @@ -315,11 +306,6 @@ function tarCode(filesInOrder, files, write) { write("\n\n\n/*** File: static/js/" + filename + " ***/\n\n\n"); 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 diff --git a/node/utils/randomstring.js b/node/utils/randomstring.js new file mode 100644 index 000000000..4c1bba244 --- /dev/null +++ b/node/utils/randomstring.js @@ -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; diff --git a/node/utils/tar.json b/node/utils/tar.json index 92883bb74..e1e6fb2b1 100644 --- a/node/utils/tar.json +++ b/node/utils/tar.json @@ -1,6 +1,8 @@ { "pad.js": [ "jquery.js" + , "pad.js" + , "ace2_common.js" , "pad_utils.js" , "plugins.js" , "undo-xpopup.js" @@ -16,7 +18,6 @@ , "pad_impexp.js" , "pad_savedrevs.js" , "pad_connectionstatus.js" - , "pad2.js" , "jquery-ui.js" , "chat.js" , "excanvas.js" @@ -29,6 +30,7 @@ , "json2.js" , "colorutils.js" , "draggable.js" + , "ace2_common.js" , "pad_utils.js" , "pad_cookie.js" , "pad_editor.js" @@ -44,5 +46,6 @@ , "broadcast.js" , "broadcast_slider.js" , "broadcast_revisions.js" + , "timeslider.js" ] } diff --git a/package.json b/package.json index 6567e5324..e24a776c3 100644 --- a/package.json +++ b/package.json @@ -18,14 +18,16 @@ "express" : "2.5.0", "clean-css" : "0.2.4", "uglify-js" : "1.1.1", - "gzip" : "0.1.0", "formidable" : "1.0.7", - "log4js" : "0.3.9", + "log4js" : "0.4.1", "jsdom-nocontextifiy" : "0.2.10", "async-stacktrace" : "0.0.2" }, "devDependencies": { "jshint" : "*" }, + "engines" : { "node" : ">=0.6.0", + "npm" : ">=1.0" + }, "version" : "1.0.0" } diff --git a/static/css/pad.css b/static/css/pad.css index 41ef75902..be9d96565 100644 --- a/static/css/pad.css +++ b/static/css/pad.css @@ -1,13 +1,13 @@ *,html,body,p{ margin: 0; padding: 0; } .clear { clear: both; } -html { font-size: 62.5%; } +html { font-size: 62.5%; width: 100%; } body, textarea { font-family: Helvetica, Arial, sans-serif; } iframe {position:absolute;} #users { position: absolute; - z-index: 10; + z-index:500; background-color: #000; background-color: rgba(0,0,0,0.7); width: 160px; @@ -560,28 +560,6 @@ table#otheruserstable { display: none; } display: none; z-index: 55; } #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 so that modals are on top in IE */ } .modalfield { font-size: 1.2em; padding: 1px; border: 1px solid #bbb;} @@ -763,38 +741,8 @@ a#topbarmaximize { 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 { @@ -850,6 +798,7 @@ ul#colorpickerswatches li:hover left:0px; top:25px; bottom:25px; + z-index:1002; } #chattext p @@ -986,40 +935,8 @@ position: relative; 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{ - line-height:20px; + margin-top: 2px; background-repeat:no-repeat; padding-left:25px; background-image: url("../../static/img/etherpad_lite_icons.png"); @@ -1028,8 +945,8 @@ position: relative; } #importexportline{ - border: dotted 1px; - height: 185px; + border-left: 1px solid #fff; + height: 190px; position:absolute; width:0px; left:260px; @@ -1069,10 +986,6 @@ position: relative; background-position: 0px -459px; } -#export a{ - text-decoration: none; -} - #importstatusball{ display:none; } @@ -1122,6 +1035,59 @@ background-repeat: no-repeat; margin-left: 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 { @@ -1145,18 +1111,22 @@ width:33px !important; color: #999; } -label[for=readonlyinput] { - margin: 0 10px 0 2px; -} - - #qr_center { margin: 10px 10px auto 0; text-align: center; } -#qrcode{ - margin-left:10px; +#embedreadonlyqr { + 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) { @@ -1245,3 +1215,78 @@ label[for=readonlyinput] { .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; +} diff --git a/static/css/timeslider.css b/static/css/timeslider.css index 9df408683..6022e2d7c 100644 --- a/static/css/timeslider.css +++ b/static/css/timeslider.css @@ -195,10 +195,8 @@ float:right; color: #222; } -#importexport{ - top:103px; - width:185px; -} +#importexport { top: 118px; } +#importexport .popup { width: 185px; } ul { margin-left: 1.5em; } ul ul { margin-left: 0 !important; } diff --git a/static/index.html b/static/index.html index 1e1861639..fe38318b7 100644 --- a/static/index.html +++ b/static/index.html @@ -1,8 +1,11 @@ - - - Etherpad Lite + + + Etherpad Lite + + + + +
      New Pad

      or create/open a Pad with the name
      - +
      -
      + + + + diff --git a/static/js/ace2_inner.js b/static/js/ace2_inner.js index e97847721..977c5cdff 100644 --- a/static/js/ace2_inner.js +++ b/static/js/ace2_inner.js @@ -236,12 +236,19 @@ function OUTER(gscope) { bgcolor = fadeColor(bgcolor, info.fade); } - - dynamicCSS.selectorStyle(getAuthorColorClassSelector( - getAuthorClassName(author))).backgroundColor = bgcolor; - dynamicCSSTop.selectorStyle(getAuthorColorClassSelector( - getAuthorClassName(author))).backgroundColor = bgcolor; + // Text color + var txtcolor = (colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.45) ? '#ffffff' : '#000000'; + + var authorStyle = dynamicCSS.selectorStyle(getAuthorColorClassSelector( + 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 // in a document of divs. However, when copy-and-pasted the div will // 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 setAssoc(lineElem, "shouldBeEmpty", true); // an object property doesn't setAssoc(lineElem, "unpasted", {}); + lineElem.innerHTML = ""; // Then we make it blank.. New line and no space = Awesome :) }; var lineClass = 'ace-line'; result.appendSpan = function(txt, cls) diff --git a/static/js/broadcast.js b/static/js/broadcast.js index b49b185a5..2aa0b5d06 100644 --- a/static/js/broadcast.js +++ b/static/js/broadcast.js @@ -20,16 +20,17 @@ * limitations under the License. */ -var global = this; - var makeCSSManager = require('/cssmanager_client').makeCSSManager; var domline = require('/domline_client').domline; var Changeset = require('/easysync2_client').Changeset; var AttribPool = require('/easysync2_client').AttribPool; 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.) // 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) @@ -423,7 +424,7 @@ function loadBroadcastJS() })); } - global.changesetLoader = { + changesetLoader = { running: false, resolved: [], requestQueue1: [], @@ -763,6 +764,8 @@ function loadBroadcastJS() } receiveAuthorData(clientVars.historicalAuthorData); + + return changesetLoader; } exports.loadBroadcastJS = loadBroadcastJS; diff --git a/static/js/broadcast_revisions.js b/static/js/broadcast_revisions.js index 364ac3e8c..19f3f5ff7 100644 --- a/static/js/broadcast_revisions.js +++ b/static/js/broadcast_revisions.js @@ -22,7 +22,6 @@ // revision info is a skip list whos entries represent a particular revision // of the document. These revisions are connected together by various // changesets, or deltas, between any two revisions. -var global = this; function loadBroadcastRevisionsJS() { diff --git a/static/js/broadcast_slider.js b/static/js/broadcast_slider.js index 972190acb..0bdc2cabc 100644 --- a/static/js/broadcast_slider.js +++ b/static/js/broadcast_slider.js @@ -19,10 +19,12 @@ * See the License for the specific language governing permissions and * 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() { // wrap this code in its own namespace @@ -203,7 +205,7 @@ function loadBroadcastSliderJS() } } - global.BroadcastSlider = { + BroadcastSlider = { onSlider: onSlider, getSliderPosition: getSliderPosition, setSliderPosition: setSliderPosition, @@ -495,6 +497,8 @@ function loadBroadcastSliderJS() { $("#viewlatest").html(loc == BroadcastSlider.getSliderLength() ? "Viewing latest content" : "View latest content"); }) + + return BroadcastSlider; } exports.loadBroadcastSliderJS = loadBroadcastSliderJS; diff --git a/static/js/chat.js b/static/js/chat.js index 475d01939..9b28c3334 100644 --- a/static/js/chat.js +++ b/static/js/chat.js @@ -21,17 +21,18 @@ */ var padutils = require('/pad_utils').padutils; +var browser = require('/ace2_common').browser; +var padcookie = require('/pad_cookie').padcookie; var chat = (function() { - var bottomMargin = "0px"; + var isStuck = false; var sDuration = 500; var hDuration = 750; var chatMentions = 0; var title = document.title; - if ($.browser.mobile){ - sDuration = 0; - hDuration = 0; + if (browser.mobile){ + sDuration = hDuration = 0; } var self = { show: function () @@ -56,11 +57,12 @@ var chat = (function() { $("#focusprotector").hide(); - if($.browser.mobile) - bottommargin = "32px"; - - $("#chatbox").css({right: "20px", bottom: bottomMargin, left: "", top: ""}); - + if(browser.mobile) { + $("#chatbox").css({right: "0px", bottom: "32px", left: "", top: ""}); + } else { + $("#chatbox").css({right: "20px", bottom: "0px", left: "", top: ""}); + } + self.scrollDown(); } }); @@ -68,6 +70,23 @@ var chat = (function() chatMentions = 0; 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 () { $("#chatcounter").text("0"); @@ -177,3 +196,4 @@ var chat = (function() }()); exports.chat = chat; + diff --git a/static/js/pad2.js b/static/js/pad.js similarity index 92% rename from static/js/pad2.js rename to static/js/pad.js index 65cd72218..fb297d4af 100644 --- a/static/js/pad2.js +++ b/static/js/pad.js @@ -24,13 +24,14 @@ var socket; -var settings = {}; -settings.LineNumbersDisabled = false; -settings.noColors = false; -settings.useMonospaceFontGlobal = false; -settings.globalUserName = false; -settings.hideQRCode = false; -settings.rtlIsTrue = false; +// These jQuery things should create local references, but for now `require()` +// assigns to the global `$` and augments it with plugins. +require('/jquery'); +require('/jquery-ui'); +require('/farbtastic'); +require('/excanvas'); +require('/json2'); +require('/undo-xpopup'); var chat = require('/chat').chat; var getCollabClient = require('/collab_client').getCollabClient; @@ -45,19 +46,6 @@ var padsavedrevs = require('/pad_savedrevs').padsavedrevs; var paduserlist = require('/pad_userlist').paduserlist; 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) { if (days) @@ -309,7 +297,7 @@ function handshake() clientVars.collab_client_vars.clientAgent = "Anonymous"; //initalize the pad - pad.init(); + pad._afterHandshake(); initalized = true; // 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 var fb = $('#colorpicker').farbtastic({ callback: '#mycolorpickerpreview', width: 220}); } @@ -422,6 +409,23 @@ var pad = { }, 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; @@ -447,10 +451,10 @@ var pad = { } // order of inits is important here: - padcookie.init(clientVars.cookiePrefsToSet); - + padcookie.init(clientVars.cookiePrefsToSet, this); + $("#widthprefcheck").click(pad.toggleWidthPref); - $("#sidebarcheck").click(pad.toggleSidebar); + // $("#sidebarcheck").click(pad.togglewSidebar); pad.myUserInfo = { userId: clientVars.userId, @@ -474,16 +478,16 @@ var pad = { initialTitle: clientVars.initialTitle, initialPassword: clientVars.initialPassword, guestPolicy: pad.padOptions.guestPolicy - }); - padimpexp.init(); - padsavedrevs.init(clientVars.initialRevisionList); + }, this); + padimpexp.init(this); + 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); padconnectionstatus.init(); - padmodals.init(); + padmodals.init(this); pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, { colorPalette: pad.getColorPalette() @@ -775,15 +779,17 @@ var pad = { padsavedrevs.handleIsFullyConnected(isConnected); - pad.determineSidebarVisibility(isConnected && !isInitialConnect); + // pad.determineSidebarVisibility(isConnected && !isInitialConnect); + pad.determineChatVisibility(isConnected && !isInitialConnect); + }, - determineSidebarVisibility: function(asNowConnectedFeedback) +/* determineSidebarVisibility: function(asNowConnectedFeedback) { if (pad.isFullyConnected()) { 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); } @@ -793,6 +799,17 @@ var pad = { $("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) { if (action == "commitPerformed") @@ -841,6 +858,7 @@ var pad = { $("#widthprefcheck").toggleClass('widthprefchecked', !! newValue).toggleClass('widthprefunchecked', !newValue); pad.handleWidthChange(); }, +/* toggleSidebar: function() { var newValue = !padcookie.getPref('hideSidebar'); @@ -848,6 +866,7 @@ var pad = { $("#sidebarcheck").toggleClass('sidebarchecked', !newValue).toggleClass('sidebarunchecked', !! newValue); pad.determineSidebarVisibility(); }, +*/ handleWidthChange: function() { var isFullWidth = padcookie.getPref('fullWidth'); @@ -967,6 +986,21 @@ var alertBar = (function() 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.createCookie = createCookie; exports.readCookie = readCookie; @@ -976,4 +1010,5 @@ exports.getUrlVars = getUrlVars; exports.savePassword = savePassword; exports.handshake = handshake; exports.pad = pad; +exports.init = init; exports.alertBar = alertBar; diff --git a/static/js/pad_cookie.js b/static/js/pad_cookie.js index 24dc1e3fa..1bb5700ad 100644 --- a/static/js/pad_cookie.js +++ b/static/js/pad_cookie.js @@ -87,9 +87,9 @@ var padcookie = (function() var pad = undefined; var self = { - init: function(prefsToSet) + init: function(prefsToSet, _pad) { - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). + pad = _pad; var rawCookie = getRawCookie(); if (rawCookie) diff --git a/static/js/pad_docbar.js b/static/js/pad_docbar.js index cf461c93d..b83bf3bfe 100644 --- a/static/js/pad_docbar.js +++ b/static/js/pad_docbar.js @@ -118,9 +118,9 @@ var paddocbar = (function() var self = { title: null, password: null, - init: function(opts) + init: function(opts, _pad) { - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). + pad = _pad; panels = { impexp: { diff --git a/static/js/pad_editbar.js b/static/js/pad_editbar.js index d542b05d7..e6ff9adf7 100644 --- a/static/js/pad_editbar.js +++ b/static/js/pad_editbar.js @@ -108,17 +108,20 @@ var padeditbar = (function() { self.toogleDropDown("users"); } + else if (cmd == 'settings') + { + self.toogleDropDown("settingsmenu"); + } else if (cmd == 'embed') { self.setEmbedLinks(); - $('#embedinput').focus().select(); + $('#linkinput').focus().select(); self.toogleDropDown("embed"); } else if (cmd == 'import_export') { self.toogleDropDown("importexport"); } - else if (cmd == 'save') { padsavedrevs.saveNow(); @@ -165,7 +168,7 @@ var padeditbar = (function() }, toogleDropDown: function(moduleName) { - var modules = ["embed", "users", "readonly", "importexport"]; + var modules = ["embed", "users", "readonly", "importexport", "settingsmenu"]; //hide all modules if(moduleName == "none") diff --git a/static/js/pad_editor.js b/static/js/pad_editor.js index bb775e957..6d3cbf409 100644 --- a/static/js/pad_editor.js +++ b/static/js/pad_editor.js @@ -32,11 +32,11 @@ var padeditor = (function() ace: null, // this is accessed directly from other files viewZoom: 100, - init: function(readyFunc, initialViewOptions) + init: function(readyFunc, initialViewOptions, _pad) { Ace2Editor = require('/ace').Ace2Editor; - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). - settings = require('/pad2').settings; + pad = _pad; + settings = pad.settings; function aceReady() { @@ -87,6 +87,11 @@ var padeditor = (function() if (value == "false") return false; return defaultValue; } + + self.ace.setProperty("showsauthorcolors", settings.noColors); + + self.ace.setProperty("rtlIsTrue", settings.rtlIsTrue); + var v; v = getOption('showLineNumbers', true); @@ -100,10 +105,6 @@ var padeditor = (function() v = getOption('useMonospaceFont', false); self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif")); $("#viewfontmenu").val(v ? "monospace" : "normal"); - - self.ace.setProperty("showsauthorcolors", settings.noColors); - - self.ace.setProperty("rtlIsTrue", settings.rtlIsTrue); }, initViewZoom: function() { diff --git a/static/js/pad_impexp.js b/static/js/pad_impexp.js index aa99541ea..0037195f2 100644 --- a/static/js/pad_impexp.js +++ b/static/js/pad_impexp.js @@ -236,13 +236,9 @@ var padimpexp = (function() ///// var pad = undefined; var self = { - init: function() + init: function(_pad) { - try { - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). - } catch (e) { - // skip (doesn't require pad when required by timeslider) - } + pad = _pad; //get /p/padname var pad_root_path = new RegExp(/.*\/p\/[^\/]+/).exec(document.location.pathname) diff --git a/static/js/pad_modals.js b/static/js/pad_modals.js index 81ef0776b..b78e28f40 100644 --- a/static/js/pad_modals.js +++ b/static/js/pad_modals.js @@ -75,9 +75,9 @@ var padmodals = (function() var pad = undefined; var self = { - init: function() + init: function(_pad) { - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). + pad = _pad; self.initFeedback(); self.initShareBox(); diff --git a/static/js/pad_savedrevs.js b/static/js/pad_savedrevs.js index bb52658b2..6d37dfa81 100644 --- a/static/js/pad_savedrevs.js +++ b/static/js/pad_savedrevs.js @@ -349,9 +349,9 @@ var padsavedrevs = (function() var pad = undefined; 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); $("#savedrevs-savenow").click(function() diff --git a/static/js/pad_userlist.js b/static/js/pad_userlist.js index e0a12f838..2c063d74c 100644 --- a/static/js/pad_userlist.js +++ b/static/js/pad_userlist.js @@ -464,9 +464,9 @@ var paduserlist = (function() var pad = undefined; var self = { - init: function(myInitialUserInfo) + init: function(myInitialUserInfo, _pad) { - pad = require('/pad2').pad; // Sidestep circular dependency (should be injected). + pad = _pad; self.setMyUserInfo(myInitialUserInfo); diff --git a/static/js/pad_utils.js b/static/js/pad_utils.js index aa469d87b..071185a80 100644 --- a/static/js/pad_utils.js +++ b/static/js/pad_utils.js @@ -34,7 +34,7 @@ var padutils = { }, uniqueId: function() { - var pad = require('/pad2').pad; // Sidestep circular dependency + var pad = require('/pad').pad; // Sidestep circular dependency function encodeNum(n, width) { // returns string that is exactly 'width' chars, padding with zeros @@ -110,24 +110,6 @@ var padutils = { var x = ua.split(' ')[0]; 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" simpleDateTime: function(date) { @@ -227,7 +209,7 @@ var padutils = { }, timediff: function(d) { - var pad = require('/pad2').pad; // Sidestep circular dependency + var pad = require('/pad').pad; // Sidestep circular dependency function format(n, word) { n = Math.round(n); @@ -477,16 +459,26 @@ var padutils = { } }; -//send javascript errors to the server -window.onerror = function test (msg, url, linenumber) -{ - var errObj = {errorInfo: JSON.stringify({msg: msg, url: url, linenumber: linenumber, userAgent: navigator.userAgent})}; - var loc = document.location; - var url = loc.protocol + "//" + loc.hostname + ":" + loc.port + "/" + loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "jserror"; +var globalExceptionHandler = undefined; +function setupGlobalExceptionHandler() { + //send javascript errors to the server + if (!globalExceptionHandler) { + globalExceptionHandler = function test (msg, url, linenumber) + { + var errObj = {errorInfo: JSON.stringify({msg: msg, url: url, linenumber: linenumber, userAgent: navigator.userAgent})}; + var loc = document.location; + var url = loc.protocol + "//" + loc.hostname + ":" + loc.port + "/" + loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "jserror"; - $.post(url, errObj); + $.post(url, errObj); - return false; -}; + return false; + }; + window.onerror = globalExceptionHandler; + } +} + +padutils.setupGlobalExceptionHandler = setupGlobalExceptionHandler; + +padutils.binarySearch = require('/ace2_common').binarySearch; exports.padutils = padutils; diff --git a/static/js/timeslider.js b/static/js/timeslider.js new file mode 100644 index 000000000..939c4c642 --- /dev/null +++ b/static/js/timeslider.js @@ -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; iYou have no permission to access this pad") + } + }); + + //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; diff --git a/static/pad.html b/static/pad.html index 4b4b42261..e2e4690c2 100644 --- a/static/pad.html +++ b/static/pad.html @@ -1,350 +1,311 @@ - - - - - Etherpad Lite - - - - - - - - - - - - + - + Etherpad Lite -
      + + + - + + + - +
      + + +
      -
      +
      +
      +
      +
      +
      + Save + Cancel + +
      +
      +
      +
      +
      +
      +
      + + +
      +
      +
      +
      +
      -
      -
      - -
      +
      +
      +
      Loading...
      +
      -
      - -
      -
      - - - Save - - - Cancel - - -
      + -
      -
      -
      -
      - -
      -
      - - - - - -
      -
      - -
      -
      -
      - -
      - -
      - -
      - - - - + -
      +
      -
      - -
      -
      - Loading... -
      +
      + + Chat +
      +
      + 0 +
      -
      +
      +
      Chat
      +
      +
      +
      + +
      +
      +
      - -
      +
       
      -
      - Import from text file, HTML, PDF, Word, ODT or RTF:

      -
      -
      - -
      -
      -
      Successful!
      -
      - - - - - - -
      -
      -
      +
      +
      +
      + +
      +
      +
      +
      Connecting...
      +
      Reestablishing connection...
      +
      +

      Disconnected.

      +

      Opened in another window.

      +

      No Authorization.

      +
      +

      We're having trouble talking to the EtherPad lite synchronization server. You may be connecting through an incompatible firewall or proxy server.

      +
      +
      +

      We were unable to connect to the EtherPad lite synchronization server. This may be due to an incompatibility with your web browser or internet connection.

      +
      +
      +

      You seem to have opened this pad in another browser window. If you'd like to use this window instead, you can reconnect.

      +
      +
      +

      Lost connection with the EtherPad lite synchronization server. This may be due to a loss of network connectivity.

      +
      +
      +

      Server not responding. This may be due to network connectivity issues or high load on the server.

      +
      +
      +

      Your browser's credentials or permissions have changed while viewing this pad. Try reconnecting.

      +
      +
      +

      This pad was deleted.

      +
      +
      +

      If this continues to happen, please let us know

      +
      +
      + +
      +
      +
      + +
      + +
      -
      + - - + (function () { + require('/pad').init(); + }()); + + diff --git a/static/timeslider.html b/static/timeslider.html index 4e85047e3..cbcb3e366 100644 --- a/static/timeslider.html +++ b/static/timeslider.html @@ -15,163 +15,6 @@ - - @@ -293,18 +136,11 @@ Return to pad -
      @@ -352,7 +188,7 @@
      -
      +
      + +