feature: tiered sort
This commit is contained in:
@ -50,12 +50,12 @@ export function toDateValue(dt, local) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {Date} date
|
||||
* @param {boolean} [utc=true]
|
||||
* @returns {string}
|
||||
* 获取日期格式器
|
||||
* @param {Date} date - 待格式的日期
|
||||
* @param {boolean} [utc=true] - 是否按 UTC 时间格式化
|
||||
* @returns {any} 返回格式化工具对象
|
||||
*/
|
||||
function getFormatter(date, utc) {
|
||||
export function getFormatter(date, utc) {
|
||||
const prefix = utc !== false ? 'getUTC' : 'get';
|
||||
const r = {
|
||||
/**
|
||||
|
@ -1,4 +1,3 @@
|
||||
// import { r, global, contains, isPositive, nullOrEmpty } from "../utility";
|
||||
import './css/dropdown.scss';
|
||||
import { r } from "../utility/lgres";
|
||||
import { contains, nullOrEmpty } from "../utility/strings";
|
||||
@ -205,6 +204,7 @@ export class Dropdown {
|
||||
if (options.input) {
|
||||
label = createElement('input', 'ui-drop-text');
|
||||
label.type = 'text';
|
||||
label.autocomplete = 'off';
|
||||
label.draggable = false;
|
||||
options.placeholder && label.setAttribute('placeholder', options.placeholder);
|
||||
isPositive(options.maxLength) && label.setAttribute('maxlength', options.maxLength);
|
||||
|
@ -1,19 +1,19 @@
|
||||
import '../css/grid.scss';
|
||||
import { global, isPositive, isMobile, throttle, truncate, debounce } from "../../utility";
|
||||
import { global, isPositive, isMobile, throttle, debounce, truncate } from "../../utility";
|
||||
import { r as lang } from "../../utility/lgres";
|
||||
import { nullOrEmpty } from "../../utility/strings";
|
||||
import { createElement } from "../../functions";
|
||||
import { createIcon } from "../icon";
|
||||
import { createCheckbox } from "../checkbox";
|
||||
import { setTooltip } from "../tooltip";
|
||||
import { Popup, showAlert } from "../popup";
|
||||
import { Popup, showAlert, showConfirm } from "../popup";
|
||||
import { convertCssStyle } from "../extension";
|
||||
import { GridColumn, GridInputColumn, GridTextColumn, GridDropdownColumn, GridCheckboxColumn, GridRadioboxColumn, GridIconColumn, GridDateColumn } from "./column";
|
||||
|
||||
/**
|
||||
* @author Tsanie Lily <tsorgy@gmail.com>
|
||||
* @license MIT
|
||||
* @version 1.0.2
|
||||
* @version 1.0.3
|
||||
*/
|
||||
|
||||
const ScriptPath = (self.document == null ? self.location.href : self.document.currentScript?.src ?? '').replace(/ui\.min\.js\?.+$/, '');
|
||||
@ -258,6 +258,7 @@ let r = lang;
|
||||
* @property {(ValueItem[] | GridColumnFilterSourceCallback)} [filterSource] - 自定义列过滤器的数据源,支持调用函数返回数据源
|
||||
* @property {boolean} [filterAsValue=false] - 列头过滤强制使用 `Value` 字段
|
||||
* @property {GridItemSortCallback} [sortFilter] - 自定义列排序函数
|
||||
* @property {boolean} [sortAsText=false] - 按照 `DisplayValue` 排序
|
||||
* @property {DropdownOptions} [dropOptions] - 列为下拉列表类型时以该值设置下拉框的参数
|
||||
* @property {boolean} [dropRestrictCase=false] - 下拉列表是否区分大小写
|
||||
* @property {(GridSourceItem[] | Promise<GridSourceItem[]> | GridDropdownSourceCallback)} [source] - 列为下拉列表类型时以该值设置下拉列表数据源,支持返回异步对象,也支持调用函数返回
|
||||
@ -450,6 +451,7 @@ const GridColumnDirection = {
|
||||
* @typedef GridLanguages
|
||||
* @property {string} [all] - ( All )
|
||||
* @property {string} [ok] - OK
|
||||
* @property {string} [yes] - Yes
|
||||
* @property {string} [reset] - Reset
|
||||
* @property {string} [cancel] - Cancel
|
||||
* @property {string} [null] - ( Null )
|
||||
@ -464,6 +466,7 @@ const GridColumnDirection = {
|
||||
* @property {string} [column] - Column
|
||||
* @property {string} [order] - Order
|
||||
* @property {string} [sort] - Sort
|
||||
* @property {string} [sortArrayExists] - This will remove the current tiered sort. Do you wish to continue?
|
||||
* @property {string} [requirePrompt] - All sort criteria must have a column specified. Check the selected sort criteria and try again.
|
||||
* @property {string} [duplicatePrompt] - {column} is being sorted more than once. Delete the duplicate sort criteria and try again.
|
||||
* @interface
|
||||
@ -1348,6 +1351,7 @@ export class Grid {
|
||||
this.langs = {
|
||||
all: r('allItem', '( All )'),
|
||||
ok: r('ok', 'OK'),
|
||||
yes: r('yes', 'Yes'),
|
||||
reset: r('reset', 'Reset'),
|
||||
cancel: r('cancel', 'Cancel'),
|
||||
null: r('null', '( Null )'),
|
||||
@ -1362,6 +1366,7 @@ export class Grid {
|
||||
column: r('column', 'Column'),
|
||||
order: r('order', 'Order'),
|
||||
sort: r('sort', 'Sort'),
|
||||
sortArrayExists: r('sortArrayExists', 'This will remove the current tiered sort. Do you wish to continue?'),
|
||||
requirePrompt: r('requirePrompt', 'All sort criteria must have a column specified. Check the selected sort criteria and try again.'),
|
||||
duplicatePrompt: r('duplicatePrompt', '{column} is being sorted more than once. Delete the duplicate sort criteria and try again.')
|
||||
};
|
||||
@ -1405,10 +1410,9 @@ export class Grid {
|
||||
if (e.target === this._var.el) {
|
||||
// cancel selections
|
||||
const selectedIndexes = this._var.selectedIndexes;
|
||||
if (selectedIndexes == null || selectedIndexes.length === 0) {
|
||||
return;
|
||||
if (selectedIndexes?.length > 0) {
|
||||
selectedIndexes.splice(0);
|
||||
}
|
||||
selectedIndexes.splice(0);
|
||||
if (this.readonly) {
|
||||
this._tableRows.forEach(row => {
|
||||
row.classList.remove('selected');
|
||||
@ -1426,6 +1430,10 @@ export class Grid {
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
if (this._getParentElement(parent) !== this._var.el) {
|
||||
// sub ui-grid
|
||||
return;
|
||||
}
|
||||
const rowIndex = parent.classList.contains('ui-grid-total-row') ? -1 : this._tableRows.indexOf(parent);
|
||||
let colIndex = indexOfParent(target) - (this.expandable ? 1 : 0);
|
||||
if (colIndex >= this.columns.length) {
|
||||
@ -1799,58 +1807,64 @@ export class Grid {
|
||||
grid.onRowChanged();
|
||||
}
|
||||
buttonWrapper.append(
|
||||
createElement('span', 'button',
|
||||
createElement('span', button => {
|
||||
button.className = 'button';
|
||||
button.addEventListener('click', () => {
|
||||
let index = grid.selectedIndex;
|
||||
const n = { column: '', order: 'asc' };
|
||||
if (index >= 0) {
|
||||
index += 1;
|
||||
grid.addItem(n, index);
|
||||
} else {
|
||||
grid.addItem(n);
|
||||
index = grid.source.length - 1;
|
||||
}
|
||||
reload(index);
|
||||
});
|
||||
},
|
||||
createIcon('fa-light', 'plus'),
|
||||
createElement('span', span => {
|
||||
span.innerText = this.langs.addLevel;
|
||||
span.addEventListener('click', () => {
|
||||
let index = grid.selectedIndex;
|
||||
const n = { column: '', order: 'asc' };
|
||||
if (index >= 0) {
|
||||
index += 1;
|
||||
grid.addItem(n, index);
|
||||
} else {
|
||||
grid.addItem(n);
|
||||
index = grid.source.length - 1;
|
||||
}
|
||||
reload(index);
|
||||
});
|
||||
})
|
||||
),
|
||||
createElement('span', 'button ui-button-delete',
|
||||
createElement('span', button => {
|
||||
button.className = 'button ui-button-delete';
|
||||
button.addEventListener('click', () => {
|
||||
let index = grid.selectedIndex;
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
grid.removeItem(index);
|
||||
const length = grid.source.length;
|
||||
if (index >= length) {
|
||||
index = length - 1;
|
||||
}
|
||||
reload(index);
|
||||
});
|
||||
},
|
||||
createIcon('fa-light', 'times'),
|
||||
createElement('span', span => {
|
||||
span.innerText = this.langs.deleteLevel;
|
||||
span.addEventListener('click', () => {
|
||||
let index = grid.selectedIndex;
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
grid.removeItem(index);
|
||||
const length = grid.source.length;
|
||||
if (index >= length) {
|
||||
index = length - 1;
|
||||
}
|
||||
reload(index);
|
||||
});
|
||||
})
|
||||
),
|
||||
createElement('span', 'button ui-button-copy',
|
||||
createElement('span', button => {
|
||||
button.className = 'button ui-button-copy';
|
||||
button.addEventListener('click', () => {
|
||||
const index = grid.selectedIndex;
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
const item = grid.source[index];
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
grid.addItem(Object.assign({}, item), index + 1);
|
||||
reload(index + 1);
|
||||
});
|
||||
},
|
||||
createIcon('fa-light', 'copy'),
|
||||
createElement('span', span => {
|
||||
span.innerText = this.langs.copyLevel;
|
||||
span.addEventListener('click', () => {
|
||||
const index = grid.selectedIndex;
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
const item = grid.source[index];
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
grid.addItem(Object.assign({}, item), index + 1);
|
||||
reload(index + 1);
|
||||
});
|
||||
})
|
||||
),
|
||||
/*
|
||||
@ -2444,22 +2458,39 @@ export class Grid {
|
||||
if (isNaN(direction)) {
|
||||
direction = 1;
|
||||
}
|
||||
const editing = col.sortAsText !== true;
|
||||
return (a, b) => {
|
||||
a = this._getItemProp(a.values, true, col);
|
||||
b = this._getItemProp(b.values, true, col);
|
||||
if (typeof a === 'boolean') {
|
||||
a = a ? 2 : 1;
|
||||
}
|
||||
if (typeof b === 'boolean') {
|
||||
b = b ? 2 : 1;
|
||||
}
|
||||
if (a == null && typeof b === 'number') {
|
||||
a = 0;
|
||||
} else if (typeof a === 'number' && b == null) {
|
||||
b = 0;
|
||||
} else if (a != null && b == null) {
|
||||
return direction;
|
||||
a = this._getItemSortProp(a.values, editing, col);
|
||||
b = this._getItemSortProp(b.values, editing, col);
|
||||
if (editing) {
|
||||
if (typeof a === 'boolean') {
|
||||
a = a ? 2 : 1;
|
||||
}
|
||||
if (typeof b === 'boolean') {
|
||||
b = b ? 2 : 1;
|
||||
}
|
||||
if (a == null && typeof b === 'number') {
|
||||
a = 0;
|
||||
} else if (typeof a === 'number' && b == null) {
|
||||
b = 0;
|
||||
} else if (a != null && b == null) {
|
||||
return direction;
|
||||
} else {
|
||||
if (Array.isArray(a)) {
|
||||
a = a.join(', ');
|
||||
}
|
||||
if (Array.isArray(b)) {
|
||||
b = b.join(', ');
|
||||
}
|
||||
if (typeof a === 'string' && typeof b === 'string') {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (a != null && b == null) {
|
||||
return direction;
|
||||
}
|
||||
if (Array.isArray(a)) {
|
||||
a = a.join(', ');
|
||||
}
|
||||
@ -3546,6 +3577,21 @@ export class Grid {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GridRowItem} item
|
||||
* @param {boolean} editing
|
||||
* @param {GridColumnDefinition} col
|
||||
* @returns {any}
|
||||
*/
|
||||
_getItemSortProp(item, editing, col) {
|
||||
const value = item[col.key];
|
||||
if (value != null && Object.prototype.hasOwnProperty.call(value, 'SortValue')) {
|
||||
return value.SortValue;
|
||||
}
|
||||
return this._getItemProp(item, editing, col);
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {HTMLElement} target
|
||||
@ -3591,22 +3637,46 @@ export class Grid {
|
||||
return;
|
||||
}
|
||||
if (!this._notHeader(e.target.tagName)) {
|
||||
const index = this.columns.indexOf(col);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
if (this.sortIndex === index) {
|
||||
this.sortDirection = this.sortDirection === 1 ? -1 : 1;
|
||||
if (Array.isArray(this.sortArray) && this.sortArray.length > 0) {
|
||||
showConfirm(this.langs.sort, this.langs.sortArrayExists, [
|
||||
{
|
||||
key: 'yes',
|
||||
text: this.langs.yes
|
||||
},
|
||||
{
|
||||
text: this.langs.cancel
|
||||
}
|
||||
]).then(result => {
|
||||
if (result?.key === 'yes') {
|
||||
this._onDoHeaderSort(col);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.sortIndex = index;
|
||||
}
|
||||
this.sortColumn();
|
||||
if (typeof this.onColumnChanged === 'function') {
|
||||
this.onColumnChanged(ColumnChangedType.Sort, index, this.sortDirection);
|
||||
this._onDoHeaderSort(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {GridColumnDefinition} col
|
||||
*/
|
||||
_onDoHeaderSort(col) {
|
||||
const index = this.columns.indexOf(col);
|
||||
if (index < 0) {
|
||||
return;
|
||||
}
|
||||
if (this.sortIndex === index) {
|
||||
this.sortDirection = this.sortDirection === 1 ? -1 : 1;
|
||||
} else {
|
||||
this.sortIndex = index;
|
||||
}
|
||||
this.sortColumn();
|
||||
if (typeof this.onColumnChanged === 'function') {
|
||||
this.onColumnChanged(ColumnChangedType.Sort, index, this.sortDirection);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @param {MouseEvent} [e]
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "./css/media.scss";
|
||||
import { createElement } from "../functions";
|
||||
import { createIcon } from "./icon";
|
||||
import { get } from "../utility";
|
||||
import { get } from "../utility/request";
|
||||
|
||||
export function createPicture(url) {
|
||||
return createElement('a', a => {
|
||||
|
3
lib/ui/popup.d.ts
vendored
3
lib/ui/popup.d.ts
vendored
@ -69,7 +69,8 @@ export class Popup {
|
||||
}
|
||||
|
||||
interface PopupButton {
|
||||
tabIndex: number;
|
||||
className?: string;
|
||||
tabIndex?: number;
|
||||
key: string;
|
||||
text: string;
|
||||
trigger: (this: Popup) => boolean | Promise<boolean>;
|
||||
|
@ -271,6 +271,9 @@ export class Popup {
|
||||
container.appendChild(
|
||||
createElement('div', 'ui-popup-footer', ...option.buttons.map((b, i) => {
|
||||
const button = createElement('button', 'ui-popup-button');
|
||||
if (b.className != null) {
|
||||
button.classList.add(b.className);
|
||||
}
|
||||
if (b.tabIndex > 0) {
|
||||
button.tabIndex = b.tabIndex;
|
||||
} else {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import './css/tooltip.scss';
|
||||
import { createElement } from "../functions";
|
||||
// import { global } from "../utility";
|
||||
|
||||
const pointerHeight = 12;
|
||||
|
||||
|
Reference in New Issue
Block a user