From 513485c6c99c661470ebe4ffbff9d7109a13f015 Mon Sep 17 00:00:00 2001 From: Nelson Silva Date: Thu, 14 Feb 2013 16:01:59 +0000 Subject: [PATCH] Added JSON import --- src/node/handler/ImportHandler.js | 23 +++++++--- src/node/utils/ImportJSON.js | 74 +++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/node/utils/ImportJSON.js diff --git a/src/node/handler/ImportHandler.js b/src/node/handler/ImportHandler.js index ac856a604..f45413aef 100644 --- a/src/node/handler/ImportHandler.js +++ b/src/node/handler/ImportHandler.js @@ -28,7 +28,8 @@ var ERR = require("async-stacktrace") , settings = require('../utils/Settings') , formidable = require('formidable') , os = require("os") - , importHtml = require("../utils/ImportHtml"); + , importHtml = require("../utils/ImportHtml") + , importJSON = require("../utils/ImportJSON"); //load abiword only if its enabled if(settings.abiword != null) @@ -48,7 +49,9 @@ exports.doImport = function(req, res, padId) var srcFile, destFile , pad - , text; + , text + , fileEnding; + async.series([ //save the uploaded file to /tmp @@ -72,11 +75,14 @@ exports.doImport = function(req, res, padId) }); }, + + //ensure this is a file ending we know, else we change the file ending to .txt //this allows us to accept source code files like .c or .java function(callback) { - var fileEnding = path.extname(srcFile).toLowerCase() - , knownFileEndings = [".txt", ".doc", ".docx", ".pdf", ".odt", ".html", ".htm"] + fileEnding = path.extname(srcFile).toLowerCase(); + + var knownFileEndings = [".txt", ".doc", ".docx", ".pdf", ".odt", ".html", ".htm", ".json"] , fileEndingKnown = (knownFileEndings.indexOf(fileEnding) > -1); //if the file ending is known, continue as normal @@ -95,9 +101,12 @@ exports.doImport = function(req, res, padId) //convert file to html function(callback) { var randNum = Math.floor(Math.random()*0xFFFFFFFF); - destFile = path.join(tmpDirectory, "eplite_import_" + randNum + ".htm"); + destFile = path.join(tmpDirectory, "eplite_import_" + randNum + fileEnding); - if (abiword) { + // check if this format is supported by AbiWord + var isAbiWordSupported = (['json'].indexOf(fileEnding) == -1); + + if (abiword && isAbiWordSupported) { abiword.convertFile(srcFile, destFile, "htm", function(err) { //catch convert errors if(err) { @@ -143,6 +152,8 @@ exports.doImport = function(req, res, padId) var fileEnding = path.extname(srcFile).toLowerCase(); if (abiword || fileEnding == ".htm" || fileEnding == ".html") { importHtml.setPadHTML(pad, text); + } else if (fileEnding == ".json") { + importJSON.setPadJSON(pad, JSON.parse(text)); } else { pad.setText(text); } diff --git a/src/node/utils/ImportJSON.js b/src/node/utils/ImportJSON.js new file mode 100644 index 000000000..99fc04b72 --- /dev/null +++ b/src/node/utils/ImportJSON.js @@ -0,0 +1,74 @@ +var log4js = require('log4js'); +var Changeset = require("ep_etherpad-lite/static/js/Changeset"); + +function keepText(builder, text, from, to) { + var chars = to - from; + var keepText = text.substring(from, to); + var keepLines = keepText.split("\n").length - 1; + builder.keep(chars, keepLines); +} + +function keepTextWithAttributes(builder, text, from, to, attributes, apool) { + var keepText = text.substring(from, to); + + var linePos = 0; + var length = keepText.length; + while (linePos < length) { + var lineEnd = keepText.indexOf('\n', linePos) + 1; + var lines; + if (lineEnd != 0) { + lines = 1; + } else { + lines = 0; + lineEnd = length; + } + var chars = lineEnd - linePos; + + builder.keep(chars, lines, attributes, apool); + + linePos += chars; + } +} + +function setPadJSON(pad, json, callback) { + var apiLogger = log4js.getLogger("ImportHtml"); + + // Set the text + pad.setText(json.atext.text); + + // Set the apoll + var nextNum = Math.max.apply(null, Object.keys(json.apool)); + pad.apool().fromJsonable({numToAttrib:json.apool, nextNum:nextNum}); + + var padText = pad.text(); + var padTextLength = padText.length; + + // split the text into lines + json.atext.attributes.forEach(function(att) { + + // use a builder + var builder = Changeset.builder(padTextLength); + + var from = parseInt(att.from); + var to = parseInt(att.to); + + // Keep everything before "from" + if (from > 0) { + keepText(builder, padText, 0, from); + } + + // Keep but add the attribute + keepTextWithAttributes(builder, padText, from, to, "*" + att.id, pad.apool()); + + // Keep everything after "to" + if (to < padTextLength) { + keepText(builder, padText, to, padTextLength); + } + + // apply the revision + pad.appendRevision(builder.toString()); + }) + +} + +exports.setPadJSON = setPadJSON;