mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-30 03:14:22 +00:00
web: virtual scrolling
This commit is contained in:
parent
9eecc8d6e2
commit
7ca1ac0f3b
@ -193,18 +193,22 @@ EventEmitter.prototype.emit = function (event) {
|
|||||||
listener.apply(this, args);
|
listener.apply(this, args);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
EventEmitter.prototype.addListener = function (event, f) {
|
EventEmitter.prototype.addListener = function (events, f) {
|
||||||
|
events.split(" ").forEach(function (event) {
|
||||||
this.listeners[event] = this.listeners[event] || [];
|
this.listeners[event] = this.listeners[event] || [];
|
||||||
this.listeners[event].push(f);
|
this.listeners[event].push(f);
|
||||||
|
}.bind(this));
|
||||||
};
|
};
|
||||||
EventEmitter.prototype.removeListener = function (event, f) {
|
EventEmitter.prototype.removeListener = function (events, f) {
|
||||||
if (!(event in this.listeners)) {
|
if (!(events in this.listeners)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
events.split(" ").forEach(function (event) {
|
||||||
var index = this.listeners[event].indexOf(f);
|
var index = this.listeners[event].indexOf(f);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this.listeners[event].splice(index, 1);
|
this.listeners[event].splice(index, 1);
|
||||||
}
|
}
|
||||||
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
function _SettingsStore() {
|
function _SettingsStore() {
|
||||||
@ -926,11 +930,13 @@ var FlowRow = React.createClass({displayName: 'FlowRow',
|
|||||||
));
|
));
|
||||||
},
|
},
|
||||||
shouldComponentUpdate: function (nextProps) {
|
shouldComponentUpdate: function (nextProps) {
|
||||||
var isEqual = (
|
return true;
|
||||||
this.props.columns.length === nextProps.columns.length &&
|
// Further optimization could be done here
|
||||||
this.props.selected === nextProps.selected &&
|
// by calling forceUpdate on flow updates, selection changes and column changes.
|
||||||
this.props.flow.response === nextProps.flow.response);
|
//return (
|
||||||
return !isEqual;
|
//(this.props.columns.length !== nextProps.columns.length) ||
|
||||||
|
//(this.props.selected !== nextProps.selected)
|
||||||
|
//);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -945,30 +951,51 @@ var FlowTableHead = React.createClass({displayName: 'FlowTableHead',
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var FlowTableBody = React.createClass({displayName: 'FlowTableBody',
|
|
||||||
render: function () {
|
|
||||||
var rows = this.props.flows.map(function (flow) {
|
|
||||||
var selected = (flow == this.props.selected);
|
|
||||||
return React.createElement(FlowRow, {key: flow.id,
|
|
||||||
ref: flow.id,
|
|
||||||
flow: flow,
|
|
||||||
columns: this.props.columns,
|
|
||||||
selected: selected,
|
|
||||||
selectFlow: this.props.selectFlow}
|
|
||||||
);
|
|
||||||
}.bind(this));
|
|
||||||
return React.createElement("tbody", null, rows);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
var ROW_HEIGHT = 32;
|
||||||
|
|
||||||
var FlowTable = React.createClass({displayName: 'FlowTable',
|
var FlowTable = React.createClass({displayName: 'FlowTable',
|
||||||
mixins: [StickyHeadMixin, AutoScrollMixin],
|
mixins: [StickyHeadMixin, AutoScrollMixin],
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
return {
|
return {
|
||||||
columns: all_columns
|
columns: all_columns,
|
||||||
|
start: 0,
|
||||||
|
stop: 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
componentWillMount: function () {
|
||||||
|
if (this.props.view) {
|
||||||
|
this.props.view.addListener("add update remove recalculate", this.onChange);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function (nextProps) {
|
||||||
|
if (nextProps.view !== this.props.view) {
|
||||||
|
if (this.props.view) {
|
||||||
|
this.props.view.removeListener("add update remove recalculate");
|
||||||
|
}
|
||||||
|
nextProps.view.addListener("add update remove recalculate", this.onChange);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentDidMount: function () {
|
||||||
|
this.onScroll();
|
||||||
|
},
|
||||||
|
onScroll: function () {
|
||||||
|
this.adjustHead();
|
||||||
|
|
||||||
|
var viewport = this.getDOMNode();
|
||||||
|
var top = viewport.scrollTop;
|
||||||
|
var height = viewport.offsetHeight;
|
||||||
|
var start = Math.floor(top / ROW_HEIGHT);
|
||||||
|
var stop = start + Math.ceil(height / ROW_HEIGHT);
|
||||||
|
this.setState({
|
||||||
|
start: start,
|
||||||
|
stop: stop
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onChange: function () {
|
||||||
|
console.log("onChange");
|
||||||
|
this.forceUpdate();
|
||||||
|
},
|
||||||
scrollIntoView: function (flow) {
|
scrollIntoView: function (flow) {
|
||||||
// Now comes the fun part: Scroll the flow into the view.
|
// Now comes the fun part: Scroll the flow into the view.
|
||||||
var viewport = this.getDOMNode();
|
var viewport = this.getDOMNode();
|
||||||
@ -989,16 +1016,46 @@ var FlowTable = React.createClass({displayName: 'FlowTable',
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
var space_top = 0, space_bottom = 0, fix_nth_row = null;
|
||||||
|
var rows = [];
|
||||||
|
if (this.props.view) {
|
||||||
|
var flows = this.props.view.flows;
|
||||||
|
var max = Math.min(flows.length, this.state.stop);
|
||||||
|
console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop);
|
||||||
|
|
||||||
|
for (var i = this.state.start; i < max; i++) {
|
||||||
|
var flow = flows[i];
|
||||||
|
var selected = (flow === this.props.selected);
|
||||||
|
rows.push(
|
||||||
|
React.createElement(FlowRow, {key: flow.id,
|
||||||
|
ref: flow.id,
|
||||||
|
flow: flow,
|
||||||
|
columns: this.state.columns,
|
||||||
|
selected: selected,
|
||||||
|
selectFlow: this.props.selectFlow}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
space_top = this.state.start * ROW_HEIGHT;
|
||||||
|
space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT;
|
||||||
|
if(this.state.start % 2 === 1){
|
||||||
|
fix_nth_row = React.createElement("tr", null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "flow-table", onScroll: this.adjustHead},
|
React.createElement("div", {className: "flow-table", onScroll: this.onScroll},
|
||||||
React.createElement("table", null,
|
React.createElement("table", null,
|
||||||
React.createElement(FlowTableHead, {ref: "head",
|
React.createElement(FlowTableHead, {ref: "head",
|
||||||
columns: this.state.columns}),
|
columns: this.state.columns}),
|
||||||
React.createElement(FlowTableBody, {ref: "body",
|
React.createElement("tbody", null,
|
||||||
flows: this.props.flows,
|
React.createElement("tr", {style: {height: space_top}}),
|
||||||
selected: this.props.selected,
|
fix_nth_row,
|
||||||
selectFlow: this.props.selectFlow,
|
rows,
|
||||||
columns: this.state.columns})
|
React.createElement("tr", {style: {height: space_bottom}})
|
||||||
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -1340,26 +1397,16 @@ var MainView = React.createClass({displayName: 'MainView',
|
|||||||
this.setState({
|
this.setState({
|
||||||
view: view
|
view: view
|
||||||
});
|
});
|
||||||
view.addListener("add", this.onFlowChange);
|
|
||||||
view.addListener("update", this.onFlowChange);
|
|
||||||
view.addListener("remove", this.onFlowChange);
|
|
||||||
view.addListener("recalculate", this.onFlowChange);
|
|
||||||
},
|
},
|
||||||
closeView: function () {
|
closeView: function () {
|
||||||
this.state.view.close();
|
this.state.view.close();
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentWillMount: function () {
|
||||||
this.openView(this.props.flowStore);
|
this.openView(this.props.flowStore);
|
||||||
},
|
},
|
||||||
componentWillUnmount: function () {
|
componentWillUnmount: function () {
|
||||||
this.closeView();
|
this.closeView();
|
||||||
},
|
},
|
||||||
onFlowChange: function () {
|
|
||||||
console.warn("onFlowChange is deprecated");
|
|
||||||
this.setState({
|
|
||||||
flows: this.state.view.flows
|
|
||||||
});
|
|
||||||
},
|
|
||||||
selectFlow: function (flow) {
|
selectFlow: function (flow) {
|
||||||
if (flow) {
|
if (flow) {
|
||||||
this.replaceWith(
|
this.replaceWith(
|
||||||
@ -1455,7 +1502,7 @@ var MainView = React.createClass({displayName: 'MainView',
|
|||||||
return (
|
return (
|
||||||
React.createElement("div", {className: "main-view", onKeyDown: this.onKeyDown, tabIndex: "0"},
|
React.createElement("div", {className: "main-view", onKeyDown: this.onKeyDown, tabIndex: "0"},
|
||||||
React.createElement(FlowTable, {ref: "flowTable",
|
React.createElement(FlowTable, {ref: "flowTable",
|
||||||
flows: this.state.view ? this.state.view.flows : [],
|
view: this.state.view,
|
||||||
selectFlow: this.selectFlow,
|
selectFlow: this.selectFlow,
|
||||||
selected: selected}),
|
selected: selected}),
|
||||||
details ? React.createElement(Splitter, null) : null,
|
details ? React.createElement(Splitter, null) : null,
|
||||||
|
@ -14,11 +14,13 @@ var FlowRow = React.createClass({
|
|||||||
</tr>);
|
</tr>);
|
||||||
},
|
},
|
||||||
shouldComponentUpdate: function (nextProps) {
|
shouldComponentUpdate: function (nextProps) {
|
||||||
var isEqual = (
|
return true;
|
||||||
this.props.columns.length === nextProps.columns.length &&
|
// Further optimization could be done here
|
||||||
this.props.selected === nextProps.selected &&
|
// by calling forceUpdate on flow updates, selection changes and column changes.
|
||||||
this.props.flow.response === nextProps.flow.response);
|
//return (
|
||||||
return !isEqual;
|
//(this.props.columns.length !== nextProps.columns.length) ||
|
||||||
|
//(this.props.selected !== nextProps.selected)
|
||||||
|
//);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -33,30 +35,51 @@ var FlowTableHead = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var FlowTableBody = React.createClass({
|
|
||||||
render: function () {
|
|
||||||
var rows = this.props.flows.map(function (flow) {
|
|
||||||
var selected = (flow == this.props.selected);
|
|
||||||
return <FlowRow key={flow.id}
|
|
||||||
ref={flow.id}
|
|
||||||
flow={flow}
|
|
||||||
columns={this.props.columns}
|
|
||||||
selected={selected}
|
|
||||||
selectFlow={this.props.selectFlow}
|
|
||||||
/>;
|
|
||||||
}.bind(this));
|
|
||||||
return <tbody>{rows}</tbody>;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
var ROW_HEIGHT = 32;
|
||||||
|
|
||||||
var FlowTable = React.createClass({
|
var FlowTable = React.createClass({
|
||||||
mixins: [StickyHeadMixin, AutoScrollMixin],
|
mixins: [StickyHeadMixin, AutoScrollMixin],
|
||||||
getInitialState: function () {
|
getInitialState: function () {
|
||||||
return {
|
return {
|
||||||
columns: all_columns
|
columns: all_columns,
|
||||||
|
start: 0,
|
||||||
|
stop: 0
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
componentWillMount: function () {
|
||||||
|
if (this.props.view) {
|
||||||
|
this.props.view.addListener("add update remove recalculate", this.onChange);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentWillReceiveProps: function (nextProps) {
|
||||||
|
if (nextProps.view !== this.props.view) {
|
||||||
|
if (this.props.view) {
|
||||||
|
this.props.view.removeListener("add update remove recalculate");
|
||||||
|
}
|
||||||
|
nextProps.view.addListener("add update remove recalculate", this.onChange);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
componentDidMount: function () {
|
||||||
|
this.onScroll();
|
||||||
|
},
|
||||||
|
onScroll: function () {
|
||||||
|
this.adjustHead();
|
||||||
|
|
||||||
|
var viewport = this.getDOMNode();
|
||||||
|
var top = viewport.scrollTop;
|
||||||
|
var height = viewport.offsetHeight;
|
||||||
|
var start = Math.floor(top / ROW_HEIGHT);
|
||||||
|
var stop = start + Math.ceil(height / ROW_HEIGHT);
|
||||||
|
this.setState({
|
||||||
|
start: start,
|
||||||
|
stop: stop
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onChange: function () {
|
||||||
|
console.log("onChange");
|
||||||
|
this.forceUpdate();
|
||||||
|
},
|
||||||
scrollIntoView: function (flow) {
|
scrollIntoView: function (flow) {
|
||||||
// Now comes the fun part: Scroll the flow into the view.
|
// Now comes the fun part: Scroll the flow into the view.
|
||||||
var viewport = this.getDOMNode();
|
var viewport = this.getDOMNode();
|
||||||
@ -77,16 +100,46 @@ var FlowTable = React.createClass({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
render: function () {
|
render: function () {
|
||||||
|
var space_top = 0, space_bottom = 0, fix_nth_row = null;
|
||||||
|
var rows = [];
|
||||||
|
if (this.props.view) {
|
||||||
|
var flows = this.props.view.flows;
|
||||||
|
var max = Math.min(flows.length, this.state.stop);
|
||||||
|
console.log("render", this.props.view.flows.length, this.state.start, max - this.state.start, flows.length - this.state.stop);
|
||||||
|
|
||||||
|
for (var i = this.state.start; i < max; i++) {
|
||||||
|
var flow = flows[i];
|
||||||
|
var selected = (flow === this.props.selected);
|
||||||
|
rows.push(
|
||||||
|
<FlowRow key={flow.id}
|
||||||
|
ref={flow.id}
|
||||||
|
flow={flow}
|
||||||
|
columns={this.state.columns}
|
||||||
|
selected={selected}
|
||||||
|
selectFlow={this.props.selectFlow}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
space_top = this.state.start * ROW_HEIGHT;
|
||||||
|
space_bottom = Math.max(0, flows.length - this.state.stop) * ROW_HEIGHT;
|
||||||
|
if(this.state.start % 2 === 1){
|
||||||
|
fix_nth_row = <tr></tr>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flow-table" onScroll={this.adjustHead}>
|
<div className="flow-table" onScroll={this.onScroll}>
|
||||||
<table>
|
<table>
|
||||||
<FlowTableHead ref="head"
|
<FlowTableHead ref="head"
|
||||||
columns={this.state.columns}/>
|
columns={this.state.columns}/>
|
||||||
<FlowTableBody ref="body"
|
<tbody>
|
||||||
flows={this.props.flows}
|
<tr style={{height: space_top}}></tr>
|
||||||
selected={this.props.selected}
|
{ fix_nth_row }
|
||||||
selectFlow={this.props.selectFlow}
|
{rows}
|
||||||
columns={this.state.columns}/>
|
<tr style={{height: space_bottom}}></tr>
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -16,26 +16,16 @@ var MainView = React.createClass({
|
|||||||
this.setState({
|
this.setState({
|
||||||
view: view
|
view: view
|
||||||
});
|
});
|
||||||
view.addListener("add", this.onFlowChange);
|
|
||||||
view.addListener("update", this.onFlowChange);
|
|
||||||
view.addListener("remove", this.onFlowChange);
|
|
||||||
view.addListener("recalculate", this.onFlowChange);
|
|
||||||
},
|
},
|
||||||
closeView: function () {
|
closeView: function () {
|
||||||
this.state.view.close();
|
this.state.view.close();
|
||||||
},
|
},
|
||||||
componentDidMount: function () {
|
componentWillMount: function () {
|
||||||
this.openView(this.props.flowStore);
|
this.openView(this.props.flowStore);
|
||||||
},
|
},
|
||||||
componentWillUnmount: function () {
|
componentWillUnmount: function () {
|
||||||
this.closeView();
|
this.closeView();
|
||||||
},
|
},
|
||||||
onFlowChange: function () {
|
|
||||||
console.warn("onFlowChange is deprecated");
|
|
||||||
this.setState({
|
|
||||||
flows: this.state.view.flows
|
|
||||||
});
|
|
||||||
},
|
|
||||||
selectFlow: function (flow) {
|
selectFlow: function (flow) {
|
||||||
if (flow) {
|
if (flow) {
|
||||||
this.replaceWith(
|
this.replaceWith(
|
||||||
@ -131,7 +121,7 @@ var MainView = React.createClass({
|
|||||||
return (
|
return (
|
||||||
<div className="main-view" onKeyDown={this.onKeyDown} tabIndex="0">
|
<div className="main-view" onKeyDown={this.onKeyDown} tabIndex="0">
|
||||||
<FlowTable ref="flowTable"
|
<FlowTable ref="flowTable"
|
||||||
flows={this.state.view ? this.state.view.flows : []}
|
view={this.state.view}
|
||||||
selectFlow={this.selectFlow}
|
selectFlow={this.selectFlow}
|
||||||
selected={selected} />
|
selected={selected} />
|
||||||
{ details ? <Splitter/> : null }
|
{ details ? <Splitter/> : null }
|
||||||
|
@ -10,16 +10,20 @@ EventEmitter.prototype.emit = function (event) {
|
|||||||
listener.apply(this, args);
|
listener.apply(this, args);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
};
|
};
|
||||||
EventEmitter.prototype.addListener = function (event, f) {
|
EventEmitter.prototype.addListener = function (events, f) {
|
||||||
|
events.split(" ").forEach(function (event) {
|
||||||
this.listeners[event] = this.listeners[event] || [];
|
this.listeners[event] = this.listeners[event] || [];
|
||||||
this.listeners[event].push(f);
|
this.listeners[event].push(f);
|
||||||
|
}.bind(this));
|
||||||
};
|
};
|
||||||
EventEmitter.prototype.removeListener = function (event, f) {
|
EventEmitter.prototype.removeListener = function (events, f) {
|
||||||
if (!(event in this.listeners)) {
|
if (!(events in this.listeners)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
events.split(" ").forEach(function (event) {
|
||||||
var index = this.listeners[event].indexOf(f);
|
var index = this.listeners[event].indexOf(f);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
this.listeners[event].splice(index, 1);
|
this.listeners[event].splice(index, 1);
|
||||||
}
|
}
|
||||||
|
}.bind(this));
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user