Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import { ExplorerGrammar } from "../explorer/ExplorerGrammar"
import { ExplorerProgram } from "../explorer/ExplorerProgram"
import { CellPosition } from "../gridLang/GridLangConstants"
import Handsontable from "handsontable"
import HotContextMenu from "handsontable/plugins/contextMenu"
abstract class HotCommand {
protected program: ExplorerProgram
protected setProgramCallback?: (newProgram: string) => void
constructor(
program: ExplorerProgram,
setProgramCallback?: (newProgram: string) => void
) {
this.program = program
this.setProgramCallback = setProgramCallback
}
abstract name(hot: Handsontable): string
abstract callback(hot: Handsontable): void
abstract disabled(hot: Handsontable): boolean
abstract hidden(hot: Handsontable): boolean
protected selectedPosition(hot: Handsontable) {
const coords = hot.getSelectedLast()
if (!coords) return undefined
return { row: coords[0], column: coords[1] } as CellPosition
}
protected cell(hot: Handsontable) {
const pos = this.selectedPosition(hot)
return pos ? this.program.getCell(pos) : undefined
}
protected searchResults(hot: Handsontable) {
const pos = this.selectedPosition(hot)
return pos ? this.program.findAll(pos) : []
}
// handles the "this" binding needed by HOT
toHotCommand(): HotContextMenu.MenuItemConfig {
const baseCommand = this
return {
name: function () {
return baseCommand.name(this)
},
callback: function () {
return baseCommand.callback(this)
},
disabled: function () {
return baseCommand.disabled(this)
},
hidden: function () {
return baseCommand.hidden(this)
},
}
}
}
export class SelectAllHitsCommand extends HotCommand {
name(hot: Handsontable) {
const cell = this.cell(hot)
if (!cell) return `Nothing selected`
const searchResults = this.searchResults(hot)
if (searchResults.length === 1) return `1 match of '${cell.contents}'`
return `Select ${searchResults.length} matches of '${cell.contents}'`
}
callback(hot: Handsontable) {
const searchResults = this.searchResults(hot)
if (!searchResults.length) return
hot.selectCells(
searchResults.map(
(pos) =>
[pos.row, pos.column, pos.row, pos.column] as [
number,
number,
number,
number
]
)
)
}
hidden() {
return false
}
disabled(hot: Handsontable) {
return this.searchResults(hot).length < 2
}
}
export class AutofillColDefCommand extends HotCommand {
name() {
return "⚡ Autofill missing column definitions"
}
commandName: keyof ExplorerProgram =
"autofillMissingColumnDefinitionsForTableCommand"
async callback(hot: Handsontable) {
const selectedPosition = this.selectedPosition(hot)
const { program, commandName } = this
if (!selectedPosition) return
const tableSlugCell = program.getCell({
...selectedPosition,
column: selectedPosition.column + 1,
})
// todo: figure out typings. we need keyof ExplorerProgram but only if key is to a callable method.
const newProgram = await (program as any)[commandName](
tableSlugCell.contents
)
this.setProgramCallback!(newProgram.toString())
}
disabled() {
return false
}
hidden(hot: Handsontable) {
const cell = this.cell(hot)
return cell
? cell.cellDef?.keyword !== ExplorerGrammar.table.keyword
: true
}
}
export class InlineDataCommand extends AutofillColDefCommand {
name() {
return "⚡ Inline data and autofill columns"
}
commandName: keyof ExplorerProgram =
"replaceTableWithInlineDataAndAutofilledColumnDefsCommand"
}
|