@@ -3564,6 +3564,9 @@ var TBool = types.TBool = function(b) {
35643564jme.registerType(TBool,'boolean');
35653565
35663566/** HTML DOM element.
3567+ *
3568+ * If the element has the attribute `data-interactive="false"` then it can be safely copied and embedded multiple times.
3569+ * If the attribute is not present or has any other value, then it's assumed that it can't be safely copied.
35673570 *
35683571 * @memberof Numbas.jme.types
35693572 * @augments Numbas.jme.token
@@ -3589,6 +3592,11 @@ var THTML = types.THTML = function(html) {
35893592 this.value = Array.from(elem.childNodes);
35903593 this.html = elem.innerHTML;
35913594}
3595+ THTML.prototype = {
3596+ isInteractive: function() {
3597+ return this.value.some(e => e.getAttribute('data-interactive') !== 'false');
3598+ }
3599+ }
35923600jme.registerType(THTML,'html');
35933601
35943602/** List of elements of any data type.
@@ -6314,7 +6322,9 @@ newBuiltin('html',[TString],THTML,null, {
63146322 container.innerHTML = args[0].value;
63156323 var subber = new jme.variables.DOMcontentsubber(scope);
63166324 subber.subvars(container);
6317- return new THTML(Array.from(container.childNodes));
6325+ var nodes = Array.from(container.childNodes);
6326+ nodes.forEach(node => node.setAttribute('data-interactive', 'false'));
6327+ return new THTML(nodes);
63186328 }
63196329});
63206330newBuiltin('isnonemptyhtml',[TString],TBool,function(html) {
@@ -6335,6 +6345,7 @@ newBuiltin('image',[TString, '[number]', '[number]'],THTML,null, {
63356345 }
63366346 var subber = new jme.variables.DOMcontentsubber(scope);
63376347 var element = subber.subvars(img);
6348+ element.setAttribute('data-interactive', 'false');
63386349 return new THTML(element);
63396350 }
63406351});
@@ -6810,6 +6821,7 @@ newBuiltin('scientificnumberhtml', [TDecimal], THTML, function(n) {
68106821 var bits = math.parseScientific(n.re.toExponential());
68116822 var s = document.createElement('span');
68126823 s.innerHTML = math.niceRealNumber(bits.significand)+' × 10<sup>'+bits.exponent+'</sup>';
6824+ s.setAttribute('data-interactive', 'false');
68136825 return s;
68146826});
68156827newBuiltin('scientificnumberhtml', [TNum], THTML, function(n) {
@@ -6819,6 +6831,7 @@ newBuiltin('scientificnumberhtml', [TNum], THTML, function(n) {
68196831 var bits = math.parseScientific(math.niceRealNumber(n,{style:'scientific', scientificStyle:'plain'}));
68206832 var s = document.createElement('span');
68216833 s.innerHTML = math.niceRealNumber(bits.significand)+' × 10<sup>'+bits.exponent+'</sup>';
6834+ s.setAttribute('data-interactive', 'false');
68226835 return s;
68236836});
68246837
@@ -8378,6 +8391,7 @@ newBuiltin('table',[TList,TList],THTML, null, {
83788391 row.appendChild(td);
83798392 }
83808393 }
8394+ table.setAttribute('data-interactive','false');
83818395 return new THTML(table);
83828396 }
83838397});
@@ -8396,6 +8410,7 @@ newBuiltin('table',[TList],THTML, null, {
83968410 row.appendChild(td);
83978411 }
83988412 }
8413+ table.setAttribute('data-interactive','false');
83998414 return new THTML(table);
84008415 }
84018416});
@@ -14110,6 +14125,9 @@ jme.variables = /** @lends Numbas.jme.variables */ {
1411014125 function doToken(token) {
1411114126 if(jme.isType(token,'html')) {
1411214127 token = jme.castToType(token,'html');
14128+ if(!token.isInteractive()) {
14129+ return token.value.map(e => e.cloneNode(true));
14130+ }
1411314131 if(token.value.numbas_embedded) {
1411414132 throw(new Numbas.Error('jme.subvars.html inserted twice'))
1411514133 }
0 commit comments