summaryrefslogtreecommitdiff
path: root/src/node/utils
diff options
context:
space:
mode:
authorEgil Moeller <egil.moller@freecode.no>2012-03-02 22:02:42 +0100
committerEgil Moeller <egil.moller@freecode.no>2012-03-02 22:02:42 +0100
commitf6b9b49ab43d5f2fddcd8ddbfcffb0f2fd629e26 (patch)
tree6fd1842ca328e0f5ab0f31c80a317a2db298759a /src/node/utils
parentce5d2d86850be0496467a16333c0646d71649f7c (diff)
downloadetherpad-lite-f6b9b49ab43d5f2fddcd8ddbfcffb0f2fd629e26.zip
Added the rejected/conflicting files as .rej-files so they're not forgotten but resolved manually
Diffstat (limited to 'src/node/utils')
-rw-r--r--src/node/utils/Minify.js.rej513
1 files changed, 513 insertions, 0 deletions
diff --git a/src/node/utils/Minify.js.rej b/src/node/utils/Minify.js.rej
new file mode 100644
index 00000000..f09f49dc
--- /dev/null
+++ b/src/node/utils/Minify.js.rej
@@ -0,0 +1,513 @@
+/**
+ * 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);
+}