You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Many improvements and bug fixes
This commit is contained in:
		| @@ -3,6 +3,7 @@ import { Folder } from 'lib/models/folder.js'; | ||||
| import { Note } from 'lib/models/note.js'; | ||||
| import { cliUtils } from './cli-utils.js'; | ||||
| import { reducer, defaultState } from 'lib/reducer.js'; | ||||
| import { reg } from 'lib/registry.js'; | ||||
| import { _ } from 'lib/locale.js'; | ||||
|  | ||||
| const chalk = require('chalk'); | ||||
| @@ -56,15 +57,16 @@ class AppGui { | ||||
| 		this.commandCancelCalled_ = false; | ||||
|  | ||||
| 		this.currentShortcutKeys_ = []; | ||||
| 		this.lastShortcutKeyTime_ = 0;	 | ||||
| 		this.lastShortcutKeyTime_ = 0; | ||||
|  | ||||
| 		cliUtils.setStdout((...object) => { | ||||
| 			return this.stdout(...object); | ||||
|  | ||||
| 			// for (let i = 0; i < object.length; i++) { | ||||
| 			// 	this.widget('console').bufferPush(object[i]); | ||||
| 			// } | ||||
| 		}); | ||||
|  | ||||
| 		// Recurrent sync is setup only when the GUI is started. In | ||||
| 		// a regular command it's not necessary since the process | ||||
| 		// exits right away. | ||||
| 		reg.setupRecurrentSync(); | ||||
| 	} | ||||
|  | ||||
| 	renderer() { | ||||
|   | ||||
| @@ -417,9 +417,16 @@ class Application { | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	reducerActionToString(action) { | ||||
| 		let o = [action.type]; | ||||
| 		if (action.noteId) o.push(action.noteId); | ||||
| 		if (action.folderI) o.push(action.folderI); | ||||
| 		return o.join(', '); | ||||
| 	} | ||||
|  | ||||
| 	generalMiddleware() { | ||||
| 		const middleware = store => next => async (action) => { | ||||
| 			this.logger().info('Reducer action', action.type); | ||||
| 			this.logger().info('Reducer action', this.reducerActionToString(action)); | ||||
|  | ||||
| 			const result = next(action); | ||||
| 			const newState = store.getState(); | ||||
| @@ -429,6 +436,10 @@ class Application { | ||||
| 				await this.refreshNotes(); | ||||
| 			} | ||||
|  | ||||
| 			if (this.gui() && action.type == 'SETTINGS_UPDATE_ONE' && action.key == 'sync.interval' || action.type == 'SETTINGS_UPDATE_ALL') { | ||||
| 				reg.setupRecurrentSync(); | ||||
| 			} | ||||
|  | ||||
| 		  	return result; | ||||
| 		} | ||||
|  | ||||
|   | ||||
| @@ -86,6 +86,8 @@ class Command extends BaseCommand { | ||||
| 			if (args.options.target) this.syncTarget_ = args.options.target; | ||||
|  | ||||
| 			if (this.syncTarget_ == Setting.SYNC_TARGET_ONEDRIVE && !reg.syncHasAuth(this.syncTarget_)) { | ||||
| 				app().gui().showConsole(); | ||||
| 				app().gui().maximizeConsole(); | ||||
| 				const oneDriveApiUtils = new OneDriveApiNodeUtils(reg.oneDriveApi()); | ||||
| 				const auth = await oneDriveApiUtils.oauthDance({ | ||||
| 					log: (...s) => { return this.stdout(...s); } | ||||
|   | ||||
| @@ -10,7 +10,7 @@ class NoteListWidget extends ListWidget { | ||||
| 		this.updateIndexFromSelectedNoteId_ = false; | ||||
|  | ||||
| 		this.itemRenderer = (note) => { | ||||
| 			let label = note.title; //+ ' ' + note.id; | ||||
| 			let label = note.title; // + ' ' + note.id; | ||||
| 			if (note.is_todo) { | ||||
| 				label = '[' + (note.todo_completed ? 'X' : ' ') + '] ' + label; | ||||
| 			} | ||||
|   | ||||
| @@ -55,8 +55,22 @@ class StatusBarWidget extends BaseWidget { | ||||
| 		return this.history_; | ||||
| 	} | ||||
|  | ||||
| 	resetCursor() { | ||||
| 		if (!this.promptActive) return; | ||||
| 		if (!this.inputEventEmitter_) return; | ||||
|  | ||||
| 		this.inputEventEmitter_.redraw(); | ||||
| 		this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY); | ||||
| 		this.term.moveTo(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString) + this.inputEventEmitter_.getInput().length, this.absoluteInnerY); | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		super.render(); | ||||
|  | ||||
| 		const doSaveCursor = !this.promptActive; | ||||
| 		 | ||||
| 		if (doSaveCursor) this.term.saveCursor(); | ||||
|  | ||||
| 		this.innerClear(); | ||||
|  | ||||
| 		const textStyle = chalk.bgBlueBright.white; | ||||
| @@ -70,8 +84,9 @@ class StatusBarWidget extends BaseWidget { | ||||
| 			this.term.write(textStyle(this.promptState_.promptString)); | ||||
|  | ||||
| 			if (this.inputEventEmitter_) { | ||||
| 				this.inputEventEmitter_.redraw(); | ||||
| 				this.inputEventEmitter_.rebase(this.absoluteInnerX + termutils.textLength(this.promptState_.promptString), this.absoluteInnerY); | ||||
| 				// inputField is already waiting for input so in that case just make | ||||
| 				// sure that the cursor is at the right position and exit. | ||||
| 				this.resetCursor(); | ||||
| 				return; | ||||
| 			} | ||||
|  | ||||
| @@ -122,6 +137,8 @@ class StatusBarWidget extends BaseWidget { | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		if (doSaveCursor) this.term.restoreCursor(); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -66,18 +66,27 @@ class OneDriveApiNodeUtils { | ||||
| 					response.end(); | ||||
| 				} | ||||
|  | ||||
| 				// After the response has been received, don't destroy the server right | ||||
| 				// away or the browser might display a connection reset error (even | ||||
| 				// though it worked). | ||||
| 				const waitAndDestroy = () => { | ||||
| 					setTimeout(() => { | ||||
| 						server.destroy(); | ||||
| 					}, 1000); | ||||
| 				} | ||||
|  | ||||
| 				if (!query.code) return writeResponse(400, '"code" query parameter is missing'); | ||||
|  | ||||
| 				this.api().execTokenRequest(query.code, 'http://localhost:' + port.toString()).then(() => { | ||||
| 					writeResponse(200, _('The application has been authorised - you may now close this browser tab.')); | ||||
| 					targetConsole.log(''); | ||||
| 					targetConsole.log(_('The application has been successfully authorised.')); | ||||
| 					server.destroy(); | ||||
| 					waitAndDestroy(); | ||||
| 				}).catch((error) => { | ||||
| 					writeResponse(400, error.message); | ||||
| 					targetConsole.log(''); | ||||
| 					targetConsole.log(error.message); | ||||
| 					server.destroy(); | ||||
| 					waitAndDestroy(); | ||||
| 				}); | ||||
| 			}); | ||||
|  | ||||
|   | ||||
| @@ -98,10 +98,12 @@ class Note extends BaseItem { | ||||
| 				if (a[order.by] < b[order.by]) r = +1; | ||||
| 				if (a[order.by] > b[order.by]) r = -1; | ||||
| 				if (order.dir == 'ASC') r = -r; | ||||
| 				if (r) break; | ||||
| 				if (r !== 0) break; | ||||
| 			} | ||||
|  | ||||
| 			return r; | ||||
| 			// Makes the sort deterministic, so that if, for example, a and b have the | ||||
| 			// same updated_time, they aren't swapped every time a list is refreshed. | ||||
| 			return a.title.toLowerCase() + a.id < b.title.toLowerCase() + b.id ? -1 : +1; | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -180,6 +180,11 @@ class OneDriveApi { | ||||
| 					// or error code, so hopefully that message won't change and is not localized | ||||
| 				} else if (error.code == 'ECONNRESET') { | ||||
| 					// request to https://public-ch3302....1fab24cb1bd5f.md failed, reason: socket hang up" | ||||
| 				} else if (error.code == 'ENOTFOUND') { | ||||
| 					// OneDrive (or Node?) sometimes sends back a "not found" error for resources | ||||
| 					// that definitely exist and in this case repeating the request works. | ||||
| 					// Error is: | ||||
| 					// request to https://graph.microsoft.com/v1.0/drive/special/approot failed, reason: getaddrinfo ENOTFOUND graph.microsoft.com graph.microsoft.com:443 | ||||
| 				} else if (error.message.indexOf('network timeout') === 0) { | ||||
| 					// network timeout at: https://public-ch3302...859f9b0e3ab.md | ||||
| 				} else { | ||||
|   | ||||
| @@ -9,7 +9,6 @@ import { FileApiDriverOneDrive } from 'lib/file-api-driver-onedrive.js'; | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { time } from 'lib/time-utils.js'; | ||||
| import { FileApiDriverMemory } from 'lib/file-api-driver-memory.js'; | ||||
| import { PoorManIntervals } from 'lib/poor-man-intervals.js'; | ||||
| import { _ } from 'lib/locale.js'; | ||||
|  | ||||
| const reg = {}; | ||||
| @@ -199,7 +198,7 @@ reg.syncStarted = async () => { | ||||
|  | ||||
| reg.setupRecurrentSync = () => { | ||||
| 	if (reg.recurrentSyncId_) { | ||||
| 		PoorManIntervals.clearInterval(reg.recurrentSyncId_); | ||||
| 		shim.clearInterval(reg.recurrentSyncId_); | ||||
| 		reg.recurrentSyncId_ = null; | ||||
| 	} | ||||
|  | ||||
| @@ -208,7 +207,7 @@ reg.setupRecurrentSync = () => { | ||||
| 	} else { | ||||
| 		reg.logger().debug('Setting up recurrent sync with interval ' + Setting.value('sync.interval')); | ||||
|  | ||||
| 		reg.recurrentSyncId_ = PoorManIntervals.setInterval(() => { | ||||
| 		reg.recurrentSyncId_ = shim.setInterval(() => { | ||||
| 			reg.logger().info('Running background sync on timer...'); | ||||
| 			reg.scheduleSync(0); | ||||
| 		}, 1000 * Setting.value('sync.interval')); | ||||
|   | ||||
| @@ -1,10 +1,14 @@ | ||||
| import { shim } from 'lib/shim.js'; | ||||
| import { GeolocationReact } from 'lib/geolocation-react.js'; | ||||
| import { PoorManIntervals } from 'lib/poor-man-intervals.js'; | ||||
| import RNFetchBlob from 'react-native-fetch-blob'; | ||||
|  | ||||
| function shimInit() { | ||||
| 	shim.Geolocation = GeolocationReact; | ||||
|  | ||||
| 	shim.setInterval = PoorManIntervals.setInterval; | ||||
| 	shim.clearInterval = PoorManIntervals.clearInterval; | ||||
|  | ||||
| 	shim.fetchBlob = async function(url, options) { | ||||
| 		if (!options || !options.path) throw new Error('fetchBlob: target file path is missing'); | ||||
|  | ||||
|   | ||||
| @@ -15,5 +15,7 @@ shim.fs = null; | ||||
| shim.FileApiDriverLocal = null; | ||||
| shim.readLocalFileBase64 = () => { throw new Error('Not implemented'); } | ||||
| shim.uploadBlob = () => { throw new Error('Not implemented'); } | ||||
| shim.setInterval = setInterval; | ||||
| shim.clearInterval = clearInterval; | ||||
|  | ||||
| export { shim }; | ||||
		Reference in New Issue
	
	Block a user