1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-12-24 10:27:10 +02:00

Created list that renders only currently visible items

This commit is contained in:
Laurent Cozic 2017-11-04 19:46:37 +00:00
parent 18bb02244f
commit ec259f866f
7 changed files with 130 additions and 17 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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