diff --git a/bin/checkPad.js b/bin/checkPad.js index e77224e2e..a46c18140 100644 --- a/bin/checkPad.js +++ b/bin/checkPad.js @@ -4,7 +4,7 @@ if(process.argv.length != 3) { - console.error("Use: node checkPad.js $PADID"); + console.error("Use: node bin/checkPad.js $PADID"); process.exit(1); } //get the padID diff --git a/src/node/handler/APIHandler.js b/src/node/handler/APIHandler.js index d4d7d6ce4..98b1ed165 100644 --- a/src/node/handler/APIHandler.js +++ b/src/node/handler/APIHandler.js @@ -29,12 +29,12 @@ var randomString = require('ep_etherpad-lite/static/js/pad_utils').randomString; var apikey = null; try { - apikey = fs.readFileSync("../APIKEY.txt","utf8"); + apikey = fs.readFileSync("./APIKEY.txt","utf8"); } catch(e) { apikey = randomString(32); - fs.writeFileSync("../APIKEY.txt",apikey,"utf8"); + fs.writeFileSync("./APIKEY.txt",apikey,"utf8"); } //a list of all functions diff --git a/src/node/server.js b/src/node/server.js old mode 100644 new mode 100755 index 9d2c52e44..4eb38ea7a --- a/src/node/server.js +++ b/src/node/server.js @@ -1,3 +1,4 @@ +#!/usr/bin/env node /** * This module is started with bin/run.sh. It sets up a Express HTTP and a Socket.IO Server. * Static file Requests are answered directly from this module, Socket.IO messages are passed @@ -65,9 +66,9 @@ async.waterfall([ plugins.update, function (callback) { - console.log("Installed plugins: " + plugins.formatPlugins()); - console.log("Installed parts:\n" + plugins.formatParts()); - console.log("Installed hooks:\n" + plugins.formatHooks()); + console.info("Installed plugins: " + plugins.formatPlugins()); + console.debug("Installed parts:\n" + plugins.formatParts()); + console.debug("Installed hooks:\n" + plugins.formatHooks()); callback(); }, @@ -88,12 +89,12 @@ async.waterfall([ //let the server listen app.listen(settings.port, settings.ip); - console.log("Server is listening at " + settings.ip + ":" + settings.port); + console.log("You can access your Etherpad-Lite instance at http://" + settings.ip + ":" + settings.port + "/"); if(!_.isEmpty(settings.users)){ - console.log("Plugin admin page listening at " + settings.ip + ":" + settings.port + "/admin/plugins"); + console.log("The plugin admin page is at http://" + settings.ip + ":" + settings.port + "/admin/plugins"); } else{ - console.log("Admin username and password not set in settings.json. To access admin please uncomment and edit 'users' in settings.json"); + console.warn("Admin username and password not set in settings.json. To access admin please uncomment and edit 'users' in settings.json"); } callback(null); } diff --git a/src/node/utils/Minify.js.rej b/src/node/utils/Minify.js.rej deleted file mode 100644 index f09f49dc7..000000000 --- a/src/node/utils/Minify.js.rej +++ /dev/null @@ -1,513 +0,0 @@ -/** - * This Module manages all /minified/* requests. It controls the - * minification && compression of Javascript and CSS. - */ - -/* - * 2011 Peter 'Pita' Martischka (Primary Technology Ltd) - * - * 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. - */ - -var ERR = require("async-stacktrace"); -var settings = require('./Settings'); -var async = require('async'); -var fs = require('fs'); -var cleanCSS = require('clean-css'); -var jsp = require("uglify-js").parser; -var pro = require("uglify-js").uglify; -var path = require('path'); -var RequireKernel = require('require-kernel'); -var server = require('../server'); - -<<<<<<< HEAD -var ROOT_DIR = path.normalize(__dirname + "/../" ); -var JS_DIR = ROOT_DIR + '../static/js/'; -var CSS_DIR = ROOT_DIR + '../static/css/'; -var CACHE_DIR = path.join(settings.root, 'var'); -======= -var ROOT_DIR = path.normalize(__dirname + "/../../static/"); ->>>>>>> pita -var TAR_PATH = path.join(__dirname, 'tar.json'); -var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8')); - -// Rewrite tar to include modules with no extensions and proper rooted paths. -exports.tar = {}; -for (var key in tar) { - exports.tar['/' + key] = - tar[key].map(function (p) {return '/' + p}).concat( - tar[key].map(function (p) {return '/' + p.replace(/\.js$/, '')}) - ); -} - -/** - * creates the minifed javascript for the given minified name - * @param req the Express request - * @param res the Express response - */ -exports.minify = function(req, res, next) -{ -<<<<<<< HEAD - var jsFilename = req.params[0]; - - //choose the js files we need - var jsFiles = undefined; - if (Object.prototype.hasOwnProperty.call(tar, jsFilename)) { - jsFiles = tar[jsFilename]; - } else { - /* Not in tar list, but try anyways, if it fails, pass to `next`. - Actually try, not check in filesystem here because - we don't want to duplicate the require.resolve() handling - */ - jsFiles = [jsFilename]; - } - _handle(req, res, jsFilename, jsFiles, function (err) { - console.log("Unable to load minified file " + jsFilename + ": " + err.toString()); - /* Throw away error and generate a 404, not 500 */ - next(); - }); -} - -function _handle(req, res, jsFilename, jsFiles, next) { - res.header("Content-Type","text/javascript"); - - var cacheName = CACHE_DIR + "/minified_" + jsFilename.replace(/\//g, "_"); - - //minifying is enabled - if(settings.minify) - { - var result = undefined; - var latestModification = 0; - - async.series([ - //find out the highest modification date - function(callback) - { - var folders2check = [CSS_DIR, JS_DIR]; - - //go trough this two folders - async.forEach(folders2check, function(path, callback) - { - //read the files in the folder - fs.readdir(path, function(err, files) - { - if(ERR(err, callback)) return; - - //we wanna check the directory itself for changes too - files.push("."); - - //go trough all files in this folder - async.forEach(files, function(filename, callback) - { - //get the stat data of this file - fs.stat(path + "/" + filename, function(err, stats) - { - if(ERR(err, callback)) return; - - //get the modification time - var modificationTime = stats.mtime.getTime(); - - //compare the modification time to the highest found - if(modificationTime > latestModification) - { - latestModification = modificationTime; - } - - callback(); - }); - }, callback); - }); - }, callback); - }, - function(callback) - { - //check the modification time of the minified js - fs.stat(cacheName, function(err, stats) - { - if(err && err.code != "ENOENT") - { - ERR(err, callback); - return; - } - - //there is no minfied file or there new changes since this file was generated, so continue generating this file - if((err && err.code == "ENOENT") || stats.mtime.getTime() < latestModification) - { - callback(); - } - //the minified file is still up to date, stop minifying - else - { - callback("stop"); - } - }); - }, - //load all js files - function (callback) - { - var values = []; - tarCode( - jsFiles - , function (content) {values.push(content)} - , function (err) { - if(ERR(err, next)) return; - - result = values.join(''); - callback(); - }); - }, - //put all together and write it into a file - function(callback) - { - async.parallel([ - //write the results plain in a file - function(callback) - { - fs.writeFile(cacheName, result, "utf8", callback); - }, - //write the results compressed in a file - function(callback) - { - 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; - - fs.writeFile(cacheName + ".gz", compressedResult, callback); - }); - } - ],callback); - } - ], function(err) - { - if(err && err != "stop") - { - if(ERR(err)) return; - } - - //check if gzip is supported by this browser - var gzipSupport = req.header('Accept-Encoding', '').indexOf('gzip') != -1; - - var pathStr; - if(gzipSupport && os.type().indexOf("Windows") == -1) - { - pathStr = path.normalize(cacheName + ".gz"); - res.header('Content-Encoding', 'gzip'); - } - else - { - pathStr = path.normalize(cacheName); - } - - res.sendfile(pathStr, { maxAge: server.maxAge }); - }) - } - //minifying is disabled, so put the files together in one file - else - { - tarCode( - jsFiles - , function (content) {res.write(content)} - , function (err) { - if(ERR(err, next)) return; -======= - var filename = req.params['filename']; - - // No relative paths, especially if they may go up the file hierarchy. - filename = path.normalize(path.join(ROOT_DIR, filename)); - if (filename.indexOf(ROOT_DIR) == 0) { - filename = filename.slice(ROOT_DIR.length); - filename = filename.replace(/\\/g, '/'); // Windows (safe generally?) - } else { - res.writeHead(404, {}); - res.end(); - return; - } - - // What content type should this be? - // TODO: This should use a MIME module. - var contentType; - if (filename.match(/\.js$/)) { - contentType = "text/javascript"; - } else if (filename.match(/\.css$/)) { - contentType = "text/css"; - } else if (filename.match(/\.html$/)) { - contentType = "text/html"; - } else if (filename.match(/\.txt$/)) { - contentType = "text/plain"; - } else if (filename.match(/\.png$/)) { - contentType = "image/png"; - } else if (filename.match(/\.gif$/)) { - contentType = "image/gif"; - } else if (filename.match(/\.ico$/)) { - contentType = "image/x-icon"; - } else { - contentType = "application/octet-stream"; - } - - statFile(filename, function (error, date, exists) { - if (date) { - date = new Date(date); - res.setHeader('last-modified', date.toUTCString()); - res.setHeader('date', (new Date()).toUTCString()); - if (server.maxAge) { - var expiresDate = new Date((new Date()).getTime()+server.maxAge*1000); - res.setHeader('expires', expiresDate.toUTCString()); - res.setHeader('cache-control', 'max-age=' + server.maxAge); - } - } - - if (error) { - res.writeHead(500, {}); ->>>>>>> pita - res.end(); - } else if (!exists) { - res.writeHead(404, {}); - res.end(); - } else if (new Date(req.headers['if-modified-since']) >= date) { - res.writeHead(304, {}); - res.end(); - } else { - if (req.method == 'HEAD') { - res.header("Content-Type", contentType); - res.writeHead(200, {}); - res.end(); - } else if (req.method == 'GET') { - getFileCompressed(filename, contentType, function (error, content) { - if(ERR(error)) return; - res.header("Content-Type", contentType); - res.writeHead(200, {}); - res.write(content); - res.end(); - }); - } else { - res.writeHead(405, {'allow': 'HEAD, GET'}); - res.end(); - } - } - }); -} - -// find all includes in ace.js and embed them. -function getAceFile(callback) { - fs.readFile(ROOT_DIR + 'js/ace.js', "utf8", function(err, data) { - if(ERR(err, callback)) return; - - // Find all includes in ace.js and embed them - var founds = data.match(/\$\$INCLUDE_[a-zA-Z_]+\("[^"]*"\)/gi); - if (!settings.minify) { - founds = []; - } - // Always include the require kernel. - founds.push('$$INCLUDE_JS("../static/js/require-kernel.js")'); - - data += ';\n'; - data += 'Ace2Editor.EMBEDED = Ace2Editor.EMBEDED || {};\n'; - - // Request the contents of the included file on the server-side and write - // them into the file. - async.forEach(founds, function (item, callback) { - var filename = item.match(/"([^"]*)"/)[1]; - var request = require('request'); - - var baseURI = 'http://localhost:' + settings.port - - request(baseURI + path.normalize(path.join('/static/', filename)), function (error, response, body) { - if (!error && response.statusCode == 200) { - data += 'Ace2Editor.EMBEDED[' + JSON.stringify(filename) + '] = ' - + JSON.stringify(body || '') + ';\n'; - } else { - // Silence? - } - callback(); - }); - }, function(error) { - callback(error, data); - }); - }); -} - -// Check for the existance of the file and get the last modification date. -function statFile(filename, callback) { - if (filename == 'js/ace.js') { - // Sometimes static assets are inlined into this file, so we have to stat - // everything. - lastModifiedDateOfEverything(function (error, date) { - callback(error, date, !error); - }); - } else if (filename == 'js/require-kernel.js') { - callback(null, requireLastModified(), true); - } else { - fs.stat(ROOT_DIR + filename, function (error, stats) { - if (error) { - if (error.code == "ENOENT") { - // Stat the directory instead. - fs.stat(path.dirname(ROOT_DIR + filename), function (error, stats) { - if (error) { - if (error.code == "ENOENT") { - callback(null, null, false); - } else { - callback(error); - } - } else { - callback(null, stats.mtime.getTime(), false); - } - }); - } else { - callback(error); - } - } else { - callback(null, stats.mtime.getTime(), true); - } - }); - } -} -function lastModifiedDateOfEverything(callback) { - var folders2check = [ROOT_DIR + 'js/', ROOT_DIR + 'css/']; - var latestModification = 0; - //go trough this two folders - async.forEach(folders2check, function(path, callback) - { - //read the files in the folder - fs.readdir(path, function(err, files) - { - if(ERR(err, callback)) return; - - //we wanna check the directory itself for changes too - files.push("."); - - //go trough all files in this folder - async.forEach(files, function(filename, callback) - { - //get the stat data of this file - fs.stat(path + "/" + filename, function(err, stats) - { - if(ERR(err, callback)) return; - - //get the modification time - var modificationTime = stats.mtime.getTime(); - - //compare the modification time to the highest found - if(modificationTime > latestModification) - { - latestModification = modificationTime; - } - - callback(); - }); - }, callback); - }); - }, function () { - callback(null, latestModification); - }); -} - -// This should be provided by the module, but until then, just use startup -// time. -var _requireLastModified = new Date(); -function requireLastModified() { - return _requireLastModified.toUTCString(); -} -function requireDefinition() { - return 'var require = ' + RequireKernel.kernelSource + ';\n'; -} - -<<<<<<< HEAD -function tarCode(jsFiles, write, callback) { - write('require.define({'); - var initialEntry = true; - async.forEach(jsFiles, function (filename, callback){ - var path; - var srcPath; - if (filename.indexOf('plugins/') == 0) { - srcPath = filename.substring('plugins/'.length); - path = require.resolve(srcPath); - } else { - srcPath = '/' + filename; - path = JS_DIR + filename; - } - - srcPath = JSON.stringify(srcPath); - var srcPathAbbv = JSON.stringify(srcPath.replace(/\.js$/, '')); - - if (filename == 'ace.js') { - getAceFile(handleFile); - } else { - fs.readFile(path, "utf8", handleFile); - } - - function handleFile(err, data) { - if(ERR(err, callback)) return; - - if (!initialEntry) { - write('\n,'); - } else { - initialEntry = false; - } - write(srcPath + ': ') - data = '(function (require, exports, module) {' + data + '})'; -======= -function getFileCompressed(filename, contentType, callback) { - getFile(filename, function (error, content) { - if (error || !content) { - callback(error, content); - } else { ->>>>>>> pita - if (settings.minify) { - if (contentType == 'text/javascript') { - try { - content = compressJS([content]); - } catch (error) { - // silence - } - } else if (contentType == 'text/css') { - content = compressCSS([content]); - } - } - callback(null, content); - } -<<<<<<< HEAD - }, function (err) { - if(ERR(err, callback)) return; - write('});\n'); - callback(); -======= ->>>>>>> pita - }); -} - -function getFile(filename, callback) { - if (filename == 'js/ace.js') { - getAceFile(callback); - } else if (filename == 'js/require-kernel.js') { - callback(undefined, requireDefinition()); - } else { - fs.readFile(ROOT_DIR + filename, callback); - } -} - -function compressJS(values) -{ - var complete = values.join("\n"); - var ast = jsp.parse(complete); // parse code and get the initial AST - ast = pro.ast_mangle(ast); // get a new AST with mangled names - ast = pro.ast_squeeze(ast); // get an AST with compression optimizations - return pro.gen_code(ast); // compressed code here -} - -function compressCSS(values) -{ - var complete = values.join("\n"); - return cleanCSS.process(complete); -} diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index cb6a64033..e60446df4 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -44,7 +44,7 @@ exports.dbType = "dirty"; /** * This setting is passed with dbType to ueberDB to set up the database */ -exports.dbSettings = { "filename" : path.join(exports.root, "var/dirty.db") }; +exports.dbSettings = { "filename" : path.join(exports.root, "dirty.db") }; /** * The default Text of a new pad */ @@ -106,9 +106,15 @@ if (settingsFilename.charAt(0) != '/') { settingsFilename = path.normalize(path.join(root, settingsFilename)); } -//read the settings sync -var settingsStr = fs.readFileSync(settingsFilename).toString(); - +var settingsStr +try{ + //read the settings sync + settingsStr = fs.readFileSync(settingsFilename).toString(); +} catch(e){ + console.warn('No settings file found. Using defaults.'); + settingsStr = '{}'; +} + //remove all comments settingsStr = settingsStr.replace(/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/gm,"").replace(/#.*/g,"").replace(/\/\/.*/g,""); @@ -146,3 +152,7 @@ for(var i in settings) console.warn("This setting doesn't exist or it was removed"); } } + +if(exports.dbType === "dirty"){ + console.warn("DirtyDB is used. This is fine for testing but not recommended for production.") +} diff --git a/src/node/utils/tar.json b/src/node/utils/tar.json index 5c1abac5d..e691334dc 100644 --- a/src/node/utils/tar.json +++ b/src/node/utils/tar.json @@ -6,7 +6,6 @@ , "pad.js" , "ace2_common.js" , "pad_utils.js" - , "undo-xpopup.js" , "json2.js" , "pad_cookie.js" , "pad_editor.js" @@ -27,7 +26,6 @@ "jquery.js" , "underscore.js" , "security.js" - , "undo-xpopup.js" , "json2.js" , "colorutils.js" , "draggable.js" diff --git a/src/package.json b/src/package.json index ac56bc358..0b76ec2ed 100644 --- a/src/package.json +++ b/src/package.json @@ -14,7 +14,7 @@ "request" : "2.9.100", "require-kernel" : "1.0.5", "resolve" : "0.2.1", - "socket.io" : "0.8.7", + "socket.io" : "0.9.6", "ueberDB" : "0.1.7", "async" : "0.1.18", "express" : "2.5.8", @@ -32,6 +32,7 @@ "semver" : "1.0.13", "underscore" : "1.3.1" }, + "bin": { "etherpad-lite": "./node/server.js" }, "devDependencies": { "jshint" : "*" }, diff --git a/src/static/css/pad.css b/src/static/css/pad.css index e052c3293..40089bbfb 100644 --- a/src/static/css/pad.css +++ b/src/static/css/pad.css @@ -883,15 +883,6 @@ down on the page in IE. Strange but it works! */ line-height: 18px; padding: 2px; } -#sharebox-send { - float: right; - background-repeat: no-repeat; - background-image: url(static/img/sharebox4.gif); - display: block; - width: 87px; - height: 22px; - background-position: -383px -289px; -} #viewbarcontents { display: none } @@ -903,9 +894,7 @@ down on the page in IE. Strange but it works! */ line-height: 20px; width: auto; } -#viewzoommenu { - width: 65px -} + #bottomarea { height: 28px; overflow: hidden; @@ -949,17 +938,7 @@ down on the page in IE. Strange but it works! */ .sidebarchecked { background-position: -1px -67px } -#feedbackbutton { - display: block; - position: absolute; - width: 68px; - height: 0; - padding-top: 17px; - overflow: hidden; - background: url(static/img/bottomareagfx.gif); - top: 5px; - right: 220px; -} + #modaloverlay { z-index: 500; display: none; diff --git a/src/static/js/ace.js b/src/static/js/ace.js index 85801d33e..0003eedf2 100644 --- a/src/static/js/ace.js +++ b/src/static/js/ace.js @@ -245,14 +245,6 @@ require.setGlobalKeyPath("require");\n\ iframeHTML: iframeHTML }); - // For compatability's sake transform in and out. - for (var i = 0, ii = iframeHTML.length; i < ii; i++) { - iframeHTML[i] = JSON.stringify(iframeHTML[i]); - } - for (var i = 0, ii = iframeHTML.length; i < ii; i++) { - iframeHTML[i] = JSON.parse(iframeHTML[i]); - } - // calls to these functions ($$INCLUDE_...) are replaced when this file is processed // and compressed, putting the compressed code from the named file directly into the // source here. diff --git a/src/static/js/ace2_inner.js b/src/static/js/ace2_inner.js index 6e5f07bcb..723d410f2 100644 --- a/src/static/js/ace2_inner.js +++ b/src/static/js/ace2_inner.js @@ -166,12 +166,10 @@ function Ace2Inner(){ } var dynamicCSS = null; - var dynamicCSSTop = null; function initDynamicCSS() { dynamicCSS = makeCSSManager("dynamicsyntax"); - dynamicCSSTop = makeCSSManager("dynamicsyntax", true); } var changesetTracker = makeChangesetTracker(scheduler, rep.apool, { @@ -214,7 +212,6 @@ function Ace2Inner(){ if (dynamicCSS) { dynamicCSS.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author))); - dynamicCSSTop.removeSelectorStyle(getAuthorColorClassSelector(getAuthorClassName(author))); } } else @@ -232,23 +229,18 @@ function Ace2Inner(){ var authorStyle = dynamicCSS.selectorStyle(getAuthorColorClassSelector( getAuthorClassName(author))); - var authorStyleTop = dynamicCSSTop.selectorStyle(getAuthorColorClassSelector( - getAuthorClassName(author))); var anchorStyle = dynamicCSS.selectorStyle(getAuthorColorClassSelector( getAuthorClassName(author))+' > a') // author color authorStyle.backgroundColor = bgcolor; - authorStyleTop.backgroundColor = bgcolor; // text contrast if(colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5) { authorStyle.color = '#ffffff'; - authorStyleTop.color = '#ffffff'; }else{ authorStyle.color = null; - authorStyleTop.color = null; } // anchor text contrast @@ -3749,24 +3741,6 @@ function Ace2Inner(){ setSelection(selection); } - function getRepHTML() - { - return _.map(rep.lines.slice(), function(entry) - { - var text = entry.text; - var content; - if (text.length === 0) - { - content = '--'; - } - else - { - content = htmlPrettyEscape(text); - } - return '
' + content + '