mirror of
https://github.com/laurent22/joplin.git
synced 2024-12-24 10:27:10 +02:00
Electron: Resolves #612: Allow duplicating a note
This commit is contained in:
parent
7d7e1e1637
commit
310afb0ad6
@ -59,7 +59,7 @@ class ImportScreenComponent extends React.Component {
|
|||||||
|
|
||||||
async doImport() {
|
async doImport() {
|
||||||
const filePath = this.props.filePath;
|
const filePath = this.props.filePath;
|
||||||
const folderTitle = await Folder.findUniqueFolderTitle(filename(filePath));
|
const folderTitle = await Folder.findUniqueItemTitle(filename(filePath));
|
||||||
const messages = this.state.messages.slice();
|
const messages = this.state.messages.slice();
|
||||||
|
|
||||||
this.addMessage('start', _('New notebook "%s" will be created and file "%s" will be imported into it', folderTitle, basename(filePath)));
|
this.addMessage('start', _('New notebook "%s" will be created and file "%s" will be imported into it', folderTitle, basename(filePath)));
|
||||||
|
@ -88,6 +88,15 @@ class NoteListComponent extends React.Component {
|
|||||||
});
|
});
|
||||||
}}));
|
}}));
|
||||||
|
|
||||||
|
menu.append(new MenuItem({label: _('Duplicate'), click: async () => {
|
||||||
|
for (let i = 0; i < noteIds.length; i++) {
|
||||||
|
const note = await Note.load(noteIds[i]);
|
||||||
|
await Note.duplicate(noteIds[i], {
|
||||||
|
uniqueTitle: _('%s - Copy', note.title),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}}));
|
||||||
|
|
||||||
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
|
menu.append(new MenuItem({label: _('Switch between note and to-do type'), click: async () => {
|
||||||
for (let i = 0; i < noteIds.length; i++) {
|
for (let i = 0; i < noteIds.length; i++) {
|
||||||
const note = await Note.load(noteIds[i]);
|
const note = await Note.load(noteIds[i]);
|
||||||
|
@ -29,6 +29,19 @@ class BaseItem extends BaseModel {
|
|||||||
throw new Error('Invalid class name: ' + className);
|
throw new Error('Invalid class name: ' + className);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async findUniqueItemTitle(title) {
|
||||||
|
let counter = 1;
|
||||||
|
let titleToTry = title;
|
||||||
|
while (true) {
|
||||||
|
const item = await this.loadByField('title', titleToTry);
|
||||||
|
if (!item) return titleToTry;
|
||||||
|
titleToTry = title + ' (' + counter + ')';
|
||||||
|
counter++;
|
||||||
|
if (counter >= 100) titleToTry = title + ' (' + ((new Date()).getTime()) + ')';
|
||||||
|
if (counter >= 1000) throw new Error('Cannot find unique title');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Need to dynamically load the classes like this to avoid circular dependencies
|
// Need to dynamically load the classes like this to avoid circular dependencies
|
||||||
static getClass(name) {
|
static getClass(name) {
|
||||||
for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) {
|
for (let i = 0; i < BaseItem.syncItemDefinitions_.length; i++) {
|
||||||
|
@ -33,19 +33,6 @@ class Folder extends BaseItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static async findUniqueFolderTitle(title) {
|
|
||||||
let counter = 1;
|
|
||||||
let titleToTry = title;
|
|
||||||
while (true) {
|
|
||||||
const folder = await this.loadByField('title', titleToTry);
|
|
||||||
if (!folder) return titleToTry;
|
|
||||||
titleToTry = title + ' (' + counter + ')';
|
|
||||||
counter++;
|
|
||||||
if (counter >= 100) titleToTry = title + ' (' + ((new Date()).getTime()) + ')';
|
|
||||||
if (counter >= 1000) throw new Error('Cannot find unique title');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static noteIds(parentId) {
|
static noteIds(parentId) {
|
||||||
return this.db().selectAll('SELECT id FROM notes WHERE is_conflict = 0 AND parent_id = ?', [parentId]).then((rows) => {
|
return this.db().selectAll('SELECT id FROM notes WHERE is_conflict = 0 AND parent_id = ?', [parentId]).then((rows) => {
|
||||||
let output = [];
|
let output = [];
|
||||||
|
@ -420,6 +420,7 @@ class Note extends BaseItem {
|
|||||||
|
|
||||||
static async duplicate(noteId, options = null) {
|
static async duplicate(noteId, options = null) {
|
||||||
const changes = options && options.changes;
|
const changes = options && options.changes;
|
||||||
|
const uniqueTitle = options && options.uniqueTitle;
|
||||||
|
|
||||||
const originalNote = await Note.load(noteId);
|
const originalNote = await Note.load(noteId);
|
||||||
if (!originalNote) throw new Error('Unknown note: ' + noteId);
|
if (!originalNote) throw new Error('Unknown note: ' + noteId);
|
||||||
@ -432,6 +433,11 @@ class Note extends BaseItem {
|
|||||||
newNote[n] = changes[n];
|
newNote[n] = changes[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (uniqueTitle) {
|
||||||
|
const title = await Note.findUniqueItemTitle(uniqueTitle);
|
||||||
|
newNote.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
return this.save(newNote);
|
return this.save(newNote);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ class InteropService_Importer_Enex extends InteropService_Importer_Base {
|
|||||||
let folder = this.options_.destinationFolder;
|
let folder = this.options_.destinationFolder;
|
||||||
|
|
||||||
if (!folder) {
|
if (!folder) {
|
||||||
const folderTitle = await Folder.findUniqueFolderTitle(filename(this.sourcePath_));
|
const folderTitle = await Folder.findUniqueItemTitle(filename(this.sourcePath_));
|
||||||
folder = await Folder.save({ title: folderTitle });
|
folder = await Folder.save({ title: folderTitle });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class InteropService_Importer_Md extends InteropService_Importer_Base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.options_.destinationFolder) {
|
if (!this.options_.destinationFolder) {
|
||||||
const folderTitle = await Folder.findUniqueFolderTitle(basename(rtrimSlashes(this.sourcePath_)));
|
const folderTitle = await Folder.findUniqueItemTitle(basename(rtrimSlashes(this.sourcePath_)));
|
||||||
const folder = await Folder.save({ title: folderTitle });
|
const folder = await Folder.save({ title: folderTitle });
|
||||||
parentFolderId = folder.id;
|
parentFolderId = folder.id;
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,7 +51,7 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
|
|||||||
let defaultFolder_ = null;
|
let defaultFolder_ = null;
|
||||||
const defaultFolder = async () => {
|
const defaultFolder = async () => {
|
||||||
if (defaultFolder_) return defaultFolder_;
|
if (defaultFolder_) return defaultFolder_;
|
||||||
const folderTitle = await Folder.findUniqueFolderTitle(this.options_.defaultFolderTitle ? this.options_.defaultFolderTitle : 'Imported');
|
const folderTitle = await Folder.findUniqueItemTitle(this.options_.defaultFolderTitle ? this.options_.defaultFolderTitle : 'Imported');
|
||||||
defaultFolder_ = await Folder.save({ title: folderTitle });
|
defaultFolder_ = await Folder.save({ title: folderTitle });
|
||||||
return defaultFolder_;
|
return defaultFolder_;
|
||||||
}
|
}
|
||||||
@ -100,7 +100,7 @@ class InteropService_Importer_Raw extends InteropService_Importer_Base {
|
|||||||
|
|
||||||
if (!itemIdMap[item.id]) itemIdMap[item.id] = uuid.create();
|
if (!itemIdMap[item.id]) itemIdMap[item.id] = uuid.create();
|
||||||
item.id = itemIdMap[item.id];
|
item.id = itemIdMap[item.id];
|
||||||
item.title = await Folder.findUniqueFolderTitle(item.title);
|
item.title = await Folder.findUniqueItemTitle(item.title);
|
||||||
|
|
||||||
if (item.parent_id) {
|
if (item.parent_id) {
|
||||||
await setFolderToImportTo(item.parent_id);
|
await setFolderToImportTo(item.parent_id);
|
||||||
|
Loading…
Reference in New Issue
Block a user