You've already forked joplin
							
							
				mirror of
				https://github.com/laurent22/joplin.git
				synced 2025-10-31 00:07:48 +02:00 
			
		
		
		
	Created list that renders only currently visible items
This commit is contained in:
		| @@ -24,6 +24,20 @@ class ElectronAppWrapper { | ||||
| 		return this.logger_; | ||||
| 	} | ||||
|  | ||||
| 	store() { | ||||
| 		return this.store_; | ||||
| 	} | ||||
|  | ||||
| 	dispatch(action) { | ||||
| 		return this.store().dispatch(action); | ||||
| 	} | ||||
|  | ||||
| 	windowContentSize() { | ||||
| 		if (!this.win_) return { width: 0, height: 0 }; | ||||
| 		const s = this.win_.getContentSize(); | ||||
| 		return { width: s[0], height: s[1] }; | ||||
| 	} | ||||
|  | ||||
| 	createWindow() { | ||||
| 		// Create the browser window. | ||||
| 		this.win_ = new BrowserWindow({width: 800, height: 600}) | ||||
| @@ -45,6 +59,18 @@ class ElectronAppWrapper { | ||||
| 			// when you should delete the corresponding element. | ||||
| 			this.win_ = null | ||||
| 		}) | ||||
|  | ||||
| 		this.win_.on('resize', () => { | ||||
| 			this.dispatch({ | ||||
| 				type: 'WINDOW_CONTENT_SIZE_SET', | ||||
| 				size: this.windowContentSize(), | ||||
| 			}); | ||||
| 		}); | ||||
|  | ||||
| 		this.dispatch({ | ||||
| 			type: 'WINDOW_CONTENT_SIZE_SET', | ||||
| 			size: this.windowContentSize(), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	async waitForElectronAppReady() { | ||||
|   | ||||
| @@ -1,16 +1,66 @@ | ||||
| class ItemList extends React.Component { | ||||
|  | ||||
| 	constructor() { | ||||
| 		super(); | ||||
|  | ||||
| 		this.scrollTop_ = 0; | ||||
| 	} | ||||
|  | ||||
| 	componentWillMount() { | ||||
| 		this.setState({ | ||||
| 			topItemIndex: this.topItemIndex(), | ||||
| 			bottomItemIndex: this.bottomItemIndex(), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	onScroll(scrollTop) { | ||||
| 		this.scrollTop_ = scrollTop; | ||||
|  | ||||
| 		this.setState({ | ||||
| 			topItemIndex: this.topItemIndex(), | ||||
| 			bottomItemIndex: this.bottomItemIndex(), | ||||
| 		}); | ||||
| 	} | ||||
|  | ||||
| 	topItemIndex() { | ||||
| 		return Math.floor(this.scrollTop_ / this.props.itemHeight); | ||||
| 	} | ||||
|  | ||||
| 	visibleItemCount() { | ||||
| 		return Math.ceil(this.props.style.height / this.props.itemHeight); | ||||
| 	} | ||||
|  | ||||
| 	bottomItemIndex() { | ||||
| 		let r = this.topItemIndex() + this.visibleItemCount(); | ||||
| 		if (r >= this.props.items.length) r = this.props.items.length - 1; | ||||
| 		return r; | ||||
| 	} | ||||
|  | ||||
| 	render() { | ||||
| 		const items = this.props.items; | ||||
|  | ||||
| 		let itemComps = []; | ||||
| 		for (let i = 0; i < items.length; i++) { | ||||
| 		if (!this.props.itemHeight) throw new Error('itemHeight is required'); | ||||
|  | ||||
| 		const blankItem = function(key, height) { | ||||
| 			return <div key={key} style={{height:height}}></div> | ||||
| 		} | ||||
|  | ||||
| 		let itemComps = [blankItem('top', this.state.topItemIndex * this.props.itemHeight)]; | ||||
|  | ||||
| 		for (let i = this.state.topItemIndex; i <= this.state.bottomItemIndex; i++) { | ||||
| 			const itemComp = this.props.itemRenderer(i, items[i]); | ||||
| 			itemComps.push(itemComp); | ||||
| 		} | ||||
|  | ||||
| 		itemComps.push(blankItem('bottom', (items.length - this.state.bottomItemIndex - 1) * this.props.itemHeight)); | ||||
|  | ||||
| 		let classes = ['item-list']; | ||||
| 		if (this.props.className) classes.push(this.props.className); | ||||
|  | ||||
| 		const that = this; | ||||
|  | ||||
| 		return ( | ||||
| 			<div> | ||||
| 			<div className={classes.join(' ')} style={this.props.style} onScroll={ (event) => { this.onScroll(event.target.scrollTop) }}> | ||||
| 				{ itemComps } | ||||
| 			</div> | ||||
| 		); | ||||
|   | ||||
| @@ -10,21 +10,25 @@ class NoteListComponent extends React.Component { | ||||
|  | ||||
| 	render() { | ||||
| 		return ( | ||||
| 			<div className={"note-list"}> | ||||
| 				<h1>Notes</h1> | ||||
| 				<ItemList | ||||
| 					items={this.props.notes} | ||||
| 					itemRenderer={ (index, item) => { return this.itemRenderer(index, item) } } | ||||
| 				/> | ||||
| 			</div> | ||||
| 			<ItemList | ||||
| 				itemHeight={this.props.itemHeight} | ||||
| 				style={this.props.style} | ||||
| 				className={"note-list"} | ||||
| 				items={this.props.notes} | ||||
| 				itemRenderer={ (index, item) => { return this.itemRenderer(index, item) } } | ||||
| 			/> | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| const mapStateToProps = (state) => { | ||||
| 	let notes = []; | ||||
| 	for (let i = 0; i < 100; i++) notes.push({ title: "Note " + i }); | ||||
|  | ||||
| 	return { | ||||
| 		notes: state.notes, | ||||
| 		//notes: state.notes, | ||||
| 		notes: notes, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -10,17 +10,29 @@ const { app } = require('electron').remote.require('./app'); | ||||
| class ReactRootComponent extends React.Component { | ||||
|  | ||||
| 	render() { | ||||
| 		const style = { | ||||
| 			width: this.props.size.width, | ||||
| 			height: this.props.size.height, | ||||
| 		}; | ||||
|  | ||||
| 		const noteListStyle = { | ||||
| 			width: this.props.size.width, | ||||
| 			height: this.props.size.height, | ||||
| 		}; | ||||
|  | ||||
| 		return ( | ||||
| 			<div style={{height: "1000px"}}> | ||||
| 				<NoteList></NoteList> | ||||
| 			<div style={style}> | ||||
| 				<NoteList itemHeight={40} style={noteListStyle}></NoteList> | ||||
| 			</div> | ||||
| 		) | ||||
| 		); | ||||
| 	} | ||||
|  | ||||
| } | ||||
|  | ||||
| const mapStateToProps = (state) => { | ||||
| 	return {}; | ||||
| 	return { | ||||
| 		size: state.windowContentSize, | ||||
| 	}; | ||||
| }; | ||||
|  | ||||
| const ReactRoot = connect(mapStateToProps)(ReactRootComponent); | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
| 		<link rel="stylesheet" href="style.css"> | ||||
| 	</head> | ||||
| 	<body> | ||||
| 		<div  style="height: '1000px';" id="react-root"></div> | ||||
| 		<div id="react-root"></div> | ||||
| 		<script src="gui/Root.min.js"></script> | ||||
| 	</body> | ||||
| </html> | ||||
|   | ||||
| @@ -1,5 +1,19 @@ | ||||
| body { | ||||
| 	margin: 0; | ||||
| 	padding: 0; | ||||
| } | ||||
|  | ||||
| #react-root { | ||||
| 	height: 100%; | ||||
| } | ||||
|  | ||||
| .item-list { | ||||
| 	overflow-x: hidden; | ||||
| 	overflow-y: scroll; | ||||
| } | ||||
|  | ||||
| .note-list .item { | ||||
| 	height: 40px; | ||||
| 	height: 40px; /* This must match NoteList.itemHeight */ | ||||
| 	vertical-align: middle; | ||||
| 	cursor: pointer; | ||||
| } | ||||
|   | ||||
| @@ -29,6 +29,7 @@ const defaultState = { | ||||
| 		routeName: 'Welcome', | ||||
| 		params: {}, | ||||
| 	}, | ||||
| 	windowContentSize: { width: 0, height: 0 }, | ||||
| }; | ||||
|  | ||||
| let navHistory = []; | ||||
| @@ -410,6 +411,12 @@ const reducer = (state = defaultState, action) => { | ||||
| 				newState.appState = action.state; | ||||
| 				break; | ||||
|  | ||||
| 			case 'WINDOW_CONTENT_SIZE_SET': | ||||
|  | ||||
| 				newState = Object.assign({}, state); | ||||
| 				newState.windowContentSize = action.size; | ||||
| 				break; | ||||
|  | ||||
| 		} | ||||
| 	} catch (error) { | ||||
| 		error.message = 'In reducer: ' + error.message + ' Action: ' + JSON.stringify(action); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user