From 41f0c248e8968a7ae33e741ee3f2a28358eff695 Mon Sep 17 00:00:00 2001 From: Hike Danakian Date: Tue, 11 Jun 2013 13:23:38 -0700 Subject: [PATCH] Let Owners edit their Events in details-view Resolved ticket #876997 (https://bugzilla.mozilla.org/show_bug.cgi?id=876997). --- assets/css/event_create.less | 52 +------ assets/css/event_details.less | 16 +++ assets/css/events.less | 48 ++++++- config/s3.js | 8 ++ controllers/events.js | 226 +++++++++++++++++++----------- index.js | 1 + routes.js | 11 +- static/js/events/details/index.js | 17 +++ static/js/events/forms.js | 205 ++++++++------------------- static/js/events/index.js | 2 +- static/js/events/map/forms.js | 97 +++++++++++++ static/js/events/map/index.js | 2 +- views/events/details.html | 131 ++++++++++------- views/events/layout.html | 9 +- views/events/map.html | 14 +- 15 files changed, 494 insertions(+), 345 deletions(-) create mode 100644 static/js/events/map/forms.js diff --git a/assets/css/event_create.less b/assets/css/event_create.less index 52b1706..7a492e3 100644 --- a/assets/css/event_create.less +++ b/assets/css/event_create.less @@ -1,11 +1,11 @@ @import "ui"; -body#events .overlay-container { +body#events.map .overlay-container { position: relative; margin: 0px auto; max-width: 980px; } -body#events .map-overlay { +body#events.map .map-overlay { position: absolute; z-index: 1; margin: 20px; @@ -165,7 +165,6 @@ body#events .map-overlay { font-size: 13px; } .md-editor,input { - background: white; outline: 0px; border: 0.5px solid #444; margin: 6px 4px; @@ -182,48 +181,6 @@ body#events .map-overlay { margin-top: 8px; margin-bottom: 4px; } - .md-editor { - background: #222; - margin-left: -1px; - padding: 4px; - padding-top: 0px; - clear: left; - - textarea { - height: 34ex; - padding: 8px 10px; - - font-family: inherit; - font-size: 14px; - } - .md-preview { - min-height: 5ex; - padding: 8px 10px; - - color: #333; - } - .md-header { - background: #222; - } - .btn-group { - display: inline-block; - } - button { - .ui-btn; - .clickable; - background: inherit; - border: 0px; - border-radius: 1px; - padding: 4px 8px; - - color: #eee; - &:hover { - background: #fafafa; - text-shadow: none; - color: #222; - } - } - } input[name="title"] { min-width: 21em; } @@ -264,8 +221,3 @@ body#events .map-overlay { } } } -.ui-datepicker { - border: 1px solid #ddd; - margin-left: -34.5px; - margin-top: 11px; -} diff --git a/assets/css/event_details.less b/assets/css/event_details.less index 87e914a..a7c1659 100644 --- a/assets/css/event_details.less +++ b/assets/css/event_details.less @@ -136,4 +136,20 @@ body#events.details { border-radius: 0px 0px 4px 4px; } + form { + input { + border: 1px solid #ccc; + padding-left: 3px; + padding-left: 4px; + } + input[name="title"] { + padding-left: 10px; + + font-weight: 300; + font-size: 35px; + } + input[name="address"] { + width: 21em; + } + } } diff --git a/assets/css/events.less b/assets/css/events.less index dcbd828..bb52c36 100644 --- a/assets/css/events.less +++ b/assets/css/events.less @@ -13,7 +13,6 @@ body#events { margin-top: 0px; } } - .clear { clear: both; } .hidden { display: none; } .clickable { @@ -33,3 +32,50 @@ body#events { -ms-user-select: none; user-select: none; } +.ui-datepicker { + border: 1px solid #ddd; + margin-left: -34.5px; + margin-top: 11px; +} +.md-editor { + background: #222; + margin-left: -1px; + padding: 4px; + padding-top: 0px; + clear: left; + + textarea { + height: 34ex; + padding: 8px 10px; + + font-family: inherit; + font-size: 14px; + } + .md-preview { + min-height: 5ex; + padding: 8px 10px; + + color: #333; + } + .md-header { + background: #222; + } + .btn-group { + display: inline-block; + } + button { + .ui-btn; + .clickable; + background: inherit; + border: 0px; + border-radius: 1px; + padding: 4px 8px; + + color: #eee; + &:hover { + background: #fafafa; + text-shadow: none; + color: #222; + } + } +} diff --git a/config/s3.js b/config/s3.js index 93d70b3..1c28446 100644 --- a/config/s3.js +++ b/config/s3.js @@ -21,6 +21,14 @@ module.exports = function () { + '/' + filename : this.client.url(filename) }, + delete: function (url) { + var match = url.match(/\/([^\/]+)\/?$/); + if (match) { + this.client.del(match[1]); + return true; + } else console.error("Error: S3 url ("+url+") seems to be invalid."); + return false; + }, client: noxmox[s3_mode].createClient(s3_conf) }; }; diff --git a/controllers/events.js b/controllers/events.js index 6ebd1ae..46ebf86 100644 --- a/controllers/events.js +++ b/controllers/events.js @@ -28,64 +28,21 @@ module.exports = function (init) { }, create: function(req, res) { - var event = req.body.event || req.body; - console.log(event); - - var fields = { // undefined fields are required - title: undefined, - description: undefined, - address: undefined, - organizer: undefined, - organizerId: undefined, - latitude: null, - longitude: null, - attendees: 3, - beginDate: null, - endDate: null, - beginTime: null, - endTime: null, - registerLink: null - }; - var required = [ 'title', 'description', 'latitude', 'longitude', 'address' ]; + var event = event_input_filter(req.body.event || req.body); + if (!event) + return res.reply(400, 'Invalid Event provided'); if (!(event.organizer = req.session.email)) return res.reply(401, 'Log in to create Events'); event.organizerId = req.session.username; - if (event.picture) { - var match = event.picture.match(/^data:(image\/[\w+-]+);.*?base64,(.*)/); - event.picture = match ? { - type: match[1], - data: new Buffer(match[2], 'base64') - } : null - } - // pre-process the Date/Time fields - ['begin', 'end'].forEach(function (pfx) { - datetime_transform('Date', function (val) { - return new Date(val.split('-')); - }); - datetime_transform('Time', function (val) { - var ts = val.split(':'); - return new Date(0, 0, 0, ts[0], ts[1]); - }); - function datetime_transform(f, transform) { - var dtf = pfx + f; - event[dtf] = (function(event) { - if (!event[dtf]) return null; - var new_time = transform(event[dtf]); - return new_time != "Invalid Date" ? new_time : null; - })(event) - } - }); - function empty(x) { return x === '' || x === undefined } - var trns_event = {}; - Object.keys(fields).forEach(function (f) { - trns_event[f] = empty(event[f]) ? fields[f] : event[f]; - }); - if (!required.every(function (f) { return !empty(trns_event[f]) })) - return res.reply(400, 'Invalid Event provided'); var picture = event.picture; - Event.create(trns_event, Object.keys(fields)).success(function (event) { + delete event.picture; + + var fields = ['title', 'description', 'address', 'latitude', + 'longitude', 'attendees', 'beginDate', 'endDate', 'beginTime', + 'endTime', 'registerLink', 'organizer', 'organizerId']; + Event.create(trns_event, fields).success(function (event) { if (picture) { var filename = uuid.v4(); var s3_req = s3.client.put(filename, { @@ -108,48 +65,60 @@ module.exports = function (init) { }, details: function(req, res) { - Event.find(req.params.id).success(function (event) { - if (!event) return res.reply(404, 'Event not found'); + fetch_event(req, function (event) { res.format({ json: function () { res.reply(200, { event: event }) }, html: function () { - function fmtDate(x) { return new Date(x).toDateString() } - function fmtTime(x) { return new Date(x).toTimeString().split(' ')[0] } - - var evt = {}; - for (var p in event) switch(p) { - case 'beginDate': - case 'endDate': - evt[p] = fmtDate(event[p]); - break; - case 'beginTime': - case 'endTime': - evt[p] = fmtTime(event[p]); - break; - case 'description': - evt[p] = markdown.toHTML(event[p]); - default: - evt[p] = event[p]; - } - res.reply('details', { event: evt }); + res.reply('details', { event: event_output_filter(event) }); } }); }); }, - update: function(req, res) + change: function(req, res) { - Event.find(req.params.id).success(function (event) { - event.updateAttributes(req.params.id).success(function () { - res.reply(200, 'Event updated', { event: event }); + console.log(req.body.event || req.body); + var changes = event_input_filter(req.body.event || req.body, false, true, false); + console.log(changes); + if (!changes) + return res.reply(400, 'Invalid Event changes requested'); + var allowed = [ 'title', 'description', 'address', 'latitude', + 'longitude', 'attendees', 'beginDate', 'endDate', + 'beginTime', 'endTime', 'registerLink' ]; + + Object.keys(changes).forEach(function (k) { + if (empty(changes[k])) + delete changes[k]; + }); + var picture = changes.picture; + fetch_event(req, function (event) { + event.updateAttributes(changes, allowed).success(function () { + if (picture) { + var filename = uuid.v4(); + var s3_req = s3.client.put(filename, { + 'Content-Length': picture.data.length, + 'Content-Type': picture.type, + 'x-amz-acl': 'public-read' + }); + s3_req.on('response', function(s3_res) { + if (s3_res.statusCode === 200) + s3.delete(event.picture); + event.updateAttributes({ + picture: s3.url(filename) + }); + }); + s3_req.end(picture.data); + } + res.reply(200, 'Event modified', { event: event }); }); - }).error(function (err) { - res.reply(404, 'Event not found'); }); }, destroy: function(req, res) { Event.find(req.params.id).success(function (event) { + var picture = event.picture; event.destroy().success(function () { + if (picture) + s3.delete(picture); res.reply(200, 'Event deleted'); }); }).error(function (err) { @@ -157,4 +126,103 @@ module.exports = function (init) { }); } }; + + function empty(x) { return x === '' || x === undefined } + function event_input_filter(event, set_defaults, do_transforms, check_required) { + if (!event) return null; + + set_defaults = set_defaults === undefined ? true : set_defaults; + do_transforms = do_transforms === undefined ? true : do_transforms; + check_required = check_required === undefined ? true : check_required; + + var fields = { // undefined fields are required + title: undefined, + description: undefined, + address: undefined, + latitude: null, + longitude: null, + attendees: 3, + beginDate: null, + endDate: null, + beginTime: null, + endTime: null, + registerLink: null + }; + var required = [ 'title', 'description', 'latitude', 'longitude', 'address' ]; + + var transforms = { + picture: function (event) { + if (!event.picture) return; + var match = event.picture.match(/^data:(image\/[\w+-]+);.*?base64,(.*)/); + return match ? { + type: match[1], + data: new Buffer(match[2], 'base64') + } : undefined + } + }; + // pre-process the Date/Time fields + ['begin', 'end'].forEach(function (pfx) { + datetime_transform('Date', function (val) { + return new Date(val.split('-')); + }); + datetime_transform('Time', function (val) { + var ts = val.split(':'); + return new Date(0, 0, 0, ts[0], ts[1]); + }); + function datetime_transform(f, transform) { + var dtf = pfx + f; + transforms[dtf] = function(event) { + if (!event[dtf]) return; + var new_time = transform(event[dtf]); + if (new_time != "Invalid Date") + return new_time; + }; + } + }); + var evt = {}; + if (do_transforms) + Object.keys(transforms).forEach(function (f) { + evt[f] = transforms[f](event); + }); + console.log(evt); + Object.keys(fields).forEach(function (f) { + if (!(f in evt)) evt[f] = event[f]; + }); + if (set_defaults) + Object.keys(fields).forEach(function (f) { + evt[f] = empty(event[f]) ? fields[f] : event[f]; + }); + if (check_required) + evt = required.every(function (f) { return !empty(evt[f]) }) ? evt : null; + return evt + } + function event_output_filter(event) { + function fmtDate(x) { return new Date(x).toDateString() } + function fmtTime(x) { return new Date(x).toTimeString().split(' ')[0] } + + var evt = {}; + for (var p in event) switch(p) { + case 'beginDate': + case 'endDate': + evt[p] = fmtDate(event[p]); + break; + case 'beginTime': + case 'endTime': + evt[p] = fmtTime(event[p]); + break; + case 'description': + evt[p] = markdown.toHTML(event[p]); + default: + evt[p] = event[p]; + } + return evt; + } + function fetch_event(req, success) { + return Event.find(req.params.id).success(function (event) { + if (!event) return req.res.reply(404, 'Event not found'); + success(event); + }).error(function (err) { + req.res.reply(404, 'Event not found'); + }); + } }; diff --git a/index.js b/index.js index c1e3f68..7f9a0ba 100644 --- a/index.js +++ b/index.js @@ -38,6 +38,7 @@ exports.init = function (app, nunjucksEnv, lessMiddleware, app_root) { // Controllers ctx.controllers = require('./controllers').call(ctx, app); + app.use(express.methodOverride()); process.nextTick(require('./routes').bind(ctx, ctx.controllers, app)); // Handy shortcuts diff --git a/routes.js b/routes.js index 6c5d34e..0063979 100644 --- a/routes.js +++ b/routes.js @@ -3,9 +3,10 @@ module.exports = function (C, app) { app[method.toLowerCase()](path + '.:format?', action); } - route( 'GET', '/events', C.Events.index ); - route( 'GET', '/events/:id', C.Events.details ); - route( 'POST', '/events', C.Events.create ); - route( 'PUT', '/events/:id', C.Events.update ); - route( 'DELETE', '/events/:id', C.Events.destroy ); + route( 'GET', '/events', C.Events.index ); + route( 'GET', '/events/:id', C.Events.details ); + route( 'POST', '/events', C.Events.create ); + route( 'PATCH', '/events/:id', C.Events.change ); + //route( 'PUT', '/events/:id', C.Events.update ); + route( 'DELETE', '/events/:id', C.Events.destroy ); }; diff --git a/static/js/events/details/index.js b/static/js/events/details/index.js index e69de29..b641547 100644 --- a/static/js/events/details/index.js +++ b/static/js/events/details/index.js @@ -0,0 +1,17 @@ +define(['jquery', 'forms', 'domReady!'], +function ($, forms) { + var $editForm = $('form#edit-event'); + function toggleEditMode() { + $('.show').toggleClass('hidden'); + $('.edit').toggleClass('hidden'); + } + $editForm.find('button#edit-mode').click(function(ev) { + toggleEditMode(); + }); + $editForm.find('button#cancel-edit').click(function(ev) { + toggleEditMode(); + }); + $editForm.find('button#delete-event').click(function(ev) { + // TODO: show modal with confirmation + }); +}); diff --git a/static/js/events/forms.js b/static/js/events/forms.js index ff6c6a4..d8870e7 100644 --- a/static/js/events/forms.js +++ b/static/js/events/forms.js @@ -1,146 +1,10 @@ -define(['jquery', 'model', '../base/ui', 'bootstrap-markdown', 'jquery.timepicker', 'jquery-ui.datepicker', 'domReady!'], -function ($, EventModel, UI) { return function (mapMaker) { - $.event.props.push('dataTransfer'); - var $createForm = $('form#create-event'); - var $findForm = $('form#find-event'); +define(['jquery', '../base/ui', 'bootstrap-markdown', 'jquery.timepicker', 'jquery-ui.datepicker', 'domReady!'], +function ($, UI) { - var $fileInput = $createForm.find('input[type="file"]'); - var $uploadDiv = $createForm.find('#image-upload'); - $uploadDiv.on("click", function(ev) { - ev.preventDefault(); - $fileInput.click(); - }).on("dragenter dragover drop", function(ev) { - ev.preventDefault(); - ev.stopPropagation(); - }).on("drop", function(ev) { - ev.preventDefault(); - ev.stopPropagation(); - handleImg(ev.dataTransfer.files[0]); - }); - $fileInput.on("change", function (ev) { - handleImg(this.files[0]); - }); - // based on MDN example - function handleImg(file) { - if (file.type.match(/^image\//)) { - if (!$uploadDiv._prev_text) - $uploadDiv._prev_text = $uploadDiv.text(); - $uploadDiv.html(""); - var img = $uploadDiv.find("img")[0]; - img.file = file; - - var reader = new FileReader(); - reader.onload = (function(img) { - return function(ev) { - img.src = ev.target.result; - $createForm.find('input[name="picture"]').prop('value', img.src); - }; - })(img); - reader.readAsDataURL(file); - } - } - - $createForm.find('button[type="submit"]').click(function (ev) { - ev.preventDefault(); - $createForm.submit(); - }); - $createForm.on("submit", function(ev) { - ev.preventDefault(); - var form_fields = $createForm.serializeArray(); - var data = { event: {} }; - form_fields.forEach(function (f) { - if (f.name) switch (f.name) { - case '_csrf': - data[f.name] = f.value; - break; - case 'address': // TODO: split address into two lines - default: - data.event[f.name] = f.value; - } - }); - $.post($createForm.attr('action'), data, function (data) { - console.log(data.event); - if (data.event) { - toggleCreateForm(); - mapMaker.addMarker(new EventModel(data.event)); - } - }, 'json'); - return false; - }); - - $findForm.find('button[type="submit"]').click(function (ev) { - ev.preventDefault(); - $findForm.submit(); - }); - var $when = $findForm.find('input[name="find-when"]'); - $when.blur(function(ev) { $findForm.submit() }); - mmm = mapMaker; - $findForm.on("submit", function(ev) { - ev.preventDefault(); - EventModel.all(function (models) { - mapMaker.clearMarkers(); - var targetDateStr = $when[0].value; - if (!targetDateStr) - mapMaker.dropPins(models, false); - else { - var targetDate = new Date(targetDateStr.split('-')); - mapMaker.dropPins(models, false, function (model) { - var beginDate = new Date(model.beginDate), - endDate = new Date(model.endDate); - if (model.beginDate && model.endDate) - return beginDate <= targetDate - && endDate >= targetDate - else if (beginDate) - return beginDate <= targetDate - else if (endDate) - return endDate >= targetDate - else return true - }); - } - }); - }); - - - // setup form toggle button - function toggleCreateForm() { - var $select = $('select[name="attendees"]'); - $createForm[0].reset(); - $select.next('.ui-select').remove(); - UI.select($select); - $createForm.find('input[name="picture"]').prop('value', ''); - $uploadDiv.find('> img').prop('src', ''); - $uploadDiv.text($uploadDiv._prev_text); - - $createForm.toggleClass('hidden'); - $("#add-event-button").toggleClass('hidden'); - } - $(".formExpandButton").click(function(ev) { - ev.preventDefault(); - toggleCreateForm(); - }); - - mapMaker.setupAutocomplete($('input[name="address"]')[0], false, function (place) { - var loc = { latitude: place.geometry.location.lat(), - longitude: place.geometry.location.lng() }; - for (var k in loc) - $('form#create-event').find('input[name="'+k+'"]').val(loc[k]); - }); - mapMaker.setupAutocomplete($('input[name="find-where"]')[0], true, function (place) { - if (place.geometry) { - // If the place has a geometry, then present it on a map. - if (place.geometry.viewport) { - this.google_map.fitBounds(place.geometry.viewport); - } else { - this.google_map.setCenter(place.geometry.location); - this.google_map.setZoom(14); - } - } - }); - - $createForm.find('.datepicker').datepicker().each(function(i, elem) { + $('.datepicker').datepicker().each(function(i, elem) { $(elem).next('.icon').click(function () { $(elem).focus() }); }); - $createForm.find('.timepicker').timepicker().each(function(i, elem) { + $('.timepicker').timepicker().each(function(i, elem) { $(elem).next('.icon').click(function () { $(elem).focus() }); }).on('showTimepicker', function () { var $parent = $(this).parent(); @@ -150,11 +14,7 @@ function ($, EventModel, UI) { return function (mapMaker) { }); var $beginTime = $('[name="beginTime"]'), $endTime = $('[name="endTime"]'); - $beginTime.timepicker({ - appendTo: function (elem) { return $(elem).parent() } - }); $endTime.timepicker({ - appendTo: function (elem) { return $(elem).parent() }, durationTime: function () { var beginTime = $beginTime.timepicker('getTime'); return beginTime ? beginTime : '0:00am'; @@ -162,7 +22,58 @@ function ($, EventModel, UI) { return function (mapMaker) { showDuration: true }); - EventModel.all(function (models) { mapMaker.dropPins(models) }); - window.scroll(0,0); -}}) + + return { + setupImageUpload: function ($form) { + var $fileInput = $form.find('input[type="file"]'); + var $uploadDiv = $form.find('#image-upload'); + $.event.props.push('dataTransfer'); + $uploadDiv.on("click", function(ev) { + ev.preventDefault(); + $fileInput.click(); + }).on("dragenter dragover drop", function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + }).on("drop", function(ev) { + ev.preventDefault(); + ev.stopPropagation(); + handleImg(ev.dataTransfer.files[0]); + }); + $fileInput.on("change", function (ev) { + handleImg(this.files[0]); + }); + // based on MDN example + function handleImg(file) { + if (file.type.match(/^image\//)) { + if (!$uploadDiv._prev_text) + $uploadDiv._prev_text = $uploadDiv.text(); + $uploadDiv.html(""); + var img = $uploadDiv.find("img")[0]; + img.file = file; + + var reader = new FileReader(); + reader.onload = (function(img) { + return function(ev) { + img.src = ev.target.result; + $form.find('input[name="picture"]').prop('value', img.src); + }; + })(img); + reader.readAsDataURL(file); + } + } + $form.on('reset', function () { + $uploadDiv.find('> img').prop('src', ''); + $uploadDiv.text($uploadDiv._prev_text); + $form.find('input[name="picture"]').prop('value', ''); + }); + }, + setupSelectUI: function ($form) { + $form.on('reset', function () { + var $select = $('select[name="attendees"]'); + $select.next('.ui-select').remove(); + UI.select($select); + }); + }, + }; +}) diff --git a/static/js/events/index.js b/static/js/events/index.js index 985dd6f..05d262b 100644 --- a/static/js/events/index.js +++ b/static/js/events/index.js @@ -1,5 +1,5 @@ require.config({ - deps: ['main', 'jquery.css3finalize', 'jquery-ui.datepicker', 'bootstrap-markdown'], + deps: ['main', 'jquery.css3finalize', 'bootstrap-markdown', 'jquery.timepicker', 'jquery-ui.datepicker'], paths: { 'html': '/js/html', 'base': '/js/base', diff --git a/static/js/events/map/forms.js b/static/js/events/map/forms.js new file mode 100644 index 0000000..53e85f2 --- /dev/null +++ b/static/js/events/map/forms.js @@ -0,0 +1,97 @@ +define(['jquery', 'model', 'forms', 'bootstrap-markdown', 'domReady!'], +function ($, EventModel, forms) { return function (mapMaker) { + var $findForm = $('form#find-event'); + $findForm.find('button[type="submit"]').click(function (ev) { + ev.preventDefault(); + $findForm.submit(); + }); + var $when = $findForm.find('input[name="find-when"]'); + $when.blur(function(ev) { $findForm.submit() }); + $findForm.on("submit", function(ev) { + ev.preventDefault(); + EventModel.all(function (models) { + mapMaker.clearMarkers(); + var targetDateStr = $when[0].value; + if (!targetDateStr) + mapMaker.dropPins(models, false); + else { + var targetDate = new Date(targetDateStr.split('-')); + mapMaker.dropPins(models, false, function (model) { + var beginDate = new Date(model.beginDate), + endDate = new Date(model.endDate); + if (model.beginDate && model.endDate) + return beginDate <= targetDate + && endDate >= targetDate + else if (beginDate) + return beginDate <= targetDate + else if (endDate) + return endDate >= targetDate + else return true + }); + } + }); + }); + + var $createForm = $('form#create-event'); + $createForm.on('submit', function(ev) { + ev.preventDefault(); + var form_fields = $createForm.serializeArray(); + var data = { event: {} }; + form_fields.forEach(function (f) { + if (f.name) switch (f.name) { + case '_csrf': + data[f.name] = f.value; + break; + case 'address': // TODO: split address into two lines + default: + data.event[f.name] = f.value; + } + }); + $.post($createForm.attr('action'), data, function (data) { + console.log(data.event); + if (data.event) { + toggleCreateForm(); + mapMaker.addMarker(new EventModel(data.event)); + } + }, 'json'); + return false; + }); + var $beginTime = $createForm.find('[name="beginTime"]'), + $endTime = $createForm.find('[name="endTime"]'); + $beginTime.timepicker({ appendTo: function (elem) { return $(elem).parent() } }); + $endTime.timepicker({ appendTo: function (elem) { return $(elem).parent() } }); + + forms.setupImageUpload($createForm); + forms.setupSelectUI($createForm); + + // setup form toggle button + function toggleCreateForm() { + $createForm[0].reset(); + $createForm.toggleClass('hidden'); + $("#add-event-button").toggleClass('hidden'); + } + $(".formExpandButton").click(function(ev) { + ev.preventDefault(); + toggleCreateForm(); + }); + + mapMaker.setupAutocomplete($('input[name="address"]')[0], false, function (place) { + var loc = { latitude: place.geometry.location.lat(), + longitude: place.geometry.location.lng() }; + for (var k in loc) + $createForm.find('input[name="'+k+'"]').val(loc[k]); + }); + mapMaker.setupAutocomplete($('input[name="find-where"]')[0], true, function (place) { + if (place.geometry) { + // If the place has a geometry, then present it on a map. + if (place.geometry.viewport) { + this.google_map.fitBounds(place.geometry.viewport); + } else { + this.google_map.setCenter(place.geometry.location); + this.google_map.setZoom(14); + } + } + }); + + EventModel.all(function (models) { mapMaker.dropPins(models) }); +}}); diff --git a/static/js/events/map/index.js b/static/js/events/map/index.js index a7aaa51..652ca1b 100644 --- a/static/js/events/map/index.js +++ b/static/js/events/map/index.js @@ -6,7 +6,7 @@ require.config({ 'markerclusterer': 'map/markerclusterer', } }); -define(['jquery', 'google', 'map/map_maker', 'forms'], +define(['jquery', 'google', 'map/map_maker', 'map/forms'], function ($, google, MapMaker, EventForms) { var defaultZoom = 13; diff --git a/views/events/details.html b/views/events/details.html index fe1927b..ccca7e6 100644 --- a/views/events/details.html +++ b/views/events/details.html @@ -3,62 +3,93 @@ {% block title %}{{ event.title }}{% endblock %} {% block body %} -
+{{ super() }} +
+ +
- - +
+ {% endblock %} diff --git a/views/events/layout.html b/views/events/layout.html index 51ccddf..5dd9318 100644 --- a/views/events/layout.html +++ b/views/events/layout.html @@ -2,11 +2,18 @@ {% include 'macros.html' %} {% block title %}{% endblock %} + {% block head %} + {{ super() }} + + + {% endblock %} -{% block body %}{% endblock %} +{% block body %} +{{ gallery() }} +{% endblock %} {% block require_main %}/js/events/index{% endblock %} {% block scripts %} diff --git a/views/events/map.html b/views/events/map.html index 9e12d50..511c0d6 100644 --- a/views/events/map.html +++ b/views/events/map.html @@ -1,21 +1,15 @@ {% extends "events/layout.html" %} {% block title %}Event Map{% endblock %} -{% block head %} - {{ super() }} - - - -{% endblock %} {% block body %} - +{{ super() }}

Find an event

- + @@ -25,7 +19,7 @@

Add an event

- +

Add an event

@@ -86,7 +80,7 @@
Upload an image
- +