diff --git a/main/create-window.js b/main/actions/create-window.js
similarity index 51%
rename from main/create-window.js
rename to main/actions/create-window.js
index 6d7f4b9..32a5a49 100644
--- a/main/create-window.js
+++ b/main/actions/create-window.js
@@ -1,24 +1,12 @@
-const { app, BrowserWindow } = require('electron')
+const { BrowserWindow } = require('electron')
const { resolve } = require('app-root-path')
const dev = require('electron-is-dev')
-const startServer = require('./server')
-const setMenu = require('./menu')
-const setIPCEvents = require('./ipc-events')
-
-async function createWindow () {
- let server
-
- try {
- // when starting the window run the server
- server = await startServer()
- } catch (error) {
- console.error(error)
- app.exit(error)
- }
+const setMenu = require('../menu')
+async function createWindow (_windows) {
// after the server starts create the electron browser window
- global.win = new BrowserWindow({
+ let win = new BrowserWindow({
title: 'Pulse',
backgroundColor: '#058ecd',
height: 768,
@@ -32,25 +20,24 @@ async function createWindow () {
textAreasAreResizable: false
}
})
+ const id = win.id
// open our server URL or the build directory in production
- global.win.loadURL(dev ? 'http://localhost:8000' : `file://${resolve('./build')}/index.html`)
+ win.loadURL(dev ? 'http://localhost:8000' : `file://${resolve('./build')}/index.html`)
// in development open devtools
if (dev) {
- global.win.webContents.openDevTools()
+ win.webContents.openDevTools()
}
- global.win.once('ready-to-show', () => {
- global.win.show()
+ win.once('ready-to-show', () => {
+ win.show()
})
- global.win.on('close', () => {
- global.win = null
- if (server) server.close()
+ win.on('closed', () => {
+ _windows.delete(id)
})
- setIPCEvents()
setMenu()
// TODO: implement a way to get the Markdown data
@@ -58,6 +45,8 @@ async function createWindow () {
// const url = request.url.substr(8)
// console.log(url)
// })
+ _windows.set(id, win)
+ return win
}
module.exports = createWindow
diff --git a/main/assets/icon.icns b/main/assets/icon.icns
index a9eabc2..0d24384 100644
Binary files a/main/assets/icon.icns and b/main/assets/icon.icns differ
diff --git a/main/assets/icon.ico b/main/assets/icon.ico
index bb1103d..f1f69f5 100644
Binary files a/main/assets/icon.ico and b/main/assets/icon.ico differ
diff --git a/main/assets/icon.png b/main/assets/icon.png
index fe53d87..d791f1b 100644
Binary files a/main/assets/icon.png and b/main/assets/icon.png differ
diff --git a/main/index.js b/main/index.js
index 9d86f7b..71fefce 100644
--- a/main/index.js
+++ b/main/index.js
@@ -1,17 +1,45 @@
+const WindowManager = require('./window-manager')
const { app } = require('electron')
-const createWindow = require('./create-window')
+const dev = require('electron-is-dev')
+const startServer = require('./server')
+const setIPCEvents = require('./ipc-events')
-app.on('ready', createWindow)
+class Main {
+ constructor () {
+ this.server = null
+ this._windowManager = new WindowManager()
+ }
+ get windowManager () {
+ return this._windowManager
+ }
-app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') {
+ async onReady () {
+ if (dev) {
+ try {
+ this.server = await startServer()
+ } catch (error) {
+ console.error(error)
+ app.exit(error)
+ }
+ }
+ this._windowManager.createNewWindow()
+ }
+
+ onWindowAllClosed () {
app.quit()
}
+}
+const main = new Main()
+
+app.once('ready', () => {
+ main.onReady()
+ setIPCEvents()
})
-app.on('activate', () => {
- if (!global.win) {
- createWindow()
+app.on('window-all-closed', () => {
+ if (process.platform !== 'darwin') {
+ main.onWindowAllClosed()
}
+ if (this.server) this.server.close()
})
diff --git a/main/menu.js b/main/menu.js
index 19e8d2d..308079f 100644
--- a/main/menu.js
+++ b/main/menu.js
@@ -16,6 +16,16 @@ const template = [
}
}
},
+ {
+ label: 'New window',
+ accelerator: 'CmdOrCtrl+Alt+N',
+ click () {
+ const webContent = webContents.getFocusedWebContents()
+ if (webContent) {
+ webContent.send('shortcut-press')
+ }
+ }
+ },
{
label: 'Open...',
accelerator: 'CmdOrCtrl+O',
@@ -29,7 +39,7 @@ const template = [
{
label: 'Save file',
accelerator: 'CmdOrCtrl+S',
- click() {
+ click () {
const webContent = webContents.getFocusedWebContents()
if (webContent) {
webContent.send('trying-to-save')
diff --git a/main/window-manager.js b/main/window-manager.js
new file mode 100644
index 0000000..93e268e
--- /dev/null
+++ b/main/window-manager.js
@@ -0,0 +1,27 @@
+const { ipcMain, BrowserWindow } = require('electron')
+const createWindow = require('./actions/create-window')
+
+class WindowManager {
+ constructor () {
+ this._windows = new Map()
+ ipcMain.on('create-new-window', this._onRequestCreateNewWindow.bind(this))
+ }
+
+ reload () {
+ const w = BrowserWindow.getFocusedWindow()
+ if (w) {
+ w.reload()
+ }
+ }
+
+ createNewWindow (value = '', fileName = undefined) {
+ createWindow(this._windows, value, fileName)
+ }
+
+ _onRequestCreateNewWindow (event) {
+ this.createNewWindow()
+ event.sender.send('created-new-window')
+ }
+}
+
+module.exports = WindowManager
diff --git a/renderer/components/window-button.js b/renderer/components/window-button.js
new file mode 100644
index 0000000..d547414
--- /dev/null
+++ b/renderer/components/window-button.js
@@ -0,0 +1,48 @@
+import { Component } from 'react'
+import { Base } from 'pulse-editor/buttons'
+import { ipcRenderer } from 'electron'
+import { func } from 'prop-types'
+import isMac from 'pulse-editor/built/utils/is-mac'
+import Icon from 'react-icons/lib/fa/plus-circle'
+
+export default class CreateButton extends Component {
+ static contextTypes = {
+ setShortcut: func.isRequired,
+ removeShortcut: func.isRequired,
+ writeValue: func.isRequired,
+ setFileName: func.isRequired
+ }
+
+ componentDidMount () {
+ ipcRenderer.on('shortcut-press', this.createWindow)
+ this.context.setShortcut({
+ ctrlKey: !isMac(),
+ metaKey: isMac(),
+ altKey: true,
+ shiftKey: false,
+ keyName: 'n',
+ updater: selected => selected,
+ handler: event => {
+ this.createWindow()
+ return event.selection
+ }
+ })
+ }
+
+ componentWillUnmount () {
+ this.context.removeShortcut({ keyName: 'n' })
+ ipcRenderer.removeListener('shortcut-press', this.createWindow)
+ }
+
+ createWindow = () => ipcRenderer.send('create-new-window')
+
+ handleClick = () => this.createWindow()
+
+ render = () => (
+
+
+ New Window
+
+
+ )
+}
diff --git a/renderer/pages/index.js b/renderer/pages/index.js
index 6a79976..745eaa9 100644
--- a/renderer/pages/index.js
+++ b/renderer/pages/index.js
@@ -21,6 +21,7 @@ import Save from '../components/save-button'
import Open from '../components/open-button'
import New from '../components/new-button'
import Export from '../components/export-button'
+import Create from '../components/window-button'
import BoldIcon from 'react-icons/lib/fa/bold'
import ItalicIcon from 'react-icons/lib/fa/italic'
@@ -50,12 +51,11 @@ export default class extends Component {
setFileName: this.setFileName
}
}
-
componentDidMount () {
this.$preview = document.querySelector('.PulseEditor-preview')
this.$preview.addEventListener('click', this.handlePreviewLinkClick)
}
-
+
componentWillUnmount () {
this.$preview.removeEventListener('click', this.handlePreviewLinkClick)
}
@@ -70,7 +70,61 @@ export default class extends Component {
)
}
- handleDrop = event => event.preventDefault()
+ successMessage (fileName, successData) {
+ const resultMessage = {
+ target: {
+ value: `${this.editor.domField.value} ![${fileName}](${successData.data.link})`
+ }
+ }
+ this.editor.writeValue(resultMessage)
+ }
+
+ async sendImage (file, imageData) {
+ const response = await fetch('https://api.imgur.com/3/image',
+ {
+ method: 'POST',
+ headers: {
+ 'Authorization': `Client-ID e3f6a51d5c12580`
+ },
+ body: imageData}
+ )
+ if (response.ok) {
+ const successData = await response.json()
+ return this.successMessage(file.name, successData)
+ }
+ this.errorMessage()
+ }
+
+ errorMessage () {
+ const errorMessage = {
+ target: {
+ value: `${this.editor.domField.value} ![A problem when sending the file, please try again.]()`
+ }
+ }
+ this.editor.writeValue(errorMessage)
+ }
+ handleDrop = event => {
+ event.preventDefault()
+ // without 'preventDefault', when you drop the image, change the whole editor view
+ const defaultMessage = {
+ target: {
+ value: `${this.editor.domField.value} ![Problem with the format file](url)`
+ }
+ }
+ const file = event.dataTransfer.files[0]
+ const imageFormat = ['jpeg', 'png', 'gif', 'peg', 'apng', 'tiff', 'pdf', 'xcf']
+ const validFile = imageFormat.filter((format) => {
+ const regExp = new RegExp("\\b(" + format + ")\\b")
+ return regExp.test(file.type)
+ })
+ if (!!validFile && validFile.length !== 0) {
+ const imageData = new FormData()
+ imageData.append('image', file)
+ return this.sendImage(file, imageData, defaultMessage)
+ }
+ // if file format doesn't support by imgur, advice the user
+ return this.editor.writeValue(defaultMessage)
+ }
handleChange= event => {
if (event.markdown && this.state.fileName) {
@@ -149,6 +203,7 @@ export default class extends Component {
+