Source: lists/list-item.js


import $ from '$qui/lib/jquery.module.js'

import {mix}             from '$qui/base/mixwith.js'
import * as StringUtils  from '$qui/utils/string.js'
import VisibilityManager from '$qui/utils/visibility-manager.js'
import ViewMixin         from '$qui/views/view.js'

/**
 * A list item.
 * @alias qui.lists.ListItem
 * @mixes qui.views.ViewMixin
 */
class ListItem extends mix().with(ViewMixin) {

    /**
     * @constructs
     * @param {*} [data] user data associated with the item
     * @param {...*} args parent class parameters
     */
    constructor({data = null, ...args} = {}) {
        super(args)

        this._data = data
        this._list = null
        this._visibilityManager = null
    }

    makeHTML() {
        let html = $('<div></div>', {class: 'qui-list-child qui-list-item'})
        html.html(this.makeContent())

        this._visibilityManager = new VisibilityManager({element: html})

        return html
    }

    /**
     * Implement this method to create the actual list item content.
     * @abstract
     * @returns {jQuery}
     */
    makeContent() {
    }


    /* User data */

    /**
     * Return the value that identifies this item across updates. Two items with the same key, at the same position,
     * are the same row, so the list can update it where it is instead of building it again.
     * @returns {*} the key, or `null` if the item cannot be identified and must always be rebuilt
     */
    getKey() {
        return this.getData()
    }

    /**
     * Update this item in place, from a freshly built item representing the same row.
     *
     * The base implementation refuses, so that a list containing items which do not implement this keeps its old
     * rebuild-everything behaviour rather than silently showing stale content.
     * @param {qui.lists.ListItem} other the freshly built item
     * @returns {Boolean} `true` if the item took the update, `false` to have the list rebuild the row instead
     */
    updateFrom(other) {
        return false
    }

    /**
     * Return the item user data.
     * @returns {*}
     */
    getData() {
        return this._data
    }

    /**
     * Set the item user data.
     * @param {*} data
     */
    setData(data) {
        this._data = data
    }

    /* Selection */

    /**
     * Tell if item is selected or not.
     */
    isSelected() {
        return this.getHTML().hasClass('selected')
    }

    /**
     * Select or deselect item.
     * @param {Boolean} selected
     */
    setSelected(selected) {
        this.getHTML().toggleClass('selected', selected)
    }

    /**
     * Set select mode. This is internally called by owning {@link qui.lists.List}.
     * @param {String} selectMode one of:
     *  * {@link qui.lists.LIST_SELECT_MODE_DISABLED}
     *  * {@link qui.lists.LIST_SELECT_MODE_SINGLE} (default)
     *  * {@link qui.lists.LIST_SELECT_MODE_MULTIPLE}
     */
    setSelectMode(selectMode) {
    }


    /* Visibility */

    /**
     * Tell if the item is hidden, either because it has been explicitly hidden or because it is currently filtered
     * out by its list's search filter.
     * @returns {Boolean}
     */
    isHidden() {
        if (this._list != null && this._list.isItemFilteredOut(this)) {
            return true
        }

        return this.isExplicitlyHidden()
    }

    /**
     * Tell if the item has been hidden with {@link qui.lists.ListItem#hide}, as opposed to being filtered out by its
     * list's search filter.
     * @returns {Boolean}
     */
    isExplicitlyHidden() {
        return !this._visibilityManager.isElementVisible()
    }

    /**
     * Show the item.
     */
    show() {
        this._visibilityManager.showElement()
    }

    /**
     * Hide the field.
     */
    hide() {
        this._visibilityManager.hideElement()
    }

    /**
     * Tell if item matches a search filter. By default, uses {@link qui.utils.string.intelliSearch} on textual content
     * of the HTML element.
     * @param {String|RegExp} filter search filter, possibly precompiled with
     * {@link qui.utils.string.intelliSearchRegExp}
     * @returns {Boolean}
     */
    isMatch(filter) {
        return StringUtils.intelliSearch(this.getHTML().text().trim(), filter) != null
    }

    /**
     * Return the owning list.
     * @returns {qui.lists.List}
     */
    getList() {
        return this._list
    }

    /**
     * Set the owning list.
     * @param {qui.lists.List} list
     */
    setList(list) {
        this._list = list
    }

}


export default ListItem