mediawiki-skins-Citizen/resources/skins.citizen.search/htmlHelper.js

137 lines
3.7 KiB
JavaScript
Raw Normal View History

/**
* @typedef {Object} TypeaheadItemGroupData
* @property {string} id
* @property {string} label
* @property {TypeaheadItemData[]} items
*/
2023-08-12 18:11:06 +00:00
/**
* @typedef {Object} TypeaheadItemData
* @property {string} id
* @property {string} type
* @property {string} link
* @property {string} icon
* @property {string} thumbnail
* @property {string} title
* @property {string} label
* @property {string} desc
*/
function htmlHelper() {
2023-08-12 18:11:06 +00:00
return {
/**
* Return the HTML of an item group
*
* @param {TypeaheadItemGroupData} data
* @return {HTMLElement|void}
*/
getItemGroupElement: function ( data ) {
const itemGroup = document.createElement( 'li' );
itemGroup.classList.add( 'citizen-typeahead-item-group' );
itemGroup.setAttribute( 'data-group', `${ data.id }` );
itemGroup.setAttribute( 'role', 'presentation' );
if ( data.label ) {
const label = document.createElement( 'span' );
label.classList.add( 'citizen-typeahead-item-group-label' );
label.innerText = data.label;
itemGroup.append( label );
}
if ( data.items ) {
const list = document.createElement( 'ol' );
list.classList.add( 'citizen-typeahead-item-group-list' );
list.setAttribute( 'role', 'presentation' );
data.items.forEach( ( itemData, index ) => {
itemData.id = `citizen-typeahead-${ data.id }-${ index }`;
const item = this.getItemElement( itemData );
list.append( item );
} );
itemGroup.append( list );
}
return itemGroup;
},
2023-08-12 18:11:06 +00:00
/**
* Generate menu item HTML using the existing template
*
* @param {TypeaheadItemData} data
* @return {HTMLElement|void}
*/
getItemElement: function ( data ) {
2023-08-12 18:11:06 +00:00
// TODO: Should we use template element or Mustache or just Javascript?
const template = document.getElementById( 'citizen-typeahead-template' );
// Shouldn't happen but just to be safe
if ( !( template instanceof HTMLTemplateElement ) ) {
return;
}
const
fragment = template.content.cloneNode( true ),
item = fragment.querySelector( '.citizen-typeahead__item' );
this.updateItemElement( item, data );
2023-08-12 18:11:06 +00:00
return fragment;
},
/**
* Update typeahead item element
*
* @param {HTMLElement} item
* @param {TypeaheadItemData} data
*/
updateItemElement: function ( item, data ) {
2023-08-12 18:11:06 +00:00
if ( data.id ) {
item.setAttribute( 'id', data.id );
}
if ( data.type ) {
item.classList.add( `citizen-typeahead__item-${ data.type }` );
if ( data.type !== 'placeholder' ) {
item.setAttribute( 'role', 'option' );
}
2023-08-12 18:11:06 +00:00
}
2023-08-12 18:11:06 +00:00
if ( data.size ) {
item.classList.add( `citizen-typeahead__item-${ data.size }` );
2023-08-12 18:11:06 +00:00
}
if ( data.link ) {
item.querySelector( '.citizen-typeahead__content' ).setAttribute( 'href', data.link );
2023-08-12 18:11:06 +00:00
}
if ( data.icon || data.thumbnail ) {
const thumbnail = item.querySelector( '.citizen-typeahead__thumbnail' );
if ( data.thumbnail ) {
thumbnail.style.backgroundImage = `url('${ data.thumbnail }')`;
2023-08-12 18:11:06 +00:00
} else {
thumbnail.classList.add(
'citizen-typeahead__thumbnail',
'citizen-ui-icon',
`mw-ui-icon-wikimedia-${ data.icon }`
2023-08-12 18:11:06 +00:00
);
}
}
if ( data.title ) {
item.querySelector( '.citizen-typeahead__title' ).innerHTML = data.title;
2023-08-12 18:11:06 +00:00
}
if ( data.label ) {
item.querySelector( '.citizen-typeahead__label' ).innerHTML = data.label;
2023-08-12 18:11:06 +00:00
}
if ( data.desc ) {
item.querySelector( '.citizen-typeahead__description' ).innerHTML = data.desc;
2023-08-12 18:11:06 +00:00
}
},
/**
* Remove item group from the typeahead DOM
*
* @param {HTMLElement} typeaheadEl
* @param {string} id
*/
removeItemGroup: function ( typeaheadEl, id ) {
typeaheadEl.querySelector( `.citizen-typeahead-item-group[data-group="${ id }"]` )?.remove();
2023-08-12 18:11:06 +00:00
}
};
}
/** @module htmlHelper */
module.exports = htmlHelper;