Skip to content

Commit

Permalink
initial validate function
Browse files Browse the repository at this point in the history
  • Loading branch information
smmercuri committed Nov 9, 2023
1 parent 43f66eb commit 5a52a53
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 48 deletions.
12 changes: 10 additions & 2 deletions lang/en/qtype_stack.php
Original file line number Diff line number Diff line change
Expand Up @@ -852,8 +852,16 @@
$string['stackBlock_jsxgraph_ref'] = 'The jsxgraph-block only supports referencing inputs present in the same CASText section \'{$a->var}\' does not exist here.';
$string['stackBlock_jsxgraph_param'] = 'The jsxgraph-block supports only these parameters in this context: {$a->param}.';

$string['stackBlock_parsons_width'] = 'The width of a Parsons block must use a known CSS-length unit.';
$string['stackBlock_parsons_height'] = 'The height of a Parsons block must use a known CSS-length unit.';
$string['stackBlock_parsons_width'] = 'The width of a Parson\'s block must use a known CSS-length unit.';
$string['stackBlock_parsons_height'] = 'The height of a Parson\'s block must use a known CSS-length unit.';
$string['stackBlock_parsons_width_num'] = 'The numeric portion of the width of a Parson\'s block must be a raw number and must not contain any extra chars.';
$string['stackBlock_parsons_height_num'] = 'The numeric portion of the height of a Parson\'s block must be a raw number and must not contain any extra chars.';
$string['stackBlock_parsons_underdefined_dimension'] = 'When defining aspect-ratio for a Parson\'s block one must define either width or height of the graph.';
$string['stackBlock_parsons_overdefined_dimension'] = 'When defining aspect-ratio for a Parson\'s block one should only define width or height not both.';
$string['stackBlock_parsons_unknown_named_version'] = 'The Parson\'s block only supports versions named: {$a->version}.';
$string['stackBlock_parsons_ref'] = 'The Parson\'s block only supports referencing inputs present in the same CASText section \'{$a->var}\' does not exist here.';
$string['stackBlock_parsons_param'] = 'The Parson\'s block supports only these parameters in this context: {$a->param}.';
$string['stackBlock_parsons_contents'] = 'The contents of a Parson\'s block must be a JSON of the form \'{"steps" : {"step 1" : "...", ...,}, "options" : {"option 1" : "...", ...}}\' or \'{"step 1" : "...", ...}\'.';

// Define the stackBlock GeoGebra strings.
$string['stackBlock_geogebra_width'] = 'The width of a GeoGebra Applet must use a known CSS-length unit.';
Expand Down
103 changes: 57 additions & 46 deletions stack/cas/castext2/blocks/parsons.block.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ class stack_cas_castext2_parsons extends stack_cas_castext2_block {

/* This is not something we want people to edit in general. */
public static $namedversions = [
'cdn' => [
'js' => 'https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.15.0/Sortable.min.js',
],
'local' => [
'css' => 'cors://sortable.min.css',
'js' => 'cors://sortable.min.js'
]
];

Expand All @@ -54,6 +58,9 @@ public function compile($format, $options): ? MP_Node {
if (isset($xpars['overridecss'])) {
unset($xpars['overridecss']);
}
if (isset($xpars['overridejs'])) {
unset($xpars['overridejs']);
}

// Set default width and height here, we want to push forward to overwrite the iframe defaults
// if they are not provided in the block parameters
Expand All @@ -67,13 +74,18 @@ public function compile($format, $options): ? MP_Node {

// Figure out what scripts we serve.
$css = self::$namedversions['local']['css'];
$js = self::$namedversions['local']['js'];
if (isset($this->params['version']) &&
isset(self::$namedversions[$this->params['version']])) {
$css = self::$namedversions[$this->params['version']]['css'];
$css = self::$namedversions['local']['css'];
$js = self::$namedversions[$this->params['version']]['js'];
}
if (isset($this->params['overridecss'])) {
$css = $this->params['overridecss'];
}
if (isset($this->params['overridejs'])) {
$js = $this->params['overridejs'];
}

$r->items[] = new MP_String(json_encode($xpars));

Expand All @@ -87,6 +99,10 @@ public function compile($format, $options): ? MP_Node {
new MP_String('style'),
new MP_String(json_encode(['href' => $css]))
]);
$r->items[] = new MP_List([
new MP_String('script'),
new MP_String(json_encode(['type' => 'text/javascript', 'src' => $js]))
]);

// We need to define a size for the inner content.
$aspectratio = false;
Expand Down Expand Up @@ -149,16 +165,16 @@ public function compile($format, $options): ? MP_Node {
};

// Instantiate STACK sortable helper class
$code .= 'const sortable = new stack_sortable(proofSteps, "availableList", "usedList", id, userOpts);' . "\n";
$code .= 'const stackSortable = new stack_sortable(proofSteps, "availableList", "usedList", id, userOpts);' . "\n";
// Generate the two lists in HTML
$code .= 'sortable.generate_used();' . "\n";
$code .= 'sortable.generate_available();' . "\n";
$code .= 'stackSortable.generate_used();' . "\n";
$code .= 'stackSortable.generate_available();' . "\n";
// Typeset MathJax
if (count($inputs) > 0) {
$code .= 'MathJax.typesetPromise();' . "\n";
};
// Create the Sortable objects
$code .= 'var opts = {...sortable.options, ...{onSort: () => {sortable.update_state(sortableUsed, sortableAvailable);}}}' . "\n";
$code .= 'var opts = {...stackSortable.options, ...{onSort: () => {stackSortable.update_state(sortableUsed, sortableAvailable);}}}' . "\n";
$code .= 'var sortableUsed = Sortable.create(usedList, opts);' . "\n";
$code .= 'var sortableAvailable = Sortable.create(availableList, opts);' . "\n";

Expand All @@ -167,7 +183,6 @@ public function compile($format, $options): ? MP_Node {
};

$r->items[] = new MP_String($code);

$r->items[] = new MP_String('</script>');

return $r;
Expand All @@ -186,22 +201,21 @@ public function validate_extract_attributes(): array {
return [];
}

public function validate_JSON_contents($contents) : bool {
//$contents = json_decode($json_contents, true);
$val_types = array_unique(array_map('gettype', array_values($contents)));
return array_keys($contents) === ["steps", "options"] || (count($val_types) == 1 && $val_types[0] == "string");
}

public function validate (
&$errors = [],
$options = []
): bool {
return true;
// Basically, check that the dimensions have units we know.
// Also that the references make sense.
/*$valid = true;
$width = '500px';
$height = '400px';
if (array_key_exists('width', $this->params)) {
$width = $this->params['width'];
}
if (array_key_exists('height', $this->params)) {
$height = $this->params['height'];
}
$valid = true;
$width = array_key_exists('width', $this->params) ? $this->params['width'] : '100%';
$height = array_key_exists('height', $this->params) ? $this->params['height'] : '400px';

// NOTE! List ordered by length. For the trimming logic.
$validunits = ['vmin', 'vmax', 'rem', 'em', 'ex', 'px', 'cm', 'mm',
Expand All @@ -211,7 +225,7 @@ public function validate (
$heightend = false;
$widthtrim = $width;
$heighttrim = $height;
foreach ($validunits as $suffix) {
if (!$widthend && strlen($width) > strlen($suffix) &&
substr($width, -strlen($suffix)) === $suffix) {
Expand All @@ -231,74 +245,71 @@ public function validate (

if (!$widthend) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_width');
$err[] = stack_string('stackBlock_parsons_width');
}
if (!$heightend) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_height');
$err[] = stack_string('stackBlock_parsons_height');
}
if (!preg_match('/^[0-9]*[\.]?[0-9]+$/', $widthtrim)) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_width_num');
$err[] = stack_string('stackBlock_parsons_width_num');
}
if (!preg_match('/^[0-9]*[\.]?[0-9]+$/', $heighttrim)) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_height_num');
$err[] = stack_string('stackBlock_parsons_height_num');
}

if (array_key_exists('width', $this->params) &&
array_key_exists('height', $this->params) &&
array_key_exists('aspect-ratio', $this->params)) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_overdefined_dimension');
$err[] = stack_string('stackBlock_parsons_overdefined_dimension');
}
if (!(array_key_exists('width', $this->params) ||
array_key_exists('height', $this->params)) &&
array_key_exists('aspect-ratio', $this->params)) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_underdefined_dimension');
$err[] = stack_string('stackBlock_parsons_underdefined_dimension');
}

if (array_key_exists('version', $this->params) && array_key_exists($this->params['version'], self::$namedversions)) {
// Check version is only one of valid options
if (array_key_exists('version', $this->params) && !array_key_exists($this->params['version'], self::$namedversions)) {
$valid = false;
$err[] = stack_string('stackBlock_jsxgraph_unknown_named_version');
$validversions = ['cdn', 'local'];
$err[] = stack_string('stackBlock_parsons_unknown_named_version', ['version' => implode(', ', $validversions)]);
}

// Check that only valid parameters are passed to block header
$valids = null;
foreach ($this->params as $key => $value) {
if (substr($key, 0, 10) === 'input-ref-') {
$varname = substr($key, 10);
if (isset($options['inputs']) && !isset($options['inputs'][$varname])) {
$err[] = stack_string('stackBlock_jsxgraph_input_missing',
['var' => $varname]);
}
} else if ($key !== 'width' && $key !== 'height' && $key !== 'aspect-ratio' &&
$key !== 'version' && $key !== 'overridejs' && $key !== 'overridecss') {
$err[] = "Unknown parameter '$key' for jsxgraph-block.";
if ($key !== 'width' && $key !== 'height' && $key !== 'aspect-ratio' &&
$key !== 'version' && $key !== 'overridecss' && $key !== 'input') {
$err[] = "Unknown parameter '$key' for Parson's block.";
$valid = false;
if ($valids === null) {
$valids = ['width', 'height', 'aspect-ratio', 'version', 'overridecss', 'overridejs'];
// The variable $inputdefinitions is not defined!
if ($inputdefinitions !== null) {
$tmp = $root->get_parameter('ioblocks');
$inputs = [];
foreach ($inputdefinitions->get_names() as $key) {
$inputs[] = "input-ref-$key";
}
$valids = array_merge($valids, $inputs);
}
$err[] = stack_string('stackBlock_jsxgraph_param', [
$valids = ['width', 'height', 'aspect-ratio', 'version', 'overridecss', 'overridejs', 'input'];
$err[] = stack_string('stackBlock_parsons_param', [
'param' => implode(', ', $valids)]);
}
}
}

// Check the JSON contents are of the right format, i.e., either the depth is 1 or the depth is 2 and the keys are ['steps', 'options'].
$contents = json_decode(($this->children[0]->compile(castext2_parser_utils::RAWFORMAT, []))->value, true);
// either this is a string (when using Maxima and stackjson_stringify) or it's a JSON. The former case we sanitise on the JS side so we can ignore this here.
if (!gettype($contents) == "string") {
if (!self::validate_JSON_contents(json_decode(($this->children[0]->compile(castext2_parser_utils::RAWFORMAT, []))->value, true))) {
$err[] = stack_string('stackBlock_parsons_contents');
}
};

// Wrap the old string errors with the context details.
foreach ($err as $er) {
$errors[] = new $options['errclass']($er, $options['context'] . '/' . $this->position['start'] . '-' .
$this->position['end']);
}

return $valid;*/
return $valid;
}
}

0 comments on commit 5a52a53

Please sign in to comment.