@@ -275,7 +275,49 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
275275 constructor ( wb ) {
276276 this . value = wb ;
277277 }
278- }
278+
279+ /** Resolve a named reference or a string representation of a range to a 2D array of values or the value in a single cell.
280+ *
281+ * @param {string } ref
282+ * @returns {object } with either a property `range: Array.<Array.<string>>>` or `cell: string`
283+ */
284+ resolve_ref ( ref ) {
285+ const wb = this . value ;
286+ let range ;
287+
288+ const named_ref = wb . get_named_ref ( ref ) ;
289+ if ( named_ref ) {
290+ range = XLSX . utils . dereference_range ( named_ref ) ;
291+ if ( cells_equal ( range . e , range . s ) ) {
292+ delete range . e ;
293+ }
294+ if ( range . e === undefined ) {
295+ ref = XLSX . utils . encode_cell ( range . s ) ;
296+ }
297+ } else if ( ref . match ( / : / ) ) {
298+ range = XLSX . utils . decode_range ( ref ) ;
299+ } else {
300+ range = { s :XLSX . utils . decode_cell ( ref ) } ;
301+ }
302+
303+ const sheet = wb . get_worksheet ( range . sheet ) ;
304+
305+ if ( range . e !== undefined ) {
306+ const out = [ ] ;
307+ for ( let row = range . s . r ; row <= range . e . r ; row ++ ) {
308+ const orow = [ ] ;
309+ out . push ( orow ) ;
310+ for ( let col = range . s . c ; col <= range . e . c ; col ++ ) {
311+ const v = wb . get_cell_value ( sheet , XLSX . utils . encode_cell ( { r :row , c :col } ) ) ;
312+ orow . push ( ( v || '' ) + '' ) ;
313+ }
314+ }
315+ return { range : out } ;
316+ } else {
317+ return { cell : ( wb . get_cell_value ( sheet , ref ) || '' ) + '' } ;
318+ }
319+ }
320+ } ;
279321
280322 jme . registerType (
281323 TSpreadsheet ,
@@ -410,42 +452,33 @@ Numbas.addExtension('sheets', ['display', 'util', 'jme','sheet-element', 'xlsx']
410452
411453 sheets . scope . addFunction ( new jme . funcObj ( 'listval' , [ TSpreadsheet , TString ] , '?' , null , {
412454 evaluate : function ( args , scope ) {
413- const wb = args [ 0 ] . value ;
414- let ref = args [ 1 ] . value ;
415- let range ;
416-
417- const named_ref = wb . get_named_ref ( ref ) ;
418- if ( named_ref ) {
419- range = XLSX . utils . dereference_range ( named_ref ) ;
420- if ( cells_equal ( range . e , range . s ) ) {
421- delete range . e ;
422- }
423- if ( range . e === undefined ) {
424- ref = XLSX . utils . encode_cell ( range . s ) ;
425- }
426- } else if ( ref . match ( / : / ) ) {
427- range = XLSX . utils . decode_range ( ref ) ;
428- } else {
429- range = { s :XLSX . utils . decode_cell ( ref ) } ;
455+ const sheet = args [ 0 ] ;
456+ const ref = args [ 1 ] . value ;
457+ const result = sheet . resolve_ref ( ref ) ;
458+ if ( result . range ) {
459+ return jme . wrapValue ( result . range ) ;
460+ } else if ( result . cell ) {
461+ return new TString ( result . cell ) ;
430462 }
463+ } ,
464+ random : false
465+ } ) ) ;
431466
432-
433- const sheet = wb . get_worksheet ( range . sheet ) ;
467+ sheets . scope . addFunction ( new jme . funcObj ( 'range_as_numbers' , [ TSpreadsheet , TString , '[string or list of string]' ] , '?' , null , {
468+ evaluate : function ( args , scope ) {
469+ const sheet = args [ 0 ] ;
470+ const ref = args [ 1 ] . value ;
471+ const notationStyle = jme . unwrapValue ( args [ 2 ] ) ;
434472
473+ const result = sheet . resolve_ref ( ref ) ;
435474
436- if ( range . e !== undefined ) {
437- const out = [ ] ;
438- for ( let row = range . s . r ; row <= range . e . r ; row ++ ) {
439- const orow = [ ] ;
440- out . push ( new TList ( orow ) ) ;
441- for ( let col = range . s . c ; col <= range . e . c ; col ++ ) {
442- const v = wb . get_cell_value ( sheet , XLSX . utils . encode_cell ( { r :row , c :col } ) ) ;
443- orow . push ( new TString ( ( v || '' ) + '' ) ) ;
444- }
445- }
446- return new TList ( out ) ;
447- } else {
448- return new TString ( ( wb . get_cell_value ( sheet , ref ) || '' ) + '' ) ;
475+ function parsenumber ( s ) {
476+ return Numbas . util . parseNumber ( s , false , notationStyle , true ) ;
477+ }
478+ if ( result . range ) {
479+ return jme . wrapValue ( result . range . map ( row => row . map ( parsenumber ) ) ) ;
480+ } else if ( result . cell ) {
481+ return new TNum ( parsenumber ( result . cell ) ) ;
449482 }
450483 } ,
451484 random : false
0 commit comments