fix
This commit is contained in:
		
							parent
							
								
									aacee3c970
								
							
						
					
					
						commit
						e21c43e2aa
					
				|  | @ -0,0 +1,35 @@ | |||
| <!-- | ||||
| SPDX-FileCopyrightText: syuilo and other misskey contributors | ||||
| SPDX-License-Identifier: AGPL-3.0-only | ||||
| --> | ||||
| 
 | ||||
| <template> | ||||
| <MkTooltip ref="tooltip" :showing="showing" :targetElement="targetElement" :maxWidth="250" @closed="emit('closed')"> | ||||
| 	<div :class="$style.root"> | ||||
| 		{{ content }} | ||||
| 	</div> | ||||
| </MkTooltip> | ||||
| </template> | ||||
| 
 | ||||
| <script lang="ts" setup> | ||||
| import { } from 'vue'; | ||||
| import MkTooltip from '@/components/MkTooltip.vue'; | ||||
| 
 | ||||
| defineProps<{ | ||||
| 	showing: boolean; | ||||
| 	content: string; | ||||
| 	targetElement: HTMLElement; | ||||
| }>(); | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'closed'): void; | ||||
| }>(); | ||||
| </script> | ||||
| 
 | ||||
| <style lang="scss" module> | ||||
| .root { | ||||
| 	font-size: 0.9em; | ||||
| 	text-align: left; | ||||
| 	text-wrap: normal; | ||||
| } | ||||
| </style> | ||||
|  | @ -10,9 +10,10 @@ | |||
| 	<div | ||||
| 		:class="[ | ||||
| 			$style.root, | ||||
| 			[(cell.validation.valid || cell.selected) ? {} : $style.error], | ||||
| 			[cell.selected ? $style.selected : {}], | ||||
| 			[cell.ranged ? $style.ranged : {}], | ||||
| 			[needsContentCentering ? $style.center : {}] | ||||
| 			[needsContentCentering ? $style.center : {}], | ||||
| 		]" | ||||
| 	> | ||||
| 		<div v-if="!editing" ref="contentAreaEl"> | ||||
|  | @ -47,15 +48,12 @@ | |||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { computed, nextTick, ref, toRefs, watch } from 'vue'; | ||||
| import { | ||||
| 	CellValue, | ||||
| 	equalCellAddress, | ||||
| 	getCellAddress, | ||||
| 	GridCell, | ||||
| 	GridEventEmitter, | ||||
| 	Size, | ||||
| } from '@/components/grid/types.js'; | ||||
| import { computed, defineAsyncComponent, nextTick, ref, shallowRef, toRefs, watch } from 'vue'; | ||||
| import { GridEventEmitter, Size } from '@/components/grid/grid.js'; | ||||
| import { useTooltip } from '@/scripts/use-tooltip.js'; | ||||
| import * as os from '@/os.js'; | ||||
| import { CellValue, GridCell } from '@/components/grid/cell.js'; | ||||
| import { equalCellAddress, getCellAddress } from '@/components/grid/utils.js'; | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'operation:beginEdit', sender: GridCell): void; | ||||
|  | @ -70,9 +68,9 @@ const props = defineProps<{ | |||
| 
 | ||||
| const { cell, bus } = toRefs(props); | ||||
| 
 | ||||
| const rootEl = ref<InstanceType<typeof HTMLTableCellElement>>(); | ||||
| const contentAreaEl = ref<InstanceType<typeof HTMLDivElement>>(); | ||||
| const inputAreaEl = ref<InstanceType<typeof HTMLDivElement>>(); | ||||
| const rootEl = shallowRef<InstanceType<typeof HTMLTableCellElement>>(); | ||||
| const contentAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>(); | ||||
| const inputAreaEl = shallowRef<InstanceType<typeof HTMLDivElement>>(); | ||||
| 
 | ||||
| const editing = ref<boolean>(false); | ||||
| const editingValue = ref<CellValue>(undefined); | ||||
|  | @ -209,6 +207,19 @@ function emitContentSizeChanged() { | |||
| 	}); | ||||
| } | ||||
| 
 | ||||
| useTooltip(rootEl, (showing) => { | ||||
| 	if (cell.value.validation.valid) { | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	const content = cell.value.validation.violations.map(it => it.result.message).join('\n'); | ||||
| 	os.popup(defineAsyncComponent(() => import('@/components/grid/MkCellTooltip.vue')), { | ||||
| 		showing, | ||||
| 		content, | ||||
| 		targetElement: rootEl.value, | ||||
| 	}, {}, 'closed'); | ||||
| }); | ||||
| 
 | ||||
| </script> | ||||
| 
 | ||||
| <style module lang="scss"> | ||||
|  | @ -250,6 +261,10 @@ $cellHeight: 28px; | |||
| 	&.center { | ||||
| 		justify-content: center; | ||||
| 	} | ||||
| 
 | ||||
| 	&.error { | ||||
| 		border: solid 0.5px var(--error); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| .content { | ||||
|  |  | |||
|  | @ -19,9 +19,10 @@ | |||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { toRefs } from 'vue'; | ||||
| import { CellValue, GridCell, GridEventEmitter, GridRow, Size } from '@/components/grid/types.js'; | ||||
| import { GridEventEmitter, GridRow, Size } from '@/components/grid/grid.js'; | ||||
| import MkDataCell from '@/components/grid/MkDataCell.vue'; | ||||
| import MkNumberCell from '@/components/grid/MkNumberCell.vue'; | ||||
| import { CellValue, GridCell } from '@/components/grid/cell.js'; | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'operation:beginEdit', sender: GridCell): void; | ||||
|  |  | |||
|  | @ -36,24 +36,21 @@ | |||
| <script setup lang="ts"> | ||||
| import { computed, ref, toRefs, watch } from 'vue'; | ||||
| import { | ||||
| 	calcCellWidth, | ||||
| 	CELL_ADDRESS_NONE, | ||||
| 	CellAddress, | ||||
| 	CellValue, CellValueChangedEvent, | ||||
| 	CellValueChangedEvent, | ||||
| 	ColumnSetting, | ||||
| 	DataSource, | ||||
| 	equalCellAddress, | ||||
| 	getCellAddress, | ||||
| 	GridCell, | ||||
| 	GridColumn, | ||||
| 	GridEventEmitter, | ||||
| 	GridRow, | ||||
| 	GridState, | ||||
| 	Size, | ||||
| } from '@/components/grid/types.js'; | ||||
| } from '@/components/grid/grid.js'; | ||||
| import MkDataRow from '@/components/grid/MkDataRow.vue'; | ||||
| import MkHeaderRow from '@/components/grid/MkHeaderRow.vue'; | ||||
| import copyToClipboard from '@/scripts/copy-to-clipboard.js'; | ||||
| import { cellValidation, ValidateViolation } from '@/components/grid/cell-validators.js'; | ||||
| import { CELL_ADDRESS_NONE, CellAddress, CellValue, GridCell } from '@/components/grid/cell.js'; | ||||
| import { calcCellWidth, equalCellAddress, getCellAddress } from '@/components/grid/utils.js'; | ||||
| 
 | ||||
| const props = defineProps<{ | ||||
| 	columnSettings: ColumnSetting[], | ||||
|  | @ -61,6 +58,7 @@ const props = defineProps<{ | |||
| }>(); | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'operation:cellValidation', violation: ValidateViolation): void; | ||||
| 	(ev: 'change:cellValue', event: CellValueChangedEvent): void; | ||||
| }>(); | ||||
| 
 | ||||
|  | @ -526,10 +524,20 @@ function onHeaderCellWidthLargest(sender: GridColumn) { | |||
| 
 | ||||
| function setCellValue(sender: GridCell | CellAddress, newValue: CellValue) { | ||||
| 	const cellAddress = 'address' in sender ? sender.address : sender; | ||||
| 	cells.value[cellAddress.row][cellAddress.col].value = newValue; | ||||
| 	const cell = cells.value[cellAddress.row][cellAddress.col]; | ||||
| 
 | ||||
| 	const violation = cellValidation(cell, newValue); | ||||
| 	emit('operation:cellValidation', violation); | ||||
| 
 | ||||
| 	cell.validation = { | ||||
| 		valid: violation.valid, | ||||
| 		violations: violation.violations.filter(it => !it.valid), | ||||
| 	}; | ||||
| 	cell.value = newValue; | ||||
| 
 | ||||
| 	emit('change:cellValue', { | ||||
| 		column: columns.value[cellAddress.col], | ||||
| 		row: rows.value[cellAddress.row], | ||||
| 		column: cell.column, | ||||
| 		row: cell.row, | ||||
| 		value: newValue, | ||||
| 	}); | ||||
| } | ||||
|  | @ -709,6 +717,10 @@ function refreshData() { | |||
| 				selected: false, | ||||
| 				ranged: false, | ||||
| 				contentSize: { width: 0, height: 0 }, | ||||
| 				validation: { | ||||
| 					valid: true, | ||||
| 					violations: [], | ||||
| 				}, | ||||
| 			}; | ||||
| 
 | ||||
| 			rowCells.push(cell); | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ | |||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { computed, nextTick, ref, toRefs, watch } from 'vue'; | ||||
| import { GridColumn, GridEventEmitter, Size } from '@/components/grid/types.js'; | ||||
| import { GridColumn, GridEventEmitter, Size } from '@/components/grid/grid.js'; | ||||
| 
 | ||||
| const emit = defineEmits<{ | ||||
| 	(ev: 'operation:beginWidthChange', sender: GridColumn): void; | ||||
|  |  | |||
|  | @ -19,7 +19,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { GridColumn, GridEventEmitter, Size } from '@/components/grid/types.js'; | ||||
| import { GridColumn, GridEventEmitter, Size } from '@/components/grid/grid.js'; | ||||
| import MkHeaderCell from '@/components/grid/MkHeaderCell.vue'; | ||||
| import MkNumberCell from '@/components/grid/MkNumberCell.vue'; | ||||
| 
 | ||||
|  |  | |||
|  | @ -5,7 +5,7 @@ | |||
| </template> | ||||
| 
 | ||||
| <script setup lang="ts"> | ||||
| import { GridRow } from '@/components/grid/types.js'; | ||||
| import { GridRow } from '@/components/grid/grid.js'; | ||||
| 
 | ||||
| defineProps<{ | ||||
| 	content: string, | ||||
|  |  | |||
|  | @ -0,0 +1,68 @@ | |||
| import { GridColumn, GridRow } from '@/components/grid/grid.js'; | ||||
| import { CellValue, GridCell } from '@/components/grid/cell.js'; | ||||
| 
 | ||||
| export type ValidatorParams = { | ||||
| 	column: GridColumn; | ||||
| 	row: GridRow; | ||||
| 	value: CellValue; | ||||
| }; | ||||
| 
 | ||||
| export type ValidatorResult = { | ||||
| 	valid: boolean; | ||||
| 	message?: string; | ||||
| } | ||||
| 
 | ||||
| export type CellValidator = { | ||||
| 	name?: string; | ||||
| 	validate: (params: ValidatorParams) => ValidatorResult; | ||||
| } | ||||
| 
 | ||||
| export type ValidateViolation = { | ||||
| 	valid: boolean; | ||||
| 	params: ValidatorParams; | ||||
| 	violations: ValidateViolationItem[]; | ||||
| } | ||||
| 
 | ||||
| export type ValidateViolationItem = { | ||||
| 	valid: boolean; | ||||
| 	validator: CellValidator; | ||||
| 	result: ValidatorResult; | ||||
| } | ||||
| 
 | ||||
| export function cellValidation(cell: GridCell, newValue: CellValue): ValidateViolation { | ||||
| 	const { column, row } = cell; | ||||
| 	const validators = column.setting.validators ?? []; | ||||
| 
 | ||||
| 	const params: ValidatorParams = { | ||||
| 		column, | ||||
| 		row, | ||||
| 		value: newValue, | ||||
| 	}; | ||||
| 
 | ||||
| 	const violations: ValidateViolationItem[] = validators.map(validator => { | ||||
| 		const result = validator.validate(params); | ||||
| 		return { | ||||
| 			valid: result.valid, | ||||
| 			validator, | ||||
| 			result, | ||||
| 		}; | ||||
| 	}); | ||||
| 
 | ||||
| 	return { | ||||
| 		valid: violations.every(v => v.result.valid), | ||||
| 		params, | ||||
| 		violations, | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| export const required: CellValidator = { | ||||
| 	name: 'required', | ||||
| 	validate: (params: ValidatorParams): ValidatorResult => { | ||||
| 		const { value } = params; | ||||
| 		return { | ||||
| 			valid: value !== null && value !== undefined && value !== '', | ||||
| 			message: 'This field is required.', | ||||
| 		}; | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
|  | @ -0,0 +1,29 @@ | |||
| import { ValidateViolationItem } from '@/components/grid/cell-validators.js'; | ||||
| import { GridColumn, GridRow, Size } from '@/components/grid/grid.js'; | ||||
| 
 | ||||
| export type CellValue = string | boolean | number | undefined | null | ||||
| 
 | ||||
| export type CellAddress = { | ||||
| 	row: number; | ||||
| 	col: number; | ||||
| } | ||||
| 
 | ||||
| export const CELL_ADDRESS_NONE: CellAddress = { | ||||
| 	row: -1, | ||||
| 	col: -1, | ||||
| }; | ||||
| 
 | ||||
| export type GridCell = { | ||||
| 	address: CellAddress; | ||||
| 	value: CellValue; | ||||
| 	column: GridColumn; | ||||
| 	row: GridRow; | ||||
| 	selected: boolean; | ||||
| 	ranged: boolean; | ||||
| 	contentSize: Size; | ||||
| 	validation: { | ||||
| 		valid: boolean; | ||||
| 		violations: ValidateViolationItem[]; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | @ -0,0 +1,45 @@ | |||
| import { EventEmitter } from 'eventemitter3'; | ||||
| import { CellValidator } from '@/components/grid/cell-validators.js'; | ||||
| import { CellValue } from '@/components/grid/cell.js'; | ||||
| 
 | ||||
| export type DataSource = Record<string, CellValue>; | ||||
| 
 | ||||
| export type GridState = 'normal' | 'cellSelecting' | 'cellEditing' | 'colResizing' | 'colSelecting' | 'rowSelecting' | ||||
| 
 | ||||
| export type Size = { | ||||
| 	width: number; | ||||
| 	height: number; | ||||
| } | ||||
| 
 | ||||
| export type SizeStyle = number | 'auto' | undefined; | ||||
| 
 | ||||
| export type ColumnType = 'text' | 'number' | 'date' | 'boolean' | 'image'; | ||||
| 
 | ||||
| export type ColumnSetting = { | ||||
| 	bindTo: string; | ||||
| 	title?: string; | ||||
| 	type: ColumnType; | ||||
| 	width: SizeStyle; | ||||
| 	editable?: boolean; | ||||
| 	validators?: CellValidator[]; | ||||
| }; | ||||
| 
 | ||||
| export type GridColumn = { | ||||
| 	index: number; | ||||
| 	setting: ColumnSetting; | ||||
| 	width: string; | ||||
| 	contentSize: Size; | ||||
| } | ||||
| 
 | ||||
| export type GridRow = { | ||||
| 	index: number; | ||||
| } | ||||
| 
 | ||||
| export type CellValueChangedEvent = { | ||||
| 	column: GridColumn; | ||||
| 	row: GridRow; | ||||
| 	value: CellValue; | ||||
| } | ||||
| 
 | ||||
| export class GridEventEmitter extends EventEmitter<{}> { | ||||
| } | ||||
|  | @ -1,116 +0,0 @@ | |||
| import { EventEmitter } from 'eventemitter3'; | ||||
| 
 | ||||
| export type CellValue = string | boolean | number | undefined | null | ||||
| 
 | ||||
| export type DataSource = Record<string, CellValue>; | ||||
| 
 | ||||
| export type GridState = 'normal' | 'cellSelecting' | 'cellEditing' | 'colResizing' | 'colSelecting' | 'rowSelecting' | ||||
| 
 | ||||
| export type RowState = 'normal' | 'added' | 'deleted' | ||||
| 
 | ||||
| export type Size = { | ||||
| 	width: number; | ||||
| 	height: number; | ||||
| } | ||||
| 
 | ||||
| export type SizeStyle = number | 'auto' | undefined; | ||||
| 
 | ||||
| export type CellAddress = { | ||||
| 	row: number; | ||||
| 	col: number; | ||||
| } | ||||
| 
 | ||||
| export const CELL_ADDRESS_NONE: CellAddress = { | ||||
| 	row: -1, | ||||
| 	col: -1, | ||||
| }; | ||||
| 
 | ||||
| export type GridCell = { | ||||
| 	address: CellAddress; | ||||
| 	value: CellValue; | ||||
| 	column: GridColumn; | ||||
| 	row: GridRow; | ||||
| 	selected: boolean; | ||||
| 	ranged: boolean; | ||||
| 	contentSize: Size; | ||||
| } | ||||
| 
 | ||||
| export type ColumnType = 'text' | 'number' | 'date' | 'boolean' | 'image'; | ||||
| 
 | ||||
| export type ColumnSetting = { | ||||
| 	bindTo: string; | ||||
| 	title?: string; | ||||
| 	type: ColumnType; | ||||
| 	width: SizeStyle; | ||||
| 	editable?: boolean; | ||||
| }; | ||||
| 
 | ||||
| export type GridColumn = { | ||||
| 	index: number; | ||||
| 	setting: ColumnSetting; | ||||
| 	width: string; | ||||
| 	contentSize: Size; | ||||
| } | ||||
| 
 | ||||
| export type GridRow = { | ||||
| 	index: number; | ||||
| } | ||||
| 
 | ||||
| export type CellValueChangedEvent = { | ||||
| 	column: GridColumn; | ||||
| 	row: GridRow; | ||||
| 	value: CellValue; | ||||
| } | ||||
| 
 | ||||
| export class GridEventEmitter extends EventEmitter<{}> { | ||||
| } | ||||
| 
 | ||||
| export function isElement(elem: any): elem is HTMLElement { | ||||
| 	return elem instanceof HTMLElement; | ||||
| } | ||||
| 
 | ||||
| export function isCellElement(elem: any): elem is HTMLTableCellElement { | ||||
| 	return elem instanceof HTMLTableCellElement; | ||||
| } | ||||
| 
 | ||||
| export function isRowElement(elem: any): elem is HTMLTableRowElement { | ||||
| 	return elem instanceof HTMLTableRowElement; | ||||
| } | ||||
| 
 | ||||
| export function getCellAddress(elem: HTMLElement, parentNodeCount = 10): CellAddress { | ||||
| 	let node = elem; | ||||
| 	for (let i = 0; i < parentNodeCount; i++) { | ||||
| 		if (isCellElement(node) && isRowElement(node.parentElement)) { | ||||
| 			return { | ||||
| 				// ヘッダ行ぶんを除く
 | ||||
| 				row: node.parentElement.rowIndex - 1, | ||||
| 				// 数値列ぶんを除く
 | ||||
| 				col: node.cellIndex - 1, | ||||
| 			}; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!node.parentElement) { | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		node = node.parentElement; | ||||
| 	} | ||||
| 
 | ||||
| 	return CELL_ADDRESS_NONE; | ||||
| } | ||||
| 
 | ||||
| export function equalCellAddress(a: CellAddress, b: CellAddress): boolean { | ||||
| 	return a.row === b.row && a.col === b.col; | ||||
| } | ||||
| 
 | ||||
| export function calcCellWidth(widthSetting: SizeStyle): string { | ||||
| 	switch (widthSetting) { | ||||
| 		case undefined: | ||||
| 		case 'auto': { | ||||
| 			return 'auto'; | ||||
| 		} | ||||
| 		default: { | ||||
| 			return `${widthSetting}px`; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,49 @@ | |||
| import { SizeStyle } from '@/components/grid/types.js'; | ||||
| import { CELL_ADDRESS_NONE, CellAddress } from '@/components/grid/cell.js'; | ||||
| 
 | ||||
| export function isCellElement(elem: any): elem is HTMLTableCellElement { | ||||
| 	return elem instanceof HTMLTableCellElement; | ||||
| } | ||||
| 
 | ||||
| export function isRowElement(elem: any): elem is HTMLTableRowElement { | ||||
| 	return elem instanceof HTMLTableRowElement; | ||||
| } | ||||
| 
 | ||||
| export function calcCellWidth(widthSetting: SizeStyle): string { | ||||
| 	switch (widthSetting) { | ||||
| 		case undefined: | ||||
| 		case 'auto': { | ||||
| 			return 'auto'; | ||||
| 		} | ||||
| 		default: { | ||||
| 			return `${widthSetting}px`; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| export function getCellAddress(elem: HTMLElement, parentNodeCount = 10): CellAddress { | ||||
| 	let node = elem; | ||||
| 	for (let i = 0; i < parentNodeCount; i++) { | ||||
| 		if (isCellElement(node) && isRowElement(node.parentElement)) { | ||||
| 			return { | ||||
| 				// ヘッダ行ぶんを除く
 | ||||
| 				row: node.parentElement.rowIndex - 1, | ||||
| 				// 数値列ぶんを除く
 | ||||
| 				col: node.cellIndex - 1, | ||||
| 			}; | ||||
| 		} | ||||
| 
 | ||||
| 		if (!node.parentElement) { | ||||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		node = node.parentElement; | ||||
| 	} | ||||
| 
 | ||||
| 	return CELL_ADDRESS_NONE; | ||||
| } | ||||
| 
 | ||||
| export function equalCellAddress(a: CellAddress, b: CellAddress): boolean { | ||||
| 	return a.row === b.row && a.col === b.col; | ||||
| } | ||||
| 
 | ||||
|  | @ -35,6 +35,7 @@ | |||
| 		<MkGrid | ||||
| 			:data="convertedGridItems" | ||||
| 			:columnSettings="columnSettings" | ||||
| 			@operation:cellValidation="onCellValidation" | ||||
| 			@change:cellValue="onChangeCellValue" | ||||
| 		/> | ||||
| 	</div> | ||||
|  | @ -43,7 +44,7 @@ | |||
| 		v-if="gridItems.length > 0" | ||||
| 		:class="$style.buttons" | ||||
| 	> | ||||
| 		<MkButton primary @click="onRegistryClicked">{{ i18n.ts.registration }}</MkButton> | ||||
| 		<MkButton primary :disabled="registerButtonDisabled" @click="onRegistryClicked">{{ i18n.ts.registration }}</MkButton> | ||||
| 		<MkButton @click="onClearClicked">{{ i18n.ts.clear }}</MkButton> | ||||
| 	</div> | ||||
| </div> | ||||
|  | @ -56,7 +57,7 @@ import * as Misskey from 'misskey-js'; | |||
| import { misskeyApi } from '@/scripts/misskey-api.js'; | ||||
| import { GridItem, IGridItem } from '@/pages/admin/custom-emojis-grid.impl.js'; | ||||
| import MkGrid from '@/components/grid/MkGrid.vue'; | ||||
| import { CellValueChangedEvent, ColumnSetting } from '@/components/grid/types.js'; | ||||
| import { CellValueChangedEvent, ColumnSetting } from '@/components/grid/grid.js'; | ||||
| import { i18n } from '@/i18n.js'; | ||||
| import MkSelect from '@/components/MkSelect.vue'; | ||||
| import { uploadFile } from '@/scripts/upload.js'; | ||||
|  | @ -65,6 +66,7 @@ import { defaultStore } from '@/store.js'; | |||
| import MkFolder from '@/components/MkFolder.vue'; | ||||
| import MkButton from '@/components/MkButton.vue'; | ||||
| import * as os from '@/os.js'; | ||||
| import { required, ValidateViolation } from '@/components/grid/cell-validators.js'; | ||||
| 
 | ||||
| type FolderItem = { | ||||
| 	id?: string; | ||||
|  | @ -78,8 +80,8 @@ const emit = defineEmits<{ | |||
| }>(); | ||||
| 
 | ||||
| const columnSettings: ColumnSetting[] = [ | ||||
| 	{ bindTo: 'url', title: '🎨', type: 'image', editable: false, width: 50 }, | ||||
| 	{ bindTo: 'name', title: 'name', type: 'text', editable: true, width: 140 }, | ||||
| 	{ bindTo: 'url', title: '🎨', type: 'image', editable: false, width: 50, validators: [required] }, | ||||
| 	{ bindTo: 'name', title: 'name', type: 'text', editable: true, width: 140, validators: [required] }, | ||||
| 	{ bindTo: 'category', title: 'category', type: 'text', editable: true, width: 140 }, | ||||
| 	{ bindTo: 'aliases', title: 'aliases', type: 'text', editable: true, width: 140 }, | ||||
| 	{ bindTo: 'license', title: 'license', type: 'text', editable: true, width: 140 }, | ||||
|  | @ -92,6 +94,8 @@ const uploadFolders = ref<FolderItem[]>([]); | |||
| const gridItems = ref<IGridItem[]>([]); | ||||
| const selectedFolderId = ref(defaultStore.state.uploadFolder); | ||||
| const keepOriginalUploading = ref(defaultStore.state.keepOriginalUploading); | ||||
| const registerButtonDisabled = ref<boolean>(false); | ||||
| 
 | ||||
| const convertedGridItems = computed(() => gridItems.value.map(it => it as Record<string, any>)); | ||||
| 
 | ||||
| async function onRegistryClicked() { | ||||
|  | @ -180,6 +184,11 @@ async function onDrop(ev: DragEvent) { | |||
| 	} | ||||
| } | ||||
| 
 | ||||
| function onCellValidation(violation: ValidateViolation) { | ||||
| 	console.log(violation); | ||||
| 	registerButtonDisabled.value = !violation.valid; | ||||
| } | ||||
| 
 | ||||
| function onChangeCellValue(event: CellValueChangedEvent) { | ||||
| 	console.log(event); | ||||
| 	const item = gridItems.value[event.row.index]; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue