PennController for IBEX › Forums › Support › html code with embedded script
- This topic has 11 replies, 4 voices, and was last updated 4 years, 4 months ago by abraver.
-
AuthorPosts
-
April 15, 2020 at 11:19 am #5044EricPParticipant
Hi,
I’m trying to add a standardized headphone check as part of my experiment. There’s an html script here: https://github.com/mcdermottLab/HeadphoneCheck (code pasted below) that can run it, but I can’t figure out how (if) this can be incorporated into a PCIbex script. So, that’s my question: is there an easy (lazy) way to make this work in PCIbex, or do I need to decompose it and build from the parts? Probably good to add that I’m pretty clueless when it comes to javascript. Thanks!–for any answer and for your work on PCIbex in general.
Eric
<!DOCTYPE html>
<html>
<head>
<!– 1) Import jQuery from Google CDN –>
<script src=”https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js”></script>
<!– 2) Import HeadphoneCheck.js (minified) from McDermott S3 server –>
<script type=”text/javascript” src=”https://s3.amazonaws.com/mcd-headphone-check/v1.0/src/HeadphoneCheck.min.js”></script>
<!– 2) Import HeadphoneCheck.css from McDermott S3 server –>
<link rel=”stylesheet” type=”text/css” href=”https://s3.amazonaws.com/mcd-headphone-check/v1.0/src/HeadphoneCheckStyle.css”><script>
$(document).ready(function() {
/* 4) Define what to do when the headphone check finishes */
$(document).on(‘hcHeadphoneCheckEnd’, function(event, data) {
var headphoneCheckDidPass = data.didPass;
var headphoneCheckData = data.data;
var didPassMessage = headphoneCheckDidPass ? ‘passed’ : ‘failed’;
alert(‘Screening task ‘ + ‘.’);
});var headphoneCheckConfig = {};
/* 5) Run the headphone check, with customization options defined in headphoneCheckConfig */
HeadphoneCheck.runHeadphoneCheck(headphoneCheckConfig);
});
</script>
</head>
<body>
<!– 3) Create a container div for the headphone check –>
<div id=”hc-container”></div>
</body>
</html>April 15, 2020 at 1:47 pm #5049JeremyKeymasterHi,
Yes, it’s possible, I actually implemented an earlier version of this script before myself
Since you said you’re clueless when it comes to javascript, I don’t know how much of the script below you’ll understand, but it is a full, functional script:
PennController.ResetPrefix(null) // The Farm's jQuery library is outdated, we need to polyfill a couple methods jQuery.prototype.on = function(...args) { return jQuery.prototype.bind.apply(this, args); } jQuery.prototype.prop = function(...args) { return jQuery.prototype.attr.apply(this, args); } // Let's dynamically load the HeadphoneCheck script var HeadphoneCheckScriptTag = document.createElement("script"); HeadphoneCheckScriptTag.src = "https://s3.amazonaws.com/mcd-headphone-check/v1.0/src/HeadphoneCheck.min.js"; document.head.appendChild( HeadphoneCheckScriptTag ); newTrial( newButton("check", "Start Heaphone Check") .print() , // This Canvas will contain the test itself newCanvas("headphonecheck", 500,500) .print() , // The HeadphoneCheck module fills the element whose id is "hc-container" newFunction( () => getCanvas("headphonecheck")._element.jQueryElement.attr("id", "hc-container") ).call() , getButton("check") .wait() .remove() , // Create this Text element, but don't print it just yet newText("failure", "Sorry, you failed the heaphone check") , // This is where it all happens newFunction( () => { $(document).on('hcHeadphoneCheckEnd', function(event, data) { getCanvas("headphonecheck").remove()._runPromises(); if (data.didPass) getButton("dummy").click()._runPromises(); else getText("failure").print()._runPromises() }); HeadphoneCheck.runHeadphoneCheck() }).call() , // This is an invisible button that's clicked in the function above upon success newButton("dummy").wait() )
Jeremy
April 15, 2020 at 2:05 pm #5051EricPParticipantAwesome. I added it to my script and it works as advertised. Thanks!
June 2, 2020 at 12:36 pm #5560NcomeauParticipantIs there any way to customize the displayed instructional text for this implementation of the headphone check?
June 2, 2020 at 1:11 pm #5562JeremyKeymasterYou would need to upload HeadphoneCheck.js to your project and use that instead of directly loading it from S3. Then you could edit the text in HeadphoneCheck.js.
Jeremy
June 2, 2020 at 1:58 pm #5565NcomeauParticipantCan I refer to HeadphoneCheck.js explicitly if I have it in my scripts (HeadphoneCheckScriptTag.src = “HeadphoneCheck.js”;) or would I need to point it to the URL representing my experiment’s scripts directory?
June 2, 2020 at 2:03 pm #5566JeremyKeymasterNo as long as you have it in your scripts it will load, so you no longer need:
var HeadphoneCheckScriptTag = document.createElement("script"); HeadphoneCheckScriptTag.src = "https://s3.amazonaws.com/mcd-headphone-check/v1.0/src/HeadphoneCheck.min.js"; document.head.appendChild( HeadphoneCheckScriptTag );
But maybe move this to the top of HeadphoneCheck.js:
jQuery.prototype.on = function(...args) { return jQuery.prototype.bind.apply(this, args); } jQuery.prototype.prop = function(...args) { return jQuery.prototype.attr.apply(this, args); }
Jeremy
June 3, 2020 at 3:51 pm #5574NcomeauParticipantRemoving those lines works, but moving the jQuery lines to the top of HeadphoneCheck.js yields “Uncaught TypeError: $(…).prop is not a function” in my PennController debugger error tab right after I play the calibration sound and try to click continue. Things work fine when I leave them at the top of my main.js though.
July 25, 2020 at 6:51 pm #5865abraverParticipantHi—
I’m trying to implement the code in the above comment, but I’d like to send the result to the log, rather than have the page serve as a gate for people not using headphones.
I’ve tried everything I can think of—for example, setting a newVar inside the function and trying to get that with .log at the end of the trial—but no luck.
How can I get a JavaScript variable from inside a function to be saved to the log?
Thanks in advance.
July 25, 2020 at 9:25 pm #5866abraverParticipantFor more context, here’s the trial in question. I can print the value I’m looking for to the JavaScript console (console.log(data.data.totalCorrect) but I figure out how to get that into the PCIBex log no matter where I put the .log() function, and no matter whether I try to use data.data.totalCorrect as an argument of .log directly, or if I try to set a new variable and call getVar inside of .log.
newTrial("headphonecheck", newButton("check", "Start Heaphone Check") .print() , // This Canvas will contain the test itself newCanvas("headphonecheck", 500,500) .print() , // The HeadphoneCheck module fills the element whose id is "hc-container" newFunction( () => getCanvas("headphonecheck")._element.jQueryElement.attr("id", "hc-container") ).call() , getButton("check") .wait() .remove() , // Create this Text element, but don't print it just yet newText("failure", "Sorry, you failed the heaphone check") , // This is where it all happens newFunction( () => { $(document).on('hcHeadphoneCheckEnd', function(event, data) { getCanvas("headphonecheck").remove()._runPromises(); getButton("dummy").click()._runPromises(); console.log("totalCorrect"); console.log(data.data.totalCorrect); }); HeadphoneCheck.runHeadphoneCheck({totalTrials: 1, trialsPerPage: 1, doCalibration: false // we definitely want to change this for the real one }) }).call() , // This is an invisible button that's clicked in the function above upon success newButton("dummy").wait() )
July 27, 2020 at 5:22 pm #5870JeremyKeymasterHi,
You cannot directly send messages to the Logs (or Errors) tab of the Debug window. Your console.log commands will send messages to the javascript console.
Note that neither console.log nor a line appearing in the Logs tab of the Debug window means that the relevant event/value will be logged in the results file.
If you want to save totalCorrect in the results file, you will need to sort of “hack” into how PennController-native elements are handled. In practice, it basically just means adding ._runPromises() after the series of PennController commands (like the code’s already doing with the dummy Button element):
newTrial("headphonecheck", newButton("check", "Start Heaphone Check") .print() , // This Canvas will contain the test itself newCanvas("headphonecheck", 500,500) .print() , // The HeadphoneCheck module fills the element whose id is "hc-container" newFunction( () => getCanvas("headphonecheck")._element.jQueryElement.attr("id", "hc-container") ).call() , getButton("check") .wait() .remove() , // Create this Text element, but don't print it just yet newText("failure", "Sorry, you failed the heaphone check") , newVar("totalCorrect") .global() , // This is where it all happens newFunction( () => { $(document).on('hcHeadphoneCheckEnd', function(event, data) { getCanvas("headphonecheck").remove()._runPromises(); getButton("dummy").click()._runPromises(); getVar("totalCorrect").set( data.data.totalCorrect )._runPromises(); }); HeadphoneCheck.runHeadphoneCheck({totalTrials: 1, trialsPerPage: 1, doCalibration: false // we definitely want to change this for the real one }) }).call() , // This is an invisible button that's clicked in the function above upon success newButton("dummy").wait() ) .log( "totalCorrect" , getVar("totalCorrect") )
Note that you won’t get any reports of totalCorrect in your results file for participants who fail the headphone check, as the experiment will never move to the next trial, so nothing will get sent to the server.
Jeremy
July 27, 2020 at 5:35 pm #5871abraverParticipantMany thanks Jeremy (and thanks for this great tool in general). Works like a charm.
(And re: console.log, I was just making sure that the headphone check script was actually reporting *something* and the issue wasn’t its fault.)
-
AuthorPosts
- You must be logged in to reply to this topic.