diff --git a/.gitignore b/.gitignore index 50cd6e21..32f9ea7d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ node_modules settings.json -static/js/jquery.min.js +static/js/jquery.js APIKEY.txt bin/abiword.exe bin/node.exe diff --git a/bin/installDeps.sh b/bin/installDeps.sh index 0533caf2..a3f767a2 100755 --- a/bin/installDeps.sh +++ b/bin/installDeps.sh @@ -48,8 +48,8 @@ npm install || { echo "Ensure jQuery is downloaded and up to date..." DOWNLOAD_JQUERY="true" NEEDED_VERSION="1.7" -if [ -f "static/js/jquery.min.js" ]; then - VERSION=$(cat static/js/jquery.min.js | head -n 3 | grep -o "v[0-9].[0-9]"); +if [ -f "static/js/jquery.js" ]; then + VERSION=$(cat static/js/jquery.js | head -n 3 | grep -o "v[0-9].[0-9]"); if [ ${VERSION#v} = $NEEDED_VERSION ]; then DOWNLOAD_JQUERY="false" @@ -57,7 +57,7 @@ if [ -f "static/js/jquery.min.js" ]; then fi if [ $DOWNLOAD_JQUERY = "true" ]; then - curl -lo static/js/jquery.min.js http://code.jquery.com/jquery-$NEEDED_VERSION.min.js || exit 1 + curl -lo static/js/jquery.js http://code.jquery.com/jquery-$NEEDED_VERSION.js || exit 1 fi #Remove all minified data to force node creating it new diff --git a/node/server.js b/node/server.js index 50f48633..422bbe12 100644 --- a/node/server.js +++ b/node/server.js @@ -78,7 +78,12 @@ async.waterfall([ { //create server var app = express.createServer(); - + + app.use(function (req, res, next) { + res.header("Server", serverName); + next(); + }); + //load modules that needs a initalized db readOnlyManager = require("./db/ReadOnlyManager"); exporthtml = require("./utils/ExportHtml"); @@ -112,28 +117,13 @@ async.waterfall([ //serve static files app.get('/static/*', function(req, res) { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/.." + req.url.replace(/\.\./g, '').split("?")[0]); res.sendfile(filePath, { maxAge: exports.maxAge }); }); //serve minified files - app.get('/minified/:id', function(req, res, next) - { - res.header("Server", serverName); - - var id = req.params.id; - - if(id == "pad.js" || id == "timeslider.js") - { - minify.minifyJS(req,res,id); - } - else - { - next(); - } - }); + app.get('/minified/:filename', minify.minifyJS); //checks for padAccess function hasPadAccess(req, res, callback) @@ -178,8 +168,6 @@ async.waterfall([ //serve read only pad app.get('/ro/:id', function(req, res) { - res.header("Server", serverName); - var html; var padId; var pad; @@ -264,7 +252,6 @@ async.waterfall([ app.get('/p/:pad', function(req, res, next) { goToPad(req, res, function() { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/../static/pad.html"); res.sendfile(filePath, { maxAge: exports.maxAge }); }); @@ -274,7 +261,6 @@ async.waterfall([ app.get('/p/:pad/timeslider', function(req, res, next) { goToPad(req, res, function() { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/../static/timeslider.html"); res.sendfile(filePath, { maxAge: exports.maxAge }); }); @@ -301,7 +287,6 @@ async.waterfall([ } res.header("Access-Control-Allow-Origin", "*"); - res.header("Server", serverName); hasPadAccess(req, res, function() { @@ -321,8 +306,6 @@ async.waterfall([ return; } - res.header("Server", serverName); - hasPadAccess(req, res, function() { importHandler.doImport(req, res, req.params.pad); @@ -335,7 +318,6 @@ async.waterfall([ //This is for making an api call, collecting all post information and passing it to the apiHandler var apiCaller = function(req, res, fields) { - res.header("Server", serverName); res.header("Content-Type", "application/json; charset=utf-8"); apiLogger.info("REQUEST, " + req.params.func + ", " + JSON.stringify(fields)); @@ -396,7 +378,6 @@ async.waterfall([ //serve index.html under / app.get('/', function(req, res) { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/../static/index.html"); res.sendfile(filePath, { maxAge: exports.maxAge }); }); @@ -404,7 +385,6 @@ async.waterfall([ //serve robots.txt app.get('/robots.txt', function(req, res) { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/../static/robots.txt"); res.sendfile(filePath, { maxAge: exports.maxAge }); }); @@ -412,7 +392,6 @@ async.waterfall([ //serve favicon.ico app.get('/favicon.ico', function(req, res) { - res.header("Server", serverName); var filePath = path.normalize(__dirname + "/../static/custom/favicon.ico"); res.sendfile(filePath, { maxAge: exports.maxAge }, function(err) { diff --git a/node/utils/Minify.js b/node/utils/Minify.js index 3477cd01..1a214fb9 100644 --- a/node/utils/Minify.js +++ b/node/utils/Minify.js @@ -32,6 +32,10 @@ var gzip = require('gzip'); var server = require('../server'); var os = require('os'); +var ROOT_DIR = path.normalize(__dirname + "/../" ); +var JS_DIR = ROOT_DIR + '../static/js/'; +var CSS_DIR = ROOT_DIR + '../static/css/'; +var CACHE_DIR = ROOT_DIR + '../var/'; var TAR_PATH = path.join(__dirname, 'tar.json'); var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8')); @@ -40,20 +44,20 @@ var tar = JSON.parse(fs.readFileSync(TAR_PATH, 'utf8')); * @param req the Express request * @param res the Express response */ -exports.minifyJS = function(req, res, jsFilename) +exports.minifyJS = function(req, res, next) { - res.header("Content-Type","text/javascript"); + var jsFilename = req.params['filename']; //choose the js files we need var jsFiles = undefined; if (Object.prototype.hasOwnProperty.call(tar, jsFilename)) { jsFiles = tar[jsFilename]; } else { - throw new Error("there is no profile for creating " + name); + return next(); } - var rootPath = path.normalize(__dirname + "/../../" ); - + res.header("Content-Type","text/javascript"); + //minifying is enabled if(settings.minify) { @@ -65,7 +69,7 @@ exports.minifyJS = function(req, res, jsFilename) //find out the highest modification date function(callback) { - var folders2check = [rootPath + "static/css", rootPath + "static/js"]; + var folders2check = [CSS_DIR, JS_DIR]; //go trough this two folders async.forEach(folders2check, function(path, callback) @@ -104,7 +108,7 @@ exports.minifyJS = function(req, res, jsFilename) function(callback) { //check the modification time of the minified js - fs.stat(rootPath + "var/minified_" + jsFilename, function(err, stats) + fs.stat(CACHE_DIR + "/minified_" + jsFilename, function(err, stats) { if(err && err.code != "ENOENT") { @@ -129,7 +133,7 @@ exports.minifyJS = function(req, res, jsFilename) { async.forEach(jsFiles, function (item, callback) { - fs.readFile(rootPath + "static/js/" + item, "utf-8", function(err, data) + fs.readFile(JS_DIR + item, "utf-8", function(err, data) { if(ERR(err, callback)) return; fileValues[item] = data; @@ -158,7 +162,7 @@ exports.minifyJS = function(req, res, jsFilename) var type = item.match(/INCLUDE_[A-Z]+/g)[0].substr("INCLUDE_".length); //read the included file - fs.readFile(filename, "utf-8", function(err, data) + fs.readFile(ROOT_DIR + filename, "utf-8", function(err, data) { if(ERR(err, callback)) return; @@ -207,7 +211,7 @@ exports.minifyJS = function(req, res, jsFilename) //write the results plain in a file function(callback) { - fs.writeFile(rootPath + "var/minified_" + jsFilename, result, "utf8", callback); + fs.writeFile(CACHE_DIR + "minified_" + jsFilename, result, "utf8", callback); }, //write the results compressed in a file function(callback) @@ -221,7 +225,7 @@ exports.minifyJS = function(req, res, jsFilename) if(ERR(err, callback)) return; - fs.writeFile(rootPath + "var/minified_" + jsFilename + ".gz", compressedResult, callback); + fs.writeFile(CACHE_DIR + "minified_" + jsFilename + ".gz", compressedResult, callback); }); } //skip this step on windows @@ -245,12 +249,12 @@ exports.minifyJS = function(req, res, jsFilename) var pathStr; if(gzipSupport && os.type().indexOf("Windows") == -1) { - pathStr = path.normalize(rootPath + "var/minified_" + jsFilename + ".gz"); + pathStr = path.normalize(CACHE_DIR + "minified_" + jsFilename + ".gz"); res.header('Content-Encoding', 'gzip'); } else { - pathStr = path.normalize(rootPath + "var/minified_" + jsFilename ); + pathStr = path.normalize(CACHE_DIR + "minified_" + jsFilename ); } res.sendfile(pathStr, { maxAge: server.maxAge }); @@ -264,7 +268,7 @@ exports.minifyJS = function(req, res, jsFilename) //read all js files async.forEach(jsFiles, function (item, callback) { - fs.readFile(rootPath + "static/js/" + item, "utf-8", function(err, data) + fs.readFile(JS_DIR + item, "utf-8", function(err, data) { if(ERR(err, callback)) return; fileValues[item] = data; diff --git a/node/utils/tar.json b/node/utils/tar.json index 7cb60694..3b1ba63c 100644 --- a/node/utils/tar.json +++ b/node/utils/tar.json @@ -1,6 +1,6 @@ { "pad.js": [ - "jquery.min.js" + "jquery.js" , "pad_utils.js" , "plugins.js" , "undo-xpopup.js" @@ -23,7 +23,7 @@ , "farbtastic.js" ] , "timeslider.js": [ - "jquery.min.js" + "jquery.js" , "plugins.js" , "undo-xpopup.js" , "json2.js" diff --git a/static/js/ace.js b/static/js/ace.js index 2bcf1241..ffe00b07 100644 --- a/static/js/ace.js +++ b/static/js/ace.js @@ -30,7 +30,6 @@ Ace2Editor.registry = { function Ace2Editor() { - var thisFunctionsName = "Ace2Editor"; var ace2 = Ace2Editor; var editor = {}; @@ -323,6 +322,10 @@ function Ace2Editor() iframeHTML.push(''); iframeHTML.push(' '); + // Expose myself to global for my child frame. + var thisFunctionsName = "ChildAccessibleAce2Editor"; + (function () {return this}())[thisFunctionsName] = Ace2Editor; + var outerScript = 'editorId = "' + info.id + '"; editorInfo = parent.' + thisFunctionsName + '.registry[editorId]; ' + 'window.onload = function() ' + '{ window.onload = null; setTimeout' + '(function() ' + '{ var iframe = document.createElement("IFRAME"); ' + 'iframe.scrolling = "no"; var outerdocbody = document.getElementById("outerdocbody"); ' + 'iframe.frameBorder = 0; iframe.allowTransparency = true; ' + // for IE 'outerdocbody.insertBefore(iframe, outerdocbody.firstChild); ' + 'iframe.ace_outerWin = window; ' + 'readyFunc = function() { editorInfo.onEditorReady(); readyFunc = null; editorInfo = null; }; ' + 'var doc = iframe.contentWindow.document; doc.open(); var text = (' + JSON.stringify(iframeHTML.join('\n')) + ');doc.write(text); doc.close(); ' + '}, 0); }'; diff --git a/static/js/ace2_common.js b/static/js/ace2_common.js index 4561b919..1414f855 100644 --- a/static/js/ace2_common.js +++ b/static/js/ace2_common.js @@ -80,14 +80,8 @@ function isArray(testObject) return testObject && typeof testObject === 'object' && !(testObject.propertyIsEnumerable('length')) && typeof testObject.length === 'number'; } -if (typeof exports !== "undefined") -{ - userAgent = "node-js"; -} -else -{ - userAgent = navigator.userAgent.toLowerCase(); -} +var userAgent = (((function () {return this;})().navigator || {}).userAgent || 'node-js').toLowerCase(); + // Figure out what browser is being used (stolen from jquery 1.2.1) var browser = { version: (userAgent.match(/.+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1], diff --git a/static/js/collab_client.js b/static/js/collab_client.js index fafe0fd2..bb2351fc 100644 --- a/static/js/collab_client.js +++ b/static/js/collab_client.js @@ -25,12 +25,20 @@ $(window).bind("load", function() getCollabClient.windowLoaded = true; }); +// Dependency fill on init. This exists for `pad.socket` only. +// TODO: bind directly to the socket. +var pad = undefined; +function getSocket() { + return pad && pad.socket; +} + /** Call this when the document is ready, and a new Ace2Editor() has been created and inited. ACE's ready callback does not need to have fired yet. "serverVars" are from calling doc.getCollabClientVars() on the server. */ -function getCollabClient(ace2editor, serverVars, initialUserInfo, options) +function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad) { var editor = ace2editor; + pad = _pad; // Inject pad to avoid a circular dependency. var rev = serverVars.rev; var padId = serverVars.padId; @@ -81,7 +89,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options) $(window).bind("unload", function() { - if (socket) + if (getSocket()) { setChannelState("DISCONNECTED", "unload"); } @@ -111,7 +119,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options) function handleUserChanges() { - if ((!socket) || channelState == "CONNECTING") + if ((!getSocket()) || channelState == "CONNECTING") { if (channelState == "CONNECTING" && (((+new Date()) - initialStartConnectTime) > 20000)) { @@ -295,7 +303,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options) function sendMessage(msg) { - socket.json.send( + getSocket().json.send( { type: "COLLABROOM", component: "pad", @@ -337,7 +345,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options) { if (window.console) console.log(evt); - if (!socket) return; + if (!getSocket()) return; if (!evt.data) return; var wrapper = evt; if (wrapper.type != "COLLABROOM") return; @@ -442,7 +450,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options) userInfo.userId = userId; userSet[userId] = userInfo; tellAceActiveAuthorInfo(userInfo); - if (!socket) return; + if (!getSocket()) return; sendMessage( { type: "USERINFO_UPDATE", diff --git a/static/js/pad2.js b/static/js/pad2.js index bbb385b3..5872b7a1 100644 --- a/static/js/pad2.js +++ b/static/js/pad2.js @@ -23,12 +23,14 @@ /* global $, window */ var socket; -var LineNumbersDisabled = false; -var noColors = false; -var useMonospaceFontGlobal = false; -var globalUserName = false; -var hideQRCode = false; -var rtlIsTrue = false; + +var settings = {}; +settings.LineNumbersDisabled = false; +settings.noColors = false; +settings.useMonospaceFontGlobal = false; +settings.globalUserName = false; +settings.hideQRCode = false; +settings.rtlIsTrue = false; $(document).ready(function() { @@ -101,7 +103,7 @@ function getParams() { if(IsnoColors == "true") { - noColors = true; + settings.noColors = true; $('#clearAuthorship').hide(); } } @@ -124,20 +126,20 @@ function getParams() { if(showLineNumbers == "false") { - LineNumbersDisabled = true; + settings.LineNumbersDisabled = true; } } if(useMonospaceFont) { if(useMonospaceFont == "true") { - useMonospaceFontGlobal = true; + settings.useMonospaceFontGlobal = true; } } if(userName) { // If the username is set as a parameter we should set a global value that we can call once we have initiated the pad. - globalUserName = unescape(userName); + settings.globalUserName = unescape(userName); } if(hideQRCode) { @@ -147,7 +149,7 @@ function getParams() { if(rtl == "true") { - rtlIsTrue = true + settings.rtlIsTrue = true } } } @@ -183,7 +185,7 @@ function handshake() //find out in which subfolder we are var resource = loc.pathname.substr(1, loc.pathname.indexOf("/p/")) + "socket.io"; //connect - socket = io.connect(url, { + socket = pad.socket = io.connect(url, { resource: resource, 'max reconnection attempts': 3 }); @@ -298,33 +300,33 @@ function handshake() initalized = true; // If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers - if (LineNumbersDisabled == true) + if (settings.LineNumbersDisabled == true) { pad.changeViewOption('showLineNumbers', false); } // If the noColors value is set to true then we need to hide the backround colors on the ace spans - if (noColors == true) + if (settings.noColors == true) { pad.changeViewOption('noColors', true); } - if (rtlIsTrue == true) + if (settings.rtlIsTrue == true) { pad.changeViewOption('rtl', true); } // If the Monospacefont value is set to true then change it to monospace. - if (useMonospaceFontGlobal == true) + if (settings.useMonospaceFontGlobal == true) { pad.changeViewOption('useMonospaceFont', true); } // if the globalUserName value is set we need to tell the server and the client about the new authorname - if (globalUserName !== false) + if (settings.globalUserName !== false) { - pad.notifyChangeName(globalUserName); // Notifies the server - pad.myUserInfo.name = globalUserName; - $('#myusernameedit').attr({"value":globalUserName}); // Updates the current users UI + pad.notifyChangeName(settings.globalUserName); // Notifies the server + pad.myUserInfo.name = settings.globalUserName; + $('#myusernameedit').attr({"value":settings.globalUserName}); // Updates the current users UI } } //This handles every Message after the clientVars @@ -472,7 +474,7 @@ var pad = { pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, { colorPalette: pad.getColorPalette() - }); + }, pad); pad.collabClient.setOnUserJoin(pad.handleUserJoin); pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate); pad.collabClient.setOnUserLeave(pad.handleUserLeave); diff --git a/static/js/pad_editor.js b/static/js/pad_editor.js index 183de948..6daf5e7d 100644 --- a/static/js/pad_editor.js +++ b/static/js/pad_editor.js @@ -68,7 +68,7 @@ var padeditor = (function() pad.changeViewOption('useMonospaceFont', $("#viewfontmenu").val() == 'monospace'); }); - noColors = !noColors; // Inversed so we can pass it to showauthorcolors + settings.noColors = !settings.noColors; // Inversed so we can pass it to showauthorcolors }, setViewOptions: function(newOptions) { @@ -93,9 +93,9 @@ var padeditor = (function() self.ace.setProperty("textface", (v ? "monospace" : "Arial, sans-serif")); $("#viewfontmenu").val(v ? "monospace" : "normal"); - self.ace.setProperty("showsauthorcolors", noColors); + self.ace.setProperty("showsauthorcolors", settings.noColors); - self.ace.setProperty("rtlIsTrue", rtlIsTrue); + self.ace.setProperty("rtlIsTrue", settings.rtlIsTrue); }, initViewZoom: function() { diff --git a/static/js/plugins.js b/static/js/plugins.js index b29d01d4..74193462 100644 --- a/static/js/plugins.js +++ b/static/js/plugins.js @@ -7,7 +7,8 @@ plugins = { callHook: function(hookName, args) { - var hook = clientVars.hooks[hookName]; + var global = (function () {return this}()); + var hook = ((global.clientVars || {}).hooks || {})[hookName]; if (hook === undefined) return []; var res = []; for (var i = 0, N = hook.length; i < N; i++)