Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/containers/blocks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ class Blocks extends React.Component {
}
componentWillUnmount() {
this.detachVM()
this.onTargetsUpdate.cancel()
this.workspace.dispose()
clearTimeout(this.toolboxUpdateTimeout)
}
Expand Down
48 changes: 26 additions & 22 deletions src/containers/stage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -299,22 +299,24 @@ class Stage extends React.Component {
}
this.setState({ mouseDownTimeoutId: null })
}
drawDragCanvas(drawableData) {
const { data, width, height, x, y } = drawableData
this.dragCanvas.width = width
this.dragCanvas.height = height
// Need to convert uint8array from WebGL readPixels into Uint8ClampedArray
// for ImageData constructor. Shares underlying buffer, so it is fast.
const imageData = new ImageData(
new Uint8ClampedArray(data.buffer),
width,
height
)
drawDragCanvas(drawableData, x, y) {
const {
imageData,
x: boundsX,
y: boundsY,
width: boundsWidth,
height: boundsHeight,
} = drawableData
this.dragCanvas.width = imageData.width
this.dragCanvas.height = imageData.height
// On high-DPI devices the extracted image is larger than its CSS size
this.dragCanvas.style.width = `${boundsWidth}px`
this.dragCanvas.style.height = `${boundsHeight}px`
this.dragCanvas.getContext('2d').putImageData(imageData, 0, 0)
// Position so that pick location is at (0, 0) so that positionDragCanvas()
// Position so that pick location is at (0, 0) so that positionDragCanvas()
// can use translation to move to mouse position smoothly.
this.dragCanvas.style.left = `${-x}px`
this.dragCanvas.style.top = `${-y}px`
this.dragCanvas.style.left = `${boundsX - x}px`
this.dragCanvas.style.top = `${boundsY - y}px`
this.dragCanvas.style.display = 'block'
}
clearDragCanvas() {
Expand All @@ -334,28 +336,30 @@ class Stage extends React.Component {
if (drawableId === null) {
return
}
const drawableData = this.renderer.extractDrawable(drawableId, x, y)
const targetId = this.props.vm.getTargetIdForDrawableId(drawableId)
if (targetId === null) {
return
}
const target = this.props.vm.runtime.getTargetById(targetId)

// Only start drags on non-draggable targets in editor drag mode
if (!this.props.useEditorDragStyle) {
const target = this.props.vm.runtime.getTargetById(targetId)
if (!target.draggable) {
return
}
if (!(this.props.useEditorDragStyle || target.draggable)) {
return
}

const [scratchMouseX, scratchMouseY] = this.getScratchCoords(x, y)
const offsetX = target.x - scratchMouseX
const offsetY = -(target.y + scratchMouseY)

this.props.vm.startDrag(targetId)
this.setState({
isDragging: true,
dragId: targetId,
dragOffset: drawableData.scratchOffset,
dragOffset: [offsetX, offsetY],
})
if (this.props.useEditorDragStyle) {
this.drawDragCanvas(drawableData)
const drawableData = this.renderer.extractDrawableScreenSpace(drawableId)
this.drawDragCanvas(drawableData, x, y)
this.positionDragCanvas(x, y)
this.props.vm.postSpriteInfo({ visible: false })
}
Expand Down
9 changes: 6 additions & 3 deletions src/lib/project-save-hoc.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
import React from 'react'
import PropTypes from 'prop-types'
import {
Expand Down Expand Up @@ -225,14 +226,16 @@ const ProjectSaveHOC = (WrappedComponent) => {
dispatch: PropTypes.func,
}

return connect((state) => ({
const mapStateToProps = (state, ownProps) => ({
isEduGame: state.scratchGui.eduLayer.enabled,
projectId: state.scratchGui.project.id,
projectName: state.scratchGui.project.name,
routeProject: (state.router.params || {}).projectId || null,
routeProject: ownProps.match.params.projectId || null,
userId: state.scratchGui.project.userId,
vm: state.scratchGui.vm,
}))(ProjectSaveComponent)
})

return withRouter(connect(mapStateToProps)(ProjectSaveComponent))
}

export default ProjectSaveHOC
62 changes: 37 additions & 25 deletions src/lib/unsaved-project-blocker.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,56 @@ import { connect } from 'react-redux'
import PropTypes from 'prop-types'
import { history } from './app-state-hoc.jsx'

const LEAVE_MESSAGE =
'Möchtest du die Seite wirklich verlassen? Dein Projekt geht ohne Speichern verloren!'

const UnsavedProjectBlockerHOC = (WrappedComponent) => {
class UnsavedProjectBlocker extends React.Component {
constructor(props) {
super(props)
this.unblockRouter = null
}
stopBrowserNavigation(event) {
event.preventDefault()
event.returnValue = ''
}
routerBlock() {
const unblock = history.block(() => {
return window.confirm(
'Möchtest du die Seite wirklich verlassen? Dein Projekt geht ohne Speichern verloren!'
)
})

return () => {
unblock()
block() {
if (this.unblockRouter) {
return
}
window.addEventListener('beforeunload', this.stopBrowserNavigation)
// history v4 shows a string prompt via window.confirm
this.unblockRouter = history.block(LEAVE_MESSAGE)
}
unblock() {
window.removeEventListener('beforeunload', this.stopBrowserNavigation)
if (this.unblockRouter) {
this.unblockRouter()
this.unblockRouter = null
}
}
syncBlocker() {
if (process.env.NODE_ENV !== 'production' || typeof window !== 'object') {
return
}
if (this.props.isProjectUnsaved) {
this.block()
} else {
this.unblock()
}
}
componentDidMount() {
this.syncBlocker()
}
componentDidUpdate(oldProps) {
if (this.props.isProjectUnsaved !== oldProps.isProjectUnsaved) {
if (
process.env.NODE_ENV === 'production' &&
typeof window === 'object'
) {
if (this.props.isProjectUnsaved) {
// Warn before navigating away
window.addEventListener('beforeunload', this.stopBrowserNavigation)
this.routerBlock()
} else {
window.removeEventListener(
'beforeunload',
this.stopBrowserNavigation
)
}
}
this.syncBlocker()
}
}
componentWillUnmount() {
window.removeEventListener('beforeunload', this.stopBrowserNavigation)
if (typeof window === 'object') {
this.unblock()
}
}
render() {
const {
Expand Down
Loading