You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	mv folder in cli
This commit is contained in:
		| @@ -66,6 +66,15 @@ class Application { | ||||
| 		this.updatePrompt(); | ||||
| 	} | ||||
|  | ||||
| 	async guessTypeAndLoadItem(pattern, options = null) { | ||||
| 		let type = BaseModel.TYPE_NOTE; | ||||
| 		if (pattern.indexOf('/') === 0) { | ||||
| 			type = BaseModel.TYPE_FOLDER; | ||||
| 			pattern = pattern.substr(1); | ||||
| 		} | ||||
| 		return this.loadItem(type, pattern, options); | ||||
| 	} | ||||
|  | ||||
| 	async loadItem(type, pattern, options = null) { | ||||
| 		let output = await this.loadItems(type, pattern, options); | ||||
| 		return output.length ? output[0] : null; | ||||
|   | ||||
| @@ -18,10 +18,7 @@ class Command extends BaseCommand { | ||||
| 	} | ||||
|  | ||||
| 	async action(args) { | ||||
| 		let folder = await Folder.save({ title: args['notebook'] }, { | ||||
| 			duplicateCheck: true, | ||||
| 			reservedTitleCheck: true, | ||||
| 		}); | ||||
| 		let folder = await Folder.save({ title: args['notebook'] }, { userSideValidation: true }); | ||||
| 		 | ||||
| 		app().switchCurrentFolder(folder); | ||||
| 	} | ||||
|   | ||||
| @@ -9,11 +9,11 @@ import { autocompleteItems } from './autocomplete.js'; | ||||
| class Command extends BaseCommand { | ||||
|  | ||||
| 	usage() { | ||||
| 		return 'mv <pattern> <notebook>'; | ||||
| 		return 'mv <pattern> <destination>'; | ||||
| 	} | ||||
|  | ||||
| 	description() { | ||||
| 		return 'Moves the notes matching <pattern> to <notebook>.'; | ||||
| 		return 'Moves the notes matching <pattern> to <destination>. If <pattern> is a note, it will be moved to the notebook <destination>. If <pattern> is a notebook, it will be renamed to <destination>.'; | ||||
| 	} | ||||
|  | ||||
| 	autocomplete() { | ||||
| @@ -22,15 +22,25 @@ class Command extends BaseCommand { | ||||
|  | ||||
| 	async action(args) { | ||||
| 		const pattern = args['pattern']; | ||||
| 		const destination = args['destination']; | ||||
|  | ||||
| 		const folder = await Folder.loadByField('title', args['notebook']); | ||||
| 		if (!folder) throw new Error(_('No notebook "%s"', args['notebook'])); | ||||
| 		const item = await app().guessTypeAndLoadItem(pattern); | ||||
|  | ||||
| 		const notes = await app().loadItems(BaseModel.TYPE_NOTE, pattern); | ||||
| 		if (!notes.length) throw new Error(_('No note matches this pattern: "%s"', pattern)); | ||||
| 		if (!item) throw new Error(_('No item matches pattern "%s"', pattern)); | ||||
|  | ||||
| 		for (let i = 0; i < notes.length; i++) { | ||||
| 			await Note.moveToFolder(notes[i].id, folder.id); | ||||
| 		if (item.type_ == BaseModel.TYPE_FOLDER) { | ||||
| 			await Folder.save({ id: item.id, title: destination }, { userSideValidation: true }); | ||||
| 			await app().refreshCurrentFolder(); | ||||
| 		} else { // TYPE_NOTE | ||||
| 			const folder = await Folder.loadByField('title', destination); | ||||
| 			if (!folder) throw new Error(_('No notebook "%s"', destination)); | ||||
|  | ||||
| 			const notes = await app().loadItems(BaseModel.TYPE_NOTE, pattern); | ||||
| 			if (!notes.length) throw new Error(_('No note matches this pattern: "%s"', pattern)); | ||||
|  | ||||
| 			for (let i = 0; i < notes.length; i++) { | ||||
| 				await Note.moveToFolder(notes[i].id, folder.id); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -66,10 +66,7 @@ class FolderScreenComponent extends BaseScreenComponent { | ||||
| 		let folder = Object.assign({}, this.state.folder); | ||||
|  | ||||
| 		try { | ||||
| 			folder = await Folder.save(folder, { | ||||
| 				duplicateCheck: true, | ||||
| 				reservedTitleCheck: true, | ||||
| 			}); | ||||
| 			folder = await Folder.save(folder, { userSideValidation: true }); | ||||
|  | ||||
| 			reg.scheduleSync(); | ||||
| 		} catch (error) { | ||||
|   | ||||
| @@ -114,15 +114,29 @@ class Folder extends BaseItem { | ||||
|  | ||||
| 	// These "duplicateCheck" and "reservedTitleCheck" should only be done when a user is | ||||
| 	// manually creating a folder. They shouldn't be done for example when the folders | ||||
| 	// are being synced to avoid any strange side-effect. Technically it's possible to  | ||||
| 	// have folders and notes with duplicate titles (or no title), or with reserved words, | ||||
| 	// are being synced to avoid any strange side-effects. Technically it's possible to  | ||||
| 	// have folders and notes with duplicate titles (or no title), or with reserved words. | ||||
| 	static async save(o, options = null) { | ||||
| 		if (options && options.duplicateCheck === true && o.title) { | ||||
| 		if (!options) options = {}; | ||||
|  | ||||
| 		if (options.userSideValidation === true) { | ||||
| 			if (!('duplicateCheck' in options)) options.duplicateCheck = true; | ||||
| 			if (!('reservedTitleCheck' in options)) options.reservedTitleCheck = true; | ||||
| 			if (!('stripLeftSlashes' in options)) options.stripLeftSlashes = true;			 | ||||
| 		} | ||||
|  | ||||
| 		if (options.stripLeftSlashes === true && o.title) { | ||||
| 			while (o.title.length && (o.title[0] == '/' || o.title[0] == "\\")) { | ||||
| 				o.title = o.title.substr(1); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (options.duplicateCheck === true && o.title) { | ||||
| 			let existingFolder = await Folder.loadByTitle(o.title); | ||||
| 			if (existingFolder && existingFolder.id != o.id) throw new Error(_('A notebook with this title already exists: "%s"', o.title)); | ||||
| 		} | ||||
|  | ||||
| 		if (options && options.reservedTitleCheck === true && o.title) { | ||||
| 		if (options.reservedTitleCheck === true && o.title) { | ||||
| 			if (o.title == Folder.conflictFolderTitle()) throw new Error(_('Notebooks cannot be named "%s", which is a reserved title.', o.title)); | ||||
| 		} | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user