parrot-layout
Version:
295 lines (294 loc) • 12.7 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __values = (this && this.__values) || function (o) {
var m = typeof Symbol === "function" && o[Symbol.iterator], i = 0;
if (m) return m.call(o);
return {
next: function () {
if (o && i >= o.length) o = void 0;
return { value: o && o[i++], done: !o };
}
};
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = require("react");
var paramorph_1 = require("paramorph");
var Tile_1 = require("../Tile");
var TableOfContents_1 = require("../TableOfContents");
var Spinner_1 = require("../Spinner");
var Button_1 = require("../Button");
var Icon_1 = require("../Icon");
var s = require('./style');
;
var DEFAULT_PRELOAD_SIZE = 20;
var DEFAULT_BATCH_SIZE = 5;
var PAGE_PATH_PARAM = 'pageNumber';
var PAGE_PARAM_FORMAT = '(-\\d+-)';
var Feed = /** @class */ (function (_super) {
__extends(Feed, _super);
function Feed(props) {
var _this = _super.call(this, props) || this;
_this.loadTrigger = null;
var preloadSize = Math.min(props.preloadSize || props.batchSize || DEFAULT_PRELOAD_SIZE, props.posts.length);
_this.state = {
loading: preloadSize,
loaded: preloadSize,
};
_this.onContent = _this.onContent.bind(_this);
_this.onScroll = _this.onScroll.bind(_this);
return _this;
}
Feed.prototype.componentWillMount = function () {
var _a;
var _b = this.context, post = _b.post, requestParameterizedRender = _b.requestParameterizedRender;
if (!this.hasPathParam()) {
console.error("'" + PAGE_PATH_PARAM + PAGE_PARAM_FORMAT + "' path param not found in pathSpec: '" + post.pathSpec + "'");
return;
}
// pages in url are numbered starting from 1
var lastPageNumber = this.getLastPageNumber() + 1;
// first page is already rendered
for (var i = 2; i <= lastPageNumber + 1; ++i) {
requestParameterizedRender((_a = {}, _a[PAGE_PATH_PARAM] = "-" + i + "-", _a));
}
};
Feed.prototype.render = function () {
var _this = this;
var _a = this.context, paramorph = _a.paramorph, post = _a.post;
var _b = this.props, posts = _b.posts, _c = _b.respectLimit, respectLimit = _c === void 0 ? false : _c, props = __rest(_b, ["posts", "respectLimit"]);
var _d = this.state, loading = _d.loading, loaded = _d.loaded;
if (respectLimit) {
return React.createElement(TableOfContents_1.Branch, __assign({ posts: posts.slice(0, post.limit), shallow: true }, props));
}
var content = this.getContent();
return (React.createElement("div", { className: loaded !== loading ? s.loading : '' },
this.renderNextLink(),
content.map(function (_a) {
var post = _a.post, Content = _a.Content;
return (React.createElement(Tile_1.default, { key: post.url, post: post, Content: Content }));
}),
React.createElement("div", { className: s.loadTrigger, ref: function (e) { return _this.loadTrigger = e; } },
React.createElement(Spinner_1.default, null)),
this.renderPreviousLink()));
};
Feed.prototype.componentDidMount = function () {
var _a = this.context, paramorph = _a.paramorph, post = _a.post;
var _b = this.props.respectLimit, respectLimit = _b === void 0 ? false : _b;
var loaded = this.state.loaded;
if (!respectLimit) {
paramorph.addContentListener(this.onContent);
}
window.addEventListener('scroll', this.onScroll);
this.maybeLoadInitialBatch();
};
Feed.prototype.componentWillUnmount = function () {
var paramorph = this.context.paramorph;
var _a = this.props.respectLimit, respectLimit = _a === void 0 ? false : _a;
if (!respectLimit) {
paramorph.removeContentListener(this.onContent);
}
window.removeEventListener('scroll', this.onScroll);
};
Feed.prototype.renderPreviousLink = function () {
if (this.isOnLastPage() || !this.hasPathParam()) {
return null;
}
return (React.createElement("p", { className: s.staticLink + " " + s.previous },
React.createElement(Button_1.default, { variant: 'flat', color: 'gray', url: this.getPreviousUrl() },
"Previous Posts ",
React.createElement(Icon_1.default, { name: 'arrow_forward' }))));
};
Feed.prototype.renderNextLink = function () {
if (this.isOnFirstPage() || !this.hasPathParam()) {
return null;
}
return (React.createElement("p", { className: s.staticLink + " " + s.next },
React.createElement(Button_1.default, { variant: 'flat', color: 'gray', url: this.getNextUrl() },
React.createElement(Icon_1.default, { name: 'arrow_back' }),
" Next Posts")));
};
Feed.prototype.getContent = function () {
var e_1, _a;
var paramorph = this.context.paramorph;
var posts = this.props.posts;
var loading = this.state.loading;
var content = [];
var pageOffset = this.getPageOffset();
var pagePosts = posts.slice(pageOffset, pageOffset + loading);
try {
for (var pagePosts_1 = __values(pagePosts), pagePosts_1_1 = pagePosts_1.next(); !pagePosts_1_1.done; pagePosts_1_1 = pagePosts_1.next()) {
var post = pagePosts_1_1.value;
var Content = paramorph.content[post.url];
if (Content === undefined) {
break;
}
content.push({ post: post, Content: Content });
}
}
catch (e_1_1) { e_1 = { error: e_1_1 }; }
finally {
try {
if (pagePosts_1_1 && !pagePosts_1_1.done && (_a = pagePosts_1.return)) _a.call(pagePosts_1);
}
finally { if (e_1) throw e_1.error; }
}
return content;
};
Feed.prototype.onScroll = function () {
if (this.needsMoreContent() && !this.isAtEnd() && !this.isLoading()) {
this.loadNextBatch();
}
};
Feed.prototype.onContent = function () {
if (!this.isLoading()) {
// not loaded by us
return;
}
var loaded = this.state.loaded;
var content = this.getContent();
if (content.length > loaded) {
this.setState(function (prev) { return (__assign({}, prev, { loaded: content.length })); });
}
};
Feed.prototype.needsMoreContent = function () {
var scrollY = window.scrollY, innerHeight = window.innerHeight;
if (!this.loadTrigger) {
return false;
}
var offsetTop = getOffsetTop(this.loadTrigger);
return scrollY + innerHeight >= offsetTop;
};
Feed.prototype.isLoading = function () {
var _a = this.state, loading = _a.loading, loaded = _a.loaded;
return loading !== loaded;
};
Feed.prototype.maybeLoadInitialBatch = function () {
var _this = this;
var paramorph = this.context.paramorph;
var loaded = this.state.loaded;
var posts = this.props.posts;
var content = this.getContent();
if (content.length === loaded) {
this.onScroll();
return;
}
var pageOffset = this.getPageOffset();
var loading = Math.min(posts.length - pageOffset, this.state.loading);
this.setState(function (prev) { return (__assign({}, prev, { loading: loading, loaded: content.length })); }, function () {
var pageOffset = _this.getPageOffset();
var batch = posts.slice(pageOffset, pageOffset + loading);
batch.map(function (post) { return paramorph.loadContent(post.url); });
});
};
Feed.prototype.loadNextBatch = function () {
var _this = this;
var _a = this.context, paramorph = _a.paramorph, post = _a.post;
var _b = this.props, posts = _b.posts, _c = _b.batchSize, batchSize = _c === void 0 ? DEFAULT_BATCH_SIZE : _c;
var loading = this.state.loading;
var nextLoading = Math.min(loading + batchSize, posts.length);
this.setState(function (prev) { return (__assign({}, prev, { loading: nextLoading })); }, function () {
var pageOffset = _this.getPageOffset();
var batch = posts.slice(pageOffset + loading, pageOffset + nextLoading);
batch.map(function (post) { return paramorph.loadContent(post.url); });
});
};
Feed.prototype.isAtEnd = function () {
var loading = this.state.loading;
var posts = this.props.posts;
return loading === posts.length;
};
Feed.prototype.isOnFirstPage = function () {
return this.getPageNumber() === 0;
};
Feed.prototype.isOnLastPage = function () {
return this.getPageNumber() === this.getLastPageNumber();
};
Feed.prototype.getPageNumber = function () {
var pathParams = this.context.pathParams;
// pages in url are numbered starting from 1
var pageNumber = pathParams.get('pageNumber') || '-1-';
return Number.parseInt(pageNumber.replace(/[^\d]+/g, '')) - 1;
};
Feed.prototype.getLastPageNumber = function () {
var posts = this.props.posts;
var pageSize = this.getPageSize();
return Math.round(posts.length / pageSize);
};
Feed.prototype.getPageSize = function () {
var _a = this.props.preloadSize, preloadSize = _a === void 0 ? DEFAULT_PRELOAD_SIZE : _a;
return preloadSize;
};
Feed.prototype.getPageOffset = function () {
var pageSize = this.getPageSize();
var pageNumber = this.getPageNumber();
var offset = pageSize * pageNumber;
return offset;
};
Feed.prototype.getNextUrl = function () {
var _a = this.context, pathParams = _a.pathParams, post = _a.post;
// pages in url are numbered starting from 1
var pageNumber = this.getPageNumber() + 1;
if (pageNumber === 2) {
return post.url;
}
else {
return this.createUrl(pageNumber - 1);
}
};
Feed.prototype.getPreviousUrl = function () {
var pathParams = this.context.pathParams;
// pages in url are numbered starting from 1
var pageNumber = this.getPageNumber() + 1;
return this.createUrl(pageNumber + 1);
};
Feed.prototype.createUrl = function (pageNumber) {
var post = this.context.post;
return post.pathSpec.replace(":" + PAGE_PATH_PARAM + PAGE_PARAM_FORMAT + "?", "-" + pageNumber + "-");
};
Feed.prototype.hasPathParam = function () {
var post = this.context.post;
return post.pathSpec.indexOf(":" + PAGE_PATH_PARAM + PAGE_PARAM_FORMAT + "?/") !== -1;
};
return Feed;
}(paramorph_1.PureComponent));
exports.Feed = Feed;
exports.default = Feed;
function getOffsetTop(elem) {
var offsetParent = elem.offsetParent;
var parentOffset = (offsetParent ? getOffsetTop(offsetParent) : 0);
return elem.offsetTop + parentOffset;
}