split screenshot function/button into two parts (#1027)
* split screenshot function into 4 separate helpers * screenshot download button in import dialog box * thumbnail button inside map info box * import blue button styling * fight with styling to make the button at least appear * add more text * fix tooltip display * automatically start downloading the screenshot * eslint * revamp GlobalUI.notifyUser * fix object destructuring syntax * fix
This commit is contained in:
parent
a9f19815e4
commit
af2c6ebef1
9 changed files with 153 additions and 45 deletions
|
@ -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%;
|
||||
|
|
|
@ -34,6 +34,11 @@
|
|||
<p class="mapCreatedAt"><span>Created by:</span> {{user_name}} on {{created_at}}</p>
|
||||
<p class="mapEditedAt"><span>Last edited:</span> {{updated_at}}</p>
|
||||
<div class="mapInfoButtonsWrapper">
|
||||
<div class="mapInfoThumbnail">
|
||||
<div class="thumbnail"></div>
|
||||
<div class="tooltip">Update Thumbnail</div>
|
||||
<span>Thumb</span>
|
||||
</div>
|
||||
<div class="mapInfoDelete">
|
||||
<div class="deleteMap"></div>
|
||||
<span>Delete</span>
|
||||
|
|
|
@ -77,6 +77,11 @@
|
|||
<p class="mapCreatedAt"><span>Created by:</span> <%= @map.user == user ? "You" : @map.user.name %> on <%= @map.created_at.strftime("%m/%d/%Y") %></p>
|
||||
<p class="mapEditedAt"><span>Last edited:</span> <%= @map.updated_at.strftime("%m/%d/%Y") %></p>
|
||||
<div class="mapInfoButtonsWrapper">
|
||||
<div class="mapInfoThumbnail">
|
||||
<div class="thumbnail"></div>
|
||||
<div class="tooltip">Update Thumbnail</div>
|
||||
<span>Thumb</span>
|
||||
</div>
|
||||
<div class="mapInfoDelete">
|
||||
<div class="deleteMap"></div>
|
||||
<span>Delete</span>
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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({
|
||||
|
|
|
@ -35,9 +35,11 @@ const InfoBox = {
|
|||
data-bip-value="{{desc}}"
|
||||
>{{desc}}</span>`,
|
||||
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()
|
||||
|
|
|
@ -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!
|
||||
<a id="map-screenshot-download-link"
|
||||
href="${canvas.canvas.toDataURL()}"
|
||||
download="${filename}"
|
||||
>
|
||||
DOWNLOAD
|
||||
</a>`
|
||||
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!
|
||||
<a href="${canvas.canvas.toDataURL()}" download="${filename}">DOWNLOAD</a>`
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ export const invitedToCall = self => inviter => {
|
|||
notifyText += username + ' is inviting you to a conversation. Join live?'
|
||||
notifyText += ' <button type="button" class="toast-button button yes">Yes</button>'
|
||||
notifyText += ' <button type="button" class="toast-button button btn-no no">No</button>'
|
||||
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 += ' <button type="button" class="toast-button button yes">Yes</button>'
|
||||
notifyText += ' <button type="button" class="toast-button button btn-no no">No</button>'
|
||||
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 += ' <button type="button" class="toast-button button yes">Yes</button>'
|
||||
notifyText += ' <button type="button" class="toast-button button btn-no no">No</button>'
|
||||
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 += ' <button type="button" class="toast-button button">Yes</button>'
|
||||
notifyText += ' <button type="button" class="toast-button button btn-no">No</button>'
|
||||
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()
|
||||
|
|
|
@ -27,6 +27,9 @@ class ImportDialogBox extends Component {
|
|||
<div className="import-blue-button" onClick={this.handleExport('json')}>
|
||||
Export as JSON
|
||||
</div>
|
||||
<div className="import-blue-button" onClick={this.props.downloadScreenshot}>
|
||||
Download screenshot
|
||||
</div>
|
||||
<h3>IMPORT</h3>
|
||||
<p>To upload a file, drop it here:</p>
|
||||
<Dropzone onDropAccepted={this.handleFile}
|
||||
|
@ -42,7 +45,8 @@ class ImportDialogBox extends Component {
|
|||
|
||||
ImportDialogBox.propTypes = {
|
||||
onFileAdded: PropTypes.func,
|
||||
exampleImageUrl: PropTypes.string
|
||||
exampleImageUrl: PropTypes.string,
|
||||
downloadScreenshot: PropTypes.func
|
||||
}
|
||||
|
||||
export default ImportDialogBox
|
||||
|
|
Loading…
Reference in a new issue