2015-07-15 12:30:11 +08:00
|
|
|
/**
|
|
|
|
* The `SubtreeRetainer` class represents a Mithril virtual DOM subtree. It
|
|
|
|
* keeps track of a number of pieces of data, allowing the subtree to be
|
|
|
|
* retained if none of them have changed.
|
|
|
|
*
|
|
|
|
* @example
|
|
|
|
* // constructor
|
|
|
|
* this.subtree = new SubtreeRetainer(
|
|
|
|
* () => this.props.post.freshness,
|
|
|
|
* () => this.showing
|
|
|
|
* );
|
|
|
|
* this.subtree.check(() => this.props.user.freshness);
|
|
|
|
*
|
|
|
|
* // view
|
|
|
|
* this.subtree.retain() || 'expensive expression'
|
|
|
|
*
|
|
|
|
* @see https://lhorie.github.io/mithril/mithril.html#persisting-dom-elements-across-route-changes
|
|
|
|
*/
|
|
|
|
export default class SubtreeRetainer {
|
|
|
|
/**
|
|
|
|
* @param {...callbacks} callbacks Functions returning data to keep track of.
|
|
|
|
*/
|
|
|
|
constructor(...callbacks) {
|
|
|
|
this.callbacks = callbacks;
|
|
|
|
this.data = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Return a virtual DOM directive that will retain a subtree if no data has
|
|
|
|
* changed since the last check.
|
|
|
|
*
|
|
|
|
* @return {Object|false}
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
retain() {
|
|
|
|
let needsRebuild = false;
|
|
|
|
|
|
|
|
this.callbacks.forEach((callback, i) => {
|
|
|
|
const result = callback();
|
|
|
|
|
|
|
|
if (result !== this.data[i]) {
|
|
|
|
this.data[i] = result;
|
|
|
|
needsRebuild = true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-04-17 17:57:55 +08:00
|
|
|
return needsRebuild ? false : { subtree: 'retain' };
|
2015-07-15 12:30:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add another callback to be checked.
|
|
|
|
*
|
|
|
|
* @param {...Function} callbacks
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
check(...callbacks) {
|
|
|
|
this.callbacks = this.callbacks.concat(callbacks);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Invalidate the subtree, forcing it to be rerendered.
|
|
|
|
*
|
|
|
|
* @public
|
|
|
|
*/
|
|
|
|
invalidate() {
|
|
|
|
this.data = {};
|
|
|
|
}
|
|
|
|
}
|