Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion extensions/src/common/types/framework/blocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export type BlockDefinitions<T extends BaseGenericExtension> =
{
[k in keyof T["BlockFunctions"]]: T["BlockFunctions"][k] extends
(...args: infer A) => infer R
? DefineBlock<T, (...args: A | [...A, BlockUtility]) => R>
? DefineBlock<T, (...args: A) => R>
: never
};

Expand Down
30 changes: 24 additions & 6 deletions extensions/src/tables/View.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,25 @@
const set: ReactiveSet<Extension> = (propertyName, value) => reactiveSet((extension = extension), propertyName, value);

const container = activeClass;
const tableListDropdown = activeClass, tableBox = activeClass, tableValueInput = activeClass;
const tableListDropdown = activeClass, tableBox = activeClass, tableValueInput = activeClass, nameInput = activeClass;

const tableNames = Object.keys(extension.tables);
let selected: string = tableNames.length > 0 ? tableNames[0] : "";

type InputChangeEvent = Event & { currentTarget: EventTarget & HTMLInputElement};
const update = (e: InputChangeEvent, row: number, column: number) =>
invoke("changeTableValue", {name: selected, row, column, value: parseInt(e.currentTarget.value)});
const updateColumnName = (e: InputChangeEvent, column: number)
=>
invoke("changeColumnName", {name: selected, column, value: e.currentTarget.value});
const updateRowName = (e: InputChangeEvent, row: number)
=>
invoke("changeRowName", {name: selected, row, value: e.currentTarget.value});
</script>

<style>
.container {
width: 480px;
width: 640px!important;
padding: 1.5rem 2.25rem;
}

Expand Down Expand Up @@ -52,6 +58,14 @@
width: 3rem;
padding: .25rem;
color: var(--text-primary-transparent);
font-size: .85rem;
}

.nameInput {
font-weight: bold;
width: 4rem;
padding: .25rem;
color: var(--text-primary-transparent);
font-size: 1rem;
}
</style>
Expand All @@ -71,18 +85,22 @@
<thead>
<tr>
<th></th>
{#each [...Array(extension.tables[selected][0].length)] as _, i}
<th>{i + 1}</th>
{#each extension.columnNames[selected] as columnName, i}
<th>
<input class:nameInput type=text value={columnName} on:change={(e) => updateColumnName(e, i)} data-testid="columnNameCell">
</th>
{/each}
</tr>
</thead>
<tbody>
{#each extension.tables[selected] as row, i}
<tr>
<th>{i + 1}</th>
<th>
<input class:nameInput type=text value={extension.rowNames[selected][i]} on:change={(e) => updateRowName(e, i)} data-testid="rowNameCell">
</th>
{#each row as value, j}
<th>
<input class:tableValueInput type="number" {value} on:change={(e) => update(e, i, j)} data-testid="tableCell">
<input class:tableValueInput type=number {value} on:change={(e) => update(e, i, j)} data-testid="tableCell">
</th>
{/each}
</tr>
Expand Down
72 changes: 72 additions & 0 deletions extensions/src/tables/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ createTestSuite({ Extension, __dirname }, {
const { extension, testHelper: { expect } } = fixture;
extension.newTable({ name: 'newTable', rows: 2, columns: 2 });
expect(extension.tables.newTable.length).toBe(2);
expect(extension.rowNames.newTable[0]).toBe('row');
expect(extension.columnNames.newTable[0]).toBe('col');
},
after: async (fixture) => {
const { ui, extension, testHelper: { expect, fireEvent, updateHTMLInputValue } } = fixture;
Expand All @@ -67,8 +69,14 @@ createTestSuite({ Extension, __dirname }, {
expect(cells.length).toBe(4);
const cell = cells[0] as HTMLInputElement;

const rows = await ui.findAllByTestId('rowNameCell');
expect(rows.length).toBe(2);
const row = rows[0] as HTMLInputElement;

await fireEvent.change(cell, { target: { value: '3' } });
await fireEvent.change(row, { target: { value: 'newName' } });
expect(extension.tables.newTable[0][0]).toBe(3);
expect(extension.rowNames.newTable[0]).toBe('newName');

delete extension.tables.newTable;
}
Expand Down Expand Up @@ -112,10 +120,16 @@ createTestSuite({ Extension, __dirname }, {
input: 'newTable',
before: ({ extension }) => {
extension.tables.newTable = [[1]];
extension.rowNames.newTable = ['row'];
extension.columnNames.newTable = ['col'];
},
after: ({ extension }) => {
expect(extension.tables.newTable).toBe(undefined);
expect(extension.rowNames.newTable).toBe(undefined);
expect(extension.columnNames.newTable).toBe(undefined);
delete extension.tables.newTable;
delete extension.rowNames.newTable;
delete extension.columnNames.newTable;
}
}
},
Expand All @@ -124,11 +138,17 @@ createTestSuite({ Extension, __dirname }, {
input: 'newTable',
before: ({ extension }) => {
extension.tables.newTable = [[1]];
extension.rowNames.newTable = ['row'];
extension.columnNames.newTable = ['col'];
},
after: ({ extension }) => {
expect(extension.tables.newTable[0].length).toBe(2);
expect(extension.tables.newTable[0][1]).toBe(0);
expect(extension.columnNames.newTable.length).toBe(2);
expect(extension.rowNames.newTable.length).toBe(1);
delete extension.tables.newTable;
delete extension.rowNames.newTable;
delete extension.columnNames.newTable;
}
}
},
Expand All @@ -137,11 +157,63 @@ createTestSuite({ Extension, __dirname }, {
input: 'newTable',
before: ({ extension }) => {
extension.tables.newTable = [[1]];
extension.rowNames.newTable = ['row'];
extension.columnNames.newTable = ['col'];
},
after: ({ extension }) => {
expect(extension.tables.newTable.length).toBe(2);
expect(extension.tables.newTable[1][0]).toBe(0);
expect(extension.columnNames.newTable.length).toBe(1);
expect(extension.rowNames.newTable.length).toBe(2);
delete extension.tables.newTable;
delete extension.rowNames.newTable;
delete extension.columnNames.newTable;
}
}
},
deleteColumn: ({ expect }) => {
return {
input: ['newTable', 1],
before: ({ extension }) => {
extension.tables.newTable = [
[0, 0],
[1, 0]
];
extension.rowNames.newTable = ['row', 'row'];
extension.columnNames.newTable = ['col', 'col'];
},
after: ({ extension }) => {
expect(extension.tables.newTable.length).toBe(2);
expect(extension.tables.newTable[0].length).toBe(1);
expect(extension.tables.newTable[0][0]).toBe(0);
expect(extension.columnNames.newTable.length).toBe(1);
expect(extension.rowNames.newTable.length).toBe(2);
delete extension.tables.newTable;
delete extension.rowNames.newTable;
delete extension.columnNames.newTable;
}
}
},
deleteRow: ({ expect }) => {
return {
input: ['newTable', 1],
before: ({ extension }) => {
extension.tables.newTable = [
[0, 0],
[1, 1]
];
extension.rowNames.newTable = ['row', 'row'];
extension.columnNames.newTable = ['col', 'col'];
},
after: ({ extension }) => {
expect(extension.tables.newTable.length).toBe(1);
expect(extension.tables.newTable[0].length).toBe(2);
expect(extension.tables.newTable[0][0]).toBe(1);
expect(extension.columnNames.newTable.length).toBe(2);
expect(extension.rowNames.newTable.length).toBe(1);
delete extension.tables.newTable;
delete extension.rowNames.newTable;
delete extension.columnNames.newTable;
}
}
},
Expand Down
107 changes: 103 additions & 4 deletions extensions/src/tables/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ type Blocks = {
removeTable: (table: string) => void;
insertColumn: (table: string) => void;
insertRow: (table: string) => void;
deleteColumn: (table: string, column: number) => void;
deleteRow: (table: string, row: number) => void;
insertValueAt: (table: string, value: number, row: number, column: number) => void;
getValueAt: (table: string, row: number, column: number) => number;
numberOfRows: (table: string) => number;
Expand All @@ -32,21 +34,59 @@ type Blocks = {
@validGenericExtension()
export default class Tables extends Extension<Details, Blocks> {
tables: Record<string, number[][]>;
rowNames: Record<string, string[]>;
columnNames: Record<string, string[]>;
tableNamesArg: any;
defaultNumberArg: any;

// save tables to .sb3 when project is saved
override saveDataHandler = new SaveDataHandler({
Extension: Tables,
onSave: (self) => { return self.tables },
onLoad: (self, tables) => { self.tables = tables },
onSave: (self) => {
return {
tables: self.tables,
rowNames: self.rowNames,
columnNames: self.columnNames
};
},
onLoad: (self, data) => {
if (data.rowNames === undefined) {
// save happened before column names and row names were added
// as a feature.
// Load data into tables, and then construct default names.

self.tables = data as any;
const tableNames = Object.keys(self.tables);

self.rowNames = tableNames.reduce((rowNames, tableName, i) => {
rowNames[tableName] = self.tables[tableName].map(
(row, i) => `row${i + 1}`
);
return rowNames;
}, {});
self.columnNames = tableNames.reduce((columnNames, tableName, i) => {
columnNames[tableName] = self.tables[tableName][0].map(
(col, i) => `col${i + 1}`
);
return columnNames;
}, {});
} else {
self.tables = data.tables;
self.rowNames = data.rowNames;
self.columnNames = data.columnNames;
}
},
});

init(env: Environment) {
if (!this.tables) {
this.tables = {};
this.rowNames = {};
this.columnNames = {};
this.tables.myTable = [];
this.tables.myTable.push([0]);
this.rowNames.myTable = ['row'];
this.columnNames.myTable = ['col'];
}

// dynamic retriever of table names for block dropdowns
Expand Down Expand Up @@ -80,10 +120,11 @@ export default class Tables extends Extension<Details, Blocks> {
);
}


newTable(info: { name: string, rows: number, columns: number }) {
const { name, rows, columns } = info;
this.tables[name] = [];
this.rowNames[name] = new Array(rows).fill('row');
this.columnNames[name] = new Array(columns).fill('col');
for (let i = 0; i < rows; i++) {
let newRow = [];
for (let j = 0; j < columns; j++) newRow.push(0);
Expand All @@ -96,6 +137,16 @@ export default class Tables extends Extension<Details, Blocks> {
this.tables[name][row][column] = value;
}

changeColumnName(info: { name: string, column: number, value: string }) {
const { name, column, value } = info;
this.columnNames[name][column] = value;
}

changeRowName(info: { name: string, row: number, value: string }) {
const { name, row, value } = info;
this.rowNames[name][row] = value;
}

defineBlocks(): Tables["BlockDefinitions"] {
return {
// button that opens a modal to create a new table
Expand Down Expand Up @@ -129,7 +180,9 @@ export default class Tables extends Extension<Details, Blocks> {
text: (table) => `remove ${table}`,
operation: (table) => {
if (this.tables[table]) {
delete this.tables[table]
delete this.tables[table];
delete this.rowNames[table];
delete this.columnNames[table];
return;
} else {
alert(`that table doesn't exist`);
Expand All @@ -150,6 +203,7 @@ export default class Tables extends Extension<Details, Blocks> {
for (let i = 0; i < this.tables[table].length; i++) {
this.tables[table][i].push(0);
}
this.columnNames[table].push('col');
}
}),
// add a row to the given table
Expand All @@ -167,6 +221,51 @@ export default class Tables extends Extension<Details, Blocks> {
newRow.push(0);
}
this.tables[table].push(newRow);
this.rowNames[table].push('row');
}
}),
// removes the specified column from the table
deleteColumn: (self: Tables) => ({
type: BlockType.Command,
args: [self.tableNamesArg, self.defaultNumberArg],
text: (table, column) => `delete column ${column} from ${table}`,
operation: (table, column) => {
if (!(table in self.tables)) {
alert(`that table does not exist.`);
return;
}
if (
column > this.tables[table][0].length ||
column < 1
) {
alert(`that column number doesn't exist.`);
return;
}
for (let i = 0; i < this.tables[table].length; i++) {
this.tables[table][i].splice((column - 1), 1);
}
this.columnNames[table].splice((column - 1), 1);
}
}),
// removes the specified row from th table
deleteRow: (self: Tables) => ({
type: BlockType.Command,
args: [self.tableNamesArg, self.defaultNumberArg],
text: (table, row) => `delete row ${row} from ${table}`,
operation: (table, row) => {
if (!(table in self.tables)) {
alert(`that table does not exist.`);
return;
}
if (
row > this.tables[table].length ||
row < 1
) {
alert(`that row number doesn't exist.`);
return;
}
this.tables[table].splice((row - 1), 1);
this.rowNames[table].splice((row - 1), 1);
}
}),
// change the value in a given table cell
Expand Down