デッキまわりをCompositon API / Setup Sugarに (#8410)
* universal.widgets.vue * column.vue, antenna-column.vue * direct-column.vue, list-column.vue * main-column.vue * wip * ✌️ * fix * ✌️ * ✌️
This commit is contained in:
@@ -31,238 +31,211 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from 'vue';
|
||||
export type DeckFunc = {
|
||||
title: string;
|
||||
handler: (payload: MouseEvent) => void;
|
||||
icon?: string;
|
||||
};
|
||||
</script>
|
||||
<script lang="ts" setup>
|
||||
import { onBeforeUnmount, onMounted, provide, watch } from 'vue';
|
||||
import * as os from '@/os';
|
||||
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn } from './deck-store';
|
||||
import { updateColumn, swapLeftColumn, swapRightColumn, swapUpColumn, swapDownColumn, stackLeftColumn, popRightColumn, removeColumn, swapColumn, Column } from './deck-store';
|
||||
import { deckStore } from './deck-store';
|
||||
import { i18n } from '@/i18n';
|
||||
|
||||
export default defineComponent({
|
||||
provide: {
|
||||
shouldHeaderThin: true,
|
||||
shouldOmitHeaderTitle: true,
|
||||
},
|
||||
provide('shouldHeaderThin', true);
|
||||
provide('shouldOmitHeaderTitle', true);
|
||||
|
||||
props: {
|
||||
column: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
isStacked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
func: {
|
||||
type: Object,
|
||||
required: false,
|
||||
default: null
|
||||
},
|
||||
naked: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
indicated: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return {
|
||||
deckStore,
|
||||
dragging: false,
|
||||
draghover: false,
|
||||
dropready: false,
|
||||
};
|
||||
},
|
||||
|
||||
computed: {
|
||||
isMainColumn(): boolean {
|
||||
return this.column.type === 'main';
|
||||
},
|
||||
|
||||
active(): boolean {
|
||||
return this.column.active !== false;
|
||||
},
|
||||
|
||||
keymap(): any {
|
||||
return {
|
||||
'shift+up': () => this.$parent.$emit('parent-focus', 'up'),
|
||||
'shift+down': () => this.$parent.$emit('parent-focus', 'down'),
|
||||
'shift+left': () => this.$parent.$emit('parent-focus', 'left'),
|
||||
'shift+right': () => this.$parent.$emit('parent-focus', 'right'),
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
active(v) {
|
||||
this.$emit('change-active-state', v);
|
||||
},
|
||||
|
||||
dragging(v) {
|
||||
os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd');
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
os.deckGlobalEvents.on('column.dragStart', this.onOtherDragStart);
|
||||
os.deckGlobalEvents.on('column.dragEnd', this.onOtherDragEnd);
|
||||
},
|
||||
|
||||
beforeUnmount() {
|
||||
os.deckGlobalEvents.off('column.dragStart', this.onOtherDragStart);
|
||||
os.deckGlobalEvents.off('column.dragEnd', this.onOtherDragEnd);
|
||||
},
|
||||
|
||||
methods: {
|
||||
onOtherDragStart() {
|
||||
this.dropready = true;
|
||||
},
|
||||
|
||||
onOtherDragEnd() {
|
||||
this.dropready = false;
|
||||
},
|
||||
|
||||
toggleActive() {
|
||||
if (!this.isStacked) return;
|
||||
updateColumn(this.column.id, {
|
||||
active: !this.column.active
|
||||
});
|
||||
},
|
||||
|
||||
getMenu() {
|
||||
const items = [{
|
||||
icon: 'fas fa-pencil-alt',
|
||||
text: this.$ts.edit,
|
||||
action: async () => {
|
||||
const { canceled, result } = await os.form(this.column.name, {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: this.$ts.name,
|
||||
default: this.column.name
|
||||
},
|
||||
width: {
|
||||
type: 'number',
|
||||
label: this.$ts.width,
|
||||
default: this.column.width
|
||||
},
|
||||
flexible: {
|
||||
type: 'boolean',
|
||||
label: this.$ts.flexible,
|
||||
default: this.column.flexible
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
updateColumn(this.column.id, result);
|
||||
}
|
||||
}, null, {
|
||||
icon: 'fas fa-arrow-left',
|
||||
text: this.$ts._deck.swapLeft,
|
||||
action: () => {
|
||||
swapLeftColumn(this.column.id);
|
||||
}
|
||||
}, {
|
||||
icon: 'fas fa-arrow-right',
|
||||
text: this.$ts._deck.swapRight,
|
||||
action: () => {
|
||||
swapRightColumn(this.column.id);
|
||||
}
|
||||
}, this.isStacked ? {
|
||||
icon: 'fas fa-arrow-up',
|
||||
text: this.$ts._deck.swapUp,
|
||||
action: () => {
|
||||
swapUpColumn(this.column.id);
|
||||
}
|
||||
} : undefined, this.isStacked ? {
|
||||
icon: 'fas fa-arrow-down',
|
||||
text: this.$ts._deck.swapDown,
|
||||
action: () => {
|
||||
swapDownColumn(this.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: 'fas fa-window-restore',
|
||||
text: this.$ts._deck.stackLeft,
|
||||
action: () => {
|
||||
stackLeftColumn(this.column.id);
|
||||
}
|
||||
}, this.isStacked ? {
|
||||
icon: 'fas fa-window-maximize',
|
||||
text: this.$ts._deck.popRight,
|
||||
action: () => {
|
||||
popRightColumn(this.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: 'fas fa-trash-alt',
|
||||
text: this.$ts.remove,
|
||||
danger: true,
|
||||
action: () => {
|
||||
removeColumn(this.column.id);
|
||||
}
|
||||
}];
|
||||
|
||||
return items;
|
||||
},
|
||||
|
||||
onContextmenu(ev: MouseEvent) {
|
||||
os.contextMenu(this.getMenu(), ev);
|
||||
},
|
||||
|
||||
goTop() {
|
||||
this.$refs.body.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
},
|
||||
|
||||
onDragstart(e) {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, this.column.id);
|
||||
|
||||
// Chromeのバグで、Dragstartハンドラ内ですぐにDOMを変更する(=リアクティブなプロパティを変更する)とDragが終了してしまう
|
||||
// SEE: https://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
|
||||
window.setTimeout(() => {
|
||||
this.dragging = true;
|
||||
}, 10);
|
||||
},
|
||||
|
||||
onDragend(e) {
|
||||
this.dragging = false;
|
||||
},
|
||||
|
||||
onDragover(e) {
|
||||
// 自分自身がドラッグされている場合
|
||||
if (this.dragging) {
|
||||
// 自分自身にはドロップさせない
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const isDeckColumn = e.dataTransfer.types[0] == _DATA_TRANSFER_DECK_COLUMN_;
|
||||
|
||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||
|
||||
if (!this.dragging && isDeckColumn) this.draghover = true;
|
||||
},
|
||||
|
||||
onDragleave() {
|
||||
this.draghover = false;
|
||||
},
|
||||
|
||||
onDrop(e) {
|
||||
this.draghover = false;
|
||||
os.deckGlobalEvents.emit('column.dragEnd');
|
||||
|
||||
const id = e.dataTransfer.getData(_DATA_TRANSFER_DECK_COLUMN_);
|
||||
if (id != null && id != '') {
|
||||
swapColumn(this.column.id, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
const props = withDefaults(defineProps<{
|
||||
column: Column;
|
||||
isStacked?: boolean;
|
||||
func?: DeckFunc | null;
|
||||
naked?: boolean;
|
||||
indicated?: boolean;
|
||||
}>(), {
|
||||
isStacked: false,
|
||||
func: null,
|
||||
naked: false,
|
||||
indicated: false,
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
(e: 'parent-focus', direction: 'up' | 'down' | 'left' | 'right'): void;
|
||||
(e: 'change-active-state', v: boolean): void;
|
||||
}>();
|
||||
|
||||
let body = $ref<HTMLDivElement>();
|
||||
|
||||
let dragging = $ref(false);
|
||||
watch($$(dragging), v => os.deckGlobalEvents.emit(v ? 'column.dragStart' : 'column.dragEnd'));
|
||||
|
||||
let draghover = $ref(false);
|
||||
let dropready = $ref(false);
|
||||
|
||||
const isMainColumn = $computed(() => props.column.type === 'main');
|
||||
const active = $computed(() => props.column.active !== false);
|
||||
watch($$(active), v => emit('change-active-state', v));
|
||||
|
||||
const keymap = $computed(() => ({
|
||||
'shift+up': () => emit('parent-focus', 'up'),
|
||||
'shift+down': () => emit('parent-focus', 'down'),
|
||||
'shift+left': () => emit('parent-focus', 'left'),
|
||||
'shift+right': () => emit('parent-focus', 'right'),
|
||||
}));
|
||||
|
||||
onMounted(() => {
|
||||
os.deckGlobalEvents.on('column.dragStart', onOtherDragStart);
|
||||
os.deckGlobalEvents.on('column.dragEnd', onOtherDragEnd);
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
os.deckGlobalEvents.off('column.dragStart', onOtherDragStart);
|
||||
os.deckGlobalEvents.off('column.dragEnd', onOtherDragEnd);
|
||||
});
|
||||
|
||||
|
||||
function onOtherDragStart() {
|
||||
dropready = true;
|
||||
}
|
||||
|
||||
function onOtherDragEnd() {
|
||||
dropready = false;
|
||||
}
|
||||
|
||||
function toggleActive() {
|
||||
if (!props.isStacked) return;
|
||||
updateColumn(props.column.id, {
|
||||
active: !props.column.active
|
||||
});
|
||||
}
|
||||
|
||||
function getMenu() {
|
||||
const items = [{
|
||||
icon: 'fas fa-pencil-alt',
|
||||
text: i18n.ts.edit,
|
||||
action: async () => {
|
||||
const { canceled, result } = await os.form(props.column.name, {
|
||||
name: {
|
||||
type: 'string',
|
||||
label: i18n.ts.name,
|
||||
default: props.column.name
|
||||
},
|
||||
width: {
|
||||
type: 'number',
|
||||
label: i18n.ts.width,
|
||||
default: props.column.width
|
||||
},
|
||||
flexible: {
|
||||
type: 'boolean',
|
||||
label: i18n.ts.flexible,
|
||||
default: props.column.flexible
|
||||
}
|
||||
});
|
||||
if (canceled) return;
|
||||
updateColumn(props.column.id, result);
|
||||
}
|
||||
}, null, {
|
||||
icon: 'fas fa-arrow-left',
|
||||
text: i18n.ts._deck.swapLeft,
|
||||
action: () => {
|
||||
swapLeftColumn(props.column.id);
|
||||
}
|
||||
}, {
|
||||
icon: 'fas fa-arrow-right',
|
||||
text: i18n.ts._deck.swapRight,
|
||||
action: () => {
|
||||
swapRightColumn(props.column.id);
|
||||
}
|
||||
}, props.isStacked ? {
|
||||
icon: 'fas fa-arrow-up',
|
||||
text: i18n.ts._deck.swapUp,
|
||||
action: () => {
|
||||
swapUpColumn(props.column.id);
|
||||
}
|
||||
} : undefined, props.isStacked ? {
|
||||
icon: 'fas fa-arrow-down',
|
||||
text: i18n.ts._deck.swapDown,
|
||||
action: () => {
|
||||
swapDownColumn(props.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: 'fas fa-window-restore',
|
||||
text: i18n.ts._deck.stackLeft,
|
||||
action: () => {
|
||||
stackLeftColumn(props.column.id);
|
||||
}
|
||||
}, props.isStacked ? {
|
||||
icon: 'fas fa-window-maximize',
|
||||
text: i18n.ts._deck.popRight,
|
||||
action: () => {
|
||||
popRightColumn(props.column.id);
|
||||
}
|
||||
} : undefined, null, {
|
||||
icon: 'fas fa-trash-alt',
|
||||
text: i18n.ts.remove,
|
||||
danger: true,
|
||||
action: () => {
|
||||
removeColumn(props.column.id);
|
||||
}
|
||||
}];
|
||||
return items;
|
||||
}
|
||||
|
||||
function onContextmenu(ev: MouseEvent) {
|
||||
os.contextMenu(getMenu(), ev);
|
||||
}
|
||||
|
||||
function goTop() {
|
||||
body.scrollTo({
|
||||
top: 0,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
|
||||
function onDragstart(e) {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
e.dataTransfer.setData(_DATA_TRANSFER_DECK_COLUMN_, props.column.id);
|
||||
|
||||
// Chromeのバグで、Dragstartハンドラ内ですぐにDOMを変更する(=リアクティブなプロパティを変更する)とDragが終了してしまう
|
||||
// SEE: https://stackoverflow.com/questions/19639969/html5-dragend-event-firing-immediately
|
||||
window.setTimeout(() => {
|
||||
dragging = true;
|
||||
}, 10);
|
||||
}
|
||||
|
||||
function onDragend(e) {
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
function onDragover(e) {
|
||||
// 自分自身がドラッグされている場合
|
||||
if (dragging) {
|
||||
// 自分自身にはドロップさせない
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
return;
|
||||
}
|
||||
|
||||
const isDeckColumn = e.dataTransfer.types[0] == _DATA_TRANSFER_DECK_COLUMN_;
|
||||
|
||||
e.dataTransfer.dropEffect = isDeckColumn ? 'move' : 'none';
|
||||
|
||||
if (!dragging && isDeckColumn) draghover = true;
|
||||
}
|
||||
|
||||
function onDragleave() {
|
||||
draghover = false;
|
||||
}
|
||||
|
||||
function onDrop(e) {
|
||||
draghover = false;
|
||||
os.deckGlobalEvents.emit('column.dragEnd');
|
||||
|
||||
const id = e.dataTransfer.getData(_DATA_TRANSFER_DECK_COLUMN_);
|
||||
if (id != null && id != '') {
|
||||
swapColumn(props.column.id, id);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
Reference in New Issue
Block a user