Skip to content
Snippets Groups Projects
KeyboardDisplay.vue 3.79 KiB
Newer Older
  <div>
Valentin Rigal's avatar
Valentin Rigal committed
    <div v-if="!charTable">An error occured loading the keyboard</div>
    <div v-else v-for="(row, i) in charTable" :key="i">
      <span v-for="(char, j) in row" :key="j">
        <!-- Emit a key of the keyboard or its position when it is empty -->
Valentin Rigal's avatar
Valentin Rigal committed
        <button
          :class="{
            'is-selected':
              selectedKey && selectedKey.row == i && selectedKey.column == j,
          }"
Valentin Rigal's avatar
Valentin Rigal committed
          type="button"
          v-on:mouseup="
            char ? $emit('input', char) : $emit('input', { row: i, column: j })
          "
Valentin Rigal's avatar
Valentin Rigal committed
        >
          <template v-if="char">{{ char.character }}</template>
          <template v-else>&nbsp;</template>
Valentin Rigal's avatar
Valentin Rigal committed
        </button>
      </span>
    </div>
    <template v-if="resizable">
      <label>Rows</label>
      <!-- Directly parse field value to handle integers only -->
      <input
        :value="rows"
        v-on:change.prevent="(e) => updateRows(e.target.value)"
        :min="rowsCount"
        :max="maxKeyboardSize"
        type="number"
      />
      <label>Columns</label>
      <input
        :value="columns"
        v-on:change.prevent="(e) => updateColumns(e.target.value)"
        :min="columnsCount"
        :max="maxKeyboardSize"
        type="number"
      />
    </template>
import { mapState } from "vuex";
import { maxKeyboardSize } from "../config.js";
    // Row and column value of the selected keyboard key
    selectedKey: {
      type: Object,
      default: null,
    },
    resizable: {
      type: Boolean,
      default: false,
    },
  data: () => ({
    // Rows and columns including a potential resize of the keyboard
    rows: 0,
    columns: 0,
    maxKeyboardSize,
  }),
Valentin Rigal's avatar
Valentin Rigal committed
  computed: {
    keyboard() {
      return this.keyboards[this.keyboardIndex];
    },
Valentin Rigal's avatar
Valentin Rigal committed
    characters() {
      return this.keyboard && this.keyboard.characters;
Valentin Rigal's avatar
Valentin Rigal committed
    rowsCount() {
      // Return the number of rows from keyboard characters
      if (!this.characters.length) return 1;
Valentin Rigal's avatar
Valentin Rigal committed
      return (
        this.characters && Math.max(...this.characters.map((c) => c.row)) + 1
      );
Valentin Rigal's avatar
Valentin Rigal committed
    columnsCount() {
      // Return the number of columns from keyboard characters
      if (!this.characters.length) return 1;
Valentin Rigal's avatar
Valentin Rigal committed
      return (
        this.characters && Math.max(...this.characters.map((c) => c.column)) + 1
      );
Valentin Rigal's avatar
Valentin Rigal committed
    charTable() {
      const [tableRows, tableCols] = this.resizable
        ? [this.rows, this.columns]
        : [this.rowsCount, this.columnsCount];
      if (!tableRows || !tableCols) return;
Valentin Rigal's avatar
Valentin Rigal committed
      // Return a list of every column with padding
      const table = Array.from(Array(tableRows), () => new Array(tableCols));
Valentin Rigal's avatar
Valentin Rigal committed
      if (!this.characters) return table;
      this.characters.forEach((c) => {
        table[c.row][c.column] = c;
      });
      return table;
  methods: {
    // We need to handle input changes manually as v-model.number allows random numbers or empty strings
    updateRows(value) {
      if (isNaN(value) || value < this.rowsCount || value > maxKeyboardSize)
        return;
      this.rows = parseInt(value);
    },
    updateColumns(value) {
      if (isNaN(value) || value < this.columnsCount || value > maxKeyboardSize)
        return;
      this.columns = parseInt(value);
    },
  },
  watch: {
    rowsCount: {
      immediate: true,
      handler(n) {
        if (!this.rows) this.rows = n || 1;
      },
    },
    columnsCount: {
      immediate: true,
      handler(n) {
        if (!this.columns) this.columns = n || 1;
      },
    },
  },
  width: 3rem;
  height: 3rem;
  margin: 0.1rem;
button.is-selected {
  border: solid black 0.25rem;
  border-radius: 0.25rem;
}