diff --git a/package.json b/package.json index 53106bd36fe0923efc97a94e9056c8e640a95c33..a3bd53fb69ad3402eba91101c6fd214f69cb37b2 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "hbs": "~4.0.4", "mongoose": "^5.7.6", "morgan": "~1.9.1", + "multer": "^1.4.2", "passport": "^0.4.0", "passport-local": "^1.0.0" }, diff --git a/public/javascript/livePictures.js b/public/javascript/livePictures.js new file mode 100644 index 0000000000000000000000000000000000000000..3d3163c2efb9cfd31a523d8f167152e83ba83e2b --- /dev/null +++ b/public/javascript/livePictures.js @@ -0,0 +1,42 @@ +/** + * Adds event listener to file input so that + * it shows selected images in real time + */ +function picturesWatch() { + const picturesInput = document.querySelector('#pictures'); + const picturesOutput = document.querySelector('#pictures-display'); + + picturesInput.addEventListener('change', (e) => { + const files = e.target.files; + + // Clear existing images + while (picturesOutput.lastChild) { + picturesOutput.removeChild(picturesOutput.lastChild); + } + + for (const file of files) { + if (!file.type.startsWith('image/')) { + continue; + } + + const img = document.createElement('img'); + img.file = file; + + picturesOutput.appendChild(img); + + // Read file's contents and assign it to img + const reader = new FileReader(); + reader.onload = (function(aImg) { + return function(e) { + aImg.src = e.target.result; + }; + })(img); + reader.readAsDataURL(file); + } + }); +} + +document.addEventListener('DOMContentLoaded', function() { + picturesWatch(); + console.info('file input is being watched'); +}); diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css index 991b01ea8ac6de81bacac6e62b4f490737b7e294..085847b7b9e2cb19ef921cf214e276b096120f6d 100644 --- a/public/stylesheets/style.css +++ b/public/stylesheets/style.css @@ -24,7 +24,8 @@ form > fieldset, form > button { } div.form-input { - display: inline; + display: inline-block; + margin-bottom: 15px; } span.error-message { @@ -48,4 +49,18 @@ span.error-message { .close-btn { cursor: pointer; +} + +.ad-photos { + display: flex; + width: 100%; + justify-content: space-around; +} + +.ad-photos > img { + max-width: 20%; + max-height: 100%; + border: solid 2px #333; + padding: 2px; + margin-bottom: 15px; } \ No newline at end of file diff --git a/routes/ads.js b/routes/ads.js index bfba03eab0d36610c3b5e61db7ce06b06e2f1ad4..3755db61db58f7e3799654e9f04f2f62d8d6f8c8 100644 --- a/routes/ads.js +++ b/routes/ads.js @@ -1,13 +1,18 @@ const express = require('express'); +const multer = require('multer'); const router = new express.Router(); const adModel = require('../models/ad'); +const upload = multer({ + storage: multer.memoryStorage(), +}); + /* GET to get to get to the ad creation form */ router.get('/create', function(req, res, next) { res.render('ad_create'); }) - .post('/create', function(req, res, next) { + .post('/create', upload.array('pictures', 3), function(req, res, next) { // TODO : gérer l'upload de fichier // (avec le middleware multiparty par exemple) const body = req.body; @@ -24,6 +29,12 @@ router.get('/create', function(req, res, next) { null : body.availabilityDate, }; + if (req.files.length) { + formData.pictures = req + .files + .map((f) => ({name: f.fieldName, body: f.buffer})); + } + if (id) { // Peut-être charger l'objet en amont et le retourner si erreur ? @@ -87,6 +98,14 @@ router.get('/create', function(req, res, next) { req.flash('error', 'L\'annonce n\'a pas pu être supprimée'); }) .finally(() => res.redirect(303, '/ads/')); + }) + .get('/:id/picture/:index', function(req, res, next) { + adModel.Ad.findOne({_id: req.params.id}) + .then((ad) => { + res.type('image/*'); + res.send(ad.pictures[parseInt(req.params.index)].body); + }) + .catch(next); }); module.exports = router; diff --git a/views/ad_create.hbs b/views/ad_create.hbs index b59489641b65a87de0b2fbc53c530819487f0748..8fe4c6edc270f4c16192b4e6c006df3254cc8027 100644 --- a/views/ad_create.hbs +++ b/views/ad_create.hbs @@ -1,87 +1,100 @@