Skip to content

Commit 9f5045b

Browse files
committed
all JME functions are random: false; implement tokenToJME for TSpreadsheet
The spreadsheet modification functions are deterministic. Marking them as not-random means that spreadsheet variables constructed deterministically aren't saved in the suspend data. This commit also implements serialisation to JME for spreadsheet values, so if they do get serialised for some reason, they can be restored.
1 parent e244db8 commit 9f5045b

1 file changed

Lines changed: 24 additions & 22 deletions

File tree

src/extension.js

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,10 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
263263
return sheet[ref]?.v;
264264
}
265265

266+
to_base64() {
267+
const buffer = XLSX.write(this.wb, {type: 'array', bookType: 'xlsx'});
268+
return encode_array(buffer);
269+
}
266270
}
267271

268272
const {TString, TList, TDict, THTML} = Numbas.jme.types;
@@ -277,9 +281,6 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
277281
TSpreadsheet,
278282
'spreadsheet',
279283
{
280-
'list': function(s) {
281-
// TODO
282-
},
283284
'html': function(s) {
284285
const e = document.createElement('spread-sheet');
285286
e.setAttribute('disabled',true);
@@ -301,8 +302,7 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
301302
return '\\text{Spreadsheet}';
302303
},
303304
jme: (tree,tok,bits) => {
304-
// TODO
305-
return 'spreadsheet()';
305+
return 'spreadsheet_from_base64_file("sheet.xlsx",safe("' + Numbas.jme.escape(tok.value.to_base64())+'"))';
306306
}
307307
});
308308

@@ -315,7 +315,7 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
315315
};
316316
return new TSpreadsheet(new Workbook(workbook));
317317
},
318-
{ unwrapValues: true}
318+
{ unwrapValues: true, random: false }
319319
));
320320

321321
sheets.scope.addFunction(new jme.funcObj('spreadsheet',['list of list'],TSpreadsheet,
@@ -327,22 +327,22 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
327327
};
328328
return new TSpreadsheet(new Workbook(workbook));
329329
},
330-
{ unwrapValues: true}
330+
{ unwrapValues: true, random: false }
331331
));
332332

333333
sheets.scope.addFunction(new jme.funcObj('spreadsheet_from_base64_file', ['string', 'string'], TSpreadsheet,
334334
(filename, base64) => {
335335
const data = decode_array(base64);
336336
return new TSpreadsheet(new Workbook(XLSX.read(data, {sheetStubs: true})));
337337
},
338-
{ unwrapValues: true }
339-
))
338+
{ unwrapValues: true, random: false }
339+
));
340340

341341
sheets.scope.addFunction(new jme.funcObj('update_range',[TSpreadsheet,TString,TDict], TSpreadsheet,
342342
(spreadsheet, range_string, changes) => {
343343
return new TSpreadsheet(spreadsheet.update_range(range_string, changes));
344344
},
345-
{unwrapValues: true}
345+
{ unwrapValues: true, random: false }
346346
));
347347

348348
sheets.scope.addFunction(new jme.funcObj('update_range',[TSpreadsheet,'list of string',TDict], TSpreadsheet,
@@ -353,7 +353,7 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
353353
}
354354
return new TSpreadsheet(wb);
355355
},
356-
{unwrapValues: true}
356+
{ unwrapValues: true, random: false }
357357
));
358358

359359
sheets.scope.addFunction(new jme.funcObj('disable_cells',[TSpreadsheet,'list of string'], TSpreadsheet,
@@ -364,7 +364,7 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
364364
}
365365
return new TSpreadsheet(wb);
366366
},
367-
{unwrapValues: true}
367+
{ unwrapValues: true, random: false }
368368
));
369369

370370
sheets.scope.addFunction(new jme.funcObj('fill_range',[TSpreadsheet, TString, 'list of (string or number)'], TSpreadsheet,
@@ -379,13 +379,13 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
379379
}
380380
return new TSpreadsheet(spreadsheet.fill_range(range,values));
381381
},
382-
{unwrapValues: true}
382+
{ unwrapValues: true, random: false }
383383
));
384384
sheets.scope.addFunction(new jme.funcObj('fill_range',[TSpreadsheet,TString,'list of list of (string or number)'], TSpreadsheet,
385385
(spreadsheet, range, values) => {
386386
return new TSpreadsheet(spreadsheet.fill_range(range,values));
387387
},
388-
{unwrapValues: true}
388+
{ unwrapValues: true, random: false }
389389
));
390390

391391
/** Interpret a range string and return a list of the cells it contains.
@@ -400,12 +400,13 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
400400
}
401401
}
402402
return out;
403-
}
403+
},
404+
{ random: false }
404405
));
405406

406407
sheets.scope.addFunction(new jme.funcObj('slice', [TSpreadsheet, TString], TSpreadsheet, (wb,range) => {
407408
return wb.slice(range);
408-
}));
409+
}, {random: false}));
409410

410411
sheets.scope.addFunction(new jme.funcObj('listval', [TSpreadsheet, TString], '?', null, {
411412
evaluate: function(args, scope) {
@@ -446,12 +447,13 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
446447
} else {
447448
return new TString((wb.get_cell_value(sheet,ref) || '')+'');
448449
}
449-
}
450+
},
451+
random: false
450452
}));
451453

452454
sheets.scope.addFunction(new jme.funcObj('encode_range',['integer','integer','integer','integer'], TString, (cs,rs,ce,re) => {
453455
return XLSX.utils.encode_range({s:{c:cs,r:rs}, e:{c:ce,r:re}});
454-
}));
456+
}, {random: false}));
455457

456458
/**
457459
* Create an ArrayBuffer containing the given string.
@@ -483,21 +485,21 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
483485
link.innerHTML = `Download <code>${filename}</code>`;
484486

485487
return link;
486-
}));
488+
}, {random: false}));
487489

488490
function add_style_function(name,args,fn) {
489491
args = args.slice();
490492
sheets.scope.addFunction(new jme.funcObj(name, args, TDict, function(...args) {
491493
var style = fn(...args);
492494
return jme.wrapValue({style: style});
493-
},{unwrapValues: true}));
495+
},{unwrapValues: true, random: false}));
494496

495497
var dargs = args.slice();
496498
dargs.splice(0,0,'dict');
497499
sheets.scope.addFunction(new jme.funcObj(name, dargs, TDict, function(pd,...args) {
498500
var style = fn(...args);
499501
return jme.wrapValue(Numbas.util.deep_extend_object(pd,{style: style}));
500-
},{unwrapValues: true}));
502+
},{unwrapValues: true, random: false}));
501503
}
502504

503505
function css_color_to_rgba(color) {
@@ -555,7 +557,7 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
555557
'number': 'n'
556558
};
557559
return jme.wrapValue({t: types_map[type] || type});
558-
},{unwrapValues: true}));
560+
},{unwrapValues: true, random: false}));
559561

560562
if(Numbas.editor?.register_variable_template_type !== undefined) {
561563
class SpreadsheetVariableTemplateWidget extends HTMLElement {

0 commit comments

Comments
 (0)