2025-01-09 18:36:24 +02:00
import type { AttributeType } from "../entities/fattribute.js" ;
2018-11-13 10:25:59 +01:00
import server from "./server.js" ;
2024-12-19 20:44:21 +02:00
interface InitOptions {
$el : JQuery < HTMLElement > ;
2024-12-22 16:22:10 +02:00
attributeType? : AttributeType | ( ( ) = > AttributeType ) ;
2024-12-19 20:44:21 +02:00
open : boolean ;
2024-12-22 16:22:10 +02:00
nameCallback ? : ( ) = > string ;
2024-12-19 20:44:21 +02:00
}
2018-11-13 10:25:59 +01:00
/**
* @param $el - element on which to init autocomplete
2018-11-13 10:42:55 +01:00
* @param attributeType - "relation" or "label" or callback providing one of those values as a type of autocompleted attributes
2018-11-13 10:25:59 +01:00
* @param open - should the autocomplete be opened after init?
*/
2024-12-19 20:44:21 +02:00
function initAttributeNameAutocomplete ( { $el , attributeType , open } : InitOptions ) {
2018-11-13 10:25:59 +01:00
if ( ! $el . hasClass ( "aa-input" ) ) {
2025-01-09 18:07:02 +02:00
$el . autocomplete (
{
appendTo : document.querySelector ( "body" ) ,
hint : false ,
openOnFocus : true ,
minLength : 0 ,
tabAutocomplete : false
} ,
[
{
displayKey : "name" ,
// disabling cache is important here because otherwise cache can stay intact when switching between attribute type which will lead to autocomplete displaying attribute names for incorrect attribute type
cache : false ,
source : async ( term , cb ) = > {
const type = typeof attributeType === "function" ? attributeType ( ) : attributeType ;
const names = await server . get < string [ ] > ( ` attribute-names/?type= ${ type } &query= ${ encodeURIComponent ( term ) } ` ) ;
const result = names . map ( ( name ) = > ( { name } ) ) ;
cb ( result ) ;
}
}
]
) ;
$el . on ( "autocomplete:opened" , ( ) = > {
2020-08-11 22:52:17 +02:00
if ( $el . attr ( "readonly" ) ) {
2025-01-09 18:07:02 +02:00
$el . autocomplete ( "close" ) ;
2020-08-11 22:52:17 +02:00
}
} ) ;
2018-11-13 10:25:59 +01:00
}
if ( open ) {
$el . autocomplete ( "open" ) ;
}
}
2024-12-19 20:44:21 +02:00
async function initLabelValueAutocomplete ( { $el , open , nameCallback } : InitOptions ) {
2021-02-13 12:11:58 +01:00
if ( $el . hasClass ( "aa-input" ) ) {
2023-06-23 00:26:47 +08:00
// we reinit every time because autocomplete seems to have a bug where it retains state from last
// open even though the value was reset
2025-01-09 18:07:02 +02:00
$el . autocomplete ( "destroy" ) ;
2021-02-13 12:11:58 +01:00
}
2018-11-13 10:25:59 +01:00
2024-12-22 16:22:10 +02:00
let attributeName = "" ;
if ( nameCallback ) {
attributeName = nameCallback ( ) ;
}
2018-11-13 10:25:59 +01:00
2021-02-13 12:11:58 +01:00
if ( attributeName . trim ( ) === "" ) {
return ;
}
2018-11-13 10:25:59 +01:00
2025-01-09 18:07:02 +02:00
const attributeValues = ( await server . get < string [ ] > ( ` attribute-values/ ${ encodeURIComponent ( attributeName ) } ` ) ) . map ( ( attribute ) = > ( { value : attribute } ) ) ;
2018-11-13 10:25:59 +01:00
2021-02-13 12:11:58 +01:00
if ( attributeValues . length === 0 ) {
return ;
}
2018-11-13 10:25:59 +01:00
2025-01-09 18:07:02 +02:00
$el . autocomplete (
{
appendTo : document.querySelector ( "body" ) ,
hint : false ,
openOnFocus : false , // handled manually
minLength : 0 ,
tabAutocomplete : false
} ,
[
{
displayKey : "value" ,
cache : false ,
source : async function ( term , cb ) {
term = term . toLowerCase ( ) ;
const filtered = attributeValues . filter ( ( attr ) = > attr . value . toLowerCase ( ) . includes ( term ) ) ;
cb ( filtered ) ;
}
}
]
) ;
2021-02-13 12:11:58 +01:00
2025-01-09 18:07:02 +02:00
$el . on ( "autocomplete:opened" , ( ) = > {
2021-02-13 12:11:58 +01:00
if ( $el . attr ( "readonly" ) ) {
2025-01-09 18:07:02 +02:00
$el . autocomplete ( "close" ) ;
2021-02-13 12:11:58 +01:00
}
} ) ;
2018-11-13 10:25:59 +01:00
if ( open ) {
$el . autocomplete ( "open" ) ;
}
}
export default {
initAttributeNameAutocomplete ,
initLabelValueAutocomplete
2025-01-09 18:07:02 +02:00
} ;