Makros: UI (Button-Objekt, Verwaltungspanel, Symbolleiste)
Zweiter von zwei Commits (Fundament in e670f13). Neues, frei platzierbares
Button-Objekt auf der Fläche, das per Klick ein zugewiesenes Makro
ausführt (Zuweisung im Inspektor oder per Rechtsklick direkt am Button).
Neues "▶ Makros"-Panel (Liste + Formular, dritter "▶ Ausführen"-Button pro
Zeile) für Anlegen/Bearbeiten/Löschen/Testlauf ohne Canvas-Button.
Beim Live-Testen gefunden und behoben: ADDTABLE/ADDSHEET navigieren als
Nebeneffekt zur eingefügten Tabelle/zum eingefügten Blatt (richtig für
einen Symbolleisten-Klick, überraschend für einen Makro-Lauf im
Hintergrund) — runMacro() sichert und stellt jetzt aktives Blatt/Objekt/
Auswahl nach dem Lauf wieder her. Nebenbei zwei bestehende
"impliziter-Else"-Fehler behoben, die mit einer vierten Objektart zu
echten Fehlerquellen geworden wären (io/json.ts normaliseObject,
CanvasObject.vue Render-Dispatch).
Vollständig live per Playwright End-zu-Ende verifiziert: Makro über das
echte Formular angelegt, per Listen-Button und per Button-Objekt
ausgeführt, Rechtsklick-Zuweisung geprüft, ein absichtlich fehlerhaftes
Makro zeigt einen Fehler-Toast statt abzustürzen — keine Konsolenfehler.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* Draggable / resizable wrapper for a table or chart object on the sheet canvas.
|
||||
* Draggable / resizable wrapper for a table, chart, text or button object on
|
||||
* the sheet canvas.
|
||||
*
|
||||
* - the header strip and the frame border move the object;
|
||||
* - the SE handle resizes a chart/text freely; for a table, what it does
|
||||
@@ -25,6 +26,7 @@ import { useDocument } from '../store/document';
|
||||
import TableGrid from './TableGrid.vue';
|
||||
import ChartView from './ChartView.vue';
|
||||
import TextBox from './TextBox.vue';
|
||||
import ButtonView from './ButtonView.vue';
|
||||
|
||||
const props = defineProps<{ object: SheetObject; selected: boolean; zoom: number }>();
|
||||
const emit = defineEmits<{ (e: 'select'): void }>();
|
||||
@@ -139,7 +141,7 @@ function lastNonEmptyCol(t: TableObject): number {
|
||||
* "Automatisch" vs. "Feste Größe" split. */
|
||||
const resizeKind = computed<'free' | 'viewport' | 'grid-size'>(() => {
|
||||
const o = props.object;
|
||||
if (o.kind === 'chart' || o.kind === 'text') return 'free';
|
||||
if (o.kind === 'chart' || o.kind === 'text' || o.kind === 'button') return 'free';
|
||||
return o.view.mode === 'fixed' ? 'viewport' : 'grid-size';
|
||||
});
|
||||
|
||||
@@ -150,7 +152,7 @@ function onResizeDown(e: MouseEvent) {
|
||||
const o = props.object;
|
||||
let w: number;
|
||||
let h: number;
|
||||
if (o.kind === 'chart' || o.kind === 'text') {
|
||||
if (o.kind === 'chart' || o.kind === 'text' || o.kind === 'button') {
|
||||
w = o.width;
|
||||
h = o.height;
|
||||
} else if (o.view.mode === 'fixed') {
|
||||
@@ -174,6 +176,7 @@ function onResizeMove(e: MouseEvent) {
|
||||
if (resizeKind.value === 'free') {
|
||||
if (o.kind === 'chart') store.resizeChart(o.id, rs.w + dx, rs.h + dy);
|
||||
else if (o.kind === 'text') store.resizeText(o.id, rs.w + dx, rs.h + dy);
|
||||
else if (o.kind === 'button') store.resizeButton(o.id, rs.w + dx, rs.h + dy);
|
||||
} else if (resizeKind.value === 'viewport') {
|
||||
// "Feste Größe": pure pixel-viewport resize, independent of row/col
|
||||
// count -- cheap (setTableView never rebuilds the workbook), so a live
|
||||
@@ -205,14 +208,24 @@ function onResizeUp() {
|
||||
window.removeEventListener('mouseup', onResizeUp);
|
||||
}
|
||||
|
||||
const icon = computed(() =>
|
||||
props.object.kind === 'table' ? '▦' : props.object.kind === 'chart' ? '▤' : '¶',
|
||||
);
|
||||
const icon = computed(() => {
|
||||
switch (props.object.kind) {
|
||||
case 'table':
|
||||
return '▦';
|
||||
case 'chart':
|
||||
return '▤';
|
||||
case 'button':
|
||||
return '▶';
|
||||
case 'text':
|
||||
default:
|
||||
return '¶';
|
||||
}
|
||||
});
|
||||
|
||||
const style = computed(() => {
|
||||
const o = props.object;
|
||||
const base: Record<string, string> = { left: o.x + 'px', top: o.y + 'px' };
|
||||
if (o.kind === 'chart' || o.kind === 'text') {
|
||||
if (o.kind === 'chart' || o.kind === 'text' || o.kind === 'button') {
|
||||
base.width = o.width + 'px';
|
||||
base.height = o.height + 'px';
|
||||
}
|
||||
@@ -223,7 +236,7 @@ const style = computed(() => {
|
||||
<template>
|
||||
<div
|
||||
class="canvas-object"
|
||||
:class="{ selected, flex: object.kind === 'chart' || object.kind === 'text' }"
|
||||
:class="{ selected, flex: object.kind === 'chart' || object.kind === 'text' || object.kind === 'button' }"
|
||||
:style="style"
|
||||
@mousedown="emit('select')"
|
||||
>
|
||||
@@ -254,7 +267,8 @@ const style = computed(() => {
|
||||
<div class="content">
|
||||
<TableGrid v-if="object.kind === 'table'" :table-id="object.id" />
|
||||
<ChartView v-else-if="object.kind === 'chart'" :obj-id="object.id" />
|
||||
<TextBox v-else :obj-id="object.id" />
|
||||
<TextBox v-else-if="object.kind === 'text'" :obj-id="object.id" />
|
||||
<ButtonView v-else-if="object.kind === 'button'" :obj-id="object.id" />
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
||||
Reference in New Issue
Block a user