fix: update tree title render & switchIcon
parent
eff286d0e5
commit
e8b1f68899
|
@ -162,6 +162,7 @@ export { default as Table, TableColumn, TableColumnGroup } from './table';
|
|||
export type { TransferProps } from './transfer';
|
||||
export { default as Transfer } from './transfer';
|
||||
|
||||
export type { TreeProps, DirectoryTreeProps } from './tree';
|
||||
export { default as Tree, TreeNode, DirectoryTree } from './tree';
|
||||
|
||||
export type { TreeSelectProps } from './tree-select';
|
||||
|
|
|
@ -7,7 +7,7 @@ import VcTree, { TreeNode } from '../vc-tree';
|
|||
import PropTypes from '../_util/vue-types';
|
||||
import { filterEmpty } from '../_util/props-util';
|
||||
import initDefaultProps from '../_util/props-util/initDefaultProps';
|
||||
import type { DataNode, DragNodeEvent, FieldNames, Key } from '../vc-tree/interface';
|
||||
import type { DataNode, EventDataNode, FieldNames, Key } from '../vc-tree/interface';
|
||||
import type { TreeNodeProps } from '../vc-tree/props';
|
||||
import { treeProps as vcTreeProps } from '../vc-tree/props';
|
||||
import useConfigInject from '../_util/hooks/useConfigInject';
|
||||
|
@ -42,7 +42,7 @@ export type AntTreeNodeProps = TreeNodeProps;
|
|||
export type TreeDataItem = DataNode;
|
||||
|
||||
export interface AntTreeNodeBaseEvent {
|
||||
node: DataNode;
|
||||
node: EventDataNode;
|
||||
nativeEvent: MouseEvent;
|
||||
}
|
||||
|
||||
|
@ -63,7 +63,7 @@ export interface AntTreeNodeExpandedEvent extends AntTreeNodeBaseEvent {
|
|||
}
|
||||
|
||||
export interface AntTreeNodeMouseEvent {
|
||||
node: DataNode;
|
||||
node: EventDataNode;
|
||||
event: DragEvent;
|
||||
}
|
||||
|
||||
|
@ -72,8 +72,8 @@ export interface AntTreeNodeDragEnterEvent extends AntTreeNodeMouseEvent {
|
|||
}
|
||||
|
||||
export interface AntTreeNodeDropEvent {
|
||||
node: DragNodeEvent;
|
||||
dragNode: DragNodeEvent;
|
||||
node: EventDataNode;
|
||||
dragNode: EventDataNode;
|
||||
dragNodesKeys: Key[];
|
||||
dropPosition: number;
|
||||
dropToGap?: boolean;
|
||||
|
@ -192,7 +192,7 @@ export default defineComponent({
|
|||
const {
|
||||
showIcon,
|
||||
showLine,
|
||||
switcherIcon = slots.switcherIcon?.(),
|
||||
switcherIcon = slots.switcherIcon,
|
||||
icon = slots.icon,
|
||||
blockNode,
|
||||
checkable,
|
||||
|
|
|
@ -2,19 +2,24 @@ import type { App, Plugin } from 'vue';
|
|||
import Tree from './Tree';
|
||||
import DirectoryTree from './DirectoryTree';
|
||||
|
||||
export { EventDataNode, DataNode } from '../vc-tree/interface';
|
||||
export type { EventDataNode, DataNode } from '../vc-tree/interface';
|
||||
|
||||
export {
|
||||
export type {
|
||||
TreeProps,
|
||||
AntTreeNodeMouseEvent,
|
||||
AntTreeNodeExpandedEvent,
|
||||
AntTreeNodeCheckedEvent,
|
||||
AntTreeNodeSelectedEvent,
|
||||
AntTreeNodeDragEnterEvent,
|
||||
AntTreeNodeDropEvent,
|
||||
AntdTreeNodeAttribute,
|
||||
TreeDataItem,
|
||||
} from './Tree';
|
||||
|
||||
export { ExpandAction as DirectoryTreeExpandAction, DirectoryTreeProps } from './DirectoryTree';
|
||||
export type {
|
||||
ExpandAction as DirectoryTreeExpandAction,
|
||||
DirectoryTreeProps,
|
||||
} from './DirectoryTree';
|
||||
|
||||
Tree.TreeNode.name = 'ATreeNode';
|
||||
Tree.DirectoryTree = DirectoryTree;
|
||||
|
|
|
@ -12,41 +12,46 @@ export default function renderSwitcherIcon(
|
|||
prefixCls: string,
|
||||
switcherIcon: any,
|
||||
showLine: boolean | { showLeafIcon: boolean } | undefined,
|
||||
{ isLeaf, expanded, loading }: AntTreeNodeProps,
|
||||
props: AntTreeNodeProps,
|
||||
) {
|
||||
const { isLeaf, expanded, loading } = props;
|
||||
let icon = switcherIcon;
|
||||
if (loading) {
|
||||
return <LoadingOutlined class={`${prefixCls}-switcher-loading-icon`} />;
|
||||
}
|
||||
let showLeafIcon;
|
||||
let showLeafIcon: boolean;
|
||||
if (showLine && typeof showLine === 'object') {
|
||||
showLeafIcon = showLine.showLeafIcon;
|
||||
}
|
||||
let defaultIcon = null;
|
||||
const switcherCls = `${prefixCls}-switcher-icon`;
|
||||
if (isLeaf) {
|
||||
if (showLine) {
|
||||
if (typeof showLine === 'object' && !showLeafIcon) {
|
||||
return <span class={`${prefixCls}-switcher-leaf-line`} />;
|
||||
defaultIcon = <span class={`${prefixCls}-switcher-leaf-line`} />;
|
||||
} else {
|
||||
defaultIcon = <FileOutlined class={`${prefixCls}-switcher-line-icon`} />;
|
||||
}
|
||||
return <FileOutlined class={`${prefixCls}-switcher-line-icon`} />;
|
||||
}
|
||||
return null;
|
||||
return defaultIcon;
|
||||
} else {
|
||||
defaultIcon = <CaretDownFilled class={switcherCls} />;
|
||||
if (showLine) {
|
||||
defaultIcon = expanded ? (
|
||||
<MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
|
||||
) : (
|
||||
<PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
|
||||
);
|
||||
}
|
||||
}
|
||||
const switcherCls = `${prefixCls}-switcher-icon`;
|
||||
if (isValidElement(switcherIcon)) {
|
||||
return cloneVNode(switcherIcon, {
|
||||
|
||||
if (typeof switcherIcon === 'function') {
|
||||
icon = switcherIcon({ ...props, defaultIcon, switcherCls });
|
||||
} else if (isValidElement(icon)) {
|
||||
icon = cloneVNode(icon, {
|
||||
class: switcherCls,
|
||||
});
|
||||
}
|
||||
|
||||
if (switcherIcon) {
|
||||
return switcherIcon;
|
||||
}
|
||||
|
||||
if (showLine) {
|
||||
return expanded ? (
|
||||
<MinusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
|
||||
) : (
|
||||
<PlusSquareOutlined class={`${prefixCls}-switcher-line-icon`} />
|
||||
);
|
||||
}
|
||||
return <CaretDownFilled class={switcherCls} />;
|
||||
return icon || defaultIcon;
|
||||
}
|
||||
|
|
|
@ -101,15 +101,16 @@ const SingleSelector = defineComponent<SelectorProps>({
|
|||
// custom tree-select title by slot
|
||||
if (item && treeSelectContext.value.slots) {
|
||||
titleNode =
|
||||
item.label ||
|
||||
treeSelectContext.value.slots[item?.option?.data?.slots?.title] ||
|
||||
treeSelectContext.value.slots.title;
|
||||
treeSelectContext.value.slots.title ||
|
||||
item.label;
|
||||
if (typeof titleNode === 'function') {
|
||||
titleNode = titleNode(item.option?.data || {});
|
||||
} else if (treeSelectContext.value.slots.titleRender) {
|
||||
// 因历史 title 是覆盖逻辑,新增 titleRender,所有的 title 都走一遍 titleRender
|
||||
titleNode = treeSelectContext.value.slots.titleRender(item.option?.data || {});
|
||||
}
|
||||
// else if (treeSelectContext.value.slots.titleRender) {
|
||||
// // 因历史 title 是覆盖逻辑,新增 titleRender,所有的 title 都走一遍 titleRender
|
||||
// titleNode = treeSelectContext.value.slots.titleRender(item.option?.data || {});
|
||||
// }
|
||||
} else {
|
||||
titleNode = item?.label;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { filterEmpty } from '../../_util/props-util';
|
||||
import type { VNodeChild } from 'vue';
|
||||
import { camelize } from 'vue';
|
||||
import { warning } from '../../vc-util/warning';
|
||||
|
@ -16,7 +17,7 @@ function isTreeSelectNode(node: any) {
|
|||
}
|
||||
export function convertChildrenToData(rootNodes: VNodeChild): DataNode[] {
|
||||
function dig(treeNodes: any[] = []): DataNode[] {
|
||||
return treeNodes.map(treeNode => {
|
||||
return filterEmpty(treeNodes).map(treeNode => {
|
||||
// Filter invalidate node
|
||||
if (!isTreeSelectNode(treeNode)) {
|
||||
warning(!treeNode, 'TreeSelect/TreeSelectNode can only accept TreeSelectNode as children.');
|
||||
|
|
|
@ -245,7 +245,7 @@ export default defineComponent({
|
|||
cleanDragState();
|
||||
|
||||
if (onDragend && !outsideTree) {
|
||||
onDragend({ event, node: node.eventData.value });
|
||||
onDragend({ event, node: node.eventData });
|
||||
}
|
||||
|
||||
dragNode = null;
|
||||
|
@ -267,17 +267,17 @@ export default defineComponent({
|
|||
y: event.clientY,
|
||||
};
|
||||
|
||||
const newExpandedKeys = arrDel(expandedKeys.value, eventKey.value);
|
||||
const newExpandedKeys = arrDel(expandedKeys.value, eventKey);
|
||||
|
||||
dragState.dragging = true;
|
||||
dragState.dragChildrenKeys = getDragChildrenKeys(eventKey.value, keyEntities.value);
|
||||
dragState.dragChildrenKeys = getDragChildrenKeys(eventKey, keyEntities.value);
|
||||
indent.value = listRef.value.getIndentWidth();
|
||||
|
||||
setExpandedKeys(newExpandedKeys);
|
||||
window.addEventListener('dragend', onWindowDragEnd);
|
||||
|
||||
if (onDragstart) {
|
||||
onDragstart({ event, node: eventData.value });
|
||||
onDragstart({ event, node: eventData });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -339,25 +339,25 @@ export default defineComponent({
|
|||
clearTimeout(delayedDragEnterLogic[key]);
|
||||
});
|
||||
|
||||
if (dragNode.eventKey.value !== node.eventKey.value) {
|
||||
if (dragNode.eventKey !== node.eventKey) {
|
||||
// hoist expand logic here
|
||||
// since if logic is on the bottom
|
||||
// it will be blocked by abstract dragover node check
|
||||
// => if you dragenter from top, you mouse will still be consider as in the top node
|
||||
delayedDragEnterLogic[node.pos.value] = window.setTimeout(() => {
|
||||
delayedDragEnterLogic[node.pos] = window.setTimeout(() => {
|
||||
if (!dragState.dragging) return;
|
||||
|
||||
let newExpandedKeys = [...expandedKeys.value];
|
||||
const entity = keyEntities.value[node.eventKey.value];
|
||||
const entity = keyEntities.value[node.eventKey];
|
||||
|
||||
if (entity && (entity.children || []).length) {
|
||||
newExpandedKeys = arrAdd(expandedKeys.value, node.eventKey.value);
|
||||
newExpandedKeys = arrAdd(expandedKeys.value, node.eventKey);
|
||||
}
|
||||
setExpandedKeys(newExpandedKeys);
|
||||
|
||||
if (onExpand) {
|
||||
onExpand(newExpandedKeys, {
|
||||
node: node.eventData.value,
|
||||
node: node.eventData,
|
||||
expanded: true,
|
||||
nativeEvent: event,
|
||||
});
|
||||
|
@ -366,7 +366,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
// Skip if drag node is self
|
||||
if (dragNode.eventKey.value === dropTargetKey && dropLevelOffset === 0) {
|
||||
if (dragNode.eventKey === dropTargetKey && dropLevelOffset === 0) {
|
||||
Object.assign(dragState, {
|
||||
dragOverNodeKey: null,
|
||||
dropPosition: null,
|
||||
|
@ -393,7 +393,7 @@ export default defineComponent({
|
|||
if (onDragenter) {
|
||||
onDragenter({
|
||||
event,
|
||||
node: node.eventData.value,
|
||||
node: node.eventData,
|
||||
expandedKeys: expandedKeys.value,
|
||||
});
|
||||
}
|
||||
|
@ -431,7 +431,7 @@ export default defineComponent({
|
|||
|
||||
// Update drag position
|
||||
|
||||
if (dragNode.eventKey.value === dropTargetKey && dropLevelOffset === 0) {
|
||||
if (dragNode.eventKey === dropTargetKey && dropLevelOffset === 0) {
|
||||
if (
|
||||
!(
|
||||
dragState.dropPosition === null &&
|
||||
|
@ -476,7 +476,7 @@ export default defineComponent({
|
|||
}
|
||||
|
||||
if (onDragover) {
|
||||
onDragover({ event, node: node.eventData.value });
|
||||
onDragover({ event, node: node.eventData });
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -484,7 +484,7 @@ export default defineComponent({
|
|||
const { onDragleave } = props;
|
||||
|
||||
if (onDragleave) {
|
||||
onDragleave({ event, node: node.eventData.value });
|
||||
onDragleave({ event, node: node.eventData });
|
||||
}
|
||||
};
|
||||
const onNodeDrop = (event: MouseEvent, _node, outsideTree = false) => {
|
||||
|
@ -517,8 +517,8 @@ export default defineComponent({
|
|||
const dropResult = {
|
||||
event,
|
||||
node: convertNodePropsToEventData(abstractDropNodeProps),
|
||||
dragNode: dragNode ? dragNode.eventData.value : null,
|
||||
dragNodesKeys: [dragNode.eventKey.value].concat(dragChildrenKeys),
|
||||
dragNode: dragNode ? dragNode.eventData : null,
|
||||
dragNodesKeys: [dragNode.eventKey].concat(dragChildrenKeys),
|
||||
dropToGap: dropPosition !== 0,
|
||||
dropPosition: dropPosition + Number(posArr[posArr.length - 1]),
|
||||
};
|
||||
|
|
|
@ -2,11 +2,20 @@ import { useInjectTreeContext } from './contextTypes';
|
|||
import { getDataAndAria } from './util';
|
||||
import Indent from './Indent';
|
||||
import { convertNodePropsToEventData } from './utils/treeUtil';
|
||||
import { computed, defineComponent, onMounted, onUpdated, ref } from 'vue';
|
||||
import {
|
||||
computed,
|
||||
defineComponent,
|
||||
getCurrentInstance,
|
||||
onMounted,
|
||||
onUpdated,
|
||||
reactive,
|
||||
ref,
|
||||
} from 'vue';
|
||||
import { treeNodeProps } from './props';
|
||||
import classNames from '../_util/classNames';
|
||||
import { warning } from '../vc-util/warning';
|
||||
import type { DragNodeEvent } from './interface';
|
||||
import type { DragNodeEvent, Key } from './interface';
|
||||
import pick from 'lodash-es/pick';
|
||||
|
||||
const ICON_OPEN = 'open';
|
||||
const ICON_CLOSE = 'close';
|
||||
|
@ -87,16 +96,36 @@ export default defineComponent({
|
|||
|
||||
return treeSelectable;
|
||||
});
|
||||
|
||||
const renderArgsData = computed(() => {
|
||||
return {
|
||||
...pick(props, [
|
||||
'active',
|
||||
'checkable',
|
||||
'checked',
|
||||
'disableCheckbox',
|
||||
'disabled',
|
||||
'expanded',
|
||||
'isLeaf',
|
||||
'loading',
|
||||
'selectable',
|
||||
'selected',
|
||||
'halfChecked',
|
||||
]),
|
||||
...props.data,
|
||||
dataRef: props.data,
|
||||
isLeaf: isLeaf.value,
|
||||
};
|
||||
});
|
||||
const eventData = computed(() => {
|
||||
return convertNodePropsToEventData(props);
|
||||
});
|
||||
const dragNodeEvent: DragNodeEvent = {
|
||||
const dragNodeEvent: DragNodeEvent = reactive({
|
||||
eventData,
|
||||
eventKey: computed(() => props.eventKey),
|
||||
selectHandle,
|
||||
pos: computed(() => props.pos),
|
||||
};
|
||||
key: getCurrentInstance().vnode.key as Key,
|
||||
});
|
||||
expose(dragNodeEvent);
|
||||
const onSelectorDoubleClick = (e: MouseEvent) => {
|
||||
const { onNodeDoubleClick } = context.value;
|
||||
|
@ -214,7 +243,7 @@ export default defineComponent({
|
|||
onNodeExpand(e, eventData.value);
|
||||
};
|
||||
|
||||
const renderSwitcherIconDom = (isLeaf: boolean) => {
|
||||
const renderSwitcherIconDom = () => {
|
||||
const {
|
||||
switcherIcon: switcherIconFromProps = slots.switcherIcon ||
|
||||
context.value.slots?.[props.data?.slots?.switcherIcon],
|
||||
|
@ -224,7 +253,7 @@ export default defineComponent({
|
|||
const switcherIcon = switcherIconFromProps || switcherIconFromCtx;
|
||||
// if switcherIconDom is null, no render switcher span
|
||||
if (typeof switcherIcon === 'function') {
|
||||
return switcherIcon({ ...props, isLeaf });
|
||||
return switcherIcon(renderArgsData.value);
|
||||
}
|
||||
return switcherIcon;
|
||||
};
|
||||
|
@ -259,11 +288,9 @@ export default defineComponent({
|
|||
const renderSwitcher = () => {
|
||||
const { expanded } = props;
|
||||
const { prefixCls } = context.value;
|
||||
|
||||
// if switcherIconDom is null, no render switcher span
|
||||
const switcherIconDom = renderSwitcherIconDom();
|
||||
if (isLeaf.value) {
|
||||
// if switcherIconDom is null, no render switcher span
|
||||
const switcherIconDom = renderSwitcherIconDom(true);
|
||||
|
||||
return switcherIconDom !== false ? (
|
||||
<span class={classNames(`${prefixCls}-switcher`, `${prefixCls}-switcher-noop`)}>
|
||||
{switcherIconDom}
|
||||
|
@ -276,8 +303,6 @@ export default defineComponent({
|
|||
`${prefixCls}-switcher_${expanded ? ICON_OPEN : ICON_CLOSE}`,
|
||||
);
|
||||
|
||||
const switcherIconDom = renderSwitcherIconDom(false);
|
||||
|
||||
return switcherIconDom !== false ? (
|
||||
<span onClick={onExpand} class={switcherCls}>
|
||||
{switcherIconDom}
|
||||
|
@ -348,14 +373,19 @@ export default defineComponent({
|
|||
// Icon + Title
|
||||
const renderSelector = () => {
|
||||
const {
|
||||
title = slots.title ||
|
||||
context.value.slots?.[props.data?.slots?.title] ||
|
||||
context.value.slots?.title,
|
||||
// title = slots.title ||
|
||||
// context.value.slots?.[props.data?.slots?.title] ||
|
||||
// context.value.slots?.title,
|
||||
selected,
|
||||
icon = slots.icon,
|
||||
loading,
|
||||
data,
|
||||
} = props;
|
||||
const title =
|
||||
slots.title ||
|
||||
context.value.slots?.[props.data?.slots?.title] ||
|
||||
context.value.slots?.title ||
|
||||
props.title;
|
||||
const {
|
||||
prefixCls,
|
||||
showIcon,
|
||||
|
@ -377,7 +407,7 @@ export default defineComponent({
|
|||
|
||||
$icon = currentIcon ? (
|
||||
<span class={classNames(`${prefixCls}-iconEle`, `${prefixCls}-icon__customize`)}>
|
||||
{typeof currentIcon === 'function' ? currentIcon(props) : currentIcon}
|
||||
{typeof currentIcon === 'function' ? currentIcon(renderArgsData.value) : currentIcon}
|
||||
</span>
|
||||
) : (
|
||||
renderIcon()
|
||||
|
@ -389,9 +419,9 @@ export default defineComponent({
|
|||
// Title
|
||||
let titleNode: any;
|
||||
if (typeof title === 'function') {
|
||||
titleNode = title(data);
|
||||
titleNode = title(renderArgsData.value);
|
||||
} else if (contextSlots.titleRender) {
|
||||
titleNode = contextSlots.titleRender(data);
|
||||
titleNode = contextSlots.titleRender(renderArgsData.value);
|
||||
} else {
|
||||
titleNode = title;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import type { ComputedRef, CSSProperties, Ref, VNode } from 'vue';
|
||||
import type { CSSProperties, VNode } from 'vue';
|
||||
import type { TreeNodeProps } from './props';
|
||||
export type { ScrollTo } from '../vc-virtual-list/List';
|
||||
|
||||
|
@ -43,10 +43,11 @@ export type Key = string | number;
|
|||
export type NodeElement = VNode<TreeNodeProps>;
|
||||
|
||||
export type DragNodeEvent = {
|
||||
eventData: ComputedRef<EventDataNode>;
|
||||
eventKey: ComputedRef<Key>;
|
||||
selectHandle: Ref<HTMLSpanElement>;
|
||||
pos: ComputedRef<string>;
|
||||
key: Key;
|
||||
eventData: EventDataNode;
|
||||
eventKey: Key;
|
||||
selectHandle: HTMLSpanElement;
|
||||
pos: string;
|
||||
};
|
||||
export interface Entity {
|
||||
node: NodeElement;
|
||||
|
|
|
@ -108,7 +108,7 @@ export function calcDropPosition(
|
|||
const rawDropLevelOffset = (horizontalMouseOffset - 12) / indent;
|
||||
|
||||
// find abstract drop node by horizontal offset
|
||||
let abstractDropNodeEntity: DataEntity = keyEntities[targetNode.eventKey.value];
|
||||
let abstractDropNodeEntity: DataEntity = keyEntities[targetNode.eventKey];
|
||||
|
||||
if (clientY < top + height / 2) {
|
||||
// first half, set abstract drop node to previous node
|
||||
|
@ -150,7 +150,7 @@ export function calcDropPosition(
|
|||
dropNode: abstractDropDataNode,
|
||||
dropPosition: -1,
|
||||
}) &&
|
||||
abstractDropNodeEntity.key === targetNode.eventKey.value
|
||||
abstractDropNodeEntity.key === targetNode.eventKey
|
||||
) {
|
||||
// first half of first node in first level
|
||||
dropPosition = -1;
|
||||
|
|
|
@ -14,6 +14,7 @@ import Omit from 'omit.js';
|
|||
import type { VNodeChild } from 'vue';
|
||||
import { camelize } from 'vue';
|
||||
import type { TreeNodeProps } from '../props';
|
||||
import { filterEmpty } from '../../_util/props-util';
|
||||
|
||||
export function getKey(key: Key, pos: string) {
|
||||
if (key !== null && key !== undefined) {
|
||||
|
@ -66,7 +67,7 @@ export function warningWithoutKey(treeData: DataNode[], fieldNames: FieldNames)
|
|||
*/
|
||||
export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
|
||||
function dig(node: VNodeChild = []): DataNode[] {
|
||||
const treeNodes = node as NodeElement[];
|
||||
const treeNodes = filterEmpty(node as NodeElement[]);
|
||||
return treeNodes.map(treeNode => {
|
||||
// Filter invalidate node
|
||||
if (!isTreeNode(treeNode)) {
|
||||
|
@ -114,7 +115,6 @@ export function convertTreeToData(rootNodes: VNodeChild): DataNode[] {
|
|||
return dataNode;
|
||||
});
|
||||
}
|
||||
|
||||
return dig(rootNodes);
|
||||
}
|
||||
|
||||
|
|
2
v2-doc
2
v2-doc
|
@ -1 +1 @@
|
|||
Subproject commit 3f94a02d16bac2377d71e26948ffe45571dae49e
|
||||
Subproject commit bf82708b6f320f1e9b185c6eba58b4ce08593fc3
|
Loading…
Reference in New Issue