diff --git a/app/assets/stylesheets/application.scss.erb b/app/assets/stylesheets/application.scss.erb index 988b8241..35665918 100644 --- a/app/assets/stylesheets/application.scss.erb +++ b/app/assets/stylesheets/application.scss.erb @@ -1558,6 +1558,7 @@ h3.filterBox { box-sizing: border-box; margin: 0.75em; padding: 0.75em; + padding-top: 0.85em; height: 3em; background-color: #AAB0FB; border-radius: 0.3em; @@ -2051,6 +2052,43 @@ and it won't be important on password protected instances */ .yourMap .mapInfoDelete { display: block; } + +.mapInfoButtonsWrapper .mapInfoThumbnail { + display: block; + background-image: url(<%= asset_path('screenshot_sprite.png') %>); + width: 32px; + height: 32px; + + & > span { + bottom: -9px; + right: 3px; + font-size: 10px; + color: #eee; + + &:hover { + color: white; + } + } + + .tooltip { + display: none; + } + + &:hover { + background-position: -32px 0; + + .tooltip { + display: block; + position: absolute; + bottom: 30px; + background: black; + color: white; + border-radius: 2px; + padding: 3px 5px 2px 5px; + } + } +} + .mapInfoButtonsWrapper span { position: absolute; width: 100%; diff --git a/app/views/layouts/_templates.html.erb b/app/views/layouts/_templates.html.erb index efb3ed68..4fbbd12d 100644 --- a/app/views/layouts/_templates.html.erb +++ b/app/views/layouts/_templates.html.erb @@ -34,6 +34,11 @@

Created by: {{user_name}} on {{created_at}}

Last edited: {{updated_at}}

+
+
+
Update Thumbnail
+ Thumb +
Delete diff --git a/app/views/maps/_mapinfobox.html.erb b/app/views/maps/_mapinfobox.html.erb index 650125ee..9ded6a02 100644 --- a/app/views/maps/_mapinfobox.html.erb +++ b/app/views/maps/_mapinfobox.html.erb @@ -77,6 +77,11 @@

Created by: <%= @map.user == user ? "You" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %>

Last edited: <%= @map.updated_at.strftime("%m/%d/%Y") %>

+
+
+
Update Thumbnail
+ Thumb +
Delete diff --git a/frontend/src/Metamaps/GlobalUI/ImportDialog.js b/frontend/src/Metamaps/GlobalUI/ImportDialog.js index dfc319b7..1428ab6d 100644 --- a/frontend/src/Metamaps/GlobalUI/ImportDialog.js +++ b/frontend/src/Metamaps/GlobalUI/ImportDialog.js @@ -7,6 +7,7 @@ import outdent from 'outdent' import ImportDialogBox from '../../components/ImportDialogBox' import PasteInput from '../PasteInput' +import Map from '../Map' const ImportDialog = { openLightbox: null, @@ -24,14 +25,19 @@ const ImportDialog = { `)) ReactDOM.render(React.createElement(ImportDialogBox, { onFileAdded: PasteInput.handleFile, - exampleImageUrl: serverData['import-example.png'] + exampleImageUrl: serverData['import-example.png'], + downloadScreenshot: ImportDialog.downloadScreenshot }), $('.importDialogWrapper').get(0)) }, show: function() { ImportDialog.openLightbox('import-dialog') }, hide: function() { - ImportDialog.closeLightbox('import-dialog') + ImportDialog.closeLightbox() + }, + downloadScreenshot: function() { + ImportDialog.hide() + Map.offerScreenshotDownload() } } diff --git a/frontend/src/Metamaps/GlobalUI/index.js b/frontend/src/Metamaps/GlobalUI/index.js index 932e3319..a1d2bbff 100644 --- a/frontend/src/Metamaps/GlobalUI/index.js +++ b/frontend/src/Metamaps/GlobalUI/index.js @@ -12,9 +12,11 @@ import NotificationIcon from './NotificationIcon' const GlobalUI = { notifyTimeout: null, + notifyQueue: [], + notifying: false, lightbox: null, init: function(serverData) { - var self = GlobalUI + const self = GlobalUI self.Search.init(serverData) self.CreateMap.init(serverData) @@ -45,7 +47,7 @@ const GlobalUI = { }, 200, 'easeInCubic', function() { $(this).hide() }) }, openLightbox: function(which) { - var self = GlobalUI + const self = GlobalUI $('.lightboxContent').hide() $('#' + which).show() @@ -72,7 +74,7 @@ const GlobalUI = { }, closeLightbox: function(event) { - var self = GlobalUI + const self = GlobalUI if (event) event.preventDefault() @@ -96,23 +98,45 @@ const GlobalUI = { } self.lightbox = null }, - notifyUser: function(message, leaveOpen) { - var self = GlobalUI + notifyUser: function(message, opts = {}) { + const self = GlobalUI + + if (self.notifying) { + self.notifyQueue.push({ message, opts }) + return + } else { + self._notifyUser(message, opts) + } + }, + // note: use the wrapper function notifyUser instead of this one + _notifyUser: function(message, opts = {}) { + const self = GlobalUI + + const { leaveOpen = false, timeOut = 8000 } = opts $('#toast').html(message) self.showDiv('#toast') clearTimeout(self.notifyTimeOut) + if (!leaveOpen) { self.notifyTimeOut = setTimeout(function() { - self.hideDiv('#toast') - }, 8000) + GlobalUI.clearNotify() + }, timeOut) } + + self.notifying = true }, clearNotify: function() { - var self = GlobalUI + const self = GlobalUI - clearTimeout(self.notifyTimeOut) - self.hideDiv('#toast') + // if there are messages remaining, display them + if (self.notifyQueue.length > 0) { + const { message, opts } = self.notifyQueue.shift() + self._notifyUser(message, opts) + } else { + self.hideDiv('#toast') + self.notifying = false + } }, shareInvite: function(inviteLink) { clipboard.copy({ diff --git a/frontend/src/Metamaps/Map/InfoBox.js b/frontend/src/Metamaps/Map/InfoBox.js index 21d947ad..1949e96e 100644 --- a/frontend/src/Metamaps/Map/InfoBox.js +++ b/frontend/src/Metamaps/Map/InfoBox.js @@ -35,9 +35,11 @@ const InfoBox = { data-bip-value="{{desc}}" >{{desc}}`, userImageUrl: '', - init: function(serverData) { + init: function(serverData, updateThumbnail) { var self = InfoBox + self.updateThumbnail = updateThumbnail + $('.mapInfoIcon').click(self.toggleBox) $('.mapInfoBox').click(function(event) { event.stopPropagation() @@ -181,6 +183,7 @@ const InfoBox = { $('.mapInfoBox.yourMap').unbind('.yourMap').bind('click.yourMap', self.hidePermissionSelect) $('.yourMap .mapInfoDelete').unbind().click(self.deleteActiveMap) + $('.mapInfoThumbnail').unbind().click(self.updateThumbnail) $('.mapContributors span, #mapContribs').unbind().click(function(event) { $('.mapContributors .tip').toggle() diff --git a/frontend/src/Metamaps/Map/index.js b/frontend/src/Metamaps/Map/index.js index 51038b87..3df5a3e2 100644 --- a/frontend/src/Metamaps/Map/index.js +++ b/frontend/src/Metamaps/Map/index.js @@ -45,7 +45,10 @@ const Map = { GlobalUI.CreateMap.emptyForkMapForm = $('#fork_map').html() self.updateStar() - InfoBox.init(serverData) + + InfoBox.init(serverData, function updateThumbnail() { + self.uploadMapScreenshot() + }) CheatSheet.init(serverData) $('.viewOnly .requestAccess').click(self.requestAccess) @@ -251,6 +254,48 @@ const Map = { } }, exportImage: function() { + Map.uploadMapScreenshot() + Map.offerScreenshotDownload() + GlobalUI.notifyUser('Note: this button is going away. Check the map card or the import box for setting the map thumbnail or downloading a screenshot.') + }, + offerScreenshotDownload: () => { + const canvas = Map.getMapCanvasForScreenshots() + const filename = Map.getMapScreenshotFilename(Active.Map) + + var downloadMessage = outdent` + Captured map screenshot! + + DOWNLOAD + ` + GlobalUI.notifyUser(downloadMessage) + }, + uploadMapScreenshot: () => { + const canvas = Map.getMapCanvasForScreenshots() + const filename = Map.getMapScreenshotFilename(Active.Map) + + canvas.canvas.toBlob(imageBlob => { + const formData = new window.FormData() + formData.append('map[screenshot]', imageBlob, filename) + $.ajax({ + type: 'PATCH', + dataType: 'json', + url: `/maps/${Active.Map.id}`, + data: formData, + processData: false, + contentType: false, + success: function(data) { + GlobalUI.notifyUser('Successfully updated map screenshot.') + }, + error: function() { + GlobalUI.notifyUser('Failed to update map screenshot.') + } + }) + }) + }, + getMapCanvasForScreenshots: () => { var canvas = {} canvas.canvas = document.createElement('canvas') @@ -336,8 +381,9 @@ const Map = { node.visited = !T }) - var map = Active.Map - + return canvas + }, + getMapScreenshotFilename: map => { var today = new Date() var dd = today.getDate() var mm = today.getMonth() + 1 // January is 0! @@ -352,30 +398,7 @@ const Map = { var mapName = map.get('name').split(' ').join(['-']) const filename = `metamap-${map.id}-${mapName}-${today}.png` - - var downloadMessage = outdent` - Captured map screenshot! - DOWNLOAD` - GlobalUI.notifyUser(downloadMessage) - - canvas.canvas.toBlob(imageBlob => { - const formData = new window.FormData() - formData.append('map[screenshot]', imageBlob, filename) - $.ajax({ - type: 'PATCH', - dataType: 'json', - url: `/maps/${map.id}`, - data: formData, - processData: false, - contentType: false, - success: function(data) { - console.log('successfully uploaded map screenshot') - }, - error: function() { - console.log('failed to save map screenshot') - } - }) - }) + return filename } } diff --git a/frontend/src/Metamaps/Realtime/receivable.js b/frontend/src/Metamaps/Realtime/receivable.js index dd37fd99..f673d2e5 100644 --- a/frontend/src/Metamaps/Realtime/receivable.js +++ b/frontend/src/Metamaps/Realtime/receivable.js @@ -149,7 +149,7 @@ export const invitedToCall = self => inviter => { notifyText += username + ' is inviting you to a conversation. Join live?' notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.acceptCall(inviter)) $('#toast button.no').click(e => self.denyCall(inviter)) } @@ -162,7 +162,7 @@ export const invitedToJoin = self => inviter => { var notifyText = username + ' is inviting you to the conversation. Join?' notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => self.denyInvite(inviter)) } @@ -201,7 +201,7 @@ export const callInProgress = self => () => { var notifyText = "There's a conversation happening, want to join?" notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => GlobalUI.clearNotify()) ChatView.conversationInProgress() @@ -212,7 +212,7 @@ export const callStarted = self => () => { var notifyText = "There's a conversation starting, want to join?" notifyText += ' ' notifyText += ' ' - GlobalUI.notifyUser(notifyText, true) + GlobalUI.notifyUser(notifyText, { leaveOpen: true }) $('#toast button.yes').click(e => self.joinCall()) $('#toast button.no').click(e => GlobalUI.clearNotify()) ChatView.conversationInProgress() diff --git a/frontend/src/components/ImportDialogBox.js b/frontend/src/components/ImportDialogBox.js index ddf81c38..85b3ee67 100644 --- a/frontend/src/components/ImportDialogBox.js +++ b/frontend/src/components/ImportDialogBox.js @@ -27,6 +27,9 @@ class ImportDialogBox extends Component {
Export as JSON
+
+ Download screenshot +

IMPORT

To upload a file, drop it here: