Update: update dialog API to Electron 6.0 (#1317)

This commit is contained in:
Ran Luo 2019-09-02 21:46:51 +08:00 committed by GitHub
parent 96909e23a9
commit e25f5d8540
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 165 additions and 163 deletions

View File

@ -488,19 +488,18 @@ class App {
// --- renderer ------------------- // --- renderer -------------------
ipcMain.on('mt::select-default-directory-to-open', e => { ipcMain.on('mt::select-default-directory-to-open', async e => {
const { preferences } = this._accessor const { preferences } = this._accessor
const { defaultDirectoryToOpen } = preferences.getAll() const { defaultDirectoryToOpen } = preferences.getAll()
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
defaultPath: defaultDirectoryToOpen, defaultPath: defaultDirectoryToOpen,
properties: ['openDirectory', 'createDirectory'] properties: ['openDirectory', 'createDirectory']
}, paths => {
if (paths) {
preferences.setItems({ defaultDirectoryToOpen: paths[0] })
}
}) })
if (filePaths) {
preferences.setItems({ defaultDirectoryToOpen: filePaths[0] })
}
}) })
ipcMain.on('mt::open-setting-window', () => { ipcMain.on('mt::open-setting-window', () => {

View File

@ -168,13 +168,13 @@ class DataCenter extends EventEmitter {
win.webContents.send('AGANI::user-preference', userData) win.webContents.send('AGANI::user-preference', userData)
}) })
ipcMain.on('mt::ask-for-modify-image-folder-path', e => { ipcMain.on('mt::ask-for-modify-image-folder-path', async e => {
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
const folder = dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openDirectory', 'createDirectory'] properties: ['openDirectory', 'createDirectory']
}) })
if (folder && folder[0]) { if (filePaths && filePaths[0]) {
this.setItem('imageFolderPath', folder[0]) this.setItem('imageFolderPath', filePaths[0])
} }
}) })
@ -182,17 +182,18 @@ class DataCenter extends EventEmitter {
this.setItems(userData) this.setItems(userData)
}) })
ipcMain.on('mt::ask-for-image-path', e => { ipcMain.on('mt::ask-for-image-path', async e => {
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
const files = dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openFile'], properties: ['openFile'],
filters: [{ filters: [{
name: 'Images', name: 'Images',
extensions: IMAGE_EXTENSIONS extensions: IMAGE_EXTENSIONS
}] }]
}) })
if (files && files[0]) {
e.returnValue = files[0] if (filePaths && filePaths[0]) {
e.returnValue = filePaths[0]
} else { } else {
e.returnValue = '' e.returnValue = ''
} }

View File

@ -32,7 +32,7 @@ const exceptionToString = (error, type) => {
`Stack: ${stack}\n` `Stack: ${stack}\n`
} }
const handleError = (title, error, type) => { const handleError = async (title, error, type) => {
const { message, stack } = error const { message, stack } = error
// Write error into file // Write error into file
@ -52,7 +52,7 @@ const handleError = (title, error, type) => {
// show error dialog // show error dialog
if (app.isReady()) { if (app.isReady()) {
// Blocking message box // Blocking message box
const result = dialog.showMessageBox({ const { response } = await dialog.showMessageBox({
type: 'error', type: 'error',
buttons: [ buttons: [
'OK', 'OK',
@ -65,7 +65,7 @@ const handleError = (title, error, type) => {
detail: stack detail: stack
}) })
switch (result) { switch (response) {
case 1: { case 1: {
clipboard.writeText(`${title}\n${stack}`) clipboard.writeText(`${title}\n${stack}`)
break break

View File

@ -1,6 +1,5 @@
import fs from 'fs' import fs from 'fs'
import path from 'path' import path from 'path'
import { promisify } from 'util'
import { BrowserWindow, dialog, ipcMain, shell } from 'electron' import { BrowserWindow, dialog, ipcMain, shell } from 'electron'
import log from 'electron-log' import log from 'electron-log'
import { isDirectory, isFile } from 'common/filesystem' import { isDirectory, isFile } from 'common/filesystem'
@ -26,36 +25,36 @@ const handleResponseForExport = async (e, { type, content, pathname, markdown })
} }
const defaultPath = path.join(dirname, `${nakedFilename}${extension}`) const defaultPath = path.join(dirname, `${nakedFilename}${extension}`)
dialog.showSaveDialog(win, { const { filePath, canceled } = await dialog.showSaveDialog(win, {
defaultPath defaultPath
}, async filePath => { })
if (filePath) {
let data = content if (filePath && !canceled) {
try { let data = content
if (!content && type === 'pdf') { try {
data = await promisify(win.webContents.printToPDF.bind(win.webContents))({ printBackground: true }) if (!content && type === 'pdf') {
removePrintServiceFromWindow(win) data = await win.webContents.printToPDF({ printBackground: true })
}
if (data) {
await writeFile(filePath, data, extension)
win.webContents.send('AGANI::export-success', { type, filePath })
}
} catch (err) {
log.error(err)
const ERROR_MSG = err.message || `Error happened when export ${filePath}`
win.webContents.send('AGANI::show-notification', {
title: 'Export failure',
type: 'error',
message: ERROR_MSG
})
}
} else {
// User canceled save dialog
if (type === 'pdf') {
removePrintServiceFromWindow(win) removePrintServiceFromWindow(win)
} }
if (data) {
await writeFile(filePath, data, extension)
win.webContents.send('AGANI::export-success', { type, filePath })
}
} catch (err) {
log.error(err)
const ERROR_MSG = err.message || `Error happened when export ${filePath}`
win.webContents.send('AGANI::show-notification', {
title: 'Export failure',
type: 'error',
message: ERROR_MSG
})
} }
}) } else {
// User canceled save dialog
if (type === 'pdf') {
removePrintServiceFromWindow(win)
}
}
} }
const handleResponseForPrint = e => { const handleResponseForPrint = e => {
@ -69,7 +68,7 @@ const handleResponseForPrint = e => {
noLink: true, noLink: true,
message: 'Printing doesn\'t work', message: 'Printing doesn\'t work',
detail: 'Printing is disabled due to an Electron upstream issue. Please export the document as PDF and print the PDF file. We apologize for the inconvenience!' detail: 'Printing is disabled due to an Electron upstream issue. Please export the document as PDF and print the PDF file. We apologize for the inconvenience!'
}, () => {}) })
// win.webContents.print({ printBackground: true }, () => { // win.webContents.print({ printBackground: true }, () => {
// removePrintServiceFromWindow(win) // removePrintServiceFromWindow(win)
// }) // })
@ -88,13 +87,15 @@ const handleResponseForSave = async (e, { id, markdown, pathname, options }) =>
const alreadyExistOnDisk = !!pathname const alreadyExistOnDisk = !!pathname
let filePath = pathname let filePath = pathname
if (!filePath) { if (!filePath) {
filePath = await new Promise((resolve, reject) => { const { filePath: dialogPath, canceled } = await dialog.showSaveDialog(win, {
// TODO: Use asynchronous version that returns a "Promise" with Electron 6. defaultPath: path.join(getPath('documents'), `${recommendFilename}.md`)
dialog.showSaveDialog(win, {
defaultPath: path.join(getPath('documents'), `${recommendFilename}.md`)
}, resolve)
}) })
if (dialogPath && !canceled) {
filePath = dialogPath
}
} }
// Save dialog canceled by user - no error. // Save dialog canceled by user - no error.
@ -123,29 +124,27 @@ const handleResponseForSave = async (e, { id, markdown, pathname, options }) =>
}) })
} }
const showUnsavedFilesMessage = (win, files) => { const showUnsavedFilesMessage = async (win, files) => {
return new Promise((resolve, reject) => { const { response } = await dialog.showMessageBox(win, {
dialog.showMessageBox(win, { type: 'warning',
type: 'warning', buttons: ['Save', 'Cancel', 'Don\'t save'],
buttons: ['Save', 'Cancel', 'Don\'t save'], defaultId: 0,
defaultId: 0, message: `Do you want to save the changes you made to ${files.length} ${files.length === 1 ? 'file' : 'files'}?\n\n${files.map(f => f.filename).join('\n')}`,
message: `Do you want to save the changes you made to ${files.length} ${files.length === 1 ? 'file' : 'files'}?\n\n${files.map(f => f.filename).join('\n')}`, detail: 'Your changes will be lost if you don\'t save them.',
detail: 'Your changes will be lost if you don\'t save them.', cancelId: 1,
cancelId: 1, noLink: true
noLink: true
}, index => {
switch (index) {
case 2:
resolve({ needSave: false })
break
case 0:
setTimeout(() => {
resolve({ needSave: true })
})
break
}
})
}) })
switch (response) {
case 2:
return { needSave: false }
case 0:
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ needSave: true })
})
})
}
} }
const noticePandocNotFound = win => { const noticePandocNotFound = win => {
@ -197,7 +196,7 @@ ipcMain.on('mt::save-and-close-tabs', async (e, unsavedFiles) => {
} }
}) })
ipcMain.on('AGANI::response-file-save-as', (e, { id, markdown, pathname, options }) => { ipcMain.on('AGANI::response-file-save-as', async (e, { id, markdown, pathname, options }) => {
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
let recommendFilename = getRecommendTitleFromMarkdownString(markdown) let recommendFilename = getRecommendTitleFromMarkdownString(markdown)
if (!recommendFilename) { if (!recommendFilename) {
@ -209,36 +208,36 @@ ipcMain.on('AGANI::response-file-save-as', (e, { id, markdown, pathname, options
// on disk nevertheless but is already tracked by Mark Text. // on disk nevertheless but is already tracked by Mark Text.
const alreadyExistOnDisk = !!pathname const alreadyExistOnDisk = !!pathname
dialog.showSaveDialog(win, { let { filePath, canceled } = await dialog.showSaveDialog(win, {
defaultPath: pathname || getPath('documents') + `/${recommendFilename}.md` defaultPath: pathname || getPath('documents') + `/${recommendFilename}.md`
}, filePath => {
if (filePath) {
filePath = path.resolve(filePath)
writeMarkdownFile(filePath, markdown, options, win)
.then(() => {
if (!alreadyExistOnDisk) {
ipcMain.emit('window-add-file-path', win.id, filePath)
ipcMain.emit('menu-add-recently-used', filePath)
const filename = path.basename(filePath)
win.webContents.send('mt::set-pathname', { id, pathname: filePath, filename })
} else if (pathname !== filePath) {
// Update window file list and watcher.
ipcMain.emit('window-change-file-path', win.id, filePath, pathname)
const filename = path.basename(filePath)
win.webContents.send('mt::set-pathname', { id, pathname: filePath, filename })
} else {
ipcMain.emit('window-file-saved', win.id, filePath)
win.webContents.send('mt::tab-saved', id)
}
})
.catch(err => {
log.error(err)
win.webContents.send('mt::tab-save-failure', id, err.message)
})
}
}) })
if (filePath && !canceled) {
filePath = path.resolve(filePath)
writeMarkdownFile(filePath, markdown, options, win)
.then(() => {
if (!alreadyExistOnDisk) {
ipcMain.emit('window-add-file-path', win.id, filePath)
ipcMain.emit('menu-add-recently-used', filePath)
const filename = path.basename(filePath)
win.webContents.send('mt::set-pathname', { id, pathname: filePath, filename })
} else if (pathname !== filePath) {
// Update window file list and watcher.
ipcMain.emit('window-change-file-path', win.id, filePath, pathname)
const filename = path.basename(filePath)
win.webContents.send('mt::set-pathname', { id, pathname: filePath, filename })
} else {
ipcMain.emit('window-file-saved', win.id, filePath)
win.webContents.send('mt::tab-saved', id)
}
})
.catch(err => {
log.error(err)
win.webContents.send('mt::tab-save-failure', id, err.message)
})
}
}) })
ipcMain.on('mt::close-window-confirm', async (e, unsavedFiles) => { ipcMain.on('mt::close-window-confirm', async (e, unsavedFiles) => {
@ -259,11 +258,12 @@ ipcMain.on('mt::close-window-confirm', async (e, unsavedFiles) => {
buttons: ['Close', 'Keep It Open'], buttons: ['Close', 'Keep It Open'],
message: 'Failure while saving files', message: 'Failure while saving files',
detail: err.message detail: err.message
}, code => {
if (win.id && code === 0) {
ipcMain.emit('window-close-by-id', win.id)
}
}) })
.then(({ response }) => {
if (win.id && response === 0) {
ipcMain.emit('window-close-by-id', win.id)
}
})
}) })
} else { } else {
ipcMain.emit('window-close-by-id', win.id) ipcMain.emit('window-close-by-id', win.id)
@ -297,7 +297,7 @@ ipcMain.on('AGANI::window::drop', async (e, fileList) => {
} }
}) })
ipcMain.on('mt::rename', (e, { id, pathname, newPathname }) => { ipcMain.on('mt::rename', async (e, { id, pathname, newPathname }) => {
if (pathname === newPathname) return if (pathname === newPathname) return
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
@ -320,51 +320,51 @@ ipcMain.on('mt::rename', (e, { id, pathname, newPathname }) => {
if (!isFile(newPathname)) { if (!isFile(newPathname)) {
doRename() doRename()
} else { } else {
dialog.showMessageBox(win, { const { response } = await dialog.showMessageBox(win, {
type: 'warning', type: 'warning',
buttons: ['Replace', 'Cancel'], buttons: ['Replace', 'Cancel'],
defaultId: 1, defaultId: 1,
message: `The file "${path.basename(newPathname)}" already exists. Do you want to replace it?`, message: `The file "${path.basename(newPathname)}" already exists. Do you want to replace it?`,
cancelId: 1, cancelId: 1,
noLink: true noLink: true
}, index => { })
if (index === 0) {
doRename() if (response === 0) {
doRename()
}
}
})
ipcMain.on('AGANI::response-file-move-to', async (e, { id, pathname }) => {
const win = BrowserWindow.fromWebContents(e.sender)
const { filePath, canceled } = await dialog.showSaveDialog(win, {
buttonLabel: 'Move to',
nameFieldLabel: 'Filename:',
defaultPath: pathname
})
if (filePath && !canceled) {
fs.rename(pathname, filePath, err => {
if (err) {
log.error(`mt::rename: Cannot rename "${pathname}" to "${filePath}".\n${err.stack}`)
return
} }
ipcMain.emit('window-change-file-path', win.id, filePath, pathname)
e.sender.send('mt::set-pathname', { id, pathname: filePath, filename: path.basename(filePath) })
}) })
} }
}) })
ipcMain.on('AGANI::response-file-move-to', (e, { id, pathname }) => { ipcMain.on('mt::ask-for-open-project-in-sidebar', async e => {
const win = BrowserWindow.fromWebContents(e.sender) const win = BrowserWindow.fromWebContents(e.sender)
dialog.showSaveDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
buttonLabel: 'Move to',
nameFieldLabel: 'Filename:',
defaultPath: pathname
}, newPath => {
if (newPath) {
fs.rename(pathname, newPath, err => {
if (err) {
log.error(`mt::rename: Cannot rename "${pathname}" to "${newPath}".\n${err.stack}`)
return
}
ipcMain.emit('window-change-file-path', win.id, newPath, pathname)
e.sender.send('mt::set-pathname', { id, pathname: newPath, filename: path.basename(newPath) })
})
}
})
})
ipcMain.on('mt::ask-for-open-project-in-sidebar', e => {
const win = BrowserWindow.fromWebContents(e.sender)
dialog.showOpenDialog(win, {
properties: ['openDirectory', 'createDirectory'] properties: ['openDirectory', 'createDirectory']
}, directories => {
if (directories && directories[0]) {
ipcMain.emit('app-open-directory-by-id', win.id, directories[0], true)
}
}) })
if (filePaths && filePaths[0]) {
ipcMain.emit('app-open-directory-by-id', win.id, filePaths[0], true)
}
}) })
ipcMain.on('AGANI::format-link-click', (e, { data, dirname }) => { ipcMain.on('AGANI::format-link-click', (e, { data, dirname }) => {
@ -397,45 +397,45 @@ export const importFile = async win => {
return noticePandocNotFound(win) return noticePandocNotFound(win)
} }
dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openFile'], properties: ['openFile'],
filters: [{ filters: [{
name: 'All Files', name: 'All Files',
extensions: PANDOC_EXTENSIONS extensions: PANDOC_EXTENSIONS
}] }]
}, filePath => {
if (filePath) {
openPandocFile(win.id, filePath)
}
}) })
if (filePaths && filePaths[0]) {
openPandocFile(win.id, filePaths[0])
}
} }
export const print = win => { export const print = win => {
win.webContents.send('AGANI::print') win.webContents.send('AGANI::print')
} }
export const openFile = win => { export const openFile = async win => {
dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openFile', 'multiSelections'], properties: ['openFile', 'multiSelections'],
filters: [{ filters: [{
name: 'text', name: 'text',
extensions: MARKDOWN_EXTENSIONS extensions: MARKDOWN_EXTENSIONS
}] }]
}, paths => {
if (paths && Array.isArray(paths)) {
ipcMain.emit('app-open-files-by-id', win.id, paths)
}
}) })
if (filePaths && Array.isArray(filePaths)) {
ipcMain.emit('app-open-files-by-id', win.id, filePaths)
}
} }
export const openFolder = win => { export const openFolder = async win => {
dialog.showOpenDialog(win, { const { filePaths } = await dialog.showOpenDialog(win, {
properties: ['openDirectory', 'createDirectory'] properties: ['openDirectory', 'createDirectory']
}, directories => {
if (directories && directories[0]) {
openFileOrFolder(win, directories[0])
}
}) })
if (filePaths && filePaths[0]) {
openFileOrFolder(win, filePaths[0])
}
} }
export const openFileOrFolder = (win, pathname) => { export const openFileOrFolder = (win, pathname) => {

View File

@ -100,23 +100,25 @@ class EditorWindow extends BaseWindow {
log.error(`The window failed to load or was cancelled: ${errorCode}; ${errorDescription}`) log.error(`The window failed to load or was cancelled: ${errorCode}; ${errorDescription}`)
}) })
win.webContents.once('crashed', (event, killed) => { win.webContents.once('crashed', async (event, killed) => {
const msg = `The renderer process has crashed unexpected or is killed (${killed}).` const msg = `The renderer process has crashed unexpected or is killed (${killed}).`
log.error(msg) log.error(msg)
dialog.showMessageBox(win, { const { response } = await dialog.showMessageBox(win, {
type: 'warning', type: 'warning',
buttons: ['Close', 'Reload', 'Keep It Open'], buttons: ['Close', 'Reload', 'Keep It Open'],
message: 'Mark Text has crashed', message: 'Mark Text has crashed',
detail: msg detail: msg
}, code => {
if (win.id) {
switch (code) {
case 0: return this.destroy()
case 1: return this.reload()
}
}
}) })
if (win.id) {
switch (response) {
case 0:
return this.destroy()
case 1:
return this.reload()
}
}
}) })
win.on('focus', () => { win.on('focus', () => {