LCOV - code coverage report
Current view: top level - src/components/SSVGPropEdit - RelationEdit.vue.js (source / functions) Hit Total Coverage
Test: lcov.info Lines: 23 79 29.1 %
Date: 2025-06-29 02:18:36 Functions: 12 21 57.1 %

          Line data    Source code
       1             : // @ts-check
       2             : 
       3             : import Vue from "vue";
       4             : import { mapState } from "vuex";
       5             : import { get, isNil, noop } from "lodash";
       6             : import { select } from "d3-selection";
       7             : import { isCSS } from "@cern/ssvg-engine";
       8             : import RelationCodeEditor from "./RelationCodeEditor.vue";
       9             : import Card from "../Card.vue";
      10             : import { getAttribute } from "../../utils/element";
      11             : import d from "debug";
      12             : import RelationEditValue from "./RelationEditValue.vue";
      13             : import { BaseKeyboardEventMixin as KBMixin } from "@cern/base-vue";
      14             : 
      15           1 : const debug = d("app:edit");
      16             : 
      17             : /**
      18             :  * @typedef {{ card: V.Instance<Card>, cm: V.Instance<RelationCodeEditor> }} Refs
      19             :  */
      20             : 
      21             : export default /** @type {V.Constructor<any, Refs>} */(Vue).extend({
      22             :   name: "RelationEdit",
      23             :   components: { Card, RelationCodeEditor, RelationEditValue },
      24             :   mixins: [ KBMixin({ local: true }) ],
      25             :   props: { title: { type: String, default: "Relation" } },
      26             :   /**
      27             :    * @return {{
      28             :    *  selection: any,
      29             :    *  directSelection: any,
      30             :    *  value: any,
      31             :    *  timer: NodeJS.Timeout|null,
      32             :    *  attributeName: string,
      33             :    *  querySelector: string,
      34             :    *  attributeType: string,
      35             :    *  initialValue: any,
      36             :    * }}
      37             :    */
      38             :   data() {
      39           3 :     return {
      40             :       selection: null,
      41             :       directSelection: null,
      42             :       value: null,
      43             :       timer: null,
      44             :       attributeName: "",
      45             :       querySelector: "",
      46             :       attributeType: "auto",
      47             :       initialValue: undefined
      48             :     };
      49             :   },
      50             :   computed: {
      51             :     .../**
      52             :       @type {{ normalizedValue(): number, relation(): Element|null }}
      53             :     */(mapState("selection", [ "relation", "normalizedValue" ])),
      54             :     .../**
      55             :       @type {{ directSvg(): any, svg(): any, state(): any, svgSelectors(): any }}
      56             :     */(mapState("engine", {
      57           5 :       directSvg: (state) => get(state, [ "directEngine", "svg" ]),
      58           5 :       svg: (state) => get(state, [ "engine", "svg" ]),
      59           7 :       state: (state) => get(state, [ "state" ]),
      60           0 :       svgSelectors: (state) => get(state, [ "svgSelectors" ])
      61             :     })),
      62             :     .../** @type {{ showKeyHints(): boolean }} */(mapState("ui", [ "showKeyHints" ]))
      63             :   },
      64             :   watch: {
      65             :     relation: {
      66             :       immediate: true,
      67           5 :       handler() { this.restore(); this.load(); }
      68             :     },
      69           2 :     svg() { this.updateSelection(); },
      70             :     state: {
      71             :       immediate: true,
      72             :       deep: true,
      73             :       handler() {
      74           7 :         if (this.timer) {
      75           4 :           clearTimeout(this.timer);
      76             :         }
      77           7 :         this.timer = setTimeout(this.onTimer, 150);
      78             :       }
      79             :     }
      80             :   },
      81             :   mounted() {
      82           3 :     this.onKey("ctrl-s-keydown", (/** @type {Event} */e) => {
      83           0 :       if (this.$refs.card?.isFocused) {
      84           0 :         e.preventDefault(); this.doApply();
      85             :       }
      86             :     });
      87             :   },
      88             :   beforeDestroy() {
      89           3 :     if (this.timer) {
      90           3 :       clearTimeout(this.timer);
      91             :     }
      92           3 :     this.restore();
      93             :   },
      94             :   methods: {
      95             :     load() {
      96           5 :       this.attributeName = getAttribute(this.relation, "attribute-name");
      97           5 :       this.querySelector = getAttribute(this.relation, "query-selector");
      98           5 :       this.attributeType = getAttribute(this.relation, "attribute-type") || "auto";
      99           5 :       this.updateSelection();
     100             :     },
     101             :     updateSelection() {
     102           7 :       this.selection = select(this.svg).selectAll(this.querySelector);
     103           7 :       this.directSelection = select(this.directSvg).selectAll(this.querySelector);
     104             :     },
     105             :     onTimer() {
     106           0 :       if (!this.$refs.card?.isFocused) {
     107           0 :         const attributeName = this.getAttributeName();
     108           0 :         if (!this.directSelection?.node()) {
     109           0 :           this.value = null;
     110             :         }
     111           0 :         else if (isNil(attributeName)) {
     112           0 :           this.value = this.directSelection.text();
     113             :         }
     114           0 :         else if ("CSS" === this.getAttributeType()) {
     115           0 :           this.value = this.directSelection.style(attributeName);
     116             :         }
     117             :         else {
     118           0 :           this.value = this.directSelection.attr(attributeName);
     119             :         }
     120             :       }
     121           0 :       this.timer = setTimeout(this.onTimer, 500);
     122             :     },
     123             :     /**
     124             :      * @param  {string} value
     125             :      */ /* eslint-disable-next-line complexity */
     126             :     setValue(value) {
     127           0 :       debug("setValue:%s", value);
     128           0 :       if (!this.selection || !this.directSelection) { return; }
     129             : 
     130           0 :       this.value = value;
     131           0 :       const attributeName = this.getAttributeName();
     132           0 :       if (isNil(attributeName)) {
     133           0 :         if (this.initialValue === undefined && this.selection?.node()) {
     134           0 :           this.initialValue = this.selection.text();
     135             :         }
     136           0 :         this.selection.text(value);
     137           0 :         this.directSelection.text(value);
     138             :       }
     139           0 :       else if ("CSS" === this.getAttributeType()) {
     140           0 :         if (this.initialValue === undefined && this.selection?.node()) {
     141           0 :           this.initialValue = this.selection.style(attributeName);
     142             :         }
     143           0 :         this.selection.style(attributeName, value);
     144           0 :         this.directSelection.style(attributeName, value);
     145             :       }
     146             :       else {
     147           0 :         if (this.initialValue === undefined && this.selection?.node()) {
     148           0 :           this.initialValue = this.selection.attr(attributeName);
     149             :         }
     150           0 :         this.selection.attr(attributeName, value);
     151           0 :         this.directSelection.attr(attributeName, value);
     152             :       }
     153           0 :       debug("set initalValue:%s", this.initialValue);
     154             :     },
     155             :     restore() {
     156           8 :       debug("restore value:%s", this.initialValue);
     157           8 :       if (!this.selection || !this.directSelection) { return; }
     158           5 :       else if (this.initialValue === undefined) { return; }
     159             : 
     160           0 :       const attributeName = this.getAttributeName();
     161           0 :       if (isNil(attributeName)) {
     162           0 :         this.selection.text(this.initialValue);
     163           0 :         this.directSelection.text(this.initialValue);
     164             :       }
     165           0 :       else if ("CSS" === this.getAttributeType()) {
     166           0 :         this.selection.style(attributeName, this.initialValue);
     167           0 :         this.directSelection.style(attributeName, this.initialValue);
     168             :       }
     169             :       else {
     170           0 :         this.selection.attr(attributeName, this.initialValue);
     171           0 :         this.directSelection.attr(attributeName, this.initialValue);
     172             :       }
     173           0 :       this.value = this.initialValue;
     174           0 :       this.initialValue = undefined;
     175             :     },
     176             :     /**
     177             :      * @param {string} name
     178             :      * @param {string} value
     179             :      */
     180             :     setParam(name, value) {
     181           0 :       debug("setParam %s=%s", name, value);
     182           0 :       this.restore();
     183           0 :       Vue.set(this, name, value);
     184           0 :       this.updateSelection();
     185           0 :       this.setValue(this.value);
     186             :     },
     187             :     /**
     188             :      * @return {string}
     189             :      */
     190             :     getAttributeType() {
     191           0 :       if (!this.attributeType || this.attributeType === "auto") {
     192           0 :         return isCSS(this.getAttributeName()) ? "CSS" : "XML";
     193             :       }
     194             :       else {
     195           0 :         return this.attributeType;
     196             :       }
     197             :     },
     198             :     /**
     199             :      * @return {string}
     200             :      */
     201             :     getAttributeName() {
     202           0 :       return this.attributeName;
     203             :     },
     204             :     async doApply() {
     205           0 :       if (!this.relation) { return; }
     206           0 :       this.$refs.cm?.doApply();
     207             :     },
     208             :     doDelete() {
     209           0 :       if (!this.relation) { return; }
     210           0 :       this.$store.dispatch("remove", "relation").catch(noop);
     211             :     }
     212             :   }
     213             : });

Generated by: LCOV version 1.16