Reply To: DashedSentence in a PennController trial

PennController for IBEX Forums FAQ / Tips DashedSentence in a PennController trial Reply To: DashedSentence in a PennController trial

#6970
Jeremy
Keymaster

Hi Matthias,

Since what you need is not natively supported by Ibex’s DashedSentence controller, and is not immediately implementable in PennController from a simple string, you must resort to at least some javascript code. The snippet from my previous message defines a function that takes a string and automatically generates a series of PennController commands that reproduce certain behaviors of the native-Ibex DashedSentence controller

PennController lets you inject some native-Ibex controller inside your trial’s script, but you cannot use (bits of) PennController code to edit a native-Ibex controller. This means that you cannot simply integrate the function above (which, again, simply outputs a simple series of PennController commands) into the DashedSentence controller

I decided to exclusively rely on PennController for several reasons. First, this is a PennController support space 😉 This means that people here know at least some PennController code, but they do not necessarily know the quite advanced javascript making up the DashedSentence controller’s code. Second, PennController gives you more control over the elements in your trial (technically, you could access each chunk separately, since each is a Text element). Third, I think it’s much easier to understand. This is the output of dashed("myDashed", "Hello world") (for the above definition of dashed):

newText("myDashed","").css({display:'flex','flex-direction':'row','flex-wrap':'wrap','line-height':'2em','max-width':'100%'}).print()
,
newText("myDashed-0", "<span class='DashedSentence-ospan'><span class='DashedSentence-ispan'>Hello</span></span>"))
    .css("margin","0em 0.2em")
    .print(getText("myDashed"))
,
newText("myDashed-1", "<span class='DashedSentence-ospan'><span class='DashedSentence-ispan'>world</span></span>"))
    .css("margin","0em 0.2em")
    .print(getText("myDashed"))
,
newKey("0-Hello"," ").log().wait(),
getText("myDashed-0").text("Hello")
,
newKey("0-Hello"," ").log().wait(),
getText("myDashed-1").text("world")

This output is reasonably simple PennController code. The tricky part is seeing how exactly the dashed function maps the string onto that series of commands. This part does most of the job ...sentence.split(/[\s\t<>]+/): it splits the string at every space/tab/</> character, and generates commands for each chunk. The code is further obscured by the need to handle <br>s, which include linebreaks (rendered as content-less Text elements which occupy 100% of the available page’s width, visually resulting in linebreaks)

Replacing the space/tab separator character with * so as to split chunks of words rather than individual words is pretty straightforward, all that’s needed is to replace the regular expression /[\s\t<>]+/ with /[*<>]+/. Masking the previous word again when revealing the next word requires some slight rearrangement, so that the function outputs “reveal word; wait for keypress; hide word” for each chunk instead of just “wait for keypress; reveal word.” as it does now.

So here’s what you get (I also made it use hyphens instead of underscores after I went back to your previous messages):

dashed = (name,sentence) => [
    newText(name,"").css({display:'flex','flex-direction':'row','flex-wrap':'wrap','line-height':'2em','max-width':'100%'}).print()
    ,
    ...sentence.split(/[*<>]+/).map( (w,i) => (w=="br"?
            newText("").css("width","100vw").print(getText(name))
            :
            newText(name+'-'+i, w.replace(/([^.,?:;!\s])/g,'-'))
                .css({margin:"0em 0.2em",'font-family':'monospace',"font-size":"large"})
                .print(getText(name))
    ))
    ,
    newKey(name+'-start', " ").log().wait() // first keypress, to reveal first chunk
    ,
    ...sentence.split(/[*<>]+/).map((w,i)=>(w!="br"?[
        getText(name+'-'+i).text(w) // reveal chunk
        ,
        newKey(i+"-"+w," ").log().wait() // wait for keypress
        ,
        getText(name+'-'+i).text(w.replace(/([^.,?:;!\s])/g,'-')) // hide chunk
    ]:null))
]

newTrial(
    dashed("myDashed",  "This is a test.*This is the second,*longer part of the test!*"+
                        "<br>And now*this is a third part,*just to test whether*it will automatically*insert a linebreak")
    ,
    getText("myDashed").remove()
    ,
    newButton("Finish").print().wait()
)

Here’s a live example: https://farm.pcibex.net/r/frrjaU/

Let me know if you have any questions

Jeremy