diff options
Diffstat (limited to 'src/node/utils')
-rw-r--r-- | src/node/utils/ExportHtml.js | 61 | ||||
-rw-r--r-- | src/node/utils/LibreOffice.js | 93 | ||||
-rw-r--r-- | src/node/utils/Settings.js | 22 |
3 files changed, 156 insertions, 20 deletions
diff --git a/src/node/utils/ExportHtml.js b/src/node/utils/ExportHtml.js index 9e1ba124..ffc7bc58 100644 --- a/src/node/utils/ExportHtml.js +++ b/src/node/utils/ExportHtml.js @@ -19,6 +19,7 @@ var async = require("async"); var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var padManager = require("../db/PadManager"); var ERR = require("async-stacktrace"); +var _ = require('underscore'); var Security = require('ep_etherpad-lite/static/js/security'); var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks'); var _analyzeLine = require('./ExportHelper')._analyzeLine; @@ -78,8 +79,15 @@ function getHTMLFromAtext(pad, atext, authorColors) var props = ['heading1', 'heading2', 'bold', 'italic', 'underline', 'strikethrough']; hooks.aCallAll("exportHtmlAdditionalTags", pad, function(err, newProps){ + // newProps can be simply a string (which means it is stored as attribute in the form of ['tag', 'true']) + // or it can be a pair of values in an Array (for the case when it is stored as ['tag', 'value']). + // The later scenario will generate HTML with tags like <span data-tag="value"> newProps.forEach(function (propName, i){ - tags.push(propName); + if (_.isArray(propName)) { + tags.push('span data-' + propName[0] + '="' + propName[1] + '"'); + } else { + tags.push(propName); + } props.push(propName); }); }); @@ -115,8 +123,8 @@ function getHTMLFromAtext(pad, atext, authorColors) var newLength = props.push(propName); anumMap[a] = newLength -1; - css+=".removed {text-decoration: line-through; " + - "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)'; "+ + css+=".removed {text-decoration: line-through; " + + "-ms-filter:'progid:DXImageTransform.Microsoft.Alpha(Opacity=80)'; "+ "filter: alpha(opacity=80); "+ "opacity: 0.8; "+ "}\n"; @@ -130,7 +138,12 @@ function getHTMLFromAtext(pad, atext, authorColors) // this pad, and if yes puts its attrib id->props value into anumMap props.forEach(function (propName, i) { - var propTrueNum = apool.putAttrib([propName, true], true); + var attrib = [propName, true]; + if (_.isArray(propName)) { + // propName can be in the form of ['color', 'red'] + attrib = propName; + } + var propTrueNum = apool.putAttrib(attrib, true); if (propTrueNum >= 0) { anumMap[propTrueNum] = i; @@ -154,6 +167,11 @@ function getHTMLFromAtext(pad, atext, authorColors) var property = props[i]; + // we are not insterested on properties in the form of ['color', 'red'] + if (_.isArray(property)) { + return false; + } + if(property.substr(0,6) === "author"){ return stripDotFromAuthorID(property); } @@ -165,6 +183,11 @@ function getHTMLFromAtext(pad, atext, authorColors) return false; } + function isSpanWithData(i){ + var property = props[i]; + return _.isArray(property); + } + function emitOpenTag(i) { openTags.unshift(i); @@ -186,8 +209,9 @@ function getHTMLFromAtext(pad, atext, authorColors) { openTags.shift(); var spanClass = getSpanClassFor(i); + var spanWithData = isSpanWithData(i); - if(spanClass){ + if(spanClass || spanWithData){ assem.append('</span>'); } else { assem.append('</'); @@ -263,7 +287,7 @@ function getHTMLFromAtext(pad, atext, authorColors) var s = taker.take(chars); - //removes the characters with the code 12. Don't know where they come + //removes the characters with the code 12. Don't know where they come //from but they break the abiword parser and are completly useless s = s.replace(String.fromCharCode(12), ""); @@ -377,7 +401,7 @@ function getHTMLFromAtext(pad, atext, authorColors) pieces.push('<br><br>'); } }*/ - else//means we are getting closer to the lowest level of indentation or are at the same level + else//means we are getting closer to the lowest level of indentation or are at the same level { var toClose = lists.length > 0 ? listLevels[listLevels.length - 2] - line.listLevel : 0 if( toClose > 0){ @@ -431,7 +455,7 @@ function getHTMLFromAtext(pad, atext, authorColors) } } } - + for (var k = lists.length - 1; k >= 0; k--) { if(lists[k][1] == "number") @@ -460,14 +484,17 @@ exports.getPadHTMLDocument = function (padId, revNum, noDocType, callback) stylesForExportCSS += css; }); // Core inclusion of head etc. - var head = - (noDocType ? '' : '<!doctype html>\n') + - '<html lang="en">\n' + (noDocType ? '' : '<head>\n' + + var head = + (noDocType ? '' : '<!doctype html>\n') + + '<html lang="en">\n' + (noDocType ? '' : '<head>\n' + '<title>' + Security.escapeHTML(padId) + '</title>\n' + - '<meta charset="utf-8">\n' + - '<style> * { font-family: arial, sans-serif;\n' + - 'font-size: 13px;\n' + - 'line-height: 17px; }' + + '<meta name="generator" content="Etherpad">\n' + + '<meta name="author" content="Etherpad">\n' + + '<meta name="changedby" content="Etherpad">\n' + + '<meta charset="utf-8">\n' + + '<style> * { font-family: arial, sans-serif;\n' + + 'font-size: 13px;\n' + + 'line-height: 17px; }' + 'ul.indent { list-style-type: none; }' + 'ol { list-style-type: none; padding-left:0;}' + @@ -553,8 +580,8 @@ exports.getPadHTMLDocument = function (padId, revNum, noDocType, callback) 'ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol{ text-indent: 140px; }' + 'ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol > ol{ text-indent: 150px; }' + - stylesForExportCSS + - '</style>\n' + '</head>\n') + + stylesForExportCSS + + '</style>\n' + '</head>\n') + '<body>'; var foot = '</body>\n</html>\n'; diff --git a/src/node/utils/LibreOffice.js b/src/node/utils/LibreOffice.js new file mode 100644 index 00000000..41577245 --- /dev/null +++ b/src/node/utils/LibreOffice.js @@ -0,0 +1,93 @@ +/** + * Controls the communication with LibreOffice + */ + +/* + * 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 async = require("async"); +var fs = require("fs"); +var os = require("os"); +var path = require("path"); +var settings = require("./Settings"); +var spawn = require("child_process").spawn; + +// Conversion tasks will be queued up, so we don't overload the system +var queue = async.queue(doConvertTask, 1); + +/** + * Convert a file from one type to another + * + * @param {String} srcFile The path on disk to convert + * @param {String} destFile The path on disk where the converted file should be stored + * @param {String} type The type to convert into + * @param {Function} callback Standard callback function + */ +exports.convertFile = function(srcFile, destFile, type, callback) { + queue.push({"srcFile": srcFile, "destFile": destFile, "type": type, "callback": callback}); +}; + +function doConvertTask(task, callback) { + var tmpDir = os.tmpdir(); + + async.series([ + // Generate a PDF file with LibreOffice + function(callback) { + var soffice = spawn(settings.soffice, [ + '--headless', + '--invisible', + '--nologo', + '--nolockcheck', + '--convert-to', task.type, + task.srcFile, + '--outdir', tmpDir + ]); + + var stdoutBuffer = ''; + + // Delegate the processing of stdout to another function + soffice.stdout.on('data', function(data) { + stdoutBuffer += data.toString(); + }); + + // Append error messages to the buffer + soffice.stderr.on('data', function(data) { + stdoutBuffer += data.toString(); + }); + + // Throw an exception if libreoffice failed + soffice.on('exit', function(code) { + if (code != 0) { + return callback("LibreOffice died with exit code " + code + " and message: " + stdoutBuffer); + } + + callback(); + }) + }, + + // Move the PDF file to the correct place + function(callback) { + var filename = path.basename(task.srcFile); + var pdfFilename = filename.substr(0, filename.lastIndexOf('.')) + '.' + task.type; + var pdfPath = path.join(tmpDir, pdfFilename); + fs.rename(pdfPath, task.destFile, callback); + } + ], function(err) { + // Invoke the callback for the local queue + callback(); + + // Invoke the callback for the task + task.callback(err); + }); +} diff --git a/src/node/utils/Settings.js b/src/node/utils/Settings.js index 2cc6a926..f76cebdc 100644 --- a/src/node/utils/Settings.js +++ b/src/node/utils/Settings.js @@ -83,7 +83,7 @@ exports.dbSettings = { "filename" : path.join(exports.root, "dirty.db") }; /** * The default Text of a new pad */ -exports.defaultPadText = "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nEtherpad on Github: http:\/\/j.mp/ep-lite\n"; +exports.defaultPadText = "Welcome to Etherpad!\n\nThis pad text is synchronized as you type, so that everyone viewing this page sees the same text. This allows you to collaborate seamlessly on documents!\n\nEtherpad on Github: https:\/\/github.com\/ether\/etherpad-lite\n"; /** * The default Pad Settings for a user (Can be overridden by changing the setting @@ -153,6 +153,11 @@ exports.minify = true; exports.abiword = null; /** + * The path of the libreoffice executable + */ +exports.soffice = null; + +/** * The path of the tidy executable */ exports.tidyHtml = null; @@ -177,6 +182,11 @@ exports.disableIPlogging = false; */ exports.loadTest = false; +/** + * Enable indentation on new lines + */ +exports.indentationOnNewLine = true; + /* * log4js appender configuration */ @@ -218,8 +228,14 @@ exports.getGitCommit = function() { try { var rootPath = path.resolve(npm.dir, '..'); - var ref = fs.readFileSync(rootPath + "/.git/HEAD", "utf-8"); - var refPath = rootPath + "/.git/" + ref.substring(5, ref.indexOf("\n")); + if (fs.lstatSync(rootPath + '/.git').isFile()) { + rootPath = fs.readFileSync(rootPath + '/.git', "utf8"); + rootPath = rootPath.split(' ').pop().trim(); + } else { + rootPath += '/.git'; + } + var ref = fs.readFileSync(rootPath + "/HEAD", "utf-8"); + var refPath = rootPath + "/" + ref.substring(5, ref.indexOf("\n")); version = fs.readFileSync(refPath, "utf-8"); version = version.substring(0, 7); } |