You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-24 20:19:10 +02:00
Compare commits
1 Commits
v3.4.5
...
orphaned_r
Author | SHA1 | Date | |
---|---|---|---|
|
666707ec67 |
@@ -3,7 +3,6 @@ import { useState, useEffect, useRef, forwardRef, useCallback, useImperativeHand
|
||||
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
import { EditorCommand, NoteBodyEditorProps } from '../../utils/types';
|
||||
import { commandAttachFileToBody, handlePasteEvent } from '../../utils/resourceHandling';
|
||||
import { ScrollOptions, ScrollOptionTypes } from '../../utils/types';
|
||||
import { useScrollHandler, usePrevious, cursorPositionToTextOffset, useRootSize } from './utils';
|
||||
import Toolbar from './Toolbar';
|
||||
@@ -129,7 +128,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
editorRef.current.insertAtCursor(cmd.value.markdownTags.join('\n'));
|
||||
} else if (cmd.value.type === 'files') {
|
||||
const pos = cursorPositionToTextOffset(editorRef.current.getCursor(), props.content);
|
||||
const newBody = await commandAttachFileToBody(props.content, cmd.value.paths, { createFileURL: !!cmd.value.createFileURL, position: pos });
|
||||
const newBody = await props.attachNoteToBody(props.content, cmd.value.paths, { createFileURL: !!cmd.value.createFileURL, position: pos });
|
||||
editorRef.current.updateBody(newBody);
|
||||
} else {
|
||||
reg.logger().warn('CodeMirror: unsupported drop item: ', cmd);
|
||||
@@ -187,7 +186,7 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
const cursor = editorRef.current.getCursor();
|
||||
const pos = cursorPositionToTextOffset(cursor, props.content);
|
||||
|
||||
const newBody = await commandAttachFileToBody(props.content, null, { position: pos });
|
||||
const newBody = await props.attachNoteToBody(props.content, null, { position: pos });
|
||||
if (newBody) editorRef.current.updateBody(newBody);
|
||||
},
|
||||
textNumberedList: () => {
|
||||
@@ -212,15 +211,15 @@ function CodeMirror(props: NoteBodyEditorProps, ref: any) {
|
||||
return commandOutput;
|
||||
},
|
||||
};
|
||||
}, [props.content, addListItem, wrapSelectionWithStrings, setEditorPercentScroll, setViewerPercentScroll, resetScroll, renderedBody]);
|
||||
}, [props.content, addListItem, wrapSelectionWithStrings, setEditorPercentScroll, setViewerPercentScroll, resetScroll, renderedBody, props.attachNoteToBody]);
|
||||
|
||||
const onEditorPaste = useCallback(async (event: any = null) => {
|
||||
const resourceMds = await handlePasteEvent(event);
|
||||
const resourceMds = await props.handlePasteEvent(event);
|
||||
if (!resourceMds.length) return;
|
||||
if (editorRef.current) {
|
||||
editorRef.current.replaceSelection(resourceMds.join('\n'));
|
||||
}
|
||||
}, []);
|
||||
}, [props.handlePasteEvent]);
|
||||
|
||||
const editorCutText = useCallback(() => {
|
||||
if (editorRef.current) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { useState, useEffect, useCallback, useRef, forwardRef, useImperativeHandle } from 'react';
|
||||
import { ScrollOptions, ScrollOptionTypes, EditorCommand, NoteBodyEditorProps } from '../../utils/types';
|
||||
import { resourcesStatus, commandAttachFileToBody, handlePasteEvent } from '../../utils/resourceHandling';
|
||||
import { resourcesStatus } from '../../utils/resourceHandling';
|
||||
import useScroll from './utils/useScroll';
|
||||
import styles_ from './styles';
|
||||
import CommandService from '@joplin/lib/services/CommandService';
|
||||
@@ -171,13 +171,11 @@ const TinyMCE = (props:NoteBodyEditorProps, ref:any) => {
|
||||
};
|
||||
|
||||
const insertResourcesIntoContent = useCallback(async (filePaths:string[] = null, options:any = null) => {
|
||||
const resourceMd = await commandAttachFileToBody('', filePaths, options);
|
||||
const resourceMd = await props.attachNoteToBody('', filePaths, options);
|
||||
if (!resourceMd) return;
|
||||
const result = await props.markupToHtml(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, resourceMd, markupRenderOptions({ bodyOnly: true }));
|
||||
editor.insertContent(result.html);
|
||||
// editor.fire('joplinChange');
|
||||
// dispatchDidUpdate(editor);
|
||||
}, [props.markupToHtml, editor]);
|
||||
}, [props.markupToHtml, props.attachNoteToBody, editor]);
|
||||
|
||||
const insertResourcesIntoContentRef = useRef(null);
|
||||
insertResourcesIntoContentRef.current = insertResourcesIntoContent;
|
||||
@@ -979,7 +977,7 @@ const TinyMCE = (props:NoteBodyEditorProps, ref:any) => {
|
||||
}
|
||||
|
||||
async function onPaste(event:any) {
|
||||
const resourceMds = await handlePasteEvent(event);
|
||||
const resourceMds = await props.handlePasteEvent(event);
|
||||
if (resourceMds.length) {
|
||||
const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, resourceMds.join('\n'), markupRenderOptions({ bodyOnly: true }));
|
||||
editor.insertContent(result.html);
|
||||
@@ -1039,7 +1037,7 @@ const TinyMCE = (props:NoteBodyEditorProps, ref:any) => {
|
||||
console.warn('Error removing events', error);
|
||||
}
|
||||
};
|
||||
}, [props.onWillChange, props.onChange, props.contentMarkupLanguage, props.contentOriginalCss, editor]);
|
||||
}, [props.onWillChange, props.onChange, props.contentMarkupLanguage, props.contentOriginalCss, editor, props.handlePasteEvent]);
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
// Destroy the editor when unmounting
|
||||
|
@@ -29,7 +29,11 @@ import NoteTitleBar from './NoteTitle/NoteTitleBar';
|
||||
import markupLanguageUtils from '@joplin/lib/markupLanguageUtils';
|
||||
import usePrevious from '../hooks/usePrevious';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
|
||||
const { clipboard } = require('electron');
|
||||
const mimeUtils = require('@joplin/lib/mime-utils.js').mime;
|
||||
const md5 = require('md5');
|
||||
const { themeStyle } = require('@joplin/lib/theme');
|
||||
const { substrWithEllipsis } = require('@joplin/lib/string-utils');
|
||||
const NoteSearchBar = require('../NoteSearchBar.min.js');
|
||||
@@ -363,6 +367,70 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const attachNoteToBody = useCallback(async (body:string, filePaths:string[] = null, options:any = null) => {
|
||||
options = {
|
||||
createFileURL: false,
|
||||
position: 0,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (!filePaths) {
|
||||
filePaths = bridge().showOpenDialog({
|
||||
properties: ['openFile', 'createDirectory', 'multiSelections'],
|
||||
});
|
||||
if (!filePaths || !filePaths.length) return null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < filePaths.length; i++) {
|
||||
const filePath = filePaths[i];
|
||||
try {
|
||||
reg.logger().info(`Attaching ${filePath}`);
|
||||
const newBody = await shim.attachFileToNoteBody(formNote.id, body, filePath, options.position, {
|
||||
createFileURL: options.createFileURL,
|
||||
resizeLargeImages: 'ask',
|
||||
});
|
||||
|
||||
if (!newBody) {
|
||||
reg.logger().info('File attachment was cancelled');
|
||||
return null;
|
||||
}
|
||||
|
||||
body = newBody;
|
||||
reg.logger().info('File was attached.');
|
||||
} catch (error) {
|
||||
reg.logger().error(error);
|
||||
bridge().showErrorMessageBox(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}, [formNote.id]);
|
||||
|
||||
const handlePasteEvent = useCallback(async (event:any) => {
|
||||
const output = [];
|
||||
const formats = clipboard.availableFormats();
|
||||
for (let i = 0; i < formats.length; i++) {
|
||||
const format = formats[i].toLowerCase();
|
||||
const formatType = format.split('/')[0];
|
||||
|
||||
if (formatType === 'image') {
|
||||
if (event) event.preventDefault();
|
||||
|
||||
const image = clipboard.readImage();
|
||||
|
||||
const fileExt = mimeUtils.toFileExtension(format);
|
||||
const filePath = `${Setting.value('tempDir')}/${md5(Date.now())}.${fileExt}`;
|
||||
|
||||
await shim.writeImageToFile(image, format, filePath);
|
||||
const md = await attachNoteToBody('', [filePath]);
|
||||
await shim.fsDriver().remove(filePath);
|
||||
|
||||
if (md) output.push(md);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}, [attachNoteToBody]);
|
||||
|
||||
const searchMarkers = useSearchMarkers(showLocalSearch, localSearchMarkerOptions, props.searches, props.selectedSearchId, props.highlightedWords);
|
||||
|
||||
const editorProps:NoteBodyEditorProps = {
|
||||
@@ -389,6 +457,8 @@ function NoteEditor(props: NoteEditorProps) {
|
||||
visiblePanes: props.noteVisiblePanes || ['editor', 'viewer'],
|
||||
keyboardMode: Setting.value('editor.keyboardMode'),
|
||||
locale: Setting.value('locale'),
|
||||
attachNoteToBody: attachNoteToBody,
|
||||
handlePasteEvent: handlePasteEvent,
|
||||
onDrop: onDrop,
|
||||
noteToolbarButtonInfos: props.toolbarButtonInfos,
|
||||
plugins: props.plugins,
|
||||
|
@@ -1,15 +1,9 @@
|
||||
import shim from '@joplin/lib/shim';
|
||||
const Setting = require('@joplin/lib/models/Setting').default;
|
||||
const Note = require('@joplin/lib/models/Note.js');
|
||||
const BaseModel = require('@joplin/lib/BaseModel').default;
|
||||
const Resource = require('@joplin/lib/models/Resource.js');
|
||||
const bridge = require('electron').remote.require('./bridge').default;
|
||||
const ResourceFetcher = require('@joplin/lib/services/ResourceFetcher.js');
|
||||
const { reg } = require('@joplin/lib/registry.js');
|
||||
const joplinRendererUtils = require('@joplin/renderer').utils;
|
||||
const { clipboard } = require('electron');
|
||||
const mimeUtils = require('@joplin/lib/mime-utils.js').mime;
|
||||
const md5 = require('md5');
|
||||
|
||||
export async function handleResourceDownloadMode(noteBody: string) {
|
||||
if (noteBody && Setting.value('sync.resourceDownloadMode') === 'auto') {
|
||||
@@ -52,45 +46,6 @@ export async function attachedResources(noteBody: string): Promise<any> {
|
||||
return output;
|
||||
}
|
||||
|
||||
export async function commandAttachFileToBody(body:string, filePaths:string[] = null, options:any = null) {
|
||||
options = {
|
||||
createFileURL: false,
|
||||
position: 0,
|
||||
...options,
|
||||
};
|
||||
|
||||
if (!filePaths) {
|
||||
filePaths = bridge().showOpenDialog({
|
||||
properties: ['openFile', 'createDirectory', 'multiSelections'],
|
||||
});
|
||||
if (!filePaths || !filePaths.length) return null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < filePaths.length; i++) {
|
||||
const filePath = filePaths[i];
|
||||
try {
|
||||
reg.logger().info(`Attaching ${filePath}`);
|
||||
const newBody = await shim.attachFileToNoteBody(body, filePath, options.position, {
|
||||
createFileURL: options.createFileURL,
|
||||
resizeLargeImages: 'ask',
|
||||
});
|
||||
|
||||
if (!newBody) {
|
||||
reg.logger().info('File attachment was cancelled');
|
||||
return null;
|
||||
}
|
||||
|
||||
body = newBody;
|
||||
reg.logger().info('File was attached.');
|
||||
} catch (error) {
|
||||
reg.logger().error(error);
|
||||
bridge().showErrorMessageBox(error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
export function resourcesStatus(resourceInfos: any) {
|
||||
let lowestIndex = joplinRendererUtils.resourceStatusIndex('ready');
|
||||
for (const id in resourceInfos) {
|
||||
@@ -101,27 +56,3 @@ export function resourcesStatus(resourceInfos: any) {
|
||||
return joplinRendererUtils.resourceStatusName(lowestIndex);
|
||||
}
|
||||
|
||||
export async function handlePasteEvent(event:any) {
|
||||
const output = [];
|
||||
const formats = clipboard.availableFormats();
|
||||
for (let i = 0; i < formats.length; i++) {
|
||||
const format = formats[i].toLowerCase();
|
||||
const formatType = format.split('/')[0];
|
||||
|
||||
if (formatType === 'image') {
|
||||
if (event) event.preventDefault();
|
||||
|
||||
const image = clipboard.readImage();
|
||||
|
||||
const fileExt = mimeUtils.toFileExtension(format);
|
||||
const filePath = `${Setting.value('tempDir')}/${md5(Date.now())}.${fileExt}`;
|
||||
|
||||
await shim.writeImageToFile(image, format, filePath);
|
||||
const md = await commandAttachFileToBody('', [filePath]);
|
||||
await shim.fsDriver().remove(filePath);
|
||||
|
||||
if (md) output.push(md);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
@@ -60,6 +60,8 @@ export interface NoteBodyEditorProps {
|
||||
resourceInfos: ResourceInfos,
|
||||
locale: string,
|
||||
onDrop: Function,
|
||||
attachNoteToBody: Function,
|
||||
handlePasteEvent: Function,
|
||||
noteToolbarButtonInfos: ToolbarButtonInfo[],
|
||||
plugins: PluginStates,
|
||||
}
|
||||
|
@@ -43,6 +43,13 @@ export default class NoteResource extends BaseModel {
|
||||
await this.db().transactionExecBatch(queries);
|
||||
}
|
||||
|
||||
static async addOrphanedResource(resourceId:string) {
|
||||
await this.db().exec({
|
||||
sql: 'INSERT INTO note_resources (note_id, resource_id, is_associated, last_seen_time) VALUES (?, ?, ?, ?)',
|
||||
params: ['', resourceId, 0, 0],
|
||||
});
|
||||
}
|
||||
|
||||
static async addOrphanedResources() {
|
||||
const missingResources = await this.db().selectAll('SELECT id FROM resources WHERE id NOT IN (SELECT DISTINCT resource_id FROM note_resources)');
|
||||
const queries = [];
|
||||
|
@@ -7,6 +7,7 @@ const FsDriverNode = require('./fs-driver-node').default;
|
||||
const mimeUtils = require('./mime-utils.js').mime;
|
||||
const Note = require('./models/Note.js');
|
||||
const Resource = require('./models/Resource.js');
|
||||
const ResourceService = require('./services/ResourceService').default;
|
||||
const urlValidator = require('valid-url');
|
||||
const { _ } = require('./locale');
|
||||
const http = require('http');
|
||||
@@ -244,7 +245,7 @@ function shimInit(sharp = null, keytar = null) {
|
||||
return Resource.save(resource, saveOptions);
|
||||
};
|
||||
|
||||
shim.attachFileToNoteBody = async function(noteBody, filePath, position = null, options = null) {
|
||||
shim.attachFileToNoteBody = async function(noteId, noteBody, filePath, position = null, options = null) {
|
||||
options = Object.assign({}, {
|
||||
createFileURL: false,
|
||||
}, options);
|
||||
@@ -277,17 +278,22 @@ function shimInit(sharp = null, keytar = null) {
|
||||
|
||||
if (noteBody) newBody.push(noteBody.substr(position));
|
||||
|
||||
return newBody.join('\n\n');
|
||||
const output = newBody.join('\n\n');
|
||||
|
||||
await ResourceService.instance().setAssociatedResources(noteId, output)
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
shim.attachFileToNote = async function(note, filePath, position = null, options = null) {
|
||||
const newBody = await shim.attachFileToNoteBody(note.body, filePath, position, options);
|
||||
const newBody = await shim.attachFileToNoteBody(note.id, note.body, filePath, position, options);
|
||||
if (!newBody) return null;
|
||||
|
||||
const newNote = Object.assign({}, note, {
|
||||
body: newBody,
|
||||
});
|
||||
return await Note.save(newNote);
|
||||
|
||||
return Note.save(newNote);
|
||||
};
|
||||
|
||||
shim.imageFromDataUrl = async function(imageDataUrl, filePath, options = null) {
|
||||
|
@@ -184,7 +184,7 @@ const shim = {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
attachFileToNoteBody: async (_body:string, _filePath:string, _position:number, _options:any):Promise<string> => {
|
||||
attachFileToNoteBody: async (_noteId:string, _body:string, _filePath:string, _position:number, _options:any):Promise<string> => {
|
||||
throw new Error('Not implemented');
|
||||
},
|
||||
|
||||
|
Reference in New Issue
Block a user