1
0
mirror of https://github.com/laurent22/joplin.git synced 2025-08-24 20:19:10 +02:00

Compare commits

...

1 Commits

Author SHA1 Message Date
Laurent Cozic
666707ec67 All: Resolves #932: Trying to fix orphaned resource bug, but not working 2020-11-08 16:50:40 +00:00
8 changed files with 100 additions and 87 deletions

View File

@@ -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) {

View File

@@ -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

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -60,6 +60,8 @@ export interface NoteBodyEditorProps {
resourceInfos: ResourceInfos,
locale: string,
onDrop: Function,
attachNoteToBody: Function,
handlePasteEvent: Function,
noteToolbarButtonInfos: ToolbarButtonInfo[],
plugins: PluginStates,
}

View File

@@ -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 = [];

View File

@@ -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) {

View File

@@ -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');
},