UNPKG

apisearch-ui

Version:

Javascript User Interface of Apisearch.

434 lines (433 loc) 19.9 kB
"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) { 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); }; exports.__esModule = true; var ItemUUID_1 = require("apisearch/lib/Model/ItemUUID"); var preact_1 = require("preact"); var compat_1 = require("preact/compat"); var Constants_1 = require("../../Constants"); var Container_1 = require("../../Container"); var Template_1 = require("../Template"); var defaultTemplates_1 = require("./defaultTemplates"); var Item_1 = require("./Item"); var ResultActions_1 = require("./ResultActions"); var Common_1 = require("../Common"); /** * Result Component */ var ResultComponent = /** @class */ (function (_super) { __extends(ResultComponent, _super); /** * Constructor */ function ResultComponent(props) { var _this = _super.call(this, props) || this; _this.fromLoadingNextPage = false; _this.observer = compat_1.useRef(); _this.endResultsBoxRef = compat_1.useCallback(function (node) { if (_this.observer.current instanceof IntersectionObserver) { _this.observer.current.disconnect(); } _this.observer.current = new IntersectionObserver(function (entries) { if (entries[0].isIntersecting) { _this.loadNextPage(); } }); if ((_this.observer.current instanceof IntersectionObserver) && node) { _this.observer.current.observe(node); } }, []); /** * @param word */ _this.handleAlternativeClick = function (word) { var props = _this.props; /** * Dispatch action */ Common_1.onWordClickAction(props.environmentId, props.store.getCurrentQuery(), props.repository, word); }; _this.state = { customResponse: "", focus: props.fadeInSelector === "", hasNewPage: false, items: [], page: 0 }; return _this; } ResultComponent.prototype.loadNextPage = function () { var _a = this.props, environmentId = _a.environmentId, store = _a.store, repository = _a.repository; this.fromLoadingNextPage = true; this.currentExpectedPage = this.state.page + 1; ResultActions_1.infiniteScrollNextPageAction(environmentId, store.getCurrentQuery(), repository, this.currentExpectedPage); }; /** * Hook that change state once mouse clicks inside or outside the container */ ResultComponent.prototype.addMouseDownListeners = function (ref, fadeInSelector) { var _this = this; compat_1.useEffect(function () { var self = _this; /** * Alert if clicked on outside of element */ function handleClickOutside(event) { self.setState(function () { return { focus: event.target.closest(fadeInSelector) != null }; }); } // Bind the event listener document.addEventListener("mousedown", handleClickOutside); return function () { // Unbind the event listener on clean up document.removeEventListener("mousedown", handleClickOutside); }; }, [ref]); }; /** * Component will receive props * * @param props */ ResultComponent.prototype.componentWillReceiveProps = function (props) { if (props.store.getCurrentResult() == null) { this.setState(function (_) { return { customResponse: "", hasNewPage: false, items: [], page: 0 }; }); return; } var currentResult = props.store.getCurrentResult(); var currentQuery = props.store.getCurrentQuery(); var items = currentResult.getItems(); var currentPage = this.page(); var hasNewPage = (currentResult.getTotalHits() > (currentPage * currentQuery.getSize())); var currentItems = this.fromLoadingNextPage ? this.state.items.concat(items) : items; this.fromLoadingNextPage = false; this.currentExpectedPage = undefined; this.setState(function (_) { return { customResponse: currentResult.getMetadataValue("custom_response"), hasNewPage: hasNewPage, items: currentItems, page: currentPage }; }); }; /** * Component will mount */ ResultComponent.prototype.componentWillMount = function () { var props = this.props; /** * Dispatch action */ ResultActions_1.configureQuery(props.environmentId, props.store.getCurrentQuery(), props.itemsPerPage, props.highlightsEnabled, props.promote.map(function (itemUUID) { return itemUUID instanceof ItemUUID_1.ItemUUID ? itemUUID : ItemUUID_1.ItemUUID.createFromArray(itemUUID); }), props.exclude.map(function (itemUUID) { return itemUUID instanceof ItemUUID_1.ItemUUID ? itemUUID : ItemUUID_1.ItemUUID.createFromArray(itemUUID); }), props.fields, props.filter, props.minScore); }; /** * @private */ ResultComponent.prototype.page = function () { var _a; return (_a = this.currentExpectedPage) !== null && _a !== void 0 ? _a : this.props.store.getCurrentQuery().getPage(); }; /** * Render * * @return {any} */ ResultComponent.prototype.render = function () { var _this = this; var _a; var that = this; var props = this.props; var dirty = props.store.isDirty(); var containerClassName = props.classNames.container; var itemsListClassName = props.classNames.itemsList; var placeholderClassName = props.classNames.placeholder; var itemsListTemplate = props.template.itemsList; var placeholderTemplate = (_a = props.template.placeholder) !== null && _a !== void 0 ? _a : ""; var currentResult = props.store.getCurrentResult(); var currentQuery = props.store.getCurrentQuery(); var currentVisibleResults = props.currentVisibleResults; var subResults = Object.values(currentResult.getSubresults()); var wrapperRef = compat_1.useRef(null); var customResponse = currentResult.getMetadataValue("custom_response"); var redirection = currentResult.getMetadataValue("redirection"); // Check for custom response html var customResponseBody; if (customResponse) { customResponseBody = (preact_1.h(Template_1["default"], { template: customResponse.content, className: "as-result__custom_response", dictionary: this.props.dictionary })); if (customResponse.only) { return customResponseBody; } } var withoutEnterRedirection = false; if (redirection) { if (redirection.type === "automatic") { window.top.location.href = redirection.url; } else if (redirection.type === "on_enter") { window.postMessage({ name: "apisearch_bind_enter_redirection", url: redirection.url }, "*"); withoutEnterRedirection = false; } } if (withoutEnterRedirection) { window.postMessage({ name: "apisearch_bind_enter_redirection", url: undefined }, "*"); } var hasInfiniteScrollNextPage = (props.infiniteScroll !== false) && ((props.infiniteScroll === true) || (props.infiniteScroll >= 0)) && this.state.hasNewPage; var infiniteScrollMargin = hasInfiniteScrollNextPage ? (props.infiniteScroll === true ? 0 : props.infiniteScroll) : undefined; if (props.fadeInSelector !== "") { this.addMouseDownListeners(wrapperRef, props.fadeInSelector); } if (!currentVisibleResults || !this.state.focus) { return (preact_1.h("div", { className: "as-result " + containerClassName })); } /** * Data accessible to the template */ var items = this.state.items; var reducedTemplateData = { query: currentQuery.getQueryText(), suggestions: currentResult.getSuggestions() }; /** * We should add positions to items * When the number of items to render is higher than the page size, we are in front of infinite scroll */ var page = this.state.page; var isInfiniteActive = page > 1; var firstItem = ((this.state.page - 1) * currentQuery.getSize()); var itemsForEvent = items; if (isInfiniteActive) { itemsForEvent = Array.prototype.slice.call(items, firstItem); } Array.prototype.forEach.call(itemsForEvent, function (item) { item.position = ++firstItem; item.id = item.getId(); }); window.postMessage({ name: "apisearch_result_items", query: currentQuery.toArray(), query_text: currentQuery.getQueryText(), with_results: items.length > 0, page: this.state.page, site: props.store.getSite(), device: props.store.getDevice(), items: itemsForEvent.map(function (item) { return { fields: item.fields, uuid: item.uuid }; }) }, "*"); /** * Uses defined a custom items list. Old version */ if (props.template.itemsList !== defaultTemplates_1.defaultItemsListTemplate) { return (preact_1.h("div", { className: "as-result " + containerClassName, ref: wrapperRef, style: "position: relative" }, (dirty) ? preact_1.h(Template_1["default"], { template: placeholderTemplate, className: "as-result__placeholder " + placeholderClassName, dictionary: this.props.dictionary }) : preact_1.h(Template_1["default"], { template: itemsListTemplate, data: __assign(__assign({}, reducedTemplateData), { items: (items) ? items.map(function (item) { return _this.hydrateItem(item); }) : [] }), className: "as-result__itemsList " + itemsListClassName, dictionary: this.props.dictionary }), hasInfiniteScrollNextPage ? (props.infiniteScrollButton ? preact_1.h("div", { onClick: function (e) { that.loadNextPage(); } }, preact_1.h(Template_1["default"], { template: props.template.next_page_button, data: { page: this.state.page + 1 } })) : preact_1.h("div", { ref: this.endResultsBoxRef, style: "bottom: " + infiniteScrollMargin + "px; position: relative;" })) : "")); } if (dirty) { return (preact_1.h("div", { className: "as-result " + containerClassName, ref: wrapperRef }, preact_1.h(Template_1["default"], { template: placeholderTemplate, className: "as-result__placeholder " + placeholderClassName, dictionary: props.dictionary }))); } /** * New version */ return (preact_1.h("div", { className: "as-result " + containerClassName, ref: wrapperRef }, customResponseBody, (dirty) ? preact_1.h(Template_1["default"], { template: placeholderTemplate, className: "as-result__placeholder " + placeholderClassName, dictionary: this.props.dictionary }) : ((items.length > 0) ? (preact_1.h("div", { className: "as-result__itemsList " + props.classNames.itemsList }, items.map(function (item) { return preact_1.h(Item_1["default"], { data: __assign(__assign({}, reducedTemplateData), _this.hydrateItem(item)), template: props.template.item, className: "as-result__item " + props.classNames.item, dictionary: props.dictionary }); }), hasInfiniteScrollNextPage ? (props.infiniteScrollButton ? "" : (preact_1.h("div", { id: "as-result__infinite_scroll_inspector", ref: this.endResultsBoxRef, style: "bottom: " + infiniteScrollMargin + "px; position: relative; width: 100%;" }))) : "")) : ""), hasInfiniteScrollNextPage ? (props.infiniteScrollButton ? (preact_1.h("div", { onClick: function (e) { that.loadNextPage(); } }, preact_1.h(Template_1["default"], { template: props.template.next_page_button, data: { page: this.state.page + 1 } }))) : "") : "", (subResults.length > 0) ? preact_1.h("div", { className: "as-result__alternativeList" }, subResults.map(function (subResult) { return preact_1.h("div", { className: "as-result__alternative" }, preact_1.h("div", { className: "as-result__alternative_query" }, preact_1.h("span", { onClick: function (e) { e.stopPropagation(); e.preventDefault(); that.handleAlternativeClick(subResult.metadata.query_text); } }, preact_1.h(Template_1["default"], { template: props.template.alternative_title, data: { word: subResult.metadata.query_text_html } })), preact_1.h("a", { onClick: function (e) { e.stopPropagation(); e.preventDefault(); that.handleAlternativeClick(subResult.metadata.query_text); } }, preact_1.h(Template_1["default"], { template: props.template.alternative_all_results, data: { num: subResult.getTotalHits() }, dictionary: props.dictionary }))), preact_1.h("div", { className: "as-result__alternative_items" }, subResult.items.map(function (item) { return preact_1.h(Item_1["default"], { data: __assign(__assign({}, reducedTemplateData), _this.hydrateItem(item)), template: props.template.item, className: "as-result__alternative_item " + props.classNames.item, dictionary: _this.props.dictionary }); }))); })) : ((items.length === 0) ? preact_1.h(Template_1["default"], { template: props.template.noResults, data: { query: currentQuery.getQueryText() }, className: "as-result__noresults " + props.classNames.noResults, dictionary: props.dictionary }) : ""))); }; /** * @param item */ ResultComponent.prototype.hydrateItem = function (item) { var props = this.props; var environmentId = props.environmentId; var config = Container_1["default"].get(Constants_1.APISEARCH_CONFIG + "__" + environmentId); var apisearchUI = Container_1["default"].get(Constants_1.APISEARCH_UI + "__" + environmentId); var apisearchReference = apisearchUI.reference; var appId = config.app_id; var appUUID = item.getAppUUID(); if (typeof appUUID === "object") { appId = appUUID.composedUUID(); } var indexId = config.index_id; var indexUUID = item.getIndexUUID(); if (typeof indexUUID === "object") { indexId = indexUUID.composedUUID(); } var itemId = item.getUUID().composedUUID(); var mainFields = {}; Object.assign(mainFields, item.getMetadata(), item.getIndexedMetadata()); var fieldsConciliation = {}; Object.keys(props.fieldsConciliation).map(function (field, index) { var _a; fieldsConciliation[field] = (_a = mainFields[props.fieldsConciliation[field]]) !== null && _a !== void 0 ? _a : undefined; }); Object.assign(mainFields, fieldsConciliation); item.fields = mainFields; var queryText = ""; if (this.props.store.getCurrentQuery()) { queryText = this.props.store.getCurrentQuery().getQueryText(); } return __assign(__assign({}, props.formatData(item)), { key: "item_" + itemId, uuid_composed: itemId, click: apisearchReference + '.click("' + appId + '", "' + indexId + '", "' + itemId + '");', add_to_cart: apisearchReference + '.interact("add_cart", "' + appId + '", "' + indexId + '", "' + itemId + '");', query_text: queryText, highlights_enabled: this.props.highlightsEnabled, striptags: function () { return function (val, render) { return render(val).replace(/(<([^>]+)>)/ig, ""); }; } }); }; return ResultComponent; }(preact_1.Component)); ResultComponent.defaultProps = { fields: [], itemsPerPage: 10, highlightsEnabled: false, promote: [], exclude: [], filter: function (query) { return null; }, classNames: { container: "", itemsList: "", item: "", noResults: "", placeholder: "" }, template: { itemsList: defaultTemplates_1.defaultItemsListTemplate, item: defaultTemplates_1.defaultItemTemplate, noResults: defaultTemplates_1.defaultNoResultsItemTemplate, placeholder: null, alternative_title: defaultTemplates_1.defaultAlternativeTitleTemplate, alternative_all_results: defaultTemplates_1.defaultAlternativeAllResultsTemplate, next_page_button: defaultTemplates_1.defaultNextPageButtonTemplate }, formatData: function (data) { return data; }, fadeInSelector: "", fieldsConciliation: {} }; exports["default"] = ResultComponent;