diff --git a/Build/Sources/TypeScript/backend/live-search/element/result/item/item-container.ts b/Build/Sources/TypeScript/backend/live-search/element/result/item/item-container.ts index b5165b0821a55d58d279dd8363793c03e4ba0d52..262af16deca2db1d4f54f8af7607738c039d0f4a 100644 --- a/Build/Sources/TypeScript/backend/live-search/element/result/item/item-container.ts +++ b/Build/Sources/TypeScript/backend/live-search/element/result/item/item-container.ts @@ -11,10 +11,13 @@ * The TYPO3 project - inspiring people to share! */ -import {customElement, property} from 'lit/decorators'; +import '@typo3/backend/element/spinner-element'; +import LiveSearchConfigurator from '@typo3/backend/live-search/live-search-configurator'; import {css, html, LitElement, TemplateResult} from 'lit'; -import './item'; +import {customElement, property} from 'lit/decorators'; +import {until} from 'lit/directives/until'; import '../../provider/default-result-item'; +import './item'; import {Item, ResultItemActionInterface, ResultItemInterface} from './item'; type GroupedResultItems = { [key: string ]: ResultItemInterface[] }; @@ -24,7 +27,6 @@ export const componentName = 'typo3-backend-live-search-result-item-container'; @customElement(componentName) export class ItemContainer extends LitElement { @property({type: Object, attribute: false}) results: ResultItemInterface[]|null = null; - @property({type: Object, attribute: false}) renderers: { [key: string]: Function } = {}; public connectedCallback() { super.connectedCallback(); @@ -60,17 +62,22 @@ export class ItemContainer extends LitElement { const items = []; for (let [type, results] of Object.entries(groupedResults)) { items.push(html`<h6 class="livesearch-result-item-group-label">${type}</h6>`); - items.push(...results.map((result: ResultItemInterface) => this.renderResultItem(result))); + items.push(...results.map((result: ResultItemInterface) => html`${until( + this.renderResultItem(result), + html`<typo3-backend-spinner></typo3-backend-spinner>` + )}`)); } return html`${items}` } - private renderResultItem(resultItem: ResultItemInterface): TemplateResult { + private async renderResultItem(resultItem: ResultItemInterface): Promise<TemplateResult> { + const renderers = LiveSearchConfigurator.getRenderers(); let innerResultItemComponent; - if (typeof this.renderers[resultItem.provider] === 'function') { - innerResultItemComponent = this.renderers[resultItem.provider](resultItem); + if (renderers[resultItem.provider] !== undefined) { + await import(renderers[resultItem.provider].module); + innerResultItemComponent = renderers[resultItem.provider].callback(resultItem); } else { innerResultItemComponent = html`<typo3-backend-live-search-result-item-default title="${resultItem.typeLabel}: ${resultItem.itemTitle}" diff --git a/Build/Sources/TypeScript/backend/live-search/element/result/result-container.ts b/Build/Sources/TypeScript/backend/live-search/element/result/result-container.ts index 32917de52afcf7dbff15bb3a13e391a6ca5feac4..4c056bfc0962f7c1b3b57c3556a802c107e94855 100644 --- a/Build/Sources/TypeScript/backend/live-search/element/result/result-container.ts +++ b/Build/Sources/TypeScript/backend/live-search/element/result/result-container.ts @@ -11,6 +11,7 @@ * The TYPO3 project - inspiring people to share! */ +import LiveSearchConfigurator from '@typo3/backend/live-search/live-search-configurator'; import {customElement, property, query} from 'lit/decorators'; import {html, LitElement, TemplateResult} from 'lit'; import {lll} from '@typo3/core/lit-helper'; @@ -24,20 +25,20 @@ export const componentName = 'typo3-backend-live-search-result-container'; @customElement(componentName) export class ResultContainer extends LitElement { - @property({type: Object, attribute: false}) results: ResultItemInterface[]|null = null; + @property({type: Object}) results: ResultItemInterface[]|null = null; @property({type: Boolean, attribute: false}) loading: boolean = false; - @property({type: Object, attribute: false}) renderers: { [key: string]: Function } = {}; - @property({type: Object, attribute: false}) invokeHandlers: { [key: string]: Function } = {}; @query('typo3-backend-live-search-result-item-container') itemContainer: ItemContainer; @query('typo3-backend-live-search-result-item-detail-container') resultDetailContainer: ResultDetailContainer; public connectedCallback() { super.connectedCallback(); + this.addEventListener('livesearch:request-actions', (e: CustomEvent): void => { this.resultDetailContainer.resultItem = e.detail.resultItem; }) this.addEventListener('livesearch:invoke-action', (e: CustomEvent): void => { + const invokeHandlers = LiveSearchConfigurator.getInvokeHandlers(); const resultItem = e.detail.resultItem; const action = e.detail.action; @@ -45,8 +46,8 @@ export class ResultContainer extends LitElement { return; } - if (typeof this.invokeHandlers[resultItem.provider + '_' + action.identifier] === 'function') { - this.invokeHandlers[resultItem.provider + '_' + action.identifier](resultItem, action); + if (typeof invokeHandlers[resultItem.provider + '_' + action.identifier] === 'function') { + invokeHandlers[resultItem.provider + '_' + action.identifier](resultItem, action); } else { // Default handler to open the URL TYPO3.Backend.ContentContainer.setUrl(action.url); @@ -76,7 +77,7 @@ export class ResultContainer extends LitElement { } return html` - <typo3-backend-live-search-result-item-container .results="${this.results}" .renderers="${this.renderers}"></typo3-backend-live-search-result-item-container> + <typo3-backend-live-search-result-item-container .results="${this.results}"></typo3-backend-live-search-result-item-container> <typo3-backend-live-search-result-item-detail-container></typo3-backend-live-search-result-item-detail-container> `; } diff --git a/Build/Sources/TypeScript/backend/live-search/live-search-configurator.ts b/Build/Sources/TypeScript/backend/live-search/live-search-configurator.ts new file mode 100644 index 0000000000000000000000000000000000000000..2d0528e7496903602364f7e7fb3411b2646aea8c --- /dev/null +++ b/Build/Sources/TypeScript/backend/live-search/live-search-configurator.ts @@ -0,0 +1,48 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ + +type RendererDeclaration = { module: string, callback: Function }; +type RendererDeclarationCollection = { [key: string]: RendererDeclaration }; +type FunctionObjects = { [key: string]: Function }; + +class LiveSearchConfigurator { + private renderers: RendererDeclarationCollection = {}; + private invokeHandlers: FunctionObjects = {}; + + public getRenderers(): RendererDeclarationCollection { + return this.renderers; + } + + public addRenderer(type: string, module: string, callback: Function): void { + this.renderers[type] = { module, callback }; + } + + public getInvokeHandlers(): FunctionObjects { + return this.invokeHandlers; + } + + public addInvokeHandler(type: string, action: string, callback: Function): void { + this.invokeHandlers[type + '_' + action] = callback; + } +} + +let configuratorObject: LiveSearchConfigurator; +if (!top.TYPO3.LiveSearchConfigurator) { + configuratorObject = new LiveSearchConfigurator(); + top.TYPO3.LiveSearchConfigurator = configuratorObject; +} else { + configuratorObject = top.TYPO3.LiveSearchConfigurator; +} + +export default configuratorObject; + diff --git a/Build/Sources/TypeScript/backend/live-search/result-types/default-result-type.ts b/Build/Sources/TypeScript/backend/live-search/result-types/default-result-type.ts index 1b199f1d40da9049803fec9bb9102966b4acd7ad..75df36fee8b560e757b5ef747d3deaf481feed15 100644 --- a/Build/Sources/TypeScript/backend/live-search/result-types/default-result-type.ts +++ b/Build/Sources/TypeScript/backend/live-search/result-types/default-result-type.ts @@ -1,12 +1,12 @@ -import {ResultItemActionInterface, ResultItemInterface} from '@typo3/backend/live-search/element/result/item/item'; -import LiveSearch from '@typo3/backend/toolbar/live-search'; +import LiveSearchConfigurator from '@typo3/backend/live-search/live-search-configurator'; +import {ResultItemInterface} from '@typo3/backend/live-search/element/result/item/item'; import '@typo3/backend/live-search/element/provider/page-provider-result-item'; import AjaxRequest from '@typo3/core/ajax/ajax-request'; import {AjaxResponse} from '@typo3/core/ajax/ajax-response'; import Notification from '@typo3/backend/notification'; export function registerType(type: string) { - LiveSearch.addInvokeHandler(type, 'switch_backend_user', (resultItem: ResultItemInterface): void => { + LiveSearchConfigurator.addInvokeHandler(type, 'switch_backend_user', (resultItem: ResultItemInterface): void => { (new AjaxRequest(TYPO3.settings.ajaxUrls.switch_user)).post({ targetUser: resultItem.extraData.uid, }).then(async (response: AjaxResponse): Promise<any> => { diff --git a/Build/Sources/TypeScript/backend/live-search/result-types/page-result-type.ts b/Build/Sources/TypeScript/backend/live-search/result-types/page-result-type.ts index e683a2944d6c85937182a29523007e4c1034fa8a..ff6f6db6416e717ebbd056cccdc63f2eb8836757 100644 --- a/Build/Sources/TypeScript/backend/live-search/result-types/page-result-type.ts +++ b/Build/Sources/TypeScript/backend/live-search/result-types/page-result-type.ts @@ -1,20 +1,23 @@ +import LiveSearchConfigurator from '@typo3/backend/live-search/live-search-configurator'; import {html, TemplateResult} from 'lit'; import {ResultItemActionInterface, ResultItemInterface} from '@typo3/backend/live-search/element/result/item/item'; -import LiveSearch from '@typo3/backend/toolbar/live-search'; -import '@typo3/backend/live-search/element/provider/page-provider-result-item'; import windowManager from '@typo3/backend/window-manager'; export function registerRenderer(type: string) { - LiveSearch.addRenderer(type, (attributes: ResultItemInterface): TemplateResult => { - return html`<typo3-backend-live-search-result-item-page-provider - .icon="${attributes.icon}" - .itemTitle="${attributes.itemTitle}" - .typeLabel="${attributes.typeLabel}" - .extraData="${attributes.extraData}"> - </typo3-backend-live-search-result-item-page-provider>`; - }); + LiveSearchConfigurator.addRenderer( + type, + '@typo3/backend/live-search/element/provider/page-provider-result-item.js', + (attributes: ResultItemInterface): TemplateResult => { + return html`<typo3-backend-live-search-result-item-page-provider + .icon="${attributes.icon}" + .itemTitle="${attributes.itemTitle}" + .typeLabel="${attributes.typeLabel}" + .extraData="${attributes.extraData}"> + </typo3-backend-live-search-result-item-page-provider>`; + } + ); - LiveSearch.addInvokeHandler(type, 'preview_page', (resultItem: ResultItemInterface, action: ResultItemActionInterface): void => { + LiveSearchConfigurator.addInvokeHandler(type, 'preview_page', (resultItem: ResultItemInterface, action: ResultItemActionInterface): void => { windowManager.localOpen(action.url, true); }); } diff --git a/Build/Sources/TypeScript/backend/toolbar/live-search.ts b/Build/Sources/TypeScript/backend/toolbar/live-search.ts index 09f17727ef7a140e493e12ce9ae7d523e031d17e..be8d7a75609437247e1ee08d91113a466d1e7644 100644 --- a/Build/Sources/TypeScript/backend/toolbar/live-search.ts +++ b/Build/Sources/TypeScript/backend/toolbar/live-search.ts @@ -45,8 +45,6 @@ interface SearchOption { * @exports @typo3/backend/toolbar/live-search */ class LiveSearch { - private renderers: { [key: string]: Function } = {}; - private invokeHandlers: { [key: string]: Function } = {}; private searchTerm: string = ''; private searchOptions: { [key: string]: string[] } = {}; @@ -56,14 +54,6 @@ class LiveSearch { }); } - public addRenderer(type: string, callback: Function): void { - this.renderers[type] = callback; - } - - public addInvokeHandler(type: string, action: string, callback: Function): void { - this.invokeHandlers[type + '_' + action] = callback; - } - private registerEvents(): void { new RegularEvent('click', (): void => { this.openSearchModal(); @@ -185,8 +175,6 @@ class LiveSearch { searchAllButton.parentElement.hidden = searchResults === null || searchResults.length === 0; const searchResultContainer: ResultContainer = document.querySelector('typo3-backend-live-search-result-container') as ResultContainer; - searchResultContainer.renderers = this.renderers; - searchResultContainer.invokeHandlers = this.invokeHandlers; searchResultContainer.results = searchResults; searchResultContainer.loading = false; diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/item/item-container.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/item/item-container.js index 2930aec1270a11a35cccd6286c8c057117ab3e59..e9604e19f7579e30afdd378347f83bf5c4f878e3 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/item/item-container.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/item/item-container.js @@ -10,9 +10,9 @@ * * The TYPO3 project - inspiring people to share! */ -var __decorate=function(e,t,r,n){var l,s=arguments.length,i=s<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)i=Reflect.decorate(e,t,r,n);else for(var o=e.length-1;o>=0;o--)(l=e[o])&&(i=(s<3?l(i):s>3?l(t,r,i):l(t,r))||i);return s>3&&i&&Object.defineProperty(t,r,i),i};import{customElement,property}from"lit/decorators.js";import{css,html,LitElement}from"lit";import"@typo3/backend/live-search/element/result/item/item.js";import"@typo3/backend/live-search/element/provider/default-result-item.js";export const componentName="typo3-backend-live-search-result-item-container";let ItemContainer=class extends LitElement{constructor(){super(...arguments),this.results=null,this.renderers={}}connectedCallback(){super.connectedCallback(),this.addEventListener("scroll",this.onScroll)}disconnectedCallback(){this.removeEventListener("scroll",this.onScroll),super.disconnectedCallback()}createRenderRoot(){return this}render(){const e={};return this.results.forEach((t=>{t.typeLabel in e?e[t.typeLabel].push(t):e[t.typeLabel]=[t]})),html`<typo3-backend-live-search-result-list> +var __decorate=function(e,t,r,n){var l,i=arguments.length,o=i<3?t:null===n?n=Object.getOwnPropertyDescriptor(t,r):n;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,r,n);else for(var s=e.length-1;s>=0;s--)(l=e[s])&&(o=(i<3?l(o):i>3?l(t,r,o):l(t,r))||o);return i>3&&o&&Object.defineProperty(t,r,o),o};import"@typo3/backend/element/spinner-element.js";import LiveSearchConfigurator from"@typo3/backend/live-search/live-search-configurator.js";import{css,html,LitElement}from"lit";import{customElement,property}from"lit/decorators.js";import{until}from"lit/directives/until.js";import"@typo3/backend/live-search/element/provider/default-result-item.js";import"@typo3/backend/live-search/element/result/item/item.js";export const componentName="typo3-backend-live-search-result-item-container";let ItemContainer=class extends LitElement{constructor(){super(...arguments),this.results=null}connectedCallback(){super.connectedCallback(),this.addEventListener("scroll",this.onScroll)}disconnectedCallback(){this.removeEventListener("scroll",this.onScroll),super.disconnectedCallback()}createRenderRoot(){return this}render(){const e={};return this.results.forEach((t=>{t.typeLabel in e?e[t.typeLabel].push(t):e[t.typeLabel]=[t]})),html`<typo3-backend-live-search-result-list> ${this.renderGroupedResults(e)} - </typo3-backend-live-search-result-list>`}renderGroupedResults(e){const t=[];for(let[r,n]of Object.entries(e))t.push(html`<h6 class="livesearch-result-item-group-label">${r}</h6>`),t.push(...n.map((e=>this.renderResultItem(e))));return html`${t}`}renderResultItem(e){let t;return t="function"==typeof this.renderers[e.provider]?this.renderers[e.provider](e):html`<typo3-backend-live-search-result-item-default + </typo3-backend-live-search-result-list>`}renderGroupedResults(e){const t=[];for(let[r,n]of Object.entries(e))t.push(html`<h6 class="livesearch-result-item-group-label">${r}</h6>`),t.push(...n.map((e=>html`${until(this.renderResultItem(e),html`<typo3-backend-spinner></typo3-backend-spinner>`)}`)));return html`${t}`}async renderResultItem(e){const t=LiveSearchConfigurator.getRenderers();let r;return void 0!==t[e.provider]?(await import(t[e.provider].module),r=t[e.provider].callback(e)):r=html`<typo3-backend-live-search-result-item-default title="${e.typeLabel}: ${e.itemTitle}" .icon="${e.icon}" .itemTitle="${e.itemTitle}" @@ -22,8 +22,8 @@ var __decorate=function(e,t,r,n){var l,s=arguments.length,i=s<3?t:null===n?n=Obj .resultItem="${e}" @click="${()=>this.invokeAction(e,e.actions[0])}" @focus="${()=>this.requestActions(e)}"> - ${t} - </typo3-backend-live-search-result-item>`}requestActions(e){this.parentElement.dispatchEvent(new CustomEvent("livesearch:request-actions",{detail:{resultItem:e}}))}invokeAction(e,t){this.parentElement.dispatchEvent(new CustomEvent("livesearch:invoke-action",{detail:{resultItem:e,action:t}}))}onScroll(e){this.querySelectorAll(".livesearch-result-item-group-label").forEach((t=>{t.classList.toggle("sticky",t.offsetTop<=e.target.scrollTop)}))}};__decorate([property({type:Object,attribute:!1})],ItemContainer.prototype,"results",void 0),__decorate([property({type:Object,attribute:!1})],ItemContainer.prototype,"renderers",void 0),ItemContainer=__decorate([customElement(componentName)],ItemContainer);export{ItemContainer};let ResultList=class extends LitElement{connectedCallback(){this.parentContainer=this.closest("typo3-backend-live-search-result-container"),this.resultItemDetailContainer=this.parentContainer.querySelector("typo3-backend-live-search-result-item-detail-container"),super.connectedCallback(),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("keyup",this.handleKeyUp)}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("keyup",this.handleKeyUp),super.disconnectedCallback()}render(){return html`<slot></slot>`}handleKeyDown(e){if(!["ArrowDown","ArrowUp","ArrowRight"].includes(e.key))return;const t="typo3-backend-live-search-result-item";if(document.activeElement.tagName.toLowerCase()!==t)return;let r;if(e.preventDefault(),"ArrowDown"===e.key){let e=document.activeElement.nextElementSibling;for(;null!==e&&e.tagName.toLowerCase()!==t;)e=e.nextElementSibling;r=e}else if("ArrowUp"===e.key){let e=document.activeElement.previousElementSibling;for(;null!==e&&e.tagName.toLowerCase()!==t;)e=e.previousElementSibling;r=e,null===r&&(r=document.querySelector("typo3-backend-live-search").querySelector('input[type="search"]'))}else"ArrowRight"===e.key&&(r=this.resultItemDetailContainer.querySelector("typo3-backend-live-search-result-item-action"));null!==r&&r.focus()}handleKeyUp(e){if(!["Enter"," "].includes(e.key))return;e.preventDefault();const t=e.target.resultItem;this.invokeAction(t)}invokeAction(e){this.parentContainer.dispatchEvent(new CustomEvent("livesearch:invoke-action",{detail:{resultItem:e,action:e.actions[0]}}))}};ResultList.styles=css` + ${r} + </typo3-backend-live-search-result-item>`}requestActions(e){this.parentElement.dispatchEvent(new CustomEvent("livesearch:request-actions",{detail:{resultItem:e}}))}invokeAction(e,t){this.parentElement.dispatchEvent(new CustomEvent("livesearch:invoke-action",{detail:{resultItem:e,action:t}}))}onScroll(e){this.querySelectorAll(".livesearch-result-item-group-label").forEach((t=>{t.classList.toggle("sticky",t.offsetTop<=e.target.scrollTop)}))}};__decorate([property({type:Object,attribute:!1})],ItemContainer.prototype,"results",void 0),ItemContainer=__decorate([customElement(componentName)],ItemContainer);export{ItemContainer};let ResultList=class extends LitElement{connectedCallback(){this.parentContainer=this.closest("typo3-backend-live-search-result-container"),this.resultItemDetailContainer=this.parentContainer.querySelector("typo3-backend-live-search-result-item-detail-container"),super.connectedCallback(),this.addEventListener("keydown",this.handleKeyDown),this.addEventListener("keyup",this.handleKeyUp)}disconnectedCallback(){this.removeEventListener("keydown",this.handleKeyDown),this.removeEventListener("keyup",this.handleKeyUp),super.disconnectedCallback()}render(){return html`<slot></slot>`}handleKeyDown(e){if(!["ArrowDown","ArrowUp","ArrowRight"].includes(e.key))return;const t="typo3-backend-live-search-result-item";if(document.activeElement.tagName.toLowerCase()!==t)return;let r;if(e.preventDefault(),"ArrowDown"===e.key){let e=document.activeElement.nextElementSibling;for(;null!==e&&e.tagName.toLowerCase()!==t;)e=e.nextElementSibling;r=e}else if("ArrowUp"===e.key){let e=document.activeElement.previousElementSibling;for(;null!==e&&e.tagName.toLowerCase()!==t;)e=e.previousElementSibling;r=e,null===r&&(r=document.querySelector("typo3-backend-live-search").querySelector('input[type="search"]'))}else"ArrowRight"===e.key&&(r=this.resultItemDetailContainer.querySelector("typo3-backend-live-search-result-item-action"));null!==r&&r.focus()}handleKeyUp(e){if(!["Enter"," "].includes(e.key))return;e.preventDefault();const t=e.target.resultItem;this.invokeAction(t)}invokeAction(e){this.parentContainer.dispatchEvent(new CustomEvent("livesearch:invoke-action",{detail:{resultItem:e,action:e.actions[0]}}))}};ResultList.styles=css` :host { display: block; } diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/result-container.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/result-container.js index 4ac64709742c498c47fd4838778b13318af1c05a..1745a8bbdd0e7ea8215fd0fec90825490b0a5055 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/result-container.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/element/result/result-container.js @@ -10,7 +10,7 @@ * * The TYPO3 project - inspiring people to share! */ -var __decorate=function(e,t,r,i){var n,o=arguments.length,l=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,r,i);else for(var s=e.length-1;s>=0;s--)(n=e[s])&&(l=(o<3?n(l):o>3?n(t,r,l):n(t,r))||l);return o>3&&l&&Object.defineProperty(t,r,l),l};import{customElement,property,query}from"lit/decorators.js";import{html,LitElement}from"lit";import{lll}from"@typo3/core/lit-helper.js";import"@typo3/backend/live-search/element/result/item/item-container.js";import"@typo3/backend/live-search/element/result/result-detail-container.js";export const componentName="typo3-backend-live-search-result-container";let ResultContainer=class extends LitElement{constructor(){super(...arguments),this.results=null,this.loading=!1,this.renderers={},this.invokeHandlers={}}connectedCallback(){super.connectedCallback(),this.addEventListener("livesearch:request-actions",(e=>{this.resultDetailContainer.resultItem=e.detail.resultItem})),this.addEventListener("livesearch:invoke-action",(e=>{const t=e.detail.resultItem,r=e.detail.action;void 0!==r&&("function"==typeof this.invokeHandlers[t.provider+"_"+r.identifier]?this.invokeHandlers[t.provider+"_"+r.identifier](t,r):TYPO3.Backend.ContentContainer.setUrl(r.url),this.dispatchEvent(new CustomEvent("live-search:item-chosen",{detail:{resultItem:t}})))}))}createRenderRoot(){return this}render(){return this.loading?html`<div class="d-flex flex-fill justify-content-center mt-2"><typo3-backend-spinner size="large"></typo3-backend-spinner></div>`:null===this.results?html``:0===this.results.length?html`<div class="alert alert-info">${lll("liveSearch_listEmptyText")}</div>`:html` - <typo3-backend-live-search-result-item-container .results="${this.results}" .renderers="${this.renderers}"></typo3-backend-live-search-result-item-container> +var __decorate=function(e,t,r,i){var n,o=arguments.length,l=o<3?t:null===i?i=Object.getOwnPropertyDescriptor(t,r):i;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)l=Reflect.decorate(e,t,r,i);else for(var a=e.length-1;a>=0;a--)(n=e[a])&&(l=(o<3?n(l):o>3?n(t,r,l):n(t,r))||l);return o>3&&l&&Object.defineProperty(t,r,l),l};import LiveSearchConfigurator from"@typo3/backend/live-search/live-search-configurator.js";import{customElement,property,query}from"lit/decorators.js";import{html,LitElement}from"lit";import{lll}from"@typo3/core/lit-helper.js";import"@typo3/backend/live-search/element/result/item/item-container.js";import"@typo3/backend/live-search/element/result/result-detail-container.js";export const componentName="typo3-backend-live-search-result-container";let ResultContainer=class extends LitElement{constructor(){super(...arguments),this.results=null,this.loading=!1}connectedCallback(){super.connectedCallback(),this.addEventListener("livesearch:request-actions",(e=>{this.resultDetailContainer.resultItem=e.detail.resultItem})),this.addEventListener("livesearch:invoke-action",(e=>{const t=LiveSearchConfigurator.getInvokeHandlers(),r=e.detail.resultItem,i=e.detail.action;void 0!==i&&("function"==typeof t[r.provider+"_"+i.identifier]?t[r.provider+"_"+i.identifier](r,i):TYPO3.Backend.ContentContainer.setUrl(i.url),this.dispatchEvent(new CustomEvent("live-search:item-chosen",{detail:{resultItem:r}})))}))}createRenderRoot(){return this}render(){return this.loading?html`<div class="d-flex flex-fill justify-content-center mt-2"><typo3-backend-spinner size="large"></typo3-backend-spinner></div>`:null===this.results?html``:0===this.results.length?html`<div class="alert alert-info">${lll("liveSearch_listEmptyText")}</div>`:html` + <typo3-backend-live-search-result-item-container .results="${this.results}"></typo3-backend-live-search-result-item-container> <typo3-backend-live-search-result-item-detail-container></typo3-backend-live-search-result-item-detail-container> - `}};__decorate([property({type:Object,attribute:!1})],ResultContainer.prototype,"results",void 0),__decorate([property({type:Boolean,attribute:!1})],ResultContainer.prototype,"loading",void 0),__decorate([property({type:Object,attribute:!1})],ResultContainer.prototype,"renderers",void 0),__decorate([property({type:Object,attribute:!1})],ResultContainer.prototype,"invokeHandlers",void 0),__decorate([query("typo3-backend-live-search-result-item-container")],ResultContainer.prototype,"itemContainer",void 0),__decorate([query("typo3-backend-live-search-result-item-detail-container")],ResultContainer.prototype,"resultDetailContainer",void 0),ResultContainer=__decorate([customElement(componentName)],ResultContainer);export{ResultContainer}; \ No newline at end of file + `}};__decorate([property({type:Object})],ResultContainer.prototype,"results",void 0),__decorate([property({type:Boolean,attribute:!1})],ResultContainer.prototype,"loading",void 0),__decorate([query("typo3-backend-live-search-result-item-container")],ResultContainer.prototype,"itemContainer",void 0),__decorate([query("typo3-backend-live-search-result-item-detail-container")],ResultContainer.prototype,"resultDetailContainer",void 0),ResultContainer=__decorate([customElement(componentName)],ResultContainer);export{ResultContainer}; \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/live-search-configurator.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/live-search-configurator.js new file mode 100644 index 0000000000000000000000000000000000000000..819701a552546afc0da8a52ea94ad7c3d0d2a10b --- /dev/null +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/live-search-configurator.js @@ -0,0 +1,13 @@ +/* + * This file is part of the TYPO3 CMS project. + * + * It is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License, either version 2 + * of the License, or any later version. + * + * For the full copyright and license information, please read the + * LICENSE.txt file that was distributed with this source code. + * + * The TYPO3 project - inspiring people to share! + */ +class LiveSearchConfigurator{constructor(){this.renderers={},this.invokeHandlers={}}getRenderers(){return this.renderers}addRenderer(r,e,t){this.renderers[r]={module:e,callback:t}}getInvokeHandlers(){return this.invokeHandlers}addInvokeHandler(r,e,t){this.invokeHandlers[r+"_"+e]=t}}let configuratorObject;top.TYPO3.LiveSearchConfigurator?configuratorObject=top.TYPO3.LiveSearchConfigurator:(configuratorObject=new LiveSearchConfigurator,top.TYPO3.LiveSearchConfigurator=configuratorObject);export default configuratorObject; \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/default-result-type.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/default-result-type.js index 3c87155d5f576760601e2bbdcb707cfdd6d0b7e6..ce04ea026cbfd22b441c31501c5f304713cf26a4 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/default-result-type.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/default-result-type.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import LiveSearch from"@typo3/backend/toolbar/live-search.js";import"@typo3/backend/live-search/element/provider/page-provider-result-item.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import Notification from"@typo3/backend/notification.js";export function registerType(e){LiveSearch.addInvokeHandler(e,"switch_backend_user",(e=>{new AjaxRequest(TYPO3.settings.ajaxUrls.switch_user).post({targetUser:e.extraData.uid}).then((async e=>{const t=await e.resolve();!0===t.success&&t.url?top.window.location.href=t.url:Notification.error("Switching to user went wrong.")}))}))} \ No newline at end of file +import LiveSearchConfigurator from"@typo3/backend/live-search/live-search-configurator.js";import"@typo3/backend/live-search/element/provider/page-provider-result-item.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import Notification from"@typo3/backend/notification.js";export function registerType(e){LiveSearchConfigurator.addInvokeHandler(e,"switch_backend_user",(e=>{new AjaxRequest(TYPO3.settings.ajaxUrls.switch_user).post({targetUser:e.extraData.uid}).then((async e=>{const r=await e.resolve();!0===r.success&&r.url?top.window.location.href=r.url:Notification.error("Switching to user went wrong.")}))}))} \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/page-result-type.js b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/page-result-type.js index 96ac8f52d9d02c278cbd2823e0ff8119f98fdd5a..224c042a5e54b2a5f9241b6f2b62d8d428e5a8f5 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/page-result-type.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/live-search/result-types/page-result-type.js @@ -10,9 +10,9 @@ * * The TYPO3 project - inspiring people to share! */ -import{html}from"lit";import LiveSearch from"@typo3/backend/toolbar/live-search.js";import"@typo3/backend/live-search/element/provider/page-provider-result-item.js";import windowManager from"@typo3/backend/window-manager.js";export function registerRenderer(e){LiveSearch.addRenderer(e,(e=>html`<typo3-backend-live-search-result-item-page-provider - .icon="${e.icon}" - .itemTitle="${e.itemTitle}" - .typeLabel="${e.typeLabel}" - .extraData="${e.extraData}"> - </typo3-backend-live-search-result-item-page-provider>`)),LiveSearch.addInvokeHandler(e,"preview_page",((e,r)=>{windowManager.localOpen(r.url,!0)}))} \ No newline at end of file +import LiveSearchConfigurator from"@typo3/backend/live-search/live-search-configurator.js";import{html}from"lit";import windowManager from"@typo3/backend/window-manager.js";export function registerRenderer(e){LiveSearchConfigurator.addRenderer(e,"@typo3/backend/live-search/element/provider/page-provider-result-item.js",(e=>html`<typo3-backend-live-search-result-item-page-provider + .icon="${e.icon}" + .itemTitle="${e.itemTitle}" + .typeLabel="${e.typeLabel}" + .extraData="${e.extraData}"> + </typo3-backend-live-search-result-item-page-provider>`)),LiveSearchConfigurator.addInvokeHandler(e,"preview_page",((e,r)=>{windowManager.localOpen(r.url,!0)}))} \ No newline at end of file diff --git a/typo3/sysext/backend/Resources/Public/JavaScript/toolbar/live-search.js b/typo3/sysext/backend/Resources/Public/JavaScript/toolbar/live-search.js index 7ba6305800fd5a56e7a359d93bc4b243f3ac3654..ede0cfc3e1b74901969c78b91685173949cf0649 100644 --- a/typo3/sysext/backend/Resources/Public/JavaScript/toolbar/live-search.js +++ b/typo3/sysext/backend/Resources/Public/JavaScript/toolbar/live-search.js @@ -10,4 +10,4 @@ * * The TYPO3 project - inspiring people to share! */ -import{lll}from"@typo3/core/lit-helper.js";import Modal from"@typo3/backend/modal.js";import"@typo3/backend/element/icon-element.js";import"@typo3/backend/input/clearable.js";import"@typo3/backend/live-search/element/search-option-item.js";import"@typo3/backend/live-search/element/show-all.js";import"@typo3/backend/live-search/live-search-shortcut.js";import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";import DebounceEvent from"@typo3/core/event/debounce-event.js";import{SeverityEnum}from"@typo3/backend/enum/severity.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import BrowserSession from"@typo3/backend/storage/browser-session.js";import{componentName as resultContainerComponentName}from"@typo3/backend/live-search/element/result/result-container.js";var Identifiers;!function(e){e.toolbarItem=".t3js-topbar-button-search",e.searchOptionDropdown=".t3js-search-provider-dropdown",e.searchOptionDropdownToggle=".t3js-search-provider-dropdown-toggle"}(Identifiers||(Identifiers={}));class LiveSearch{constructor(){this.renderers={},this.invokeHandlers={},this.searchTerm="",this.searchOptions={},this.search=async()=>{BrowserSession.set("livesearch-term",this.searchTerm);let e=null;if(""!==this.searchTerm){document.querySelector(resultContainerComponentName).loading=!0;const r=await new AjaxRequest(TYPO3.settings.ajaxUrls.livesearch).post({q:this.searchTerm,options:this.searchOptions});e=await r.raw().json()}this.updateSearchResults(e)},DocumentService.ready().then((()=>{this.registerEvents()}))}addRenderer(e,r){this.renderers[e]=r}addInvokeHandler(e,r,t){this.invokeHandlers[e+"_"+r]=t}registerEvents(){new RegularEvent("click",(()=>{this.openSearchModal()})).delegateTo(document,Identifiers.toolbarItem),new RegularEvent("typo3:live-search:trigger-open",(()=>{Modal.currentModal||this.openSearchModal()})).bindTo(document)}openSearchModal(){const e=Modal.advanced({type:Modal.types.ajax,content:TYPO3.settings.ajaxUrls.livesearch_form+"&q="+(BrowserSession.get("livesearch-term")??""),title:lll("labels.search"),severity:SeverityEnum.notice,size:Modal.sizes.medium});e.addEventListener("typo3-modal-shown",(()=>{this.searchTerm=BrowserSession.get("livesearch-term")??"";const r=Object.entries(BrowserSession.getByPrefix("livesearch-option-")).filter((e=>"1"===e[1])).map((e=>{const r=e[0].replace("livesearch-option-",""),[t,o]=r.split("-",2);return{key:t,value:o}}));this.composeSearchOptions(r);const t=e.querySelector('input[type="search"]');t.clearable({onClear:()=>{this.searchTerm="",this.search()}}),t.focus(),t.select();const o=document.querySelector("typo3-backend-live-search-result-container");new RegularEvent("live-search:item-chosen",(()=>{Modal.dismiss()})).bindTo(o),new RegularEvent("hide.bs.dropdown",(()=>{const r=Array.from(e.querySelectorAll(Identifiers.searchOptionDropdown+" typo3-backend-live-search-option-item")).filter((e=>e.active)).map((e=>({key:e.optionName,value:e.optionId})));this.composeSearchOptions(r),this.search()})).bindTo(e.querySelector(Identifiers.searchOptionDropdownToggle)),new DebounceEvent("input",(e=>{this.searchTerm=e.target.value,this.search()})).bindTo(t),new RegularEvent("keydown",this.handleKeyDown).bindTo(t),this.search()}))}composeSearchOptions(e){this.searchOptions={},e.forEach((e=>{void 0===this.searchOptions[e.key]&&(this.searchOptions[e.key]=[]),this.searchOptions[e.key].push(e.value)}))}handleKeyDown(e){if("ArrowDown"!==e.key)return;e.preventDefault();document.querySelector("typo3-backend-live-search").querySelector("typo3-backend-live-search-result-item")?.focus()}updateSearchResults(e){document.querySelector("typo3-backend-live-search-show-all").parentElement.hidden=null===e||0===e.length;const r=document.querySelector("typo3-backend-live-search-result-container");r.renderers=this.renderers,r.invokeHandlers=this.invokeHandlers,r.results=e,r.loading=!1}}export default top.TYPO3.LiveSearch??new LiveSearch; \ No newline at end of file +import{lll}from"@typo3/core/lit-helper.js";import Modal from"@typo3/backend/modal.js";import"@typo3/backend/element/icon-element.js";import"@typo3/backend/input/clearable.js";import"@typo3/backend/live-search/element/search-option-item.js";import"@typo3/backend/live-search/element/show-all.js";import"@typo3/backend/live-search/live-search-shortcut.js";import DocumentService from"@typo3/core/document-service.js";import RegularEvent from"@typo3/core/event/regular-event.js";import DebounceEvent from"@typo3/core/event/debounce-event.js";import{SeverityEnum}from"@typo3/backend/enum/severity.js";import AjaxRequest from"@typo3/core/ajax/ajax-request.js";import BrowserSession from"@typo3/backend/storage/browser-session.js";import{componentName as resultContainerComponentName}from"@typo3/backend/live-search/element/result/result-container.js";var Identifiers;!function(e){e.toolbarItem=".t3js-topbar-button-search",e.searchOptionDropdown=".t3js-search-provider-dropdown",e.searchOptionDropdownToggle=".t3js-search-provider-dropdown-toggle"}(Identifiers||(Identifiers={}));class LiveSearch{constructor(){this.searchTerm="",this.searchOptions={},this.search=async()=>{BrowserSession.set("livesearch-term",this.searchTerm);let e=null;if(""!==this.searchTerm){document.querySelector(resultContainerComponentName).loading=!0;const t=await new AjaxRequest(TYPO3.settings.ajaxUrls.livesearch).post({q:this.searchTerm,options:this.searchOptions});e=await t.raw().json()}this.updateSearchResults(e)},DocumentService.ready().then((()=>{this.registerEvents()}))}registerEvents(){new RegularEvent("click",(()=>{this.openSearchModal()})).delegateTo(document,Identifiers.toolbarItem),new RegularEvent("typo3:live-search:trigger-open",(()=>{Modal.currentModal||this.openSearchModal()})).bindTo(document)}openSearchModal(){const e=Modal.advanced({type:Modal.types.ajax,content:TYPO3.settings.ajaxUrls.livesearch_form+"&q="+(BrowserSession.get("livesearch-term")??""),title:lll("labels.search"),severity:SeverityEnum.notice,size:Modal.sizes.medium});e.addEventListener("typo3-modal-shown",(()=>{this.searchTerm=BrowserSession.get("livesearch-term")??"";const t=Object.entries(BrowserSession.getByPrefix("livesearch-option-")).filter((e=>"1"===e[1])).map((e=>{const t=e[0].replace("livesearch-option-",""),[r,o]=t.split("-",2);return{key:r,value:o}}));this.composeSearchOptions(t);const r=e.querySelector('input[type="search"]');r.clearable({onClear:()=>{this.searchTerm="",this.search()}}),r.focus(),r.select();const o=document.querySelector("typo3-backend-live-search-result-container");new RegularEvent("live-search:item-chosen",(()=>{Modal.dismiss()})).bindTo(o),new RegularEvent("hide.bs.dropdown",(()=>{const t=Array.from(e.querySelectorAll(Identifiers.searchOptionDropdown+" typo3-backend-live-search-option-item")).filter((e=>e.active)).map((e=>({key:e.optionName,value:e.optionId})));this.composeSearchOptions(t),this.search()})).bindTo(e.querySelector(Identifiers.searchOptionDropdownToggle)),new DebounceEvent("input",(e=>{this.searchTerm=e.target.value,this.search()})).bindTo(r),new RegularEvent("keydown",this.handleKeyDown).bindTo(r),this.search()}))}composeSearchOptions(e){this.searchOptions={},e.forEach((e=>{void 0===this.searchOptions[e.key]&&(this.searchOptions[e.key]=[]),this.searchOptions[e.key].push(e.value)}))}handleKeyDown(e){if("ArrowDown"!==e.key)return;e.preventDefault();document.querySelector("typo3-backend-live-search").querySelector("typo3-backend-live-search-result-item")?.focus()}updateSearchResults(e){document.querySelector("typo3-backend-live-search-show-all").parentElement.hidden=null===e||0===e.length;const t=document.querySelector("typo3-backend-live-search-result-container");t.results=e,t.loading=!1}}export default top.TYPO3.LiveSearch??new LiveSearch; \ No newline at end of file