Skip to content

Instantly share code, notes, and snippets.

@florinpopescu
Last active October 30, 2020 21:52
Show Gist options
  • Save florinpopescu/c486c028c201f7026fd8e0a212fb3bb1 to your computer and use it in GitHub Desktop.
Save florinpopescu/c486c028c201f7026fd8e0a212fb3bb1 to your computer and use it in GitHub Desktop.
Froala WYSIWYG Editor - NodeJS integration example
var Busboy = require('busboy');
var path = require('path');
var fs = require('fs');
var sha1 = require('sha1');
// Gets a filename extension.
function getExtension(filename) {
return filename.split('.').pop();
}
// Test if a file is valid based on its extension and mime type.
function isFileValid(filename, mimetype) {
var allowedExts = ['txt', 'pdf', 'doc'];
var allowedMimeTypes = ['text/plain', 'application/msword', 'application/x-pdf', 'application/pdf'];
// Get file extension.
var extension = getExtension(filename);
return allowedExts.indexOf(extension.toLowerCase()) != -1 &&
allowedMimeTypes.indexOf(mimetype) != -1
;
}
function upload (req, callback) {
// The route on which the file is saved.
var fileRoute = '/uploads/';
// Server side file path on which the file is saved.
var saveToPath = null;
// Flag to tell if a stream had an error.
var hadStreamError = null;
// Used for sending response.
var link = null;
// Stream error handler.
function handleStreamError(error) {
// Do not enter twice in here.
if (hadStreamError) {
return;
}
hadStreamError = error;
// Cleanup: delete the saved path.
if (saveToPath) {
return fs.unlink(saveToPath, function (err) {
return callback(error);
});
}
return callback(error);
}
// Instantiate Busboy.
try {
var busboy = new Busboy({ headers: req.headers });
} catch(e) {
return callback(e);
}
// Handle file arrival.
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
// Check fieldname:
if ('file' != fieldname) {
// Stop receiving from this stream.
file.resume();
return callback('Fieldname is not correct. It must be "file".');
}
// Generate link.
var randomName = sha1(new Date().getTime()) + '.' + getExtension(filename);
link = fileRoute + randomName;
// Generate path where the file will be saved.
var appDir = path.dirname(require.main.filename);
saveToPath = path.join(appDir, link);
// Pipe reader stream (file from client) into writer stream (file from disk).
file.on('error', handleStreamError);
// Create stream writer to save to file to disk.
var diskWriterStream = fs.createWriteStream(saveToPath);
diskWriterStream.on('error', handleStreamError);
// Validate file after it is successfully saved to disk.
diskWriterStream.on('finish', function() {
// Check if file is valid
var status = isFileValid(saveToPath, mimetype);
if (!status) {
return handleStreamError('File does not meet the validation.');
}
return callback(null, {link: link});
});
// Save file to disk.
file.pipe(diskWriterStream);
});
// Handle file upload termination.
busboy.on('error', handleStreamError);
req.on('error', handleStreamError);
// Pipe reader stream into writer stream.
return req.pipe(busboy);
}
module.exports = upload;
var Busboy = require('busboy');
var path = require('path');
var fs = require('fs');
var sha1 = require('sha1');
// Gets a filename extension.
function getExtension(filename) {
return filename.split('.').pop();
}
// Test if a image is valid based on its extension and mime type.
function isImageValid(filename, mimetype) {
var allowedExts = ['gif', 'jpeg', 'jpg', 'png', 'svg', 'blob'];
var allowedMimeTypes = ['image/gif', 'image/jpeg', 'image/pjpeg', 'image/x-png', 'image/png', 'image/svg+xml'];
// Get image extension.
var extension = getExtension(filename);
return allowedExts.indexOf(extension.toLowerCase()) != -1 &&
allowedMimeTypes.indexOf(mimetype) != -1
;
}
function upload (req, callback) {
// The route on which the image is saved.
var fileRoute = '/uploads/';
// Server side file path on which the image is saved.
var saveToPath = null;
// Flag to tell if a stream had an error.
var hadStreamError = null;
// Used for sending response.
var link = null;
// Stream error handler.
function handleStreamError(error) {
// Do not enter twice in here.
if (hadStreamError) {
return;
}
hadStreamError = error;
// Cleanup: delete the saved path.
if (saveToPath) {
return fs.unlink(saveToPath, function (err) {
return callback(error);
});
}
return callback(error);
}
// Instantiate Busboy.
try {
var busboy = new Busboy({ headers: req.headers });
} catch(e) {
return callback(e);
}
// Handle file arrival.
busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
// Check fieldname:
if ('file' != fieldname) {
// Stop receiving from this stream.
file.resume();
return callback('Fieldname is not correct. It must be "file".');
}
// Generate link.
var randomName = sha1(new Date().getTime()) + '.' + getExtension(filename);
link = fileRoute + randomName;
// Generate path where the file will be saved.
var appDir = path.dirname(require.main.filename);
saveToPath = path.join(appDir, link);
// Pipe reader stream (file from client) into writer stream (file from disk).
file.on('error', handleStreamError);
// Create stream writer to save to file to disk.
var diskWriterStream = fs.createWriteStream(saveToPath);
diskWriterStream.on('error', handleStreamError);
// Validate image after it is successfully saved to disk.
diskWriterStream.on('finish', function() {
// Check if image is valid
var status = isImageValid(saveToPath, mimetype);
if (!status) {
return handleStreamError('File does not meet the validation.');
}
return callback(null, {link: link});
});
// Save image to disk.
file.pipe(diskWriterStream);
});
// Handle file upload termination.
busboy.on('error', handleStreamError);
req.on('error', handleStreamError);
// Pipe reader stream into writer stream.
return req.pipe(busboy);
}
module.exports = upload;
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0, maximum-scale=1.0"/>
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
<!-- Include Font Awesome. -->
<link href="/bower_components/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css" />
<!-- Include Froala Editor styles -->
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/froala_editor.min.css" />
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/froala_style.min.css" />
<!-- Include Froala Editor Plugins styles -->
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/char_counter.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/code_view.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/colors.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/emoticons.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/file.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/fullscreen.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/image_manager.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/image.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/line_breaker.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/table.css">
<link rel="stylesheet" href="/bower_components/froala-wysiwyg-editor/css/plugins/video.css">
<!-- Include Froala Editor -->
<script src="/bower_components/froala-wysiwyg-editor/js/froala_editor.min.js"></script>
<!-- Include Froala Editor Plugins -->
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/align.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/char_counter.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/code_beautifier.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/code_view.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/colors.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/emoticons.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/entities.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/file.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/font_family.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/font_size.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/fullscreen.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/image.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/image_manager.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/inline_style.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/line_breaker.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/link.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/lists.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/paragraph_format.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/paragraph_style.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/quote.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/save.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/table.min.js"></script>
<script src="/bower_components/froala-wysiwyg-editor/js/plugins/video.min.js"></script>
<!-- End Froala -->
</head>
<body>
<div>
<h2>File/Image upload example.</h2>
<form>
<textarea id="edit" name="content"></textarea>
</form>
</div>
<script>
$(function() {
$('#edit').froalaEditor({
fileUploadURL: './file_upload',
fileUploadParams: {
id: 'my_editor'
},
imageUploadURL: './image_upload',
imageUploadParams: {
id: 'my_editor'
},
})
});
</script>
</body>
</html>
var express = require('express');
var app = express();
var bodyParser = require('body-parser')
var path = require('path');
var fs = require('fs');
var upload_file = require('./file_upload.js');
var upload_image = require('./image_upload.js');
app.use(express.static(__dirname + '/'));
app.use(bodyParser.urlencoded({ extended: false }));
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
// File POST handler.
app.post('/file_upload', function (req, res) {
upload_file(req, function(err, data) {
if (err) {
return res.status(404).end(JSON.stringify(err));
}
res.send(data);
});
});
// Image POST handler.
app.post('/image_upload', function (req, res) {
upload_image(req, function(err, data) {
if (err) {
return res.status(404).end(JSON.stringify(err));
}
res.send(data);
});
});
// Create folder for uploading files.
var filesDir = path.join(path.dirname(require.main.filename), 'uploads');
if (!fs.existsSync(filesDir)){
fs.mkdirSync(filesDir);
}
// Init server.
app.listen(3000, function () {
console.log('Example app listening on port 3000!');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment