This repository has been archived by the owner on Oct 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 224
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: enable clipboard usage between alva instances
- Loading branch information
Showing
22 changed files
with
1,263 additions
and
708 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import * as AlvaUtil from '../alva-util'; | ||
import * as Electron from 'electron'; | ||
import * as Message from '../message'; | ||
import { isMessage } from '../sender/is-message'; | ||
import * as uuid from 'uuid'; | ||
|
||
export function setClipboard(payload: Message.Clipboard['payload']): void { | ||
Electron.clipboard.writeBuffer( | ||
'application/alva', | ||
Buffer.from( | ||
JSON.stringify({ | ||
type: Message.MessageType.Clipboard, | ||
id: uuid.v4(), | ||
payload | ||
}) | ||
) | ||
); | ||
} | ||
|
||
export function getClipboard(): Message.Clipboard | undefined { | ||
const rawData = Electron.clipboard.readBuffer('application/alva').toString(); | ||
|
||
if (!rawData) { | ||
return; | ||
} | ||
|
||
const parseResult = AlvaUtil.parseJSON(rawData); | ||
|
||
if (parseResult.type === AlvaUtil.ParseResultType.Error) { | ||
console.error(parseResult.error); | ||
return; | ||
} | ||
|
||
if (!isMessage(parseResult.result)) { | ||
console.error(`Received malformed clipboard message: ${parseResult.data}`); | ||
return; | ||
} | ||
|
||
if (parseResult.result.type !== Message.MessageType.Clipboard) { | ||
return; | ||
} | ||
|
||
return parseResult.result as Message.Clipboard; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
import * as Electron from 'electron'; | ||
import * as Message from '../message'; | ||
import * as uuid from 'uuid'; | ||
import { checkForUpdates } from './auto-updater'; | ||
import * as electronIsDev from 'electron-is-dev'; | ||
import { showError } from './show-error'; | ||
import { requestAppSafely } from './request-app'; | ||
import { requestProjectSafely } from './request-project'; | ||
import { showContextMenu } from './show-context-menu'; | ||
import { showMainMenu } from './show-main-menu'; | ||
|
||
import { | ||
ServerMessageHandlerContext, | ||
ServerMessageHandlerInjection | ||
} from './create-server-message-handler'; | ||
|
||
export async function createAppMessageHandler( | ||
ctx: ServerMessageHandlerContext, | ||
injection: ServerMessageHandlerInjection | ||
): Promise<(message: Message.Message) => Promise<void>> { | ||
return async function appMessageHandler(message: Message.Message): Promise<void> { | ||
switch (message.type) { | ||
case Message.MessageType.CheckForUpdatesRequest: { | ||
if (ctx.win) { | ||
checkForUpdates(ctx.win, true); | ||
} | ||
break; | ||
} | ||
case Message.MessageType.AppLoaded: { | ||
const pathToOpen = await injection.ephemeralStore.getProjectPath(); | ||
|
||
injection.sender.send({ | ||
id: uuid.v4(), | ||
type: Message.MessageType.StartApp, | ||
payload: { | ||
app: await injection.ephemeralStore.getAppState(), | ||
port: ctx.port as number | ||
} | ||
}); | ||
|
||
if (electronIsDev && pathToOpen) { | ||
injection.sender.send({ | ||
id: uuid.v4(), | ||
type: Message.MessageType.OpenFileRequest, | ||
payload: { path: pathToOpen } | ||
}); | ||
} | ||
|
||
break; | ||
} | ||
case Message.MessageType.Reload: { | ||
injection.emitter.emit('reload', message.payload || {}); | ||
break; | ||
} | ||
case Message.MessageType.Maximize: { | ||
if (ctx.win) { | ||
ctx.win.isMaximized() ? ctx.win.unmaximize() : ctx.win.maximize(); | ||
} | ||
break; | ||
} | ||
case Message.MessageType.ShowError: { | ||
const error = new Error(message.payload.message); | ||
error.stack = message.payload.stack; | ||
showError(error); | ||
break; | ||
} | ||
case Message.MessageType.OpenExternalURL: { | ||
Electron.shell.openExternal(message.payload); | ||
break; | ||
} | ||
case Message.MessageType.ContextMenuRequest: { | ||
showContextMenu(message.payload, { sender: injection.sender }); | ||
break; | ||
} | ||
case Message.MessageType.ChangeApp: { | ||
injection.ephemeralStore.setAppState(message.payload.app); | ||
const project = await requestProjectSafely(injection.sender); | ||
|
||
showMainMenu( | ||
{ app: message.payload.app, project: project ? project.toJSON() : undefined }, | ||
{ sender: injection.sender } | ||
); | ||
|
||
break; | ||
} | ||
case Message.MessageType.ChangeProject: { | ||
const app = await requestAppSafely(injection.sender); | ||
|
||
if (!app) { | ||
return; | ||
} | ||
|
||
showMainMenu( | ||
{ app: app.toJSON(), project: message.payload.project }, | ||
{ sender: injection.sender } | ||
); | ||
} | ||
} | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import * as Clipboard from './clipboard'; | ||
import * as Message from '../message'; | ||
import { requestProject } from './request-project'; | ||
import * as Types from '../types'; | ||
import * as uuid from 'uuid'; | ||
|
||
import { | ||
ServerMessageHandlerContext, | ||
ServerMessageHandlerInjection | ||
} from './create-server-message-handler'; | ||
|
||
export async function createEditMessageHandler( | ||
ctx: ServerMessageHandlerContext, | ||
injection: ServerMessageHandlerInjection | ||
): Promise<(message: Message.Message) => Promise<void>> { | ||
return async function editMessageHandler(message: Message.Message): Promise<void> { | ||
switch (message.type) { | ||
case Message.MessageType.Cut: | ||
case Message.MessageType.Copy: { | ||
const project = await requestProject(injection.sender); | ||
const focusedItemType = project.getFocusedItemType(); | ||
const focusedItem = project.getFocusedItem(); | ||
|
||
if (!focusedItem || focusedItemType === Types.ItemType.None) { | ||
return; | ||
} | ||
|
||
Clipboard.setClipboard({ | ||
type: serializeItemType(focusedItemType), | ||
item: focusedItem.toJSON(), | ||
project: project.toJSON() | ||
}); | ||
|
||
break; | ||
} | ||
case Message.MessageType.CutElement: | ||
case Message.MessageType.CopyElement: { | ||
const project = await requestProject(injection.sender); | ||
const element = project.getElementById(message.payload); | ||
|
||
if (!element) { | ||
return; | ||
} | ||
|
||
Clipboard.setClipboard({ | ||
type: serializeItemType(Types.ItemType.Element), | ||
item: element.toJSON(), | ||
project: project.toJSON() | ||
}); | ||
|
||
break; | ||
} | ||
case Message.MessageType.Paste: { | ||
const clipboard = Clipboard.getClipboard(); | ||
|
||
if (!clipboard) { | ||
return; | ||
} | ||
|
||
const itemType = deserializeItemType(clipboard.payload.type); | ||
const targetType = message.payload | ||
? message.payload.targetType | ||
: Types.ElementTargetType.Auto; | ||
const targetId = message.payload ? message.payload.id : ''; | ||
|
||
switch (itemType) { | ||
case Types.ItemType.Element: | ||
injection.sender.send({ | ||
id: uuid.v4(), | ||
type: Message.MessageType.PasteElement, | ||
payload: { | ||
element: clipboard.payload.item as Types.SerializedElement, | ||
project: clipboard.payload.project, | ||
targetType, | ||
targetId | ||
} | ||
}); | ||
break; | ||
case Types.ItemType.Page: | ||
injection.sender.send({ | ||
id: uuid.v4(), | ||
type: Message.MessageType.PastePage, | ||
payload: { | ||
page: clipboard.payload.item as Types.SerializedPage, | ||
project: clipboard.payload.project | ||
} | ||
}); | ||
} | ||
} | ||
} | ||
}; | ||
} | ||
|
||
function serializeItemType(type: Types.ItemType): Types.SerializedItemType { | ||
switch (type) { | ||
case Types.ItemType.Element: | ||
return 'element'; | ||
case Types.ItemType.Page: | ||
return 'page'; | ||
case Types.ItemType.None: | ||
return 'none'; | ||
} | ||
} | ||
|
||
function deserializeItemType(type: Types.SerializedItemType): Types.ItemType { | ||
switch (type) { | ||
case 'element': | ||
return Types.ItemType.Element; | ||
case 'page': | ||
return Types.ItemType.Page; | ||
case 'none': | ||
return Types.ItemType.None; | ||
} | ||
} |
Oops, something went wrong.