Forum Replies Created
-
AuthorPosts
-
March 17, 2020 at 3:52 pm in reply to: HTML links/input not working on post-experiment HTML page #4884
JeremyKeymasterThey shouldn’t, this is a bug—which version of PennController are you using? I’ll need to fix that
March 17, 2020 at 3:26 pm in reply to: HTML links/input not working on post-experiment HTML page #4882
JeremyKeymasterHi,
I’m not familiar with this bug, but it sounds like there’s an invisible element covering part of the document: do you have a Canvas in another trial (maybe in Header?) that could cause problems if not removed from the screen? Feel free to share the link to the experiment with me if you need further assistance
Jeremy
JeremyKeymasterIf you log your audio elements using the command log("play"), your results file will report a line whenever the audio file is played, indicating its name and when it started playing, this way you can tell which was played first by comparing the timestamps. Another option is to store
randomAudios[0]andrandomAudios[1]in a couple of global Var elements that you log at the end of yournewTrial, following the same method as described on this tutorial page.
JeremyKeymasterHi,
There are two undocumented commandsandandorthat let you do just what you want, e.g:newTrial( newScale("score", 10).print() , newSelector("text") , newText("hello").print().selector("text") , newText("world").print().selector("text") , newButton("validate") .print() .wait( getScale("score").test.selected(5).and( getSelector("text").test.selected( getText("hello") ) ) ) )Be careful with
selector.test.selectedthough, as it will crash if run when no element is selected. I’ll fix this bug in the next release, for the moment you should probably use awaitcommand on the selector before testing it.
JeremyKeymasterHi!
Unfortunately there’s no pure-PennController way of doing this yet, but here is a simple enough workaround injecting some javascript in a trial script (fisherYatesis an Ibex-native function):AddHost("https://upload.wikimedia.org/wikipedia/commons/") // This is where the files are newTrial( newButton("start").print().wait().remove() , randomAudios = ["8/8f/Nl-winputje.ogg","2/2a/Nl-zonderegisters.ogg"],fisherYates(randomAudios) , newAudio(randomAudios[0]) .play() .wait() , newAudio(randomAudios[1]) .play() .wait() , newButton("ok").print().wait() )
JeremyKeymasterHi Elise,
1. It really depends on how you want to counterbalance the position of your pictures. One option is to take care of counterbalancing directly in your table. Another option is to toggle a global Var element on every trial to alternatively display each picture on the left/right. Here’s an example where I alternate showing the text/picture to the left/right on every other trial (note that I’m using PennController 1.7, which shortens command names):
Sequence( randomize("test") ) // This is just a dummy table for this example AddTable("myTable", `DummyColumn dummyRow1 dummyRow2 dummyRow3 dummyRow4`) Template( "myTable" , row => newTrial( "test" , defaultImage.size(200,200) // I want to make sure my images fit in my canvases , newCanvas(400,200) .add( 0 , 0 , newCanvas("left" , 200, 200) ) // The 'left' and 'right' canvases .add( 200 , 0 , newCanvas("right", 200, 200) ) // are simple containers .print() , newVar("toggle", 1) // Initialize with value 1 .global().set( v=>1-v ).test.is(1) // Set to 1 - itself = 1 or 0 on every other trial .success( newImage("pcibex-logo.png").print(0,0,getCanvas("left")), // Fill the containers newText( row.DummyColumn ).print(0,0,getCanvas("right")) // accordingly ) .failure( newImage("pcibex-logo.png").print(0,0,getCanvas("right")), newText( row.DummyColumn ).print( 0,0,getCanvas("left") ) ) , newButton("Next").print().wait() ) )If you’d rather counterbalance upon generation rather than upon execution, ie. have a half-half overall distribution but randomly distributed, add
var i = 0just above yourTemplateline, and replacev=>v-1in thesetcommand with(i++)%22.
Re. preloading: unfortunately there’s no built-in function in PennController yet to control that. What you can do is detect when the preloading message pops up usingrequestAnimationFrameand replace it manually using javascript. It’s not very clean but it does the job. Here’s an example (this code goes at the top of your script, and replace<p>This is a test</p>with whatever HTML content you want to display):let replacePreloadingText = ()=>{ let mainPs = $(".PennController-PennController div p"); if (mainPs.length == 2 && mainPs[0].innerHTML == "Please wait while the resources are preloading"){ mainPs.remove(); $(".PennController-PennController div").append("This is a test
"); } else window.requestAnimationFrame( replacePreloadingText ); } window.requestAnimationFrame( replacePreloadingText );Re. sending the results: there is a native-Ibex option to overwrite the message documented in the manual which consists in defining the variable
sendingResultsMessageto whatever message you want to display instead. Not sure whether you can use HTML there.Let me know if you have any questions
Jeremy
-
This reply was modified 5 years, 8 months ago by
Jeremy.
JeremyKeymasterTo follow-up on this, I just released PennController 1.7 which lets you use SendResults() as a command to… send the results. So one can replace the whole
newFunction...bit in the code above (includingcall()) withSendResults()
JeremyKeymasterYes, you also need to do it when you call
getVarJust a question, when you say that you included a
getVarat the top of your Template function, do you mean inside or outside the nestedPennControllercommand (the one starting after=>)?Feel free to share your code if the problem persists
Jeremy
JeremyKeymasterHi,
There is a known bug with global Var elements which will be fixed with the release of PennController 1.7—I am not quite ready to make that release yet, but if you’re in a hurry I just published a version 1.7 alpha, you can sync it to your project following the steps described here and typing
1.7alphain the branch fieldAlso, did you make sure to also call
.settings.global()on thegetVarjust before you useset?Jeremy
JeremyKeymasterHi Diane,
Yes, it’s possible, but clicking that button would be a point of no return for the participant. Here is one way of doing it (some of this code is hard to make sense of if you’re not already familiar with the arcane of Ibex)
PennController.ResetPrefix(null); PennController.AddTable("myTable", `Label,Text target,Hello filler,hello target,World filler,world`) PennController.Sequence("welcome", rshuffle("target","filler")) PennController.Header( newCanvas("confirmation", '75vw', '80vh') .settings.css("background-color", "floralwhite") .settings.add( "center at 50%", "middle at 25%" , newText("Are you sure you want to send your incomplete results now?") ) .settings.add( "center at 50%", "middle at 75%" , newScale("quit", "Yes", "No").settings.button() ) , newButton("stop", "Stop").settings.callback( getCanvas("confirmation") .print("center at 50vw", "middle at 50vh") , getScale("quit").wait() , getCanvas("confirmation").remove() , getScale("quit").test.selected("Yes") .success( getButton("stop").remove() , newFunction( () => { let mainNode = $("p.PennController-PennController"); mainNode.empty(); let options = { _finishedCallback: r=>console.log("sent",r) , _cssPrefix: '', _utils: { setTimeout: ()=>null } }; addSafeBindMethodPair('__SendResults__'); mainNode['__SendResults__'](options); }).call() ) ) .print("bottom at 98vh","right at 98vw") ) PennController( "welcome" , newButton("Start").print().wait() ) .noHeader() PennController.Template( "myTable", row => PennController( newButton(row.Text).print().wait() ) )I’ll try to implement a user-friendly option in the next release
I’m also working on a new PCIbex Farm which will use a new engine, and I’m trying to see if it could try to regular send partial results after each trial
Let me know if you have any questions
Jeremy
JeremyKeymasterHi,
I think the problem still has to do with quotas—unfortunately for now you still need to let me know when you’ve freed up some space after exceeding the quota (I’m working on a new farm that should handle those things much more smoothly). I double-checked and the lab’s account indeed appeared on the quota-exceeding list, even though it now occupies less than 32MB. I’ve took it off the list, you should be good to go now. Sorry for the inconvenience.
Jeremy
JeremyKeymasterHi Elise,
There must be something else going on in your script, because when I try the script above, neither “wrong” nor “correct” appears on the screen until I press the corresponding key. Do you have any
printcommand elsewhere, maybe called on defaultText? Do you use theprintcommand on the wrong-feedback element somewhere ahead of the key test?Jeremy
JeremyKeymasterThe problem is coming from the Canvas elements: PennController doesn’t understand that you specified the dimension of an anonymous element, instead it takes the first number to be the element’s id (in your case, 700 for the first Canvas, 500 for the second one). As a result the second number is interpreted as the Canvas’ width instead of its height, and so its height is null, making the feedback and button appear behind the Canvas (= under a 0px tall element). Give a name to each of you Canvas and the problem should go away (I would also suggest resizing your Canvas, they are very big right now)
Jeremy
JeremyKeymasterHi Elise,
The problem is coming from the
PennControllercommand that you call from inside anotherPennControllercommand, just before yourgetKey("answer"). It simply shouldn’t be there. Try again with the fixed script below:PennController.Template("Materials_Practice.csv", row => ["dashed_practice", "DashedSentence", {s: row.Sentence}, "PennController", PennController( newImage("CoveredPicture", "covered.png") .settings.size(500,500) , newImage("1", row.Picture) .settings.size(500,500) , newText("leftLabel","(F)") , newText("rightLabel","(J)") , newCanvas(700,500) .settings.add( 350 , 0 , getImage("CoveredPicture")) .settings.add( -250, 0 , getImage("1") ) .print() , newCanvas(500,500) .settings.add(0,500, getText("leftLabel")) .settings.add(600,500, getText("rightLabel")) .print() , newKey("answer","FJ") .wait() , newText("positive feedback", "Correct!") , newText("negative feedback", "Wrong...") , getKey("answer") .test.pressed("F") .success( getText("positive feedback") .print() ) .failure( getText("negative feedback") .print() ) , newButton("continue", "Next") .print() .wait() // You need to wait before going to the next trial )] )Jeremy
February 11, 2020 at 10:44 am in reply to: Trouble loading a batch of images into the experiment #4690
JeremyKeymasterHi!
If all the pictures fail to show up (and you only have their contour) the problem is probably bad URLs. Do you get the filenames from a table? Sometimes there’s a problem with that and you end up with the wrong link (e.g. missing a
/somewhere) Did you check the Debug window’s logs?
Feel free to share the link to your experiment so we can get a better idea of what’s going onWhen you need to load many files the best solution from the participant’s perspective is to use a ZIP file: this way, there’s only one request and you’re certain that when they get the file, no resource is missing (as long as you included them all in the file). But it’s true that the setup can be challenging depending on your hosting platform.
Best
Jeremy -
This reply was modified 5 years, 8 months ago by
-
AuthorPosts