Skip to content

Commit a2a349b

Browse files
authoredJul 19, 2021
Merge pull request #19 from BUPTlhuanyu/restructure
Restructure
2 parents 7ee5e82 + 8bc1d8e commit a2a349b

File tree

15 files changed

+184
-15
lines changed

15 files changed

+184
-15
lines changed
 

‎.eslintrc.json

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"@typescript-eslint/no-use-before-define": [1],
2020
"operator-linebreak": "off",
2121
"@typescript-eslint/no-parameter-properties": "off",
22-
"spaced-comment": "off"
22+
"spaced-comment": "off",
23+
"max-len": "off"
2324
}
24-
}
25+
}

‎packages/services/files/fileService.ts

+20
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import {IFileService} from './files';
55
import EventEmitter from 'events';
66
import fs from 'fs';
77
import paths from 'path';
8+
import Jimp from 'jimp';
9+
import {USER_HOME, USER_DATA_FOLDER} from 'shared/common/constant';
810

911
export const fileEvent = new EventEmitter();
1012
// 域名设计
@@ -110,4 +112,22 @@ export class FileService implements IFileService {
110112
encoding: 'utf8'
111113
});
112114
}
115+
116+
async storeImgFromBase64(path: string, data: any): Promise<any> {
117+
if (!path) {
118+
return Promise.reject();
119+
}
120+
path = `${USER_HOME}/${USER_DATA_FOLDER}/${path}`
121+
const buffer = Buffer.from(data.split(',')[1], 'base64');
122+
return Jimp.read(buffer).then((res) => {
123+
try {
124+
res.quality(1).write(path);
125+
return Promise.resolve(path);
126+
} catch(err) {
127+
return Promise.reject();
128+
}
129+
}).catch(err => {
130+
console.error(err);
131+
});
132+
}
113133
}

‎packages/services/files/files.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -34,5 +34,7 @@ export interface IFileService {
3434
*/
3535
writeFile(resource: URI, content: string): Promise<string>;
3636

37-
getDirTree(resource: URI): any[] | null
37+
getDirTree(resource: URI): any[] | null;
38+
39+
storeImgFromBase64(resource: URI, content: string): Promise<string>;
3840
}

‎packages/services/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"private": true,
66
"dependencies": {
77
"highlight.js": "^10.6.0",
8+
"jimp": "^0.16.1",
89
"shared": "^0.0.0"
910
},
1011
"author": "lhuanyu <lhuanyutot@163.com>",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export {};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
export class FileUserDataProvider {
2+
constructor() {}
3+
4+
watch() {}
5+
6+
stat() {}
7+
8+
mkdir() {}
9+
10+
rename() {}
11+
12+
readFile() {}
13+
14+
readFileStream() {}
15+
16+
readdir() {}
17+
18+
writeFile() {}
19+
20+
close() {}
21+
22+
read() {}
23+
24+
write() {}
25+
26+
delete() {}
27+
}

‎packages/shared/common/constant.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,6 @@
1-
export const DEVELOP_PORT = 3000;
1+
export const DEVELOP_PORT = 3000;
2+
3+
export const USER_HOME = process.env.HOME || process.env.USERPROFILE;
4+
export const USER_DATA_FOLDER = 'Library/Application Support/pandora-user-images';
5+
6+
export const PROTOCOL_IMG = 'pandora-img';

‎packages/shared/utils/chunk.ts

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* @file
3+
*/
4+
export default class Uploader {
5+
6+
}
7+
8+
export function uploader(sender: any, data: string) {
9+
return sender.send(data);
10+
}

‎packages/shared/utils/img.ts

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/**
2+
* @file
3+
*/
4+
export function blobToBase64(blob: File) {
5+
return new Promise((resolve, reject) => {
6+
let reader = new FileReader();
7+
8+
reader.onload = function (e: ProgressEvent<FileReader>) {
9+
e.target ? resolve(e.target.result) : reject(new Error('transfer base64 failed'));
10+
};
11+
12+
reader.readAsDataURL(blob);
13+
});
14+
}
15+
16+
// TODO: 完善并放到 common 中
17+
export function getFileName() {
18+
const date = new Date();
19+
const year = date.getFullYear();
20+
const month = date.getMonth();
21+
const day = date.getDay();
22+
const hours = date.getHours();
23+
const second = date.getSeconds();
24+
const milsecond = date.getMilliseconds();
25+
return `${year}${month}${day}${hours}${second}${milsecond}${Math.random()* 1e6 | 0}.png`;
26+
}

‎packages/views/src/components/md-view/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ interface MdViewProps {
1010
value: string;
1111
}
1212

13-
let md = getMd('wx');
13+
let md = getMd('wx', {html: true});
1414

1515
export default function MdView(props: MdViewProps) {
1616
const [mdString, setMdString] = useState<string>('');

‎packages/views/src/components/useCodemirror/index.tsx

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React, {useState, useEffect, useRef, useCallback} from 'react';
22
import codemirror, {createCodemirror} from './code';
33

4-
interface CodemirrorObj {
4+
export interface CodemirrorObj {
55
code: string;
66
setCodemirrorEle: React.Dispatch<React.SetStateAction<Element | null>>;
77
scroll: {
@@ -48,7 +48,6 @@ export default function useCodemirror(): CodemirrorObj {
4848
(editor: codemirror.Editor | null) => {
4949
if (editor) {
5050
const {clientHeight, height, top} = editor.getScrollInfo();
51-
console.log('updateScrollInfo', clientHeight, height, top);
5251
setScroll({
5352
scrollTop: top,
5453
clientHeight,

‎packages/views/src/pages/editor/editor.tsx

+50-4
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import './editor.scss';
22

33
import React, {useRef, useEffect, useCallback, useState, useContext} from 'react';
44
import {useMount} from 'ahooks';
5-
import useCodemirror from '../../components/useCodemirror';
5+
import useCodemirror, {CodemirrorObj} from '../../components/useCodemirror';
66
import {FileContext} from './store/sidbar';
77
import {EditorContext} from 'views/src/pages/editor/store/editor';
88

@@ -12,12 +12,16 @@ import MdView from '../../components/md-view';
1212
import ToolBar from './components/tool-bar';
1313
import Footer from './components/footer';
1414

15-
import {success, error} from '../../utils/message';
15+
import {success, error} from 'views/src/utils/message';
1616
import {isFilePath} from 'views/src/utils/tools';
1717

18-
import {fileEvent, FS_SAVE} from '../../utils/event';
18+
import {fileEvent, FS_SAVE} from 'views/src/utils/event';
1919
import {pandora} from 'views/src/services/pandora';
2020

21+
import {blobToBase64, getFileName} from 'shared/utils/img';
22+
import {uploader} from 'shared/utils/chunk';
23+
import {PROTOCOL_IMG} from 'shared/common/constant';
24+
2125
function Editor() {
2226
const [storeState] = useContext(FileContext);
2327
const {
@@ -30,14 +34,56 @@ function Editor() {
3034
} = useCodemirror();
3135

3236
/* -------------------------------------------------------------------------- */
33-
/* store 全局状态 */
37+
/* handle pic */
3438
/* -------------------------------------------------------------------------- */
3539
const [, dispatch] = useContext(EditorContext);
3640
useEffect(() => {
3741
dispatch({
3842
type: 'storeeditor',
3943
payload: editor
4044
});
45+
if (editor) {
46+
// @ts-ignore
47+
editor.on('paste', (instance: CodemirrorObj['editor'], e: ClipboardEvent) => {
48+
if (e.clipboardData && e.clipboardData.items) {
49+
const items = e.clipboardData.items;
50+
for (let i = 0, len = items.length; i < len; i++) {
51+
let item = items[i];
52+
if (item.kind !== 'file') {
53+
return;
54+
}
55+
let pasteFile = item.getAsFile();
56+
if (!pasteFile) {
57+
return;
58+
}
59+
if (pasteFile.size > 0 && pasteFile.type.match('^image/')) {
60+
blobToBase64(pasteFile).then(data => {
61+
const imageName = getFileName();
62+
// 拒绝压缩
63+
uploader({
64+
send(data: any) {
65+
pandora.ipcRenderer.invoke('pandora:storeImage', {
66+
name: imageName,
67+
base64: data
68+
}).then((res: {success: boolean, data: string}) => {
69+
const doc = editor.getDoc();
70+
const curs = doc.getCursor();
71+
doc.replaceRange(
72+
`<img src="${PROTOCOL_IMG}:\/\/${res.data}" width="100%" height="100%" />`,
73+
{line: curs.line, ch: curs.ch}
74+
);
75+
}).catch(err => {
76+
console.warn(err);
77+
});
78+
}
79+
}, data as string);
80+
});
81+
}
82+
return;
83+
}
84+
}
85+
});
86+
}
4187
}, [editor]);
4288

4389
/* -------------------------------------------------------------------------- */

‎packages/workbench-electron/main/editor/initService.ts

+16-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ export const IPC_CHANNEL = [
1616
'pandora:dialog',
1717
'pandora:revealFileInOs',
1818
'pandora:moveFileToTrash',
19-
'pandora:fileSearch'
19+
'pandora:fileSearch',
20+
'pandora:storeImage'
2021
];
2122

2223
class CodeApplication {
@@ -106,6 +107,20 @@ class CodeApplication {
106107
data: res.data
107108
};
108109
}
110+
private async storeImage (event: Electron.IpcMainInvokeEvent, data: any) {
111+
let res = {
112+
success: false,
113+
data: ''
114+
};
115+
if (data && data.name && data.base64) {
116+
const path = await this.fileService.storeImgFromBase64(data.name, data.base64);
117+
path && (res = {
118+
success: true,
119+
data: path
120+
});
121+
}
122+
return res;
123+
}
109124
}
110125

111126
export default CodeApplication;

‎packages/workbench-electron/main/main.ts

+18-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
* @file app
33
*/
44
import path from 'path';
5-
import {app, BrowserWindow, ipcMain} from 'electron';
5+
import {app, BrowserWindow, ipcMain, protocol} from 'electron';
66
import {HomeMenubar} from './menu/menubar';
7-
import {DEVELOP_PORT} from 'shared/common/constant';
7+
import {DEVELOP_PORT, PROTOCOL_IMG} from 'shared/common/constant';
88

99
import {registerContextMenuListener} from './contextmenu/electron-main/contextmenu';
1010
import {CodeMain} from './editor/editorMain';
@@ -55,9 +55,25 @@ class Home {
5555
new HomeMenubar();
5656
this.registerListeners();
5757
}
58+
59+
// webSecurity: false 加载本地图片的安全问题
60+
private registImgProtocal() {
61+
protocol.registerFileProtocol(PROTOCOL_IMG, (request, callback) => {
62+
const url = request.url.replace(`${PROTOCOL_IMG}://`, '')
63+
try {
64+
return callback(url)
65+
}
66+
catch (error) {
67+
console.error(error)
68+
return callback('404')
69+
}
70+
})
71+
}
72+
5873
private registerListeners () {
5974
process.on('uncaughtException', err => this.onUnexpectedError(err));
6075
app.whenReady().then(async () => {
76+
this.registImgProtocal();
6177
/// #if IS_DEV
6278
installExtension(REACT_DEVELOPER_TOOLS)
6379
.then(name => console.log(`Added Extension: ${name}`))

‎packages/workbench-electron/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "workbench-electron",
3-
"version": "0.0.10",
3+
"version": "0.0.12",
44
"description": "Pandora Workbench",
55
"productName": "Pandora Workbench",
66
"private": true,

0 commit comments

Comments
 (0)
Please sign in to comment.