Skip to content

Commit

Permalink
#1902 Save hotkey CTRL+S: An atom or structure copied to the clipboar…
Browse files Browse the repository at this point in the history
…d is saved with coordinates (#1956)

* Refactor savebutton module to get rid of onSave error, update keyHandle to remove not rendered structure from one to be saved

* #1902 Add type for saver

* #1902 Small refactoring - remove duplicate code

* #1902 Create separate function to prevent not rendered structure from saving

* #1902 Remove excess comment
  • Loading branch information
porcelain11 authored Jan 10, 2023
1 parent 5a53174 commit cc5a0ec
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 36 deletions.
16 changes: 1 addition & 15 deletions packages/ketcher-react/src/script/ui/component/actionmenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,7 @@ import Icon from './view/icon'
import action from '../action'
import clsx from 'clsx'
import { hiddenAncestor } from '../state/toolbar'

const isMac = /Mac/.test(navigator.platform) // eslint-disable-line no-undef
const shortcutAliasMap = {
Escape: 'Esc',
Delete: 'Del',
Mod: isMac ? '⌘' : 'Ctrl'
}

export function shortcutStr(shortcut) {
const key = Array.isArray(shortcut) ? shortcut[0] : shortcut
return key.replace(
/(\b[a-z]\b$|Mod|Escape|Delete)/g,
(k) => shortcutAliasMap[k] || k.toUpperCase()
)
}
import { shortcutStr } from '../views/toolbars/shortcutStr'

function isMenuOpened(currentNode) {
const parentNode = hiddenAncestor(currentNode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,33 @@
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
import { OutputFormatType } from 'ketcher-core'

import { saveAs } from 'file-saver'
import React, { PropsWithChildren } from 'react'
import { useAppContext } from '../../../../hooks'

const SaveButton = (props) => {
type Props = {
server?: any
filename: string
outputFormat?: OutputFormatType
data: any
type?: string
mode?: string
onSave?: () => void
onError?: (err: any) => void
className?: string
title?: string
}

type FileSaverReturnType = Promise<
(data: Blob | string, fn, type: string | undefined) => void | never
>

type SaverType = Awaited<FileSaverReturnType>
type SaveButtonProps = PropsWithChildren<Props>

const SaveButton = (props: SaveButtonProps) => {
const noop = () => null
const {
server,
Expand All @@ -28,11 +50,12 @@ const SaveButton = (props) => {
mode = 'saveFile',
onSave = noop,
onError = noop,
className
className,
title
} = props
const { getKetcherInstance } = useAppContext()

const save = (event) => {
const save = (event: React.KeyboardEvent | React.MouseEvent) => {
event.preventDefault()
switch (mode) {
case 'saveImage':
Expand All @@ -47,7 +70,7 @@ const SaveButton = (props) => {
const saveFile = () => {
if (data) {
try {
fileSaver(server).then((saver) => {
fileSaver(server).then((saver: SaverType) => {
saver(data, filename, type)
onSave()
})
Expand All @@ -59,31 +82,33 @@ const SaveButton = (props) => {

const saveImage = () => {
const ketcherInstance = getKetcherInstance()
ketcherInstance
.generateImage(data, { outputFormat })
.then((blob) => {
saveAs(blob, `${filename}.${outputFormat}`)
onSave()
})
.catch((error) => {
onError(error)
})
if (outputFormat) {
ketcherInstance
.generateImage(data, { outputFormat })
.then((blob) => {
saveAs(blob, `${filename}.${outputFormat}`)
onSave()
})
.catch((error) => {
onError(error)
})
}
}

return (
<button
title={title}
className={className}
onClick={(event) => {
save(event)
}}
{...props}
>
{props.children}
</button>
)
}

const fileSaver = (server) => {
const fileSaver = (server): FileSaverReturnType => {
return new Promise((resolve, reject) => {
if (global.Blob && saveAs) {
resolve((data, fn, type) => {
Expand All @@ -102,4 +127,4 @@ const fileSaver = (server) => {
})
}

export default SaveButton
export { SaveButton }
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import Icon from '../../component/view/icon'

import { Dialog } from '../../views/components'
import Input from '../../component/form/input'
import SaveButton from '../../component/view/savebutton'
import { SaveButton } from '../../component/view/savebutton'
import { SdfSerializer } from 'ketcher-core'
import classes from './template-lib.module.less'
import { connect } from 'react-redux'
Expand Down
15 changes: 15 additions & 0 deletions packages/ketcher-react/src/script/ui/state/hotkeys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { debounce, isEqual } from 'lodash/fp'
import { load, onAction } from './shared'

import actions from '../action'
import tools from '../action/tools'
import keyNorm from '../data/convert/keynorm'
import { openDialog } from './modal'
import { isIE } from 'react-device-detect'
Expand All @@ -41,6 +42,16 @@ export function initKeydownListener(element) {
}
}

function removeNotRenderedStruct(actionTool, event, dispatch) {
const { code, metaKey } = event
if (actionTool.tool === 'paste' && code === 'KeyS' && metaKey) {
dispatch({
type: 'ACTION',
action: tools['select-rectangle'].action
})
}
}

/* HotKeys */
function keyHandle(dispatch, state, hotKeys, event) {
if (state.modal) return
Expand Down Expand Up @@ -72,6 +83,10 @@ function keyHandle(dispatch, state, hotKeys, event) {
event.preventDefault()
return
}
// Removing from what should be saved - structure, which was added to paste tool,
// but not yet rendered on canvas
removeNotRenderedStruct(actionTool, event, dispatch)

if (clipArea.actions.indexOf(actName) === -1) {
let newAction = actions[actName].action
const hoveredItemId = getHoveredAtomId(render.ctab.atoms)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import {
import { Dialog } from '../../../../components'
import Tabs from 'src/script/ui/component/view/Tabs'
import { ErrorsContext } from '../../../../../../../contexts'
import SaveButton from '../../../../../component/view/savebutton'
import { SaveButton } from '../../../../../component/view/savebutton'
import { check } from '../../../../../state/server'
import classes from './Save.module.less'
import { connect } from 'react-redux'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { Dialog } from '../../../../components'
import Icon from '../../../../../component/view/icon'
import MeasureInput from '../../../../../component/form/MeasureInput/measure-input'
import OpenButton from '../../../../../component/view/openbutton'
import SaveButton from '../../../../../component/view/savebutton'
import { SaveButton } from '../../../../../component/view/savebutton'
import Select from '../../../../../component/form/Select'
import Accordion from './Accordion'
import { StructService } from 'ketcher-core'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
import { isMacOs } from 'react-device-detect'

const isMac = /Mac/.test(navigator.platform) // eslint-disable-line no-undef
const shortcutAliasMap = {
Escape: 'Esc',
Delete: 'Del',
Mod: isMac ? '⌘' : 'Ctrl'
Mod: isMacOs ? '⌘' : 'Ctrl'
}

export function shortcutStr(shortcut?: string | string[]) {
Expand Down

0 comments on commit cc5a0ec

Please sign in to comment.