281 lines
9.5 KiB
JavaScript
281 lines
9.5 KiB
JavaScript
|
var renderCode = function(exampleName) {
|
||
|
var _p5 = p5;
|
||
|
var instances = [];
|
||
|
var selector = 'example';
|
||
|
var examples = document.getElementsByClassName(selector);
|
||
|
|
||
|
if (examples.length > 0) {
|
||
|
var sketches = examples[0].getElementsByTagName('code');
|
||
|
var sketches_array = Array.prototype.slice.call(sketches);
|
||
|
var i = 0;
|
||
|
sketches_array.forEach(function(s) {
|
||
|
var rc = s.parentNode.className.indexOf('norender') === -1;
|
||
|
setupCode(s, rc, i);
|
||
|
runCode(s, rc, i);
|
||
|
i++;
|
||
|
});
|
||
|
}
|
||
|
|
||
|
function enableTab(el) {
|
||
|
el.onkeydown = function(e) {
|
||
|
if (e.keyCode === 9) {
|
||
|
// tab was pressed
|
||
|
// get caret position/selection
|
||
|
var val = this.value,
|
||
|
start = this.selectionStart,
|
||
|
end = this.selectionEnd;
|
||
|
// set textarea value to: text before caret + tab + text after caret
|
||
|
this.value = val.substring(0, start) + ' ' + val.substring(end);
|
||
|
// put caret at right position again
|
||
|
this.selectionStart = this.selectionEnd = start + 2;
|
||
|
// prevent the focus lose
|
||
|
return false;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function setupCode(sketch, rc, i) {
|
||
|
var isRef = sketch.parentNode.tagName !== 'PRE';
|
||
|
var sketchNode = isRef ? sketch : sketch.parentNode;
|
||
|
var sketchContainer = sketchNode.parentNode;
|
||
|
|
||
|
if (isRef) {
|
||
|
$(sketchContainer).prepend('<h4 id="example'+i+'" class="sr-only">'+exampleName+' example '+i+'</h4>');
|
||
|
var pre = document.createElement('pre');
|
||
|
pre.classList.add('ref');
|
||
|
pre.classList.add('example_code');
|
||
|
pre.appendChild(sketchNode);
|
||
|
sketchContainer.appendChild(pre);
|
||
|
sketchContainer.className = 'example_container';
|
||
|
sketch.className = 'language-javascript';
|
||
|
if (!rc) {
|
||
|
pre.className += ' norender';
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// remove start and end lines
|
||
|
var runnable = sketch.textContent.replace(/^\s+|\s+$/g, '');
|
||
|
var rows = sketch.textContent.split('\n').length;
|
||
|
|
||
|
// store original sketch
|
||
|
var orig_sketch = document.createElement('div');
|
||
|
orig_sketch.innerHTML = sketch.innerHTML;
|
||
|
|
||
|
// create canvas
|
||
|
if (rc) {
|
||
|
var cnv = document.createElement('div');
|
||
|
cnv.className = 'cnv_div';
|
||
|
if (isRef) {
|
||
|
sketchContainer.prepend(cnv);
|
||
|
} else {
|
||
|
sketchContainer.parentNode.insertBefore(cnv, sketchContainer);
|
||
|
}
|
||
|
|
||
|
// create edit space
|
||
|
let edit_space = document.createElement('div');
|
||
|
edit_space.className = 'edit_space';
|
||
|
sketchContainer.appendChild(edit_space);
|
||
|
$(edit_space).append('<h5 class="sr-only" id="buttons"'+i+' aria-labelledby="buttons'+i+' example'+i+'">buttons</h5>');
|
||
|
|
||
|
var edit_area = document.createElement('textarea');
|
||
|
edit_area.value = runnable;
|
||
|
edit_area.rows = rows;
|
||
|
edit_area.cols = 62;
|
||
|
edit_area.classList.add('edit_area');
|
||
|
edit_space.appendChild(edit_area);
|
||
|
enableTab(edit_area);
|
||
|
|
||
|
//add buttons
|
||
|
let button_space = document.createElement('ul');
|
||
|
edit_space.appendChild(button_space);
|
||
|
|
||
|
let copy_button = document.createElement('button');
|
||
|
copy_button.value = 'copy';
|
||
|
copy_button.innerHTML = 'copy';
|
||
|
copy_button.id = 'copy' + i;
|
||
|
copy_button.setAttribute('aria-labelledby', copy_button.id + ' example' + i);
|
||
|
copy_button.className = 'copy_button';
|
||
|
copy_button.onclick = function() {
|
||
|
setMode(sketch, 'edit');
|
||
|
edit_area.select();
|
||
|
document.execCommand('copy');
|
||
|
};
|
||
|
let copy_li = button_space.appendChild(document.createElement('li'));
|
||
|
copy_li.appendChild(copy_button);
|
||
|
|
||
|
let reset_button = document.createElement('button');
|
||
|
reset_button.value = 'reset';
|
||
|
reset_button.innerHTML = 'reset';
|
||
|
reset_button.id = 'reset' + i;
|
||
|
reset_button.setAttribute('aria-labelledby', reset_button.id + ' example' + i);
|
||
|
reset_button.className = 'reset_button';
|
||
|
reset_button.onclick = function() {
|
||
|
edit_area.value = orig_sketch.textContent;
|
||
|
setMode(sketch, 'run');
|
||
|
};
|
||
|
let reset_li = button_space.appendChild(document.createElement('li'));
|
||
|
reset_li.appendChild(reset_button);
|
||
|
|
||
|
let edit_button = document.createElement('button');
|
||
|
edit_button.value = 'edit';
|
||
|
edit_button.innerHTML = 'edit';
|
||
|
edit_button.id = 'edit' + i;
|
||
|
edit_button.setAttribute('aria-labelledby', edit_button.id + ' example' + i);
|
||
|
edit_button.className = 'edit_button';
|
||
|
edit_button.onclick = function(e) {
|
||
|
if (edit_button.innerHTML === 'edit') {
|
||
|
// edit
|
||
|
setMode(sketch, 'edit');
|
||
|
} else {
|
||
|
// run
|
||
|
setMode(sketch, 'run');
|
||
|
}
|
||
|
};
|
||
|
let edit_li = button_space.appendChild(document.createElement('li'));
|
||
|
edit_li.appendChild(edit_button);
|
||
|
|
||
|
function setMode(sketch, m) {
|
||
|
if (m === 'edit') {
|
||
|
$('.example_container').each(function(ind, con) {
|
||
|
if (ind !== i) {
|
||
|
$(con).css('opacity', 0.25);
|
||
|
} else {
|
||
|
$(con).addClass('editing');
|
||
|
}
|
||
|
});
|
||
|
edit_button.innerHTML = 'run';
|
||
|
edit_area.style.display = 'block';
|
||
|
edit_area.focus();
|
||
|
} else {
|
||
|
edit_button.innerHTML = 'edit';
|
||
|
edit_area.style.display = 'none';
|
||
|
sketch.textContent = edit_area.value;
|
||
|
$('.example_container').each(function(ind, con) {
|
||
|
$(con).css('opacity', 1.0);
|
||
|
$(con).removeClass('editing');
|
||
|
});
|
||
|
runCode(sketch, true, i);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function runCode(sketch, rc, i) {
|
||
|
if (instances[i]) {
|
||
|
instances[i].remove();
|
||
|
}
|
||
|
|
||
|
var sketchNode = sketch.parentNode;
|
||
|
var isRef = sketchNode.className.indexOf('ref') !== -1;
|
||
|
var sketchContainer = sketchNode.parentNode;
|
||
|
var parent = sketchContainer.parentNode;
|
||
|
|
||
|
var runnable = sketch.textContent.replace(/^\s+|\s+$/g, '');
|
||
|
var cnv;
|
||
|
|
||
|
if (rc) {
|
||
|
if (isRef) {
|
||
|
cnv = sketchContainer.getElementsByClassName('cnv_div')[0];
|
||
|
} else {
|
||
|
cnv = parent.parentNode.getElementsByClassName('cnv_div')[0];
|
||
|
}
|
||
|
cnv.innerHTML = '';
|
||
|
|
||
|
var s = function(p) {
|
||
|
var fxns = [
|
||
|
'setup', 'draw', 'preload', 'mousePressed', 'mouseReleased',
|
||
|
'mouseMoved', 'mouseDragged', 'mouseClicked', 'doubleClicked',
|
||
|
'mouseWheel', 'touchStarted', 'touchMoved', 'touchEnded',
|
||
|
'keyPressed', 'keyReleased', 'keyTyped'
|
||
|
];
|
||
|
var _found = [];
|
||
|
// p.preload is an empty function created by the p5.sound library in order to use the p5.js preload system
|
||
|
// to load AudioWorklet modules before a sketch runs, even if that sketch doesn't have its own preload function.
|
||
|
// However, this causes an error in the eval code below because the _found array will always contain "preload",
|
||
|
// even if the sketch in question doesn't have a preload function. To get around this, we delete p.preload before
|
||
|
// eval-ing the sketch and add it back afterwards if the sketch doesn't contain its own preload function.
|
||
|
// For more info, see: https://github.com/processing/p5.js-sound/blob/master/src/audioWorklet/index.js#L22
|
||
|
if (p.preload) {
|
||
|
delete p.preload;
|
||
|
}
|
||
|
with (p) {
|
||
|
// Builds a function to detect declared functions via
|
||
|
// them being hoisted past the return statement. Does
|
||
|
// not execute runnable. Two returns with different
|
||
|
// conditions guarantee a return but suppress unreachable
|
||
|
// code warnings.
|
||
|
eval([
|
||
|
'(function() {',
|
||
|
fxns.map(function (_name) {
|
||
|
return [
|
||
|
'try {',
|
||
|
' eval(' + _name + ');',
|
||
|
' _found.push(\'' + _name + '\');',
|
||
|
'} catch(e) {',
|
||
|
' if(!(e instanceof ReferenceError)) {',
|
||
|
' throw e;',
|
||
|
' }',
|
||
|
'}'
|
||
|
].join('');
|
||
|
}).join(''),
|
||
|
'if(_found.length) return;',
|
||
|
'if(!_found.length) return;',
|
||
|
runnable,
|
||
|
'})();'
|
||
|
].join('\n'));
|
||
|
}
|
||
|
// If we haven't found any functions we'll assume it's
|
||
|
// just a setup body with an empty preload.
|
||
|
if (!_found.length) {
|
||
|
p.preload = function() {};
|
||
|
p.setup = function() {
|
||
|
p.createCanvas(100, 100);
|
||
|
p.background(200);
|
||
|
with (p) {
|
||
|
eval(runnable);
|
||
|
}
|
||
|
};
|
||
|
} else {
|
||
|
// Actually runs the code to get functions into scope.
|
||
|
with (p) {
|
||
|
eval(runnable);
|
||
|
}
|
||
|
_found.forEach(function(name) {
|
||
|
p[name] = eval(name);
|
||
|
});
|
||
|
// Ensure p.preload exists even if the sketch doesn't have a preload function.
|
||
|
p.preload = p.preload || function() {};
|
||
|
p.setup = p.setup || function() {
|
||
|
p.createCanvas(100, 100);
|
||
|
p.background(200);
|
||
|
};
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
//if (typeof prettyPrint !== 'undefined') prettyPrint();
|
||
|
if (typeof Prism !== 'undefined') {
|
||
|
Prism.highlightAll();
|
||
|
}
|
||
|
|
||
|
// when a hash is changed, remove all the sounds,
|
||
|
// even tho the p5 sketch has been disposed.
|
||
|
function registerHashChange() {
|
||
|
window.onhashchange = function(e) {
|
||
|
for (var i = 0; i < instances.length; i++) {
|
||
|
instances[i].remove();
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
|
||
|
$(document).ready(function() {
|
||
|
registerHashChange();
|
||
|
|
||
|
setTimeout(function() {
|
||
|
var myp5 = new _p5(s, cnv);
|
||
|
instances[i] = myp5;
|
||
|
}, 100);
|
||
|
});
|
||
|
}
|
||
|
};
|