Jeremy

Forum Replies Created

Viewing 15 posts - 121 through 135 (of 1,522 total)
  • Author
    Posts
  • in reply to: Can we use template literals in Pcibex? #10559
    Jeremy
    Keymaster

    Hi,

    PennController elements do not correspond to any native javascript type, and in particular PennController Var elements do not correspond to javascript variables. As illustrated here, you can pass a Var element to the text command on a Text element to set its value dynamically. In your case, it would look something like this:

    newVar("hitext").set(getVar("ID")).set(v=>`hi, ${v}`),
    newText("instructions-1").text( getVar("hitext") )

    Jeremy

    in reply to: Help with recording audio? #10550
    Jeremy
    Keymaster

    My bad, I shouldn’t have used the word “link”. DownloadRecordingButton returns a string of HTML code that represents a BUTTON HTML element, but that string needs to be parse to effectively add a BUTTON element to the page, which is why you need to pass it to newText for example. So you wouldn’t be inserting a link in a button, you would be inserting a BUTTON HTML element inside a Text PennController element, so the button can be added to the page for the participant to click, and download the archive containing the recordings

    Jeremy

    in reply to: Convert Var/Text to String for get-method #10548
    Jeremy
    Keymaster

    There is no javascript function called setVar. What you can do is:

    getButton("B1")
      .callback( 
        newFunction( ()=>{
          try { getCanvas( getVar("canvasnr")._element.value ).visible()._runPromises(); }
          catch (e) { }
        }).call()
        ,
        getVar("canvasnr").set("C3")
      )

    Jeremy

    in reply to: Help with recording audio? #10547
    Jeremy
    Keymaster

    The experiment will automatically invite the participant to download an archive containing the recordings if upload fails. You can also use DownloadRecordingButton to manually insert a link in a trial of your own, but make sure to do so after the results have been sent to the server

    Jeremy

    in reply to: Can we use template literals in Pcibex? #10546
    Jeremy
    Keymaster

    Hello,

    If you haven’t done so already, I invite you to read <the Core Concepts section in addition to the guide your reference, which also contains some pointers about the proper syntax and scope of PennController commands

    I’ll start with your second message. All PennController commands are javascript functions. When you do newTrial( /* ... */ ) whatever you write in place of /* ... */ are arguments to the function newTrial. It is illegal in javascript to use the let keyword to define a variable as part as an argument, so you cannot do things like newTrial( "myTrial", let time = 100 , newTimer("timeout", time) , /* ... */ ). However, you can do things like newTrial( "myTrial", time = 100 , newTimer("timeout", time) , /* ... */ ) because omitting let will make the expression time=100 return 100, which is a valid argument to pass to a function. Note that this would not set time as a local variable, as in “in the scope of newTrial“, because you simply are not in its scope (you’re just passing arguments)

    Now back to your first message. The files you upload to Resources are not just all thrown into the page when you open the experiment, otherwise it would be a real mess. What happens at the beginning of the experiment is your scripts get executed before body even gets populated, so any reference like document.querySelector(".form__btn--submit"); that you put at the root of your script will simply return null. However, Ibex with its Message and Form controllers, and PennController with newHtml (or newController + Message/Form) allow you to dynamically inject HTML files from the project’s Resources folder at some point during your experiment. The HTML files you upload to Resources can include CSS and javascript. However, the references in <link rel="stylesheet" href="style.css" /> and <script defer src="script.js"></script> will fail on the farm, because the project’s files are not simply exposed at the local path. So you might want to include CSS + javascript in the HTML document, as in:

    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <meta name="description" content="..." />
        <script>
            "use strict";
            // embed code in an async function so as to wait for the button element to be added to the page
            const runScript = async () => {
                /// SELECT BUTTON:
                const btnSubmit = await new Promise(function getBtn(r) {
                  const b = document.querySelector(".form__btn--submit");
                  if (b===null) window.requestAnimationFrame(()=>getBtn(r));
                  else r(b);
                });
            
                // SELECT INPUT:
                const inputSubmitName = document.querySelector(".form__input--name");
                const inputSubmitAge = document.querySelector(".form__input--age");
                 
                // SELECT BOX MESSAGE:
                 
                let welcomeMsg = document.querySelector(".welcome");
                 
                // SELECT FORM DIV
                const formDiv = document.querySelector(".operation--welcome");
                 
                // SELECT AND MANIPULATE CONTENT:
                btnSubmit.addEventListener("click", function (e) {
                  // Prevent default:
                  e.preventDefault();
                 
                  // Get name and age
                  const name = inputSubmitName.value;
                  const age = +inputSubmitAge.value; // transform string to a number
                 
                  // Make it disappear:
                 
                  formDiv.classList.add("welcome--hidden");
                 
                  // Display Welcome User Message:
                 
                  welcomeMsg.classList.remove("welcome--hidden");
                  welcomeMsg.textContent = `Hello, ${name}! You are ${age} years old. Welcome! 🤗`;  ////////////// HERE!!
                 
                  // log
                  console.log(age, name);
                });
            };
            runScript();
        </script>
        <style>
            /* general properties of document */
             
            * {
              margin: 0;
              padding: 0;
              box-sizing: inherit;
            }
             
            body {
              font-family: "Poppins", sans-serif;
              font-weight: 300;
              color: yellow; /* cor do texto */
              line-height: 1.9;
              background-color: #3616d9; /* cor do fundo */
            }
             
            .form--title {
              position: absolute;
              left: 400px;
              height: 350px;
              width: 550px;
              bottom: 90px;
            }
             
            .form--personal__info {
              position: absolute;
              left: 300px;
              height: 350px;
              width: 550px;
              bottom: 50px;
            }
             
            .welcome-message {
              background-color: aquamarine;
              text-align: center;
              font-size: 30px;
              width: 100%;
              position: absolute;
              height: 80px;
              bottom: 280px;
              color: red;
            }
             
            .welcome--hidden {
              opacity: 0;
              transform: translate(20px, 20px);
            }
        </style>
        <title>My first form</title>
      </head>
      <body>
         <div class="operation operation--welcome">
            <h2 class="form--title">Personal Info:</h2>
            <form class="form form--personal__info">
              <input type="text" 
                    class="form__input form__input--name" 
                    placeholder="Your Name here"/>
              <input type="number" 
                    class="form__input form__input--age" 
                    placeholder="Your Age Here"/>
              <button class="form__btn form__btn--submit">→</button>
              <label class="form__label">Submit your data 👈</label>
              <!-- <label class="form__label">your data 👈</label> -->
            </form>
         </div>
         <div class = "welcome welcome-message welcome--hidden">
            <h2 class="new--message">Welcome, user! 😀</h2>
         </div>
      </body>
    </html>
    

    Note that the CSS rules will come after those already in place by Ibex + PennController, so you will want to adapt them (in particular, the position:absolute; shifts your content outside the visible portion of the page)

    Then you can do something like this:

    newTrial(
        newHtml("my_file.html").print()
        ,
        newButton("Next")
            .print()
            .wait()
    )

    Jeremy

    in reply to: Problem with reading data #10535
    Jeremy
    Keymaster

    The “Item” column reports the item number according to Ibex. The other number corresponds to the PennController trial’s index: since PennController trials do not necessarily constitute the entirety of the study’s items (and certainly, in your study, you have non-PennController items, for example the one labeled “intro” does not contain a PennController trial but instead contains a single Message controller) the two number do not necessarily align. The example you mention means that the 40th item in your study corresponded to the 35th PennController trial, and that there likely are at least 5 items that are not PennController trials (I say “likely” because there are other potential sources of mismatch between Ibex’s item numbers and PennController’s trial numbers, eg. one could create some PennController trials first in a certain order and pass them as Ibex items later in a different order)

    Jeremy

    in reply to: Help with recording audio? #10533
    Jeremy
    Keymaster

    Hi,

    No, no version of Google Drive, or any other such out-of-the-box cloud storage option for the matter, will work. The destination platform needs to be able to accept (cross-origin) POST requests, which requires configuration options that only some services make available (eg. AWS or webservers with Apache + PHP, among others)

    EDIT: note that I am talking about Google Drive here, which is distinct from Cloud Storage (similar to AWS S3)

    Jeremy

    in reply to: Problem with reading data #10532
    Jeremy
    Keymaster

    Hello,

    You have four lines per trial because, by default, each PennController trial reports one line for when it starts and one line for when it ends. Then your trials use the log command on an Image element and on a Scale element, which will report two more lines per trial, one for each: one line reports when the Image element was printed onto the page, the other line reports what value was selected on the scale + when the selection occurred. This way, if you need to calculate the time difference between any pair of those four events, you have the option to do so. If all you care about is the value that was selected on the scale, you can just subset the table to those rows that report about the Scale element

    This page of the advanced tutorial illustrates how one can parse the data in R. In particular, read.pcibex will automatically name the table’s columns using the comment lines from the results file (the line starting with #) and the command filter can be used to subset to certain rows only, for example filter(PennElementName == "side-by-side" | PennElementName == "selection") %>% keeps only the rows that correspond to the elements named “side-by-side” or “selection” in the tutorial’s study

    Jeremy

    Jeremy
    Keymaster

    Hi Chloris,

    The limit on the number of rows per batch of download is 100K; you’re far from that, so that shouldn’t be a problem. Did you try logging out, closing and reopening your browser before logging in and trying to download the results again? Feel free to share the link to your study with me, here or at support@pcibex.net if the problem persists

    Jeremy

    Jeremy
    Keymaster

    Hi Chloris,

    You cannot know how many submissions you have per group unless you download the results file. The preview of the results (accessible by clicking the “…” button to the right of the “Results” button) will tell you how many submissions you have received so far in total at the corresponding link — just make sure you refresh the page to get the latest information

    You cannot set a limit to the number of submissions on the farm, as multiple participants might start the experiment in parallel and a subset of them might of might not complete it: there is no principled way of knowing in advance how many submissions you will eventually receive. One common way of handling this point, assuming you are using a crowd-sourcing platform, is to open a limited number of slots on that platform, and open new ones as needed

    Jeremy

    in reply to: Convert Var/Text to String for get-method #10526
    Jeremy
    Keymaster

    Hello Christin,

    You cannot use a reference to a PennController element inside a getX command, because the execution of (plain) JavaScript is immediate, but that of PennController commands is delayed

    What you can do is use a Function element in which you manipulate the PennController elements by accessing their methods and attributes:

    getButton("B1")
      .callback( newFunction( ()=>{
        try { getCanvas( getVar("canvasnr")._element.value ).visible()._runPromises(); } 
        catch (e) { }
      }).call() )

    Jeremy

    in reply to: help on ID information #10521
    Jeremy
    Keymaster

    Hi,

    My bad, the class \w will only capture ASCII based characters. Maybe use \S instead to capture any non-space character: .wait(getTextInput("ID").test.text(/\S/))

    Jeremy

    in reply to: problems with timeout #10519
    Jeremy
    Keymaster

    Hi,

    Use .log("first") instead of just .log() so you can capture keypresses that do not validate a wait command on the Key element:

    newKey("answerTarget", "10")
        .log("first")
        .callback(getTimer("hurry").stop())
    ,
    getTimer("hurry").wait()
    ,
    getKey("answerTarget")
        .test.pressed()
        .success(getText("target").remove())
        .failure(getText("target").remove())
        // removed this .log() as to not overwrite the first one
    ,

    Jeremy

    in reply to: server issue – sources not preloading #10512
    Jeremy
    Keymaster

    Make sure your file .htaccess is owned by the user running PHP. If you need to find out that user, you can upload a PHP file containing <?php echo exec('whoami'); ?> and visit the page in your browser. Once you know the username, just use chown apache .htaccess (assuming apache is the username). Also make sure its permissions are 755: chmod 755 .htaccess. If you do not know how to execute chown/chmod, some programs such as FileZilla will let you modify the owner and permissions of files via their graphic interface (usually through a right-click on the file and an option like “properties”)

    Jeremy

    in reply to: Progress bar for each sentence? #10511
    Jeremy
    Keymaster

    Hello Evgeniya,

    What this chunk of code does is embed a Template command inside a newTrial command, which won’t produce the desired result. If you’d like to brush up on PCIbex experiment structure, I recommend taking a look at this section of the documentation

    What you want to do is insert the commands in the newTrial you already have:

    PennController.ResetPrefix(null);
    const PROGRESS_SIZE = {w: 100, h: 20};
    
    // Experimental trial
    Template("items_pilot.csv", row => 
        newTrial("pilot_experiment",
            defaultText
                .cssContainer({"margin-bottom":"1em"})
                .css({"font-size": "large"})
                .center()
                .print()
            ,        
            newTimer("break", 1000)  //пауза между предложениями = 1 с
                .start()
                .wait()
            ,
            // Printing the Canvas element above the context (feel free to move it somewhere else)
            newCanvas("progressContainer", PROGRESS_SIZE.w, PROGRESS_SIZE.h)
                .add(0,0,newCanvas("progress", PROGRESS_SIZE.w, PROGRESS_SIZE.h).color("green"))
                .css("border","solid 1px black")
                .center()
                .print()
            ,
            newText("context", row.context)
                .css({"background-color": "LightCyan"})
            ,    
            newText("sentence", row.sentence)
            ,
            newScale("natural", "1", "2", "3", "4", "5", "6", "7")
                .before( newText("left", "Полностью неприемлемо  ") )
                .after(  newText("right", "  Полностью приемлемо")  )
                .log("last")
                .print()
                .callback(getTimer("timeout").stop())
            ,
            // Initiating the countdown just before starting the "timeout" Timer element
            newVar("timerInfo").set(()=>[Date.now(),15000]) // set the duration here
            ,
            newFunction( "updateProgress", ()=>{
                const [s,d] = getVar("timerInfo")._element.value;
                const p = (Date.now()-s) / d;
                if (p>1) return;
                getCanvas("progress").size((1-p)*PROGRESS_SIZE.w,PROGRESS_SIZE.h)._runPromises();
                window.requestAnimationFrame( getFunction("updateProgress")._element.function );
            } ).call()
            ,
            newTimer("timeout", 15000)
                .start()
                .wait()
            ,
            // Remove the progress bar once the timer ends (either naturally or by a selection)
            getCanvas("progressContainer").remove()
            ,
            // I moved this here because I presume you want to wait for a selection to happen before setting the Var element
            newVar("rating")
                .global()
                .set(getScale("natural"))
        )
        .log("group", row.group)
        .log( "rating" , getVar("rating") )
        .log("condition", row.condition)
        .log("item", row.item)
        .log("exp_number",row.exp_number)
        .log("construction", row.construction)
        .log("governor", row.governor)
        .log("noun", row.noun)
        .log("pr_n", row.pr_n)
    )

    Jeremy

Viewing 15 posts - 121 through 135 (of 1,522 total)