Global Commands

PennController

PennController( ... ) or newTrial( ... ) since version 1.7

or PennController( "label" , ... ) (since version 1.0) or newTrial( "label" , ... ) since version 1.7

The newTrial command (formerly PennController) creates a new PennController trial. You can use it in three environments: on its own to create a trial (since version 1.0), within Template to generate trials from a spreadsheet, or within the definition of the Ibex variable items to create single elements (deprecated since PennController 1.0).

It takes a sequence of commands as its parameter, which will define the trial’s script. Optionally, you can also pass a string as the first parameter to give a label to your trial which you can refer to when defining the experiment’s sequence order in Sequence. If you pass no string for a label, the trial will be labeled unlabeled.

Example:

newTrial(
    newButton("helloworld", "Hello world!")
        .print()
        .wait()
);

Template( row => 
    newTrial( row.Type ,
        newButton("button", row.ButtonText)
            .print()
            .wait()
    )
);

Creates one trial labeled unlabeled with a single button on the screen reading Hello world!, and generate one-button trials from a spreadsheet, assigning the text from its Type cells as their label and the text from its ButtonText cells as the button’s text (see Template).

PennController.AddHost

PennController.AddHost( url )

You can use AddHost to spare you from specifying a URL when you create an element with newAudio, newVideo or newImage. The URL must end with /.

You can pass multiple URL strings (separated by comma) or use AddHost as many times as you want. If you do so, PennController will try to look for audio/images at the host URLs in the order they were provided, and stop looking as soon as it finds one.

Note that you can still directly specify URLs when creating a new element even if you added a host URL with AddHost.

Example:

AddHost("https://files.lab.florianschwarz.net/test/");
AddHost("http://spellout.net/ibexfarm/static/images/");

newTrial(
    newImage("ibex", "ibex.jpg")
        .print()
    ,
    newImage("wait", "https://openclipart.org/image/300px/svg_to_png/23920/Anonymous-Sandglass.png")
        .print()
    ,
    newAudio("sentence", "test.mp3")
        .play()
        .wait()
);

The trial shows two images and plays one audio file. PennController will first try send a request for the file https://files.lab.florianschwarz.net/test/ibex.png and another one for the file http://spellout.net/ibexfarm/static/images/ibex.png. The same is true for the audio file: PennController will first send a request for the file https://files.lab.florianschwarz.net/test/test.mp3 and another one for the file http://spellout.net/ibexfarm/static/images/test.mp3. PennController uses the resource from the first successfully resolving request: in this example, assuming there is a file named ibex.png at http://spellout.net/ibexfarm/static/images/ and a file named test.mp3 at https://files.lab.florianschwarz.net/test/ (and only there), those are the resources that PennController will use (it may still trigger warnings in the console for the unsuccessful requests). PennController will only look for the wait image at https://openclipart.org/image/300px/svg_to_png/23920/Anonymous-Sandglass.png, since a full URL is provided there.

PennController.AddTable

PennController.AddTable( name, csv_string )

You can use this command to manually define a table to use with Template. You normally do not need to use this command since, as of PennController beta 0.4, you can directly upload your CSV file under Resources / chunk_includes.

Example:

AddTable( "myTable",  // Name of the table
    "Type,Sentence\n"+           // Column names (mind the \n)
    "practice,Hello world!\n"+   // First row (mind the \n)
    "test,Bye world!"            // Second row
);

Template( "myTable" , row => 
    newTrial(
        newText("type", row.Type)
            .print()
        ,
        newButton("sentence", row.Sentence)
            .print()
            .wait()
    )
);

PennController.CheckPreloaded

PennController.CheckPreloaded()

or PennController.CheckPreloaded( labels )

or PennController.CheckPreloaded( delay )

or PennController.CheckPreloaded( labels , delay )

By default, PennController starts the preloading of every image, audio and video resource used in your experiment as soon as the experiment starts running and it will wait before running a trial that all the resources it uses are preloaded. Since this could result in undesirable random breaks in the flow of your experiment, you can control when PennController should check that the resources used by (subsets of) your trials are preloaded before proceeding by using CheckPreloaded.

Note that CheckPreloaded inserts a trial in your experiment the same way newTrial does. You can label the generated trial by using the label command so you can refer to it within Sequence.

You can also define a delay after which the trial sequence will proceed anyway if preloading fails, by passing a number as the last parameter of the command (in milliseconds). Each resource that PennController fails to preload will be reported in a new line in the results file.

Example:

CheckPreloaded("audio", "video");

newTrial( "audio" ,
    newAudio("audio file", "test.mp3")
        .print()
        .play()
        .wait()
);

newTrial( "video" ,
    newVideo("video file", "skate.mp4")
        .print()
        .play()
        .wait()
);

CheckPreloaded();

newTrial( "filler" ,
    newImage("image", "square.png")
        .print()
    ,
    newKey("fj", "FJ")
        .wait()
);

newTrial( "test" ,
    newImage("image", "triangle.png")
        .print()
    ,
    newKey("fj", "FJ")
        .wait()
);

Will make sure that test.mp3 and skate.mp4 are fully preloaded before running the very first PennController trial, labeled audio. After the PennController trial labeled video has ended, will make sure that all image, audio and video resources ever used in the experiment are preloaded before running the trial labeled filler (which practically means it will check that square.png and triangle.png are preloaded, since the first preloader made sure the audio and video resources were already preloaded).

PennController.Debug

PennController.Debug() (since PennController 1.2)

Note: since PennController 1.4, this command is executed by default so you no longer need to call it.

Runs your experiment in Debug mode.

A pop-in console appears at the bottom-right corner of the page when your experiment runs in Debug mode. The Debug console gives you information on the experiment’s structure and on the current trial. Buttons in the Sequence and Log tabs let you force the experiment to move on to the next steps/trials. The Tables tab lists the tables available to your script, which you can click to explore.

In Debug mode, the items variable containing the content of all your trials is publicly accessible. This means that, for example, you can open your browser Javascript’s console and type items to take a look at how each of your trials is defined.

Make sure to use PennController.DebugOff() (since PennController 1.4) before running the final version of your experiment (the items variable will then be undefined during runtime).

Example:

PennController.Debug()

PennController(
    newButton("hello", "Hello world")
        .print()
        .wait()
)

PennController.AddTable( "Words" ,
    "item,Word\n"  +
       "1,Hello\n" +
       "2,World"
)

PennController.Template( "Words" ,
    row => PennController(
        newButton(row.Word)
            .print()
            .wait()
    )
)

PennController.DebugOff

PennController.DebugOff() (since PennController 1.4)

Tells your experiment to not run in Debug mode. Use this before publishing your experiment.

See PennController.Debug for more information about debug mode.

PennController.DownloadRecordingButton

PennController.DownloadRecordingButton( text ) (since PennController 1.8)

formerly PennController.DownloadVoiceButton( text ), now deprecated

Generates a <button> that, when clicked, proposes to download a ZIP archive containing all the media recordings collected during the experiment.

This should be used only after the recordings have been sent to the server you specified as described on this page. You would typically send the results early with SendResults and show an exit page with the button after that.

Example:

InitiateRecorder("https://myserver/uploadVoices/saveRecordings.php")

newTrial( "record" ,
    newMediaRecorder("recorder")
        .print()
        .wait()
)

SendResults()

newTrial(
    newFunction("check upload", ()=>PennController.uploadRecordingsError)
        .test.is()
        .success(
            newText("confirmation", "The recordings were sent to the server. ")
                .print()
        )
        .failure(
            newText("error", "There was a problem sending the recordings to the server. ") 
                .settings.color("red")
                .print()
        )
    ,
    newText("download", DownloadRecordingButton("Click here to download an archive of your recordings.") )
        .print()
    ,
    newTimer("inifinite", 0)
        .wait()
)

Invites the participant to make a video recording and sends the results to the server. In this case, we specified a dummy URL, so uploading the recordings will fail, and PennController.uploadRecordingsError will accordingly be defined. The last screen will inform the participant of the error (since PennController.uploadRecordingsError is not void/undefined) and will show a button to download an archive of the recordings.

PennController.EyeTrackerURL

PennController.EyeTrackerURL(url) (since PennController 1.8)

Tells the script where to send the data collected via the EyeTracker elements.

The URL should point to a PHP script that is able to parse incoming data. See the EyeTracker element page for more information.

PennController.FeedItems

Deprecated since version 1.0. See PennController.Template.

PennController.Footer

PennController.Footer( sequenceOfCommands ) (since beta 0.3)

Will append sequenceOfCommands to the end of the sequence of commands of each trial created with PennController.

Example:

Footer(
    newText("validation instructions", "Click to go to next trial")
        .print()
    ,
    newButton("validation button", "Validate")
        .print()
        .wait()
);

newTrial(
    newText("test sentence", "The cat chases the mouse")
        .print()
    ,
    newScale("natural", 5)
        .settings.slider()
        .settings.before( newText("left", "Unnatural") )
        .settings.after(  newText("right", "Natural")  )
        .print()
);

Without the footer, the trial defined above would be validated immediately after it has started running, since it includes no wait command. Thankfully, the footer adds a button at the bottom of the page that must be clicked for validation.

PennController.GetTable

PennController.GetTable( tablename )

Refers to a table, where tablename can be the filename of a CSV file you uploaded to chunk_includes or the name of a table that was created with AddTable.

You would typically use GetTable within Template when your project contains more than one table and/or when you need to use only a subset of a table, using GetTable().filter.

Example:

Template( GetTable( "spreadsheet.csv" ) , row =>
    newTrial( "button trial" , 
        newButton("test button", row.ButtonText)
            .print()
            .wait()
    )
    .log( "Group" , row.Item )
    .log( "Text"  , row.ButtonText )
);

Generate two trials from the table spreadsheet.csv which contains two rows and the columns Item and ButtonText.

PennController.GetTable().filter

PennController.GetTable( tablename ).filter( "column" , "match" )

or PennController.GetTable( tablename ).filter( "column" , /match/ )

or PennController.GetTable( tablename ).filter( function )

Returns a filtered version of the table, containing only rows whose specified column’s value is a match.

If you use a string then the column’s value must match the text exactly. Alternatively, you can use a regular expression to test the column’s value. You can also use a function that will take each row as an argument and should return true to keep the row or false to exclude it.

You can use several filters in chain.

Example:

Template( 
    GetTable( "spreadsheet.csv" )
        .filter( row => row.Item > 0 )      // 'Item' should be greater than 0, and
        .filter( "ButtonText" , /second/ )  // 'ButtonText' should contain 'second'
    ,
    row => newTrial( "button trial" ,
        newButton("test button", row.ButtonText)
            .print()
            .wait()
    )
    .log( "Item" , row.Item       )
    .log( "Text" , row.ButtonText )
);

Generates only one trial from a subset of the table spreadsheet.csv: first we only consider rows where the value in the Item column is a number greater than 0 (this is practically ineffective, for both rows in spreadsheet.csv already satisfy this condition) and we further consider only rows among those rows where the value of the ButtonText column is a text containing the string second (only the second row satisfies this condition).

PennController.GetTable().setGroupColumn

PennController.GetTable( tablename ).setGroupColumn( columnname )

Tells which column in the table assigns each row to a given group of participants, i.e. which subset of rows PennController will keep for each group of participants listed in the column.

Example:

SetCounter();

AddTable( "test_table" , 
    "Spelling,Text\n"+
    "Normal,Hello\n"+
    "Reversed,olleH\n"+
    "Normal,World\n"+
    "Reversed,dlroW"
);

Template( 
    GetTable( "test_table" ) 
            .setGroupColumn( "Spelling" )
    ,
    row => newTrial( "button trial" ,
        newButton("the button", row.Text )
            .print()
            .wait()
    )
    .log( "Group" , row.Spelling )
    .log( "Text"  , row.Text     )
);

Creates a 2×4 table called test_table with column names Spelling and Text (manual creation for purpose of illustration—you would normally upload a CSV file to chunk_includes). Uses the column Spelling from this table to identify which rows go with which groups of participants.

Every other time the experiment is run, participants will see trials generated either from the two rows where Spelling is Normal or from the two rows where Spelling is Reversed.

The very first line runs a trial incrementing Ibex’s internal counter at the beginning of the experiment, which determines which group is run, so you can cycle through the rows if you re-run the experiment.

PennController.GetURLParameter

PennController.GetURLParameter( parametername )

Retrieves the value of a parameter that was passed after ? in the URL. This is particularly useful if you pass a uniquely identifying code to the URL when you recruit your participants, like http://spellout.net/ibexexps/PennController/Demo/experiment.html?id=abcdefgh

Example:

newTrial( "my trial" ,
    newButton("helloworld", "Hello world!")
        .settings.log()
        .print()
        .wait()
)
.log( "ID" , GetURLParameter( "id" ) );

Will add a column to each result line logged by my trial reporting the value that was passed after id= in the URL.

PennController.Header

PennController.Header( sequenceOfCommands ) (since beta 0.3)

Will evaluate and run sequenceOfCommands at the beginning of each trial created with PennController.

Note that default commands are immediately evaluated (rather than evaluating upon running). As a consequence, any default command will only have an effect on PennController trials defined after the Header has been set.

Example:

Header(
    defaultText
        .print()
)

newTrial(
    newText("test sentence", "The cat is chasing the mouse")
    ,
    newText("instructions", "How natural is this sentence?")
    ,
    newScale("natural", 5)
        .settings.slider()
        .settings.before( newText("left", "Unnatural") )
        .settings.after(  newText("right", "Natural")  )
        .print()
        .wait()
)

newTrial(
    newText("test sentence", "The mouse is being chased by the cat")
    ,
    newText("instructions", "How natural is this sentence?")
    ,
    newScale("natural", 5)
        .settings.slider()
        .settings.before( newText("left", "Unnatural") )
        .settings.after(  newText("right", "Natural")  )
        .print()
        .wait()
)

Though no print command explicitly appears in the trials themselves, the Text elements will be printed onto the page because the header defines print as a default command for all Text elements.

PennController.InitiateRecorder

The recordings you collect will be uploaded as .mp3 files inside a .zip archive file for each participant. However due to a problem with how the voiceRecorder element was coded, the files actually are .ogg files. If you are unable to open them, try using VLC media player.

PennController.InitiateRecorder( url )

or PennController.InitiateRecorder( url , message )

Note: you cannot use this command if you install a custom build of PennController that does not include the VoiceRecorder element.

Use this to specify the URL of the PHP file to upload the audio recordings collected during the experiment.

InitiateRecorder creates a PennController trial asking for the participant’s consent to record audio samples. You can specify a message to replace the default one. Use the label command on it to determine when it should appear in your sequence of trials.

Example:

InitiateRecorder(
    "https://myserver/uploadVoices/saveRecordings.php"
    ,
    "This experiment collects audio recordings. <strong>Once you grant it access to your recording device, you will be notified of whether you are being recorded by a label at the top of the page</strong>"
)

newTrial(
    newVoiceRecorder("recorder")
        .print()
        .wait()
)

Adds a page asking for the participant’s authorization to use their recording device, using a custom text message.

PennController().label

PennController().label( name ) (since PennController 1.1) or newTrial().label( name ) since PennController 1.7

This is another way to assign a label to a PennController trial so you can refer to it in Sequence. It is most useful called on CheckPreloaded or InitiateRecorder since those commands do not take labels as arguments.

Example:

Sequence( "practice" , "preload-exp" , rshuffle("filler","test") )

CheckPreloaded( 
  "filler"
  ,
  "test"
).label( "preload-exp" )

Creates a trial labeled preload-exp checking that all the resources used in the PennController trials labeled filler or test are preloaded, and refers to its label in Sequence so it will be run before the filler and test trials, but after the practice trials.

PennController().log

PennController().log( name, value ) (since beta 0.3) or newTrial().log( name, value ) since 1.7

You can use the .log method to add columns to every line corresponding to this trial that is logged in the results file. You can add as many .log as you want.

Example:

newTrial(
    newButton("helloworld", "Hello world!")
        .settings.log()
        .print()
        .wait()
)
.log("Trial type", "One-Button")
.log("Text on button", "Hello world!");

Will add One-Button and Hello world! to the end of every line saved to the results file for this trial.

PennController().logAppend

PennController().logAppend( name, value ) (replaced with log since beta 0.3)

PennController().noFooter

PennController().noFooter() (since beta 0.3) or newTrial().noFooter() since 1.7

Will not run the footer sequence at the end of the trial.

Example:

Footer(
    newButton("validate", "Got it!")
        .print()
        .wait()
);

newTrial( "with footer" ,
    newScale("score", 5)
        .settings.before( newText("left","Score:") )
        .print()
        .wait()
);
  
newTrial( "without footer" ,
    newScale("score", 5)
        .settings.before( newText("left","Score:") )
        .print()
        .wait()
)
.noFooter();

The first trial (labeled with footer) will show a radio-button scale on the screen and reveal a button reading Got it! to be clicked when a radio button is selected. The second trial (labeled without footer) will end right after a radio button is selected.

PennController().noHeader

PennController().noHeader() (since beta 0.3) or newTrial().noHeader() since 1.7

Will not run the header sequence at the beginning of the trial. Note that this also concerns default commands defined in the header: those will not be run in trials where you use noHeader.

Example:

Header(
    defaultButton
        .print()
        .wait()
    ,
    newText("please", "Please give a score")
        .print()
)

newTrial( "twoClicks" ,
    newScale("score", 5)
        .print()
    ,
    newButton("validate", "Validate")
        .wait( getScale("score").test.selected() )
)

newTrial( "oneClick" ,
    newScale("score", 5)
        .print()
    ,
    newButton("validate", "Validate")
        .print()
        .wait( getScale("score").test.selected() )
)
.noHeader()

The first trial (labeled twoClicks) will show a text at the top of the page, then a radio-button scale and a button. Because the header already contains a wait command, two clicks will be necessary to validate the button (the second one having to happen after a radio-button is selected). On the contrary, the second trial (labeled oneClick) which uses noHeader, will show no text at the top of the page and will only require one click on the button to validate it (assuming a radio-button is selected), because it will only evaluate and execute one wait command.

PennController.PreloadZip

PennController.PreloadZip( url )

or PennController.PreloadZip( url1 , url2, ... )

Instead of fetching audio and images from a distant URL for every single one of your PennController trials using one, you can choose to store them in ZIP archives that you upload on your server. Use PreloadZip to tell where to look the ZIP archives up.

See this page for more details.

PennController.ResetPrefix

PennController.ResetPrefix( "prefix" )

or PennController.ResetPrefix( null )

By default, all the commands to create and refer back to elements in a PennController trial should be preceded by a prefix (PennController.Elements. as of beta 0.3). It is standard practice that every command added by a javascript module (which is what PennController is) uses a specific prefix (in this case, PennController). This is to avoid inadvertently overwriting (or being overwritten by) commands of the same names defined somewhere else, outside of the module. For instance, it could be that you or another module defined a function getImage which, say, takes a filename and adds it at the end of a certain URL (this would be useful if you defined many items using built-in Ibex controllers that contain images and you do not want to type the host URL each time).

Yet, having to write PennController.Elements. before each creation of/reference to an element would be particularly long, painful and not necessarily fit to your aesthetic preferences. Consider this:

PennController.newTrial(
    PennController.Elements.defaultImage
        .settings.size(80, 80)
    ,
    PennController.Elements.newText("helloworld", "Hello world!")
        .print()
    ,
    PennController.Elements.newCanvas("geometry", 200, 100)
        .settings.add(  10, 10, PennController.Elements.newImage("left image", "triangle.png") )
        .settings.add( 110, 10, PennController.Elements.newImage("right image", "square.png") )
        .print()
    ,
    PennController.Elements.newSelector("shapes")
        .settings.add( PennController.Elements.getImage("left image") , PennController.Elements.getImage("right image") )
        .print()
        .wait()
);

Long, painful and a little messy, right?

Now if you already have a getImage function defined somewhere else and you do not want to rename it, but you do not want PennController to erase it either, you can choose to reset the prefix to make everything shorter while keeping your own getImage function. For instance, you can choose to use the prefix E for Element (assuming no script defined a global object named E otherwise):

PennController.ResetPrefix("E");

E.newTrial(
    E.defaultImage
        .settings.size(80, 80)
    ,
    E.newText("helloworld", "Hello world!")
        .print()
    ,
    E.newCanvas("geometry", 200, 100)
        .settings.add(  10, 10, E.newImage("left image", "triangle.png") )
        .settings.add( 110, 10, E.newImage("right image", "square.png") )
        .print()
    ,
    E.newSelector("shapes")
        .settings.add( E.getImage("left image") , E.getImage("right image") )
        .print()
        .wait()
);

This is already much better. But to the extent that PennController’s element commands have names that are not used by default Ibex projects, you may want to straight out drop the prefix using PennController.ResetPrefix( null ), which is what is assumed throughout this documentation (no longer assuming the pre-existence of a getImage function in your project).

PennController.SendResults

PennController.SendResults() (since PennController 1.1)

or PennController.SendResults( "label" ) (since PennController 1.1)

Since PennController 1.7, SendResults can be used in three different environments:

  1. On its own, it creates a trial whose sole function will be to send the results to the server when it is run. You can give a label to the trial by passing a string as an argument to SendResults and then refer to it in Sequence in order to send the results early.
  2. Alternatively, you can use it directly inside Sequence in place of a reference to a label, with the same effect as above (but lifting the need to come up with a dedicated label)
  3. SendResults() can also be used as a command inside a trial: when it is run, it will send the results to the server. This is useful if you want to allow your participants to send their results early for some reason.

Sending the results early is useful if you want your participants to see a confirmation screen at the end.

Examples:

Sequence( "hello" , "world" , SendResults() , "bye" )

newTrial( "hello" ,
    newButton("Hello")
        .settings.log()
        .print()
        .wait()
)
newTrial( "world" ,
    newButton("Send & quit now")
        .settings.callback( 
            getButton("World")
                .remove()
            ,
            SendResults()
        )
        .print( 10 , 10 )
    ,
    newButton("World")
        .settings.log()
        .print()
        .wait()
)

newTrial( "bye" ,
    newText("thanks", "Thank your for participating in this experiment.")
        .print()
    ,
    newText("link", "<a href='.'>Click here to confirm your participation.</a>")
        .print()
    ,
    newTimer("forever", 1)
        .wait()            // Timer never started: will wait forever
)
.setOption("countsForProgressBar",false)

Through the Try-it interface, the Send & quit now button will crash because the experiment is not run globally but instead from within the test page.

PennController.Sequence

PennController.Sequence( labels )

Determines the order in which your trials will be run. Use your trials’ labels to manipulate the running order.

Sequence is a handler for the definition of Ibex’s shuffleSequence variable. As such, its arguments follow the same format as those of Ibex’s seq function. See Ibex’s documentation manual, section called Shuffle sequences.

Example:

Sequence( "hello" , randomize("world") )

newTrial( "world" ,
    newButton("world", "Earth")
        .print()
        .wait()
)
newTrial( "world" ,
    newButton("world", "Moon")
        .print()
        .wait()
)
newTrial( "world" ,
    newButton("world", "Mars")
        .print()
        .wait()
)

newTrial( "hello" ,
    newButton("world", "Hello...")
        .print()
        .wait()
)

Will run the trial labeled hello first, even though it is defined below the world ones, and then will run all three trials labeled world in a random order.

PennController.SetCounter

PennController.SetCounter() (since PennController 1.1)

or PennController.SetCounter( "label" ) (since PennController 1.1)

or PennController.SetCounter( number ) (since PennController 1.1)

or PennController.SetCounter( "label" , number ) (since PennController 1.1)

or PennController.SetCounter( "inc" , number ) (since PennController 1.1)

or PennController.SetCounter( "label" , "inc", number ) (since PennController 1.1)

Creates an item that will set Ibex’s internal counter when it is run.

Ibex has an internal counter which keeps track of how many people participated in your experiment in order to automatically handle group designs. By default, the counter is incremented at the end of the experiment, which has the undesirable effect of assigning the same group to all the participants who click your link before anyone has completed your experiment. You can choose to run SetCounter("inc", 1) at the very beginning of your experiment instead.

You can pass a label as the first argument, which you can then use in Sequence: this way you can make it the first item to run and therefore increment the counter at each click—provided you passed "inc" too. Note that, in the absence of "inc", if you pass a number then the counter will be set to that value.

The intended behavior of this command was to use the number to increment (if positive) or decrement (if negative) the counter accordingly, even in the absence of "inc". This is the observed behavior starting from PennController 1.7

Example:

AddTable( "myTable" , 
  "Group,Button\n"+
  "A,Hello\n"+
  "B,World"
);

Sequence("counter", "trial");

SetCounter("counter", "inc", 1);

Template( "myTable" , row => 
  newTrial( "trial" ,
    newButton( "greetings" , row.Button )
        .print()
        .wait()
  )
);

Increments the counter as soon as the experiment starts running. Since we use a table defining two groups (A and B) the button will read Hello or World every other time the experiment is run (try running it multiple times without clicking the button).

PennController().setOption

PennController().setOption(option, value) (since beta 0.3) or newTrial().setOption(option, value) since 1.7

Lets you modify a parameter of the controller, as you would for any other controller in Ibex.

This can be helpful if you want to override some default settings, such as countsForProgressBar which is used by Ibex.

Example:

newTrial(
    newScale("Score", 8)
        .settings.slider()
        .print()
        .wait()
)
.setOption("countsForProgressBar", false);

This trial will not count for the progress bar at the top of the Ibex experiment page (see the Ibex documentation manual).

PennController.Template

(PennController.FeedItems has become deprecated since version 1.0)

Template( row => PennController() )

or Template( row => ["controllername", options, "controllername", options, ...] )

or Template( row => ["label", "controllername", options, "controllername", options, ...] ) (since PennController 1.4)

or Template( table, row => ... ) (where ... is any of the continuations above)

Generates trials from a table. See this page to learn how to use it. You can have as many Template as you want (which is helpful if you use different trial templates).

You can pass the name of the table you want to use as a string, or use GetTable. If you do not explicitly specify a table, Template will use the table whose name comes first in the alpha-numerical order (if any—if you added only one table, it will automatically use that table).

The argument of Template is a function: you can use arrow functions, as illustrated in this documentation, or old-style functions: Template( function (row) { return newTrial( ... ); } ).

The variable (named row here, but you could also name it item, or however pleases you) is iteratively fed with the content of each row of the table (modulo filtering, see GetTable().filter). You retrieve the value of a given column with row.columnName or row["columnName"] (use the latter if you column’s name contains special characters, like spaces, commas, periods or dashes).

The argument function can directly return newTrial(), defining a PennController template for the trials to be generated. It can also return an array of Ibex item-elements: in that case, it should follow the same format as the definition of a standard Ibex item (though the label string is optional) (see Ibex’s documentation manual).

Examples:

AddTable( "mytable" ,
    "Type,Sentence,TargetPicture,CompetitorPicture\n"+
    "Test,This is a square,square.png,triangle.png\n"+
    "Filler,This is a triangle,triangle.png,pear.png"
);

Template( "mytable" , row => 
    newTrial( row.Type ,
        newText("sentence", row.Sentence)
            .print()
        ,
        newSelector("choice")
        ,
        defaultImage
            .settings.size(200,200)
            .settings.selector("choice")
        ,
        newCanvas( "images", 500, 200 )
            .settings.add(   0, 0, newImage("target", row.TargetPicture)     ) 
            .settings.add( 300, 0, newImage("target", row.CompetitorPicture) ) 
            .print()
        ,
        getSelector("choice")
            .shuffle()
            .wait()
    )
);

Generates trials labeled according to the Type column of the table, showing a sentence whose text is retrieved from the Sentence column of the table, and two pictures side by side retrieved from the TargetPicture and CompetitorPicture columns.

AddTable( "mytable" ,
    "Type,Sentence\n"+
    "Filler,The cat that is chasing the mouse runs fast\n"+
    "Test,The mouse that the cat is chasing runs fast"
);

Template( "mytable" , row => 
    [
        "DashedSentence", {s: row.Sentence},
        "PennController", newTrial(
            newText("question", "How natural did you find this sentence?")
                .print()
            ,
            newScale("natural", 7)
                .settings.before( newText("left", "Completely unnatural") )
                .settings.after( newText("right", "Completely natural") )
                .print()
                .wait()
        )
    ]
);

Generates two-screen trials, the first screen using the native Ibex DashedSentence with the value from the Sentence column passed as its s parameter, the second screen using PennController to show a naturalness scale.

PennController.UploadRecordings

PennController.UploadRecordings() (since PennController 1.8)

or PennController.UploadRecordings("label")

or PennController.UploadRecordings("label" , "noblock")

Creates a trial which, when executed, will send the recordings collected so far via the MediaRecorder element to the URL provided to InitiateRecorder.

You can specify a label so as to control when the UploadRecordings is to be run in the flow of your experiment, by referencing the label in Sequence.

The trial will wait until the recordings are successfully sent, or until an error occurs, before moving to the next trial. Specify "noblock" as the second argument, after the label, if you want the next trial to start immediately, even if the send request has not completed yet.

A final UploadRecordings trial is automatically inserted before your results are sent to the experiment’s server, which will wait until all the upload requests have completed before proceeding to sending the results.

Example:

Sequence( 
  "intro" 
  ,
  sepWith("sendAsync", "recordTrial") 
)

InitiateRecorder("https://my.server/path/to/uploadScript.php")
  .label("intro")

UploadRecordings("sendAsync", "noblock")

newTrial("recordTrial", 
  newText("Please act happiness").print()
  ,
  newMediaRecorder("happiness").print().log().wait()
)

newTrial("recordTrial", 
  newText("Please act sadness").print()
  ,
  newMediaRecorder("happiness").print().log().wait()
)

Will start sending each video sample to the server immediately after it is recorded.