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" } |