package.src.vaadin-grid-sorter-mixin.js Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of grid Show documentation
Show all versions of grid Show documentation
A free, flexible and high-quality Web Component for showing large amounts of tabular data
/**
* @license
* Copyright (c) 2016 - 2023 Vaadin Ltd.
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
*/
import { css, registerStyles } from '@vaadin/vaadin-themable-mixin/vaadin-themable-mixin.js';
const template = document.createElement('template');
template.innerHTML = `
`;
document.head.appendChild(template.content);
registerStyles(
'vaadin-grid-sorter',
css`
:host {
display: inline-flex;
cursor: pointer;
max-width: 100%;
}
[part='content'] {
flex: 1 1 auto;
}
[part='indicators'] {
position: relative;
align-self: center;
flex: none;
}
[part='order'] {
display: inline;
vertical-align: super;
}
[part='indicators']::before {
font-family: 'vaadin-grid-sorter-icons';
display: inline-block;
}
:host(:not([direction])) [part='indicators']::before {
content: '\\e901';
}
:host([direction='asc']) [part='indicators']::before {
content: '\\e900';
}
:host([direction='desc']) [part='indicators']::before {
content: '\\e902';
}
`,
{ moduleId: 'vaadin-grid-sorter-styles' },
);
/**
* A mixin providing common sorter functionality.
*
* @polymerMixin
*/
export const GridSorterMixin = (superClass) =>
class GridSorterMixinClass extends superClass {
static get properties() {
return {
/**
* JS Path of the property in the item used for sorting the data.
*/
path: String,
/**
* How to sort the data.
* Possible values are `asc` to use an ascending algorithm, `desc` to sort the data in
* descending direction, or `null` for not sorting the data.
* @type {GridSorterDirection | undefined}
*/
direction: {
type: String,
reflectToAttribute: true,
notify: true,
value: null,
sync: true,
},
/**
* @type {number | null}
* @protected
*/
_order: {
type: Number,
value: null,
sync: true,
},
/** @private */
_isConnected: {
type: Boolean,
observer: '__isConnectedChanged',
},
};
}
static get observers() {
return ['_pathOrDirectionChanged(path, direction)'];
}
/** @protected */
ready() {
super.ready();
this.addEventListener('click', this._onClick.bind(this));
}
/** @protected */
connectedCallback() {
super.connectedCallback();
this._isConnected = true;
}
/** @protected */
disconnectedCallback() {
super.disconnectedCallback();
this._isConnected = false;
if (!this.parentNode && this._grid) {
this._grid.__removeSorters([this]);
}
}
/** @private */
_pathOrDirectionChanged() {
this.__dispatchSorterChangedEvenIfPossible();
}
/** @private */
__isConnectedChanged(newValue, oldValue) {
if (oldValue === false) {
return;
}
this.__dispatchSorterChangedEvenIfPossible();
}
/** @private */
__dispatchSorterChangedEvenIfPossible() {
if (this.path === undefined || this.direction === undefined || !this._isConnected) {
return;
}
this.dispatchEvent(
new CustomEvent('sorter-changed', {
detail: { shiftClick: Boolean(this._shiftClick), fromSorterClick: Boolean(this._fromSorterClick) },
bubbles: true,
composed: true,
}),
);
// Cleaning up as a programatically sorting can be done after some user interaction
this._fromSorterClick = false;
this._shiftClick = false;
}
/** @private */
_getDisplayOrder(order) {
return order === null ? '' : order + 1;
}
/** @private */
_onClick(e) {
if (e.defaultPrevented) {
// Something else has already handled the click event, do nothing.
return;
}
const activeElement = this.getRootNode().activeElement;
if (this !== activeElement && this.contains(activeElement)) {
// Some focusable content inside the sorter was clicked, do nothing.
return;
}
e.preventDefault();
this._shiftClick = e.shiftKey;
this._fromSorterClick = true;
if (this.direction === 'asc') {
this.direction = 'desc';
} else if (this.direction === 'desc') {
this.direction = null;
} else {
this.direction = 'asc';
}
}
};