opds-web-client
Version:
184 lines (183 loc) • 14.2 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 (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Root = void 0;
var React = require("react");
var PropTypes = require("prop-types");
var react_redux_1 = require("react-redux");
var mergeRootProps_1 = require("./mergeRootProps");
var BookDetails_1 = require("./BookDetails");
var LoadingIndicator_1 = require("./LoadingIndicator");
var ErrorMessage_1 = require("./ErrorMessage");
var AuthProviderSelectionForm_1 = require("./AuthProviderSelectionForm");
var Search_1 = require("./Search");
var Breadcrumbs_1 = require("./Breadcrumbs");
var Collection_1 = require("./Collection");
var UrlForm_1 = require("./UrlForm");
var SkipNavigationLink_1 = require("./SkipNavigationLink");
var CatalogLink_1 = require("./CatalogLink");
var utils_1 = require("../utils");
/** The root component of the application that connects to the Redux store and
passes props to other components. */
var Root = /** @class */ (function (_super) {
__extends(Root, _super);
function Root(props) {
var _this = _super.call(this, props) || this;
_this.state = {};
return _this;
}
Root.prototype.render = function () {
var _this = this;
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
var BookDetailsContainer = this.props.BookDetailsContainer;
var Header = this.props.Header;
var Footer = this.props.Footer;
var CollectionContainer = this.props.CollectionContainer;
var collectionTitle = this.props.collectionData
? this.props.collectionData.title
: null;
var bookTitle = this.props.bookData ? this.props.bookData.title : null;
var computeBreadcrumbs = this.props.computeBreadcrumbs || Breadcrumbs_1.defaultComputeBreadcrumbs;
var breadcrumbsLinks = computeBreadcrumbs(this.props.collectionData, this.props.history);
var showBreadcrumbs = this.props.collectionData && breadcrumbsLinks.length > 0;
var showCollection = this.props.collectionData && !this.props.bookData;
var showBook = !!this.props.bookData;
var showBookWrapper = this.props.bookUrl || this.props.bookData;
var showUrlForm = !this.props.collectionUrl && !this.props.bookUrl;
var showSearch = this.props.collectionData && this.props.collectionData.search;
// The tabs should only display if the component is passed and if
// the catalog is being displayed and not a book.
var showCollectionContainer = !!CollectionContainer && !showBook;
var allLanguageSearch = this.props.allLanguageSearch;
var hasError = this.props.error && (!this.props.auth || !this.props.auth.showForm);
var errorMessage = "";
if (hasError) {
errorMessage = "Could not fetch data: ".concat((_a = this.props.error) === null || _a === void 0 ? void 0 : _a.url, "\n\n ").concat((_b = this.props.error) === null || _b === void 0 ? void 0 : _b.response);
}
return (React.createElement("div", { className: "catalog" },
React.createElement(SkipNavigationLink_1.default, { target: "#main" }),
Header ? (React.createElement(Header, { collectionTitle: collectionTitle, bookTitle: bookTitle, loansUrl: this.props.loansUrl, isSignedIn: this.props.isSignedIn, fetchLoans: this.props.fetchLoans, clearAuthCredentials: this.props.clearAuthCredentials }, showSearch && (React.createElement(Search_1.default, { url: (_d = (_c = this.props.collectionData) === null || _c === void 0 ? void 0 : _c.search) === null || _d === void 0 ? void 0 : _d.url, searchData: (_f = (_e = this.props.collectionData) === null || _e === void 0 ? void 0 : _e.search) === null || _f === void 0 ? void 0 : _f.searchData, fetchSearchDescription: this.props.fetchSearchDescription, allLanguageSearch: allLanguageSearch })))) : (React.createElement("nav", { className: "header navbar navbar-default", role: "navigation" },
React.createElement("div", { className: "container-fluid" },
React.createElement("span", { className: "navbar-brand" }, "OPDS Web Client"),
this.props.loansUrl && (React.createElement("ul", { className: "nav navbar-nav" },
React.createElement("li", null,
React.createElement(CatalogLink_1.default, { collectionUrl: this.props.loansUrl, bookUrl: null }, "My Books")),
React.createElement("li", null, this.props.isSignedIn && (React.createElement("button", { onClick: this.props.clearAuthCredentials }, "Sign Out")))))))),
(showBreadcrumbs || showSearch) && (React.createElement("div", { className: "breadcrumbs-or-search-wrapper" },
showBreadcrumbs && (React.createElement(Breadcrumbs_1.default, { links: breadcrumbsLinks, currentLink: !!showBook })),
showSearch && (React.createElement(Search_1.default, { url: (_h = (_g = this.props.collectionData) === null || _g === void 0 ? void 0 : _g.search) === null || _h === void 0 ? void 0 : _h.url, searchData: (_k = (_j = this.props.collectionData) === null || _j === void 0 ? void 0 : _j.search) === null || _k === void 0 ? void 0 : _k.searchData, fetchSearchDescription: this.props.fetchSearchDescription, allLanguageSearch: allLanguageSearch })))),
React.createElement("main", { id: "main", className: "main", role: "main", tabIndex: -1 },
this.state.authError && (React.createElement(ErrorMessage_1.default, { message: this.state.authError, close: function () {
_this.setState({ authError: null });
} })),
hasError && (React.createElement(ErrorMessage_1.default, { message: errorMessage, retry: this.props.retryCollectionAndBook })),
(this.props.isFetchingCollection || this.props.isFetchingBook) && (React.createElement(LoadingIndicator_1.default, null)),
this.props.auth && this.props.auth.showForm && (React.createElement(AuthProviderSelectionForm_1.default, { saveCredentials: this.props.saveAuthCredentials, hide: this.props.closeErrorAndHideAuthForm, callback: this.props.auth.callback, cancel: this.props.auth.cancel, title: this.props.auth.title, error: this.props.auth.error, attemptedProvider: this.props.auth.attemptedProvider, providers: this.props.auth.providers })),
showUrlForm && React.createElement(UrlForm_1.default, { collectionUrl: this.props.collectionUrl }),
React.createElement("div", { className: "body" },
showBookWrapper && (React.createElement("div", { className: "book-details-wrapper" }, this.props.bookData &&
(BookDetailsContainer &&
(this.props.bookUrl || ((_l = this.props.bookData) === null || _l === void 0 ? void 0 : _l.url)) ? (React.createElement(BookDetailsContainer, { book: (0, utils_1.loanedBookData)(this.props.bookData, this.props.loans, this.props.bookUrl), bookUrl: this.props.bookUrl || ((_m = this.props.bookData) === null || _m === void 0 ? void 0 : _m.url), collectionUrl: this.props.collectionUrl, refreshCatalog: this.props.refreshCollectionAndBook },
React.createElement(BookDetails_1.default, { book: (0, utils_1.loanedBookData)(this.props.bookData, this.props.loans, this.props.bookUrl), updateBook: this.props.updateBook, isSignedIn: this.props.isSignedIn, epubReaderUrlTemplate: this.props.epubReaderUrlTemplate }))) : (React.createElement("div", { className: "without-container" },
React.createElement(BookDetails_1.default, { book: (0, utils_1.loanedBookData)(this.props.bookData, this.props.loans, this.props.bookUrl), updateBook: this.props.updateBook, isSignedIn: this.props.isSignedIn, epubReaderUrlTemplate: this.props.epubReaderUrlTemplate })))))),
showCollection ? (showCollectionContainer && CollectionContainer ? (React.createElement(CollectionContainer, null,
React.createElement(Collection_1.default, { collection: (0, utils_1.collectionDataWithLoans)(this.props.collectionData, this.props.loans), fetchPage: this.props.fetchPage, isFetchingCollection: this.props.isFetchingCollection, isFetchingBook: this.props.isFetchingBook, isFetchingPage: this.props.isFetchingPage, error: this.props.error, updateBook: this.props.updateBook, fulfillBook: this.props.fulfillBook, indirectFulfillBook: this.props.indirectFulfillBook, isSignedIn: this.props.isSignedIn, epubReaderUrlTemplate: this.props.epubReaderUrlTemplate, preferences: this.props.preferences, setPreference: this.props.setPreference }))) : (React.createElement(Collection_1.default, { collection: (0, utils_1.collectionDataWithLoans)(this.props.collectionData, this.props.loans), fetchPage: this.props.fetchPage, isFetchingCollection: this.props.isFetchingCollection, isFetchingBook: this.props.isFetchingBook, isFetchingPage: this.props.isFetchingPage, error: this.props.error, updateBook: this.props.updateBook, fulfillBook: this.props.fulfillBook, indirectFulfillBook: this.props.indirectFulfillBook, isSignedIn: this.props.isSignedIn, epubReaderUrlTemplate: this.props.epubReaderUrlTemplate, preferences: this.props.preferences, setPreference: this.props.setPreference }))) : null)),
Footer && this.props.collectionData && (React.createElement("footer", null,
React.createElement(Footer, { collection: this.props.collectionData })))));
};
Root.prototype.componentWillMount = function () {
var _this = this;
var _a, _b;
this.updatePageTitle(this.props);
if (this.props.authCredentials && this.props.saveAuthCredentials) {
this.props.saveAuthCredentials(this.props.authCredentials);
}
var authError;
if (this.props.authPlugins) {
this.props.authPlugins.forEach(function (plugin) {
var result = plugin.lookForCredentials();
if (result && result.error) {
authError = result.error;
}
if (result && result.credentials && _this.props.saveAuthCredentials) {
_this.props.saveAuthCredentials(result.credentials);
}
});
}
if (authError) {
this.setState({ authError: authError });
}
else if (this.props.collectionUrl || this.props.bookUrl) {
return (_b = (_a = this.props).setCollectionAndBook) === null || _b === void 0 ? void 0 : _b.call(_a, this.props.collectionUrl, this.props.bookUrl).then(function (_a) {
var _b, _c;
var collectionData = _a.collectionData, bookData = _a.bookData;
if (_this.props.authCredentials &&
collectionData &&
collectionData.shelfUrl) {
(_c = (_b = _this.props).fetchLoans) === null || _c === void 0 ? void 0 : _c.call(_b, collectionData.shelfUrl);
}
});
}
};
Root.prototype.componentWillReceiveProps = function (nextProps) {
var _a, _b;
if (nextProps.collectionUrl !== this.props.collectionUrl ||
nextProps.bookUrl !== this.props.bookUrl) {
(_b = (_a = this.props).setCollectionAndBook) === null || _b === void 0 ? void 0 : _b.call(_a, nextProps.collectionUrl, nextProps.bookUrl);
}
this.updatePageTitle(nextProps);
};
Root.prototype.updatePageTitle = function (props) {
if (typeof document !== "undefined" && props.pageTitleTemplate) {
var collectionTitle = props.collectionData && props.collectionData.title;
var bookTitle = props.bookData && props.bookData.title;
document.title = props.pageTitleTemplate(collectionTitle, bookTitle);
}
};
Root.prototype.showPrevBook = function () {
this.showRelativeBook(-1);
};
Root.prototype.showNextBook = function () {
this.showRelativeBook(1);
};
Root.prototype.showRelativeBook = function (relativeIndex) {
if (this.context.router &&
this.props.collectionData &&
this.props.bookData) {
var books = this.props.collectionData.lanes.reduce(function (books, lane) {
return books.concat(lane.books);
}, this.props.collectionData.books);
var bookIds = books.map(function (book) { return book.id; });
var currentBookIndex = bookIds.indexOf(this.props.bookData.id);
if (currentBookIndex !== -1) {
// wrap index at start and end of bookIds array
var nextBookIndex = (currentBookIndex + relativeIndex + bookIds.length) % bookIds.length;
var nextBookUrl = books[nextBookIndex].url || books[nextBookIndex].id;
this.context.router.push(this.context.pathFor(this.props.collectionData.url, nextBookUrl));
}
}
};
Root.contextTypes = {
router: PropTypes.object,
pathFor: PropTypes.func.isRequired
};
return Root;
}(React.Component));
exports.Root = Root;
var connectOptions = { pure: false };
var ConnectedRoot = (0, react_redux_1.connect)(mergeRootProps_1.mapStateToProps, mergeRootProps_1.mapDispatchToProps, mergeRootProps_1.mergeRootProps, connectOptions)(Root);
exports.default = ConnectedRoot;