├── .Rbuildignore ├── .gitignore ├── .workbch ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── R ├── build_api.R ├── build_experiment.R ├── build_timeline.R ├── helpers_js.R ├── helpers_misc.R ├── trial_categorise.R ├── trial_simple.R ├── trial_survey.R └── validators.R ├── README.Rmd ├── README.md ├── _pkgdown.yml ├── docs ├── 404.html ├── LICENSE-text.html ├── authors.html ├── docsearch.css ├── docsearch.js ├── index.html ├── link.svg ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml └── reference │ ├── add_properties.html │ ├── add_resources.html │ ├── any_key.html │ ├── code.html │ ├── cue_html.html │ ├── cue_image.html │ ├── cue_text.html │ ├── experiment.html │ ├── html_button_response.html │ ├── html_keyboard_response.html │ ├── html_slider_response.html │ ├── image_button_response.html │ ├── image_keyboard_response.html │ ├── image_slider_response.html │ ├── index.html │ ├── js_array.html │ ├── js_code.html │ ├── js_logical.html │ ├── js_numeric.html │ ├── js_string.html │ ├── js_struct.html │ ├── jshelpers.html │ ├── jspsych_add.html │ ├── jspsych_create.html │ ├── jspsych_init.html │ ├── jspsych_write.html │ ├── keys.html │ ├── make_experiment.html │ ├── no_key.html │ ├── question.html │ ├── question_likert.html │ ├── question_multi.html │ ├── question_multi_choice.html │ ├── question_text.html │ ├── reexports.html │ ├── resource.html │ ├── respond_button.html │ ├── respond_key.html │ ├── respond_slider.html │ ├── response_button.html │ ├── response_buttons.html │ ├── response_freetext.html │ ├── response_key.html │ ├── response_keys.html │ ├── response_likert.html │ ├── response_pickone.html │ ├── response_picksome.html │ ├── response_slider.html │ ├── run_locally.html │ ├── set_resource.html │ ├── stimulus_html.html │ ├── stimulus_image.html │ ├── string.html │ ├── survey_likert.html │ ├── survey_multi_choice.html │ ├── survey_questions.html │ ├── timeline.html │ ├── trial.html │ ├── trial_html_button.html │ ├── trial_html_key.html │ ├── trial_html_slider.html │ ├── trial_image_button.html │ ├── trial_image_key.html │ ├── trial_image_slider.html │ ├── trial_simple.html │ ├── trial_stimulus_response.html │ ├── trial_survey.html │ ├── trial_survey_likert.html │ ├── trial_survey_multi_choice.html │ ├── trial_survey_multi_select.html │ ├── trial_survey_text.html │ ├── unquote.html │ ├── use_variable.html │ ├── variable.html │ ├── with_parameters.html │ └── with_variables.html ├── inst └── extdata │ ├── img │ ├── bisexual.png │ ├── bisexual.svg │ ├── lesbian.svg │ ├── rainbow.svg │ └── transgender.svg │ ├── jsPsych-6.1.0 │ ├── jspsych-animation.js │ ├── jspsych-audio-button-response.js │ ├── jspsych-audio-keyboard-response.js │ ├── jspsych-audio-slider-response.js │ ├── jspsych-call-function.js │ ├── jspsych-categorize-animation.js │ ├── jspsych-categorize-html.js │ ├── jspsych-categorize-image.js │ ├── jspsych-cloze.js │ ├── jspsych-external-html.js │ ├── jspsych-free-sort.js │ ├── jspsych-fullscreen.js │ ├── jspsych-html-button-response.js │ ├── jspsych-html-keyboard-response.js │ ├── jspsych-html-slider-response.js │ ├── jspsych-iat-html.js │ ├── jspsych-iat-image.js │ ├── jspsych-image-button-response.js │ ├── jspsych-image-keyboard-response.js │ ├── jspsych-image-slider-response.js │ ├── jspsych-instructions.js │ ├── jspsych-rdk.js │ ├── jspsych-reconstruction.js │ ├── jspsych-resize.js │ ├── jspsych-same-different-html.js │ ├── jspsych-same-different-image.js │ ├── jspsych-serial-reaction-time-mouse.js │ ├── jspsych-serial-reaction-time.js │ ├── jspsych-survey-html-form.js │ ├── jspsych-survey-likert.js │ ├── jspsych-survey-multi-choice.js │ ├── jspsych-survey-multi-select.js │ ├── jspsych-survey-text.js │ ├── jspsych-video-button-response.js │ ├── jspsych-video-keyboard-response.js │ ├── jspsych-video-slider-response.js │ ├── jspsych-visual-search-circle.js │ ├── jspsych-vsl-animate-occlusion.js │ ├── jspsych-vsl-grid-scene.js │ ├── jspsych.css │ ├── jspsych.js │ └── license.txt │ └── xprmntr.js ├── man ├── add_properties.Rd ├── add_resources.Rd ├── cue_html.Rd ├── cue_image.Rd ├── cue_text.Rd ├── experiment.Rd ├── jshelpers.Rd ├── question.Rd ├── reexports.Rd ├── resource.Rd ├── response_button.Rd ├── response_freetext.Rd ├── response_key.Rd ├── response_likert.Rd ├── response_pickone.Rd ├── response_picksome.Rd ├── response_slider.Rd ├── run_locally.Rd ├── timeline.Rd ├── trial.Rd ├── trial_simple.Rd ├── trial_survey.Rd ├── variable.Rd ├── with_parameters.Rd └── with_variables.Rd ├── misc ├── demo1.R ├── demo1b.R ├── jspsych-6.0.5 │ ├── css │ │ └── jspsych.css │ ├── examples │ │ ├── add-to-end-of-timeline.html │ │ ├── conditional-and-loop-functions.html │ │ ├── css │ │ │ └── jquery-ui.css │ │ ├── data-add-properties.html │ │ ├── data-as-function.html │ │ ├── data-from-timeline.html │ │ ├── data-from-url.html │ │ ├── demo-flanker.html │ │ ├── demo-simple-rt-task.html │ │ ├── demos │ │ │ ├── demo_1.html │ │ │ ├── demo_2.html │ │ │ └── demo_3.html │ │ ├── display-element-to-embed-experiment.html │ │ ├── end-active-node.html │ │ ├── end-experiment.html │ │ ├── exclusions.html │ │ ├── external_html │ │ │ └── simple_consent.html │ │ ├── img │ │ │ ├── 1.gif │ │ │ ├── 10.gif │ │ │ ├── 11.gif │ │ │ ├── 12.gif │ │ │ ├── 2.gif │ │ │ ├── 3.gif │ │ │ ├── 4.gif │ │ │ ├── 5.gif │ │ │ ├── 6.gif │ │ │ ├── 7.gif │ │ │ ├── 8.gif │ │ │ ├── 9.gif │ │ │ ├── age │ │ │ │ ├── of1.jpg │ │ │ │ ├── of2.jpg │ │ │ │ ├── of3.jpg │ │ │ │ ├── om1.jpg │ │ │ │ ├── om2.jpg │ │ │ │ ├── om3.jpg │ │ │ │ ├── yf1.jpg │ │ │ │ ├── yf4.jpg │ │ │ │ ├── yf5.jpg │ │ │ │ ├── ym2.jpg │ │ │ │ ├── ym3.jpg │ │ │ │ └── ym5.jpg │ │ │ ├── backwardN.gif │ │ │ ├── blue.png │ │ │ ├── con1.png │ │ │ ├── con2.png │ │ │ ├── fixation.gif │ │ │ ├── happy_face_1.jpg │ │ │ ├── happy_face_2.jpg │ │ │ ├── happy_face_3.jpg │ │ │ ├── happy_face_4.jpg │ │ │ ├── inc1.png │ │ │ ├── inc2.png │ │ │ ├── normalN.gif │ │ │ ├── orange.png │ │ │ ├── redX.png │ │ │ ├── ribbon.jpg │ │ │ ├── sad_face_1.jpg │ │ │ ├── sad_face_2.jpg │ │ │ ├── sad_face_3.jpg │ │ │ └── sad_face_4.jpg │ │ ├── js │ │ │ └── snap.svg-min.js │ │ ├── jspsych-RDK.html │ │ ├── jspsych-animation.html │ │ ├── jspsych-audio-button-response.html │ │ ├── jspsych-audio-keyboard-response.html │ │ ├── jspsych-audio-slider-response.html │ │ ├── jspsych-call-function.html │ │ ├── jspsych-categorize-animation.html │ │ ├── jspsych-categorize-html.html │ │ ├── jspsych-categorize-image.html │ │ ├── jspsych-form.html │ │ ├── jspsych-free-sort.html │ │ ├── jspsych-fullscreen.html │ │ ├── jspsych-html-button-response.html │ │ ├── jspsych-html-keyboard-response.html │ │ ├── jspsych-html-slider-response.html │ │ ├── jspsych-iat.html │ │ ├── jspsych-image-button-response.html │ │ ├── jspsych-image-keyboard-response.html │ │ ├── jspsych-image-slider-response.html │ │ ├── jspsych-instructions.html │ │ ├── jspsych-reconstruction.html │ │ ├── jspsych-resize.html │ │ ├── jspsych-same-different-html.html │ │ ├── jspsych-same-different-image.html │ │ ├── jspsych-serial-reaction-time-mouse.html │ │ ├── jspsych-serial-reaction-time.html │ │ ├── jspsych-survey-likert.html │ │ ├── jspsych-survey-multi-choice.html │ │ ├── jspsych-survey-multi-select.html │ │ ├── jspsych-survey-text.html │ │ ├── jspsych-video.html │ │ ├── jspsych-visual-search-circle.html │ │ ├── jspsych-vsl-animate-occlusion.html │ │ ├── jspsych-vsl-grid-scene.html │ │ ├── lexical-decision.html │ │ ├── pause-unpause.html │ │ ├── progress-bar.html │ │ ├── sound │ │ │ ├── hammer.mp3 │ │ │ ├── sound.mp3 │ │ │ ├── speech_blue.mp3 │ │ │ ├── speech_green.mp3 │ │ │ ├── speech_joke.mp3 │ │ │ ├── speech_red.mp3 │ │ │ └── tone.mp3 │ │ ├── timeline-variables-sampling.html │ │ ├── timeline-variables.html │ │ └── video │ │ │ └── sample_video.mp4 │ ├── jspsych.js │ ├── license.txt │ └── plugins │ │ ├── jspsych-RDK.js │ │ ├── jspsych-animation.js │ │ ├── jspsych-audio-button-response.js │ │ ├── jspsych-audio-keyboard-response.js │ │ ├── jspsych-audio-slider-response.js │ │ ├── jspsych-call-function.js │ │ ├── jspsych-categorize-animation.js │ │ ├── jspsych-categorize-html.js │ │ ├── jspsych-categorize-image.js │ │ ├── jspsych-external-html.js │ │ ├── jspsych-free-sort.js │ │ ├── jspsych-fullscreen.js │ │ ├── jspsych-html-button-response.js │ │ ├── jspsych-html-keyboard-response.js │ │ ├── jspsych-html-slider-response.js │ │ ├── jspsych-iat-html.js │ │ ├── jspsych-iat-image.js │ │ ├── jspsych-image-button-response.js │ │ ├── jspsych-image-keyboard-response.js │ │ ├── jspsych-image-slider-response.js │ │ ├── jspsych-instructions.js │ │ ├── jspsych-reconstruction.js │ │ ├── jspsych-resize.js │ │ ├── jspsych-same-different-html.js │ │ ├── jspsych-same-different-image.js │ │ ├── jspsych-serial-reaction-time-mouse.js │ │ ├── jspsych-serial-reaction-time.js │ │ ├── jspsych-survey-likert.js │ │ ├── jspsych-survey-multi-choice.js │ │ ├── jspsych-survey-multi-select.js │ │ ├── jspsych-survey-text.js │ │ ├── jspsych-video.js │ │ ├── jspsych-visual-search-circle.js │ │ ├── jspsych-vsl-animate-occlusion.js │ │ ├── jspsych-vsl-grid-scene.js │ │ └── template │ │ └── jspsych-plugin-template.js ├── old_trial_html.R ├── old_trial_image.R ├── old_trial_survey.R └── plumber.R └── xprmntr.Rproj /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^xprmntr\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^LICENSE\.md$ 4 | ^README\.Rmd$ 5 | ^misc$ 6 | ^_pkgdown\.yml$ 7 | ^docs$ 8 | ^pkgdown$ 9 | ^\.workbch$ 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # History files 2 | .Rhistory 3 | .Rapp.history 4 | 5 | # Session Data files 6 | .RData 7 | 8 | # Example code in package build process 9 | *-Ex.R 10 | 11 | # Output files from R CMD build 12 | /*.tar.gz 13 | 14 | # Output files from R CMD check 15 | /*.Rcheck/ 16 | 17 | # RStudio files 18 | .Rproj.user/ 19 | 20 | # produced vignettes 21 | vignettes/*.html 22 | vignettes/*.pdf 23 | 24 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 25 | .httr-oauth 26 | 27 | # knitr and R markdown default cache directories 28 | /*_cache/ 29 | /cache/ 30 | 31 | # Temporary files created by R markdown 32 | *.utf8.md 33 | *.knit.md 34 | 35 | # Shiny token, see https://shiny.rstudio.com/articles/shinyapps.html 36 | rsconnect/ 37 | .Rproj.user 38 | -------------------------------------------------------------------------------- /.workbch: -------------------------------------------------------------------------------- 1 | xprmntr 2 | QdFIpyWKCi 3 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: xprmntr 2 | Title: Behavioral Experiments in the Browser 3 | Version: 0.0.0.9000 4 | Authors@R: 5 | person(given = "Danielle", 6 | family = "Navarro", 7 | role = c("aut", "cre"), 8 | email = "d.navarro@unsw.edu.au", 9 | comment = c(ORCID = "0000-0001-7648-6578")) 10 | Description: What the package does (one paragraph). 11 | License: MIT + file LICENSE 12 | Encoding: UTF-8 13 | LazyData: true 14 | URL: https://github.com/djnavarro/xprmntr 15 | BugReports: https://github.com/djnavarro/xprmntr/issues 16 | RoxygenNote: 6.1.1 17 | Imports: 18 | jsonlite, 19 | plumber, 20 | readr, 21 | purrr, 22 | magrittr, 23 | methods, 24 | utils, 25 | tibble, 26 | rlang, 27 | dplyr 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2019 2 | COPYRIGHT HOLDER: Danielle Navarro 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export("%>%") 4 | export(add_properties) 5 | export(add_resources) 6 | export(cue_html) 7 | export(cue_image) 8 | export(cue_text) 9 | export(experiment) 10 | export(js_array) 11 | export(js_code) 12 | export(js_logical) 13 | export(js_numeric) 14 | export(js_string) 15 | export(js_struct) 16 | export(question) 17 | export(resource) 18 | export(response_button) 19 | export(response_freetext) 20 | export(response_key) 21 | export(response_likert) 22 | export(response_pickone) 23 | export(response_picksome) 24 | export(response_slider) 25 | export(run_locally) 26 | export(timeline) 27 | export(trial) 28 | export(trial_simple) 29 | export(trial_survey) 30 | export(variable) 31 | export(with_parameters) 32 | export(with_variables) 33 | importFrom(magrittr,"%>%") 34 | importFrom(rlang,"%||%") 35 | -------------------------------------------------------------------------------- /R/build_api.R: -------------------------------------------------------------------------------- 1 | # file: api_build.R 2 | # author: Danielle Navarro 3 | 4 | #' Run a jspsych experiment 5 | #' 6 | #' @param path the experiment directory 7 | #' @param port port to use 8 | #' @export 9 | run_locally <- function(path = ".", port = 8000) { 10 | 11 | pr <- plumber::plumber$new() 12 | 13 | static_site <- file.path(path, "experiment") 14 | data_folder <- file.path(path, "data") 15 | static_router <- plumber::PlumberStatic$new(static_site) 16 | 17 | pr$mount("/", static_router) 18 | pr$handle("POST", "/submit", function(req, res){ 19 | 20 | dat <- jsonlite::fromJSON(req$postBody) 21 | dat <- readr::read_csv(dat$filedata) 22 | 23 | tsp <- get_timestamp() 24 | file_id <- paste( 25 | "data", get_timestamp(), get_alphanumeric(10), sep = "_" 26 | ) 27 | dat$file_id <- file_id 28 | dat <- dat[, c(ncol(dat), 1:ncol(dat)-1), drop = FALSE] 29 | readr::write_csv(dat, file.path(data_folder, paste0(file_id, ".csv"))) 30 | }) 31 | 32 | pr$registerHook("exit", function(){ 33 | print("Done!") 34 | }) 35 | 36 | url <- paste0("http://localhost:", port) 37 | utils::browseURL(url) 38 | pr$run(swagger = FALSE, port = port) 39 | 40 | } 41 | -------------------------------------------------------------------------------- /R/build_timeline.R: -------------------------------------------------------------------------------- 1 | # file: timeline_build.R 2 | # author: Danielle Navarro 3 | 4 | #' Initialise a timeline 5 | #' 6 | #' @param ... trial objects to add to this timeline 7 | #' @export 8 | timeline <- function(...){ 9 | tl <- list(timeline = list(...)) 10 | class(tl) <- c("timeline", "list") 11 | tl 12 | } 13 | 14 | #' Adds an arbitrary trial to the timeline 15 | #' 16 | #' @param type the type of trial 17 | #' @param ... arguments passed to the trial plugin 18 | #' @export 19 | trial <- function(type, ...) { 20 | return(list(type = type, ...)) 21 | } 22 | 23 | # lifted version 24 | trial_l <- purrr::lift_dl(trial) 25 | 26 | #' Use a timeline variable 27 | #' 28 | #' @param name name of the variable to insert 29 | #' 30 | #' @export 31 | #' 32 | variable <- function(name) { 33 | str <- paste0("jsPsych.timelineVariable('",name, "')") 34 | return(js_code(str)) 35 | } 36 | 37 | #' Attach a timeline variable to timeline object 38 | #' 39 | #' @param timeline the timeline object 40 | #' @param ... name value pairs 41 | #' 42 | #' @export 43 | with_variables <- function(timeline, ...) { 44 | vars <- list(...) 45 | vars <- purrr::transpose(vars) 46 | timeline[["timeline_variables"]] <- vars 47 | return(timeline) 48 | } 49 | 50 | #' Attach a timeline variable to timeline object 51 | #' 52 | #' @param timeline the timeline object 53 | #' @param ... name value pairs 54 | #' 55 | #' @export 56 | with_parameters <- function(timeline, ...) { 57 | timeline <- c(timeline, ...) 58 | return(timeline) 59 | } 60 | 61 | 62 | -------------------------------------------------------------------------------- /R/helpers_js.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' Manually specify the JavaScript object type 4 | #' 5 | #' @param x an object to be coerced 6 | #' @param ... objects to be concatenated and coerced 7 | #' @name jshelpers 8 | NULL 9 | 10 | #' @export 11 | #' @rdname jshelpers 12 | js_code <- function(x) { 13 | class(x) <- "json" 14 | x 15 | } 16 | 17 | #' @export 18 | #' @rdname jshelpers 19 | js_logical <- function(x) { 20 | as.logical(x) 21 | } 22 | 23 | #' @export 24 | #' @rdname jshelpers 25 | js_numeric <- function(x) { 26 | as.numeric(x) 27 | } 28 | 29 | 30 | # the ... here are individual strings 31 | 32 | #' @export 33 | #' @rdname jshelpers 34 | js_string <- function(...) { 35 | s <- list(...) 36 | string_quote <- function(c) { 37 | if(methods::is(c,"json")) { return(c) } 38 | return(paste0('"',c,'"')) 39 | } 40 | s <- paste(lapply(s, string_quote), collapse = " + ") 41 | js_code(s) 42 | } 43 | 44 | # the ... here are list of name/value pairs 45 | 46 | #' @export 47 | #' @rdname jshelpers 48 | js_struct <- function(...) { 49 | list(...) 50 | } 51 | 52 | 53 | # the ... here are list of name/value pairs 54 | 55 | #' @export 56 | #' @rdname jshelpers 57 | js_array <- function(...) { 58 | classes <- purrr::map_chr(list(...), ~ class(.x)[1]) 59 | if(any(classes == "list")) { 60 | return(list(...)) 61 | } 62 | return(c(...)) 63 | } 64 | 65 | list_to_jsarray <- purrr::lift_dl(js_array) 66 | 67 | 68 | -------------------------------------------------------------------------------- /R/helpers_misc.R: -------------------------------------------------------------------------------- 1 | # file: helpers.R 2 | # author: Danielle Navarro 3 | 4 | any_key <- function() { 5 | js_code("jsPsych.ANY_KEY") 6 | } 7 | 8 | no_key <- function() { 9 | js_code("jsPsych.NO_KEY") 10 | } 11 | 12 | 13 | #' Refers to a resource file 14 | #' 15 | #' @param file path 16 | #' @export 17 | resource <- function(file) { 18 | 19 | # THIS IS A HACK -- FIX THIS 20 | audio <- c(".mp3", ".wav", ".aif", ".mid") 21 | video <- c(".mp4", ".mpg", ".mov", ".wmv") 22 | image <- c(".jpg", ".png", ".bmp", ".svg", ".tiff") 23 | script <- c(".js") 24 | style <- c(".css") 25 | 26 | # assign types based on file extensions 27 | fileext <- tolower(gsub("^.*(\\.[^\\.]*)$", "\\1", file)) 28 | type <- rep("other", length(fileext)) 29 | type[fileext %in% audio] <- "audio" 30 | type[fileext %in% video] <- "video" 31 | type[fileext %in% image] <- "image" 32 | type[fileext %in% script] <- "script" 33 | type[fileext %in% style] <- "style" 34 | 35 | file.path("resource", type, file) 36 | } 37 | 38 | drop_nulls <- function(x) { 39 | x[purrr::map_lgl(x, ~!is.null(.x))] 40 | } 41 | 42 | # returns a list of expressions 43 | capture_dots <- function(...) { 44 | as.list(substitute(list(...)))[-1L] 45 | } 46 | 47 | #' @importFrom magrittr %>% 48 | #' @export 49 | magrittr::`%>%` 50 | 51 | #' @importFrom rlang %||% 52 | NULL 53 | 54 | get_timestamp <- function() { 55 | tsp <- as.character(Sys.time()) 56 | tsp <- gsub("[ :]", "-", tsp) 57 | return(tsp) 58 | } 59 | 60 | get_alphanumeric <- function(n = 5) { 61 | x <- c("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r", 62 | "s","t","u","v","w","x","y","z","0","1","2","3","4","5","6","7","8","9") 63 | r <- sample(x, size = n, replace = TRUE) 64 | r <- paste(r, collapse = "") 65 | return(r) 66 | } 67 | -------------------------------------------------------------------------------- /R/trial_categorise.R: -------------------------------------------------------------------------------- 1 | 2 | #' Create a categorization trial 3 | #' 4 | #' @param cue the cue type for the trial 5 | #' @param response the response type for the question 6 | #' @param prompt prompt to be displayed with the stimulus (can include HTML markup) 7 | #' @param stimulus_duration how long to display stimulus in milliseconds? (default is to remain until response) 8 | #' @param trial_duration how long to wait for response in milliseconds? (default is to wait indefinitely) 9 | #' @param response_ends_trial does the trial end with response (default = TRUE) or continue until trial duration reached? 10 | #' @param ... arguments to be passed to trial() 11 | #' 12 | #' @return A trial object 13 | #' @export 14 | trial_categorize <- function( 15 | cue, # cue_image(), cue_html(), cue_animation(), 16 | response, # response_key() 17 | prompt = NULL, # not intended to be part of the "stimulus" 18 | stimulus_duration = NULL, 19 | trial_duration = NULL, 20 | response_ends_trial = TRUE, 21 | ... 22 | ) { 23 | 24 | 25 | # feedback defined by 26 | key_answer # anim + html + image 27 | text_answer 28 | correct_text 29 | incorrect_text 30 | feedback_duration 31 | 32 | force_correct_button_press # html + image 33 | show_stim_with_feedback # html 34 | show_feedback_on_timeout 35 | 36 | 37 | # animation cue parameters 38 | frame_time 39 | sequence_reps 40 | allow_responses_before_complete 41 | 42 | 43 | 44 | # validate the cue and response classes 45 | require_cue(cue, c("image", "html", "animation")) 46 | require_response(response, c("key")) 47 | 48 | # read off the types 49 | cue_type <- cue$cue_type 50 | response_type <- response$response_type 51 | if(response_type == "key") response_type <- "keyboard" 52 | 53 | # construct the plugin type 54 | plugin_type <- paste("categorize", cue_type, sep = "-") 55 | 56 | # strip the unnecessary fields 57 | cue$cue_type <- NULL 58 | response$response_type <- NULL 59 | 60 | # trial level parameters 61 | trial_parameters <- list( 62 | type = plugin_type, 63 | prompt = prompt, 64 | stimulus_duration = stimulus_duration, 65 | trial_duration = trial_duration, 66 | response_ends_trial = response_ends_trial, 67 | ... 68 | ) 69 | 70 | # return the trial object 71 | trial_data <- c(cue, response, trial_parameters) 72 | return(drop_nulls(trial_l(trial_data))) 73 | 74 | } 75 | -------------------------------------------------------------------------------- /R/validators.R: -------------------------------------------------------------------------------- 1 | 2 | require_cue <- function(cue, type = NULL) { 3 | if(class(cue)[1] != "xpt_cue") { 4 | stop("object of type 'xpt_cue' is required", call. = FALSE) 5 | } 6 | if(!is.null(type)) { 7 | if(!(cue$cue_type %in% type)) { 8 | stop("invalid cue for this trial type", call. = FALSE) 9 | } 10 | } 11 | } 12 | 13 | require_response <- function(response, type = NULL) { 14 | if(class(response)[1] != "xpt_response") { 15 | stop("object of type 'xpt_response' is required", call. = FALSE) 16 | } 17 | if(!is.null(type)) { 18 | if(!(response$response_type %in% type)) { 19 | stop("invalid response for this trial type", call. = FALSE) 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | comment = "#>", 11 | fig.path = "man/figures/README-", 12 | out.width = "100%" 13 | ) 14 | ``` 15 | # xprmntr 16 | 17 | 18 | [![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 19 | [![CRAN status](https://www.r-pkg.org/badges/version/xprmntr)](https://cran.r-project.org/package=xprmntr) 20 | 21 | 22 | The goal of `xprmntr` (pronounced: "experimenter") is to let users build behavioural experiments in R run through the browser, by providing wrappers to the [jspsych](https://www.jspsych.org/) javascript library. 23 | 24 | ## Installation 25 | 26 | The development version can be installed from [GitHub](https://github.com/) with: 27 | 28 | ``` 29 | # install.packages("devtools") 30 | devtools::install_github("djnavarro/xprmntr") 31 | ``` 32 | 33 | ## Goals 34 | 35 | The jsPsych library is organised around a system of *plugins* that generate specific trial types that can be used in a behavioural experiment. The initial goals in xprmtnr is: 36 | 37 | - To provide "general purpose" wrappers that can be used to insert *any* jsPsych plugin (including any novel plugin) 38 | - To provide a convenient API that wraps around the "standard" plugins that come bundled with jsPsych, and provides some structure for the user 39 | - To allow the client side experiment (jsPsych) to communicate with an R server using the plumber package so the experiment can call server-side R functions 40 | - To allow experiments to deploy locally, or github pages, etc. 41 | - To provide mechanisms to save locally, or to dropbox or similar cloud storage 42 | 43 | 44 | ## Notes 45 | 46 | - The "survey" family: 47 | - jspsych-survey-html-form 48 | - jspsych-survey-likert 49 | - jspsych-survey-multi-choice 50 | - jspsych-survey-multi-select 51 | - jspsych-survey-text 52 | - The "sr" family (stimulus-response): 53 | - jspsych-audio-button-response 54 | - jspsych-audio-keyboard-response 55 | - jspsych-audio-slider-response 56 | - jspsych-html-button-response 57 | - jspsych-html-keyboard-response 58 | - jspsych-html-slider-response 59 | - jspsych-image-button-response 60 | - jspsych-image-keyboard-response 61 | - jspsych-image-slider-response 62 | - jspsych-video-button-response 63 | - jspsych-video-keyboard-response 64 | - jspsych-video-slider-response 65 | - The "categorise" family: 66 | - jspsych-categorize-animation 67 | - jspsych-categorize-html 68 | - jspsych-categorize-image 69 | - Other... not sure yet 70 | - jspsych-animation 71 | - jspsych-cloze 72 | - jspsych-free-sort 73 | - jspsych-iat-html 74 | - jspsych-iat-image 75 | - jspsych-rdk 76 | - jspsych-reconstruction 77 | - jspsych-resize 78 | - jspsych-same-different-html 79 | - jspsych-same-different-image 80 | - jspsych-serial-reaction-time 81 | - jspsych-serial-reaction-time-mouse 82 | - jspsych-visual-search-circle 83 | - jspsych-vsl-animate-occlusion 84 | - jspsych-vsl-grid-scene 85 | - "Meta???" family (not strictly "trials") 86 | - jspsych-external-html 87 | - jspsych-call-function 88 | - jspsych-fullscreen 89 | - jspsych-instructions 90 | - possibly have wrappers for loop nodes & conditional nodes here?? 91 | 92 | 93 | ## Possible design: 94 | 95 | 96 | - the "cue" family is used to specify the stimulus (broadly construed) 97 | - cue_html 98 | - cue_text 99 | - cue_image 100 | - cue_audio 101 | - cue_video 102 | - cue_animation 103 | 104 | - the "response" family is used to specify a response mechanism 105 | - response_button 106 | - response_key 107 | - response_slider (continuous) 108 | - response_likert (ordinal) 109 | - response_select (radio or checkbox) 110 | - response_mouse (???) 111 | - response_text (free text??)p 112 | 113 | - the "simple" family is a simple construction 114 | - the "survey" family: the trial is built from multiple questions; a question is a combination of a display_text + response_likert + response_select ... 115 | - the "iat", "same-diff", "categorise" seem like they could be made to fit this framework easily 116 | 117 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # xprmntr 5 | 6 | 7 | 8 | [![Lifecycle: 9 | experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 10 | [![CRAN 11 | status](https://www.r-pkg.org/badges/version/xprmntr)](https://cran.r-project.org/package=xprmntr) 12 | 13 | 14 | The goal of `xprmntr` (pronounced: “experimenter”) is to let users build 15 | behavioural experiments in R run through the browser, by providing 16 | wrappers to the [jspsych](https://www.jspsych.org/) javascript library. 17 | 18 | ## Installation 19 | 20 | The development version can be installed from 21 | [GitHub](https://github.com/) with: 22 | 23 | # install.packages("devtools") 24 | devtools::install_github("djnavarro/xprmntr") 25 | 26 | ## Goals 27 | 28 | The jsPsych library is organised around a system of *plugins* that 29 | generate specific trial types that can be used in a behavioural 30 | experiment. The initial goals in xprmtnr is: 31 | 32 | - To provide “general purpose” wrappers that can be used to insert 33 | *any* jsPsych plugin (including any novel plugin) 34 | - To provide a convenient API that wraps around the “standard” plugins 35 | that come bundled with jsPsych, and provides some structure for the 36 | user 37 | - To allow the client side experiment (jsPsych) to communicate with an 38 | R server using the plumber package so the experiment can call 39 | server-side R functions 40 | - To allow experiments to deploy locally, or github pages, etc. 41 | - To provide mechanisms to save locally, or to dropbox or similar 42 | cloud storage 43 | 44 | ## Notes 45 | 46 | - The “survey” family: 47 | - jspsych-survey-html-form 48 | - jspsych-survey-likert 49 | - jspsych-survey-multi-choice 50 | - jspsych-survey-multi-select 51 | - jspsych-survey-text 52 | - The “sr” family (stimulus-response): 53 | - jspsych-audio-button-response 54 | - jspsych-audio-keyboard-response 55 | - jspsych-audio-slider-response 56 | - jspsych-html-button-response 57 | - jspsych-html-keyboard-response 58 | - jspsych-html-slider-response 59 | - jspsych-image-button-response 60 | - jspsych-image-keyboard-response 61 | - jspsych-image-slider-response 62 | - jspsych-video-button-response 63 | - jspsych-video-keyboard-response 64 | - jspsych-video-slider-response 65 | - The “categorise” family: 66 | - jspsych-categorize-animation 67 | - jspsych-categorize-html 68 | - jspsych-categorize-image 69 | - Other… not sure yet 70 | - jspsych-animation 71 | - jspsych-cloze 72 | - jspsych-free-sort 73 | - jspsych-iat-html 74 | - jspsych-iat-image 75 | - jspsych-rdk 76 | - jspsych-reconstruction 77 | - jspsych-resize 78 | - jspsych-same-different-html 79 | - jspsych-same-different-image 80 | - jspsych-serial-reaction-time 81 | - jspsych-serial-reaction-time-mouse 82 | - jspsych-visual-search-circle 83 | - jspsych-vsl-animate-occlusion 84 | - jspsych-vsl-grid-scene 85 | - “Meta???” family (not strictly “trials”) 86 | - jspsych-external-html 87 | - jspsych-call-function 88 | - jspsych-fullscreen 89 | - jspsych-instructions 90 | - possibly have wrappers for loop nodes & conditional nodes here?? 91 | 92 | ## Possible design: 93 | 94 | - the “cue” family is used to specify the stimulus (broadly construed) 95 | - cue\_html 96 | - cue\_text 97 | - cue\_image 98 | - cue\_audio 99 | - cue\_video 100 | - cue\_animation 101 | - the “response” family is used to specify a response mechanism 102 | - response\_button 103 | - response\_key 104 | - response\_slider (continuous) 105 | - response\_likert (ordinal) 106 | - response\_select (radio or checkbox) 107 | - response\_mouse (???) 108 | - response\_text (free text??)p 109 | - the “simple” family is a simple construction 110 | - the “survey” family: the trial is built from multiple questions; a 111 | question is a combination of a display\_text + response\_likert + 112 | response\_select … 113 | - the “iat”, “same-diff”, “categorise” seem like they could be made to 114 | fit this framework easily 115 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | destination: docs 2 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').scrollspy({ 8 | target: '#sidebar', 9 | offset: 60 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $(".examples, div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent; 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 2.3.1 2 | pkgdown: 1.3.0.9100 3 | pkgdown_sha: 75c3954d45c73f31750ae14fb08502d86adf3e2b 4 | articles: [] 5 | 6 | -------------------------------------------------------------------------------- /inst/extdata/img/bisexual.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/inst/extdata/img/bisexual.png -------------------------------------------------------------------------------- /inst/extdata/img/bisexual.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /inst/extdata/img/lesbian.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /inst/extdata/img/rainbow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /inst/extdata/img/transgender.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-call-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-call-function 3 | * plugin for calling an arbitrary function during a jspsych experiment 4 | * Josh de Leeuw 5 | * 6 | * documentation: docs.jspsych.org 7 | * 8 | **/ 9 | 10 | jsPsych.plugins['call-function'] = (function() { 11 | 12 | var plugin = {}; 13 | 14 | plugin.info = { 15 | name: 'call-function', 16 | description: '', 17 | parameters: { 18 | func: { 19 | type: jsPsych.plugins.parameterType.FUNCTION, 20 | pretty_name: 'Function', 21 | default: undefined, 22 | description: 'Function to call' 23 | }, 24 | async: { 25 | type: jsPsych.plugins.parameterType.BOOL, 26 | pretty_name: 'Asynchronous', 27 | default: false, 28 | description: 'Is the function call asynchronous?' 29 | } 30 | } 31 | } 32 | 33 | plugin.trial = function(display_element, trial) { 34 | trial.post_trial_gap = 0; 35 | var return_val; 36 | 37 | if(trial.async){ 38 | var done = function(data){ 39 | return_val = data; 40 | end_trial(); 41 | } 42 | trial.func(done); 43 | } else { 44 | return_val = trial.func(); 45 | end_trial(); 46 | } 47 | 48 | function end_trial(){ 49 | var trial_data = { 50 | value: return_val 51 | }; 52 | 53 | jsPsych.finishTrial(trial_data); 54 | } 55 | }; 56 | 57 | return plugin; 58 | })(); 59 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-cloze.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-cloze 3 | * Philipp Sprengholz 4 | * 5 | * Plugin for displaying a cloze test and checking participants answers against a correct solution. 6 | * 7 | * documentation: docs.jspsych.org 8 | **/ 9 | 10 | jsPsych.plugins['cloze'] = (function () { 11 | 12 | var plugin = {}; 13 | 14 | plugin.info = { 15 | name: 'cloze', 16 | description: '', 17 | parameters: { 18 | text: { 19 | type: jsPsych.plugins.parameterType.STRING, 20 | pretty_name: 'Cloze text', 21 | default: undefined, 22 | description: 'The cloze text to be displayed. Blanks are indicated by %% signs and automatically replaced by input fields. If there is a correct answer you want the system to check against, it must be typed between the two percentage signs (i.e. %solution%).' 23 | }, 24 | button_text: { 25 | type: jsPsych.plugins.parameterType.STRING, 26 | pretty_name: 'Button text', 27 | default: 'OK', 28 | description: 'Text of the button participants have to press for finishing the cloze test.' 29 | }, 30 | check_answers: { 31 | type: jsPsych.plugins.parameterType.BOOL, 32 | pretty_name: 'Check answers', 33 | default: false, 34 | description: 'Boolean value indicating if the answers given by participants should be compared against a correct solution given in the text (between % signs) after the button was clicked.' 35 | }, 36 | mistake_fn: { 37 | type: jsPsych.plugins.parameterType.FUNCTION, 38 | pretty_name: 'Mistake function', 39 | default: function () {}, 40 | description: 'Function called if check_answers is set to TRUE and there is a difference between the participants answers and the correct solution provided in the text.' 41 | } 42 | } 43 | }; 44 | 45 | plugin.trial = function (display_element, trial) { 46 | 47 | var html = '
    '; 48 | var elements = trial.text.split('%'); 49 | var solutions = []; 50 | 51 | for (i=0; i'; 61 | } 62 | } 63 | html += '
    '; 64 | 65 | display_element.innerHTML = html; 66 | 67 | var check = function() { 68 | 69 | var answers = []; 70 | var answers_correct = true; 71 | 72 | for (i=0; i'; 108 | display_element.querySelector('#finish_cloze_button').addEventListener('click', check); 109 | }; 110 | 111 | return plugin; 112 | })(); -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-external-html.js: -------------------------------------------------------------------------------- 1 | /** (July 2012, Erik Weitnauer) 2 | The html-plugin will load and display an external html pages. To proceed to the next, the 3 | user might either press a button on the page or a specific key. Afterwards, the page get hidden and 4 | the plugin will wait of a specified time before it proceeds. 5 | 6 | documentation: docs.jspsych.org 7 | */ 8 | 9 | jsPsych.plugins['external-html'] = (function() { 10 | 11 | var plugin = {}; 12 | 13 | plugin.info = { 14 | name: 'external-html', 15 | description: '', 16 | parameters: { 17 | url: { 18 | type: jsPsych.plugins.parameterType.STRING, 19 | pretty_name: 'URL', 20 | default: undefined, 21 | description: 'The url of the external html page' 22 | }, 23 | cont_key: { 24 | type: jsPsych.plugins.parameterType.KEYCODE, 25 | pretty_name: 'Continue key', 26 | default: null, 27 | description: 'The key to continue to the next page.' 28 | }, 29 | cont_btn: { 30 | type: jsPsych.plugins.parameterType.STRING, 31 | pretty_name: 'Continue button', 32 | default: null, 33 | description: 'The button to continue to the next page.' 34 | }, 35 | check_fn: { 36 | type: jsPsych.plugins.parameterType.FUNCTION, 37 | pretty_name: 'Check function', 38 | default: function() { return true; }, 39 | description: '' 40 | }, 41 | force_refresh: { 42 | type: jsPsych.plugins.parameterType.BOOL, 43 | pretty_name: 'Force refresh', 44 | default: false, 45 | description: 'Refresh page.' 46 | }, 47 | // if execute_Script == true, then all javascript code on the external page 48 | // will be executed in the plugin site within your jsPsych test 49 | execute_script: { 50 | type: jsPsych.plugins.parameterType.BOOL, 51 | pretty_name: 'Execute scripts', 52 | default: false, 53 | description: 'If true, JS scripts on the external html file will be executed.' 54 | } 55 | } 56 | } 57 | 58 | plugin.trial = function(display_element, trial) { 59 | 60 | var url = trial.url; 61 | if (trial.force_refresh) { 62 | url = trial.url + "?t=" + performance.now(); 63 | } 64 | 65 | load(display_element, url, function() { 66 | var t0 = performance.now(); 67 | var finish = function() { 68 | if (trial.check_fn && !trial.check_fn(display_element)) { return }; 69 | if (trial.cont_key) { display_element.removeEventListener('keydown', key_listener); } 70 | var trial_data = { 71 | rt: performance.now() - t0, 72 | url: trial.url 73 | }; 74 | display_element.innerHTML = ''; 75 | jsPsych.finishTrial(trial_data); 76 | }; 77 | 78 | // by default, scripts on the external page are not executed with XMLHttpRequest(). 79 | // To activate their content through DOM manipulation, we need to relocate all script tags 80 | if (trial.execute_script) { 81 | for (const scriptElement of display_element.getElementsByTagName("script")) { 82 | const relocatedScript = document.createElement("script"); 83 | relocatedScript.text = scriptElement.text; 84 | scriptElement.parentNode.replaceChild(relocatedScript, scriptElement); 85 | }; 86 | } 87 | 88 | if (trial.cont_btn) { display_element.querySelector('#'+trial.cont_btn).addEventListener('click', finish); } 89 | if (trial.cont_key) { 90 | var key_listener = function(e) { 91 | if (e.which == trial.cont_key) finish(); 92 | }; 93 | display_element.addEventListener('keydown', key_listener); 94 | } 95 | }); 96 | }; 97 | 98 | // helper to load via XMLHttpRequest 99 | function load(element, file, callback){ 100 | var xmlhttp = new XMLHttpRequest(); 101 | xmlhttp.open("GET", file, true); 102 | xmlhttp.onload = function(){ 103 | if(xmlhttp.status == 200 || xmlhttp.status == 0){ //Check if loaded 104 | element.innerHTML = xmlhttp.responseText; 105 | callback(); 106 | } 107 | } 108 | xmlhttp.send(); 109 | } 110 | 111 | return plugin; 112 | })(); 113 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-fullscreen.js: -------------------------------------------------------------------------------- 1 | /* jspsych-fullscreen.js 2 | * Josh de Leeuw 3 | * 4 | * toggle fullscreen mode in the browser 5 | * 6 | */ 7 | 8 | jsPsych.plugins.fullscreen = (function() { 9 | 10 | var plugin = {}; 11 | 12 | plugin.info = { 13 | name: 'fullscreen', 14 | description: '', 15 | parameters: { 16 | fullscreen_mode: { 17 | type: jsPsych.plugins.parameterType.BOOL, 18 | pretty_name: 'Fullscreen mode', 19 | default: true, 20 | array: false, 21 | description: 'If true, experiment will enter fullscreen mode. If false, the browser will exit fullscreen mode.' 22 | }, 23 | message: { 24 | type: jsPsych.plugins.parameterType.STRING, 25 | pretty_name: 'Message', 26 | default: '

    The experiment will switch to full screen mode when you press the button below

    ', 27 | array: false, 28 | description: 'HTML content to display above the button to enter fullscreen mode.' 29 | }, 30 | button_label: { 31 | type: jsPsych.plugins.parameterType.STRING, 32 | pretty_name: 'Button label', 33 | default: 'Continue', 34 | array: false, 35 | description: 'The text that appears on the button to enter fullscreen.' 36 | }, 37 | delay_after: { 38 | type: jsPsych.plugins.parameterType.INT, 39 | pretty_name: 'Delay after', 40 | default: 1000, 41 | array: false, 42 | description: 'The length of time to delay after entering fullscreen mode before ending the trial.' 43 | }, 44 | } 45 | } 46 | 47 | plugin.trial = function(display_element, trial) { 48 | 49 | // check if keys are allowed in fullscreen mode 50 | var keyboardNotAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element; 51 | if (keyboardNotAllowed) { 52 | // This is Safari, and keyboard events will be disabled. Don't allow fullscreen here. 53 | // do something else? 54 | endTrial(); 55 | } else { 56 | if(trial.fullscreen_mode){ 57 | display_element.innerHTML = trial.message + ''; 58 | var listener = display_element.querySelector('#jspsych-fullscreen-btn').addEventListener('click', function() { 59 | var element = document.documentElement; 60 | if (element.requestFullscreen) { 61 | element.requestFullscreen(); 62 | } else if (element.mozRequestFullScreen) { 63 | element.mozRequestFullScreen(); 64 | } else if (element.webkitRequestFullscreen) { 65 | element.webkitRequestFullscreen(); 66 | } else if (element.msRequestFullscreen) { 67 | element.msRequestFullscreen(); 68 | } 69 | endTrial(); 70 | }); 71 | } else { 72 | if (document.exitFullscreen) { 73 | document.exitFullscreen(); 74 | } else if (document.msExitFullscreen) { 75 | document.msExitFullscreen(); 76 | } else if (document.mozCancelFullScreen) { 77 | document.mozCancelFullScreen(); 78 | } else if (document.webkitExitFullscreen) { 79 | document.webkitExitFullscreen(); 80 | } 81 | endTrial(); 82 | } 83 | } 84 | 85 | function endTrial() { 86 | 87 | display_element.innerHTML = ''; 88 | 89 | jsPsych.pluginAPI.setTimeout(function(){ 90 | 91 | var trial_data = { 92 | success: !keyboardNotAllowed 93 | }; 94 | 95 | jsPsych.finishTrial(trial_data); 96 | 97 | }, trial.delay_after); 98 | 99 | } 100 | 101 | }; 102 | 103 | return plugin; 104 | })(); 105 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-html-keyboard-response.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-html-keyboard-response 3 | * Josh de Leeuw 4 | * 5 | * plugin for displaying a stimulus and getting a keyboard response 6 | * 7 | * documentation: docs.jspsych.org 8 | * 9 | **/ 10 | 11 | 12 | jsPsych.plugins["html-keyboard-response"] = (function() { 13 | 14 | var plugin = {}; 15 | 16 | plugin.info = { 17 | name: 'html-keyboard-response', 18 | description: '', 19 | parameters: { 20 | stimulus: { 21 | type: jsPsych.plugins.parameterType.HTML_STRING, 22 | pretty_name: 'Stimulus', 23 | default: undefined, 24 | description: 'The HTML string to be displayed' 25 | }, 26 | choices: { 27 | type: jsPsych.plugins.parameterType.KEYCODE, 28 | array: true, 29 | pretty_name: 'Choices', 30 | default: jsPsych.ALL_KEYS, 31 | description: 'The keys the subject is allowed to press to respond to the stimulus.' 32 | }, 33 | prompt: { 34 | type: jsPsych.plugins.parameterType.STRING, 35 | pretty_name: 'Prompt', 36 | default: null, 37 | description: 'Any content here will be displayed below the stimulus.' 38 | }, 39 | stimulus_duration: { 40 | type: jsPsych.plugins.parameterType.INT, 41 | pretty_name: 'Stimulus duration', 42 | default: null, 43 | description: 'How long to hide the stimulus.' 44 | }, 45 | trial_duration: { 46 | type: jsPsych.plugins.parameterType.INT, 47 | pretty_name: 'Trial duration', 48 | default: null, 49 | description: 'How long to show trial before it ends.' 50 | }, 51 | response_ends_trial: { 52 | type: jsPsych.plugins.parameterType.BOOL, 53 | pretty_name: 'Response ends trial', 54 | default: true, 55 | description: 'If true, trial will end when subject makes a response.' 56 | }, 57 | 58 | } 59 | } 60 | 61 | plugin.trial = function(display_element, trial) { 62 | 63 | var new_html = '
    '+trial.stimulus+'
    '; 64 | 65 | // add prompt 66 | if(trial.prompt !== null){ 67 | new_html += trial.prompt; 68 | } 69 | 70 | // draw 71 | display_element.innerHTML = new_html; 72 | 73 | // store response 74 | var response = { 75 | rt: null, 76 | key: null 77 | }; 78 | 79 | // function to end trial when it is time 80 | var end_trial = function() { 81 | 82 | // kill any remaining setTimeout handlers 83 | jsPsych.pluginAPI.clearAllTimeouts(); 84 | 85 | // kill keyboard listeners 86 | if (typeof keyboardListener !== 'undefined') { 87 | jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener); 88 | } 89 | 90 | // gather the data to store for the trial 91 | var trial_data = { 92 | "rt": response.rt, 93 | "stimulus": trial.stimulus, 94 | "key_press": response.key 95 | }; 96 | 97 | // clear the display 98 | display_element.innerHTML = ''; 99 | 100 | // move on to the next trial 101 | jsPsych.finishTrial(trial_data); 102 | }; 103 | 104 | // function to handle responses by the subject 105 | var after_response = function(info) { 106 | 107 | // after a valid response, the stimulus will have the CSS class 'responded' 108 | // which can be used to provide visual feedback that a response was recorded 109 | display_element.querySelector('#jspsych-html-keyboard-response-stimulus').className += ' responded'; 110 | 111 | // only record the first response 112 | if (response.key == null) { 113 | response = info; 114 | } 115 | 116 | if (trial.response_ends_trial) { 117 | end_trial(); 118 | } 119 | }; 120 | 121 | // start the response listener 122 | if (trial.choices != jsPsych.NO_KEYS) { 123 | var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({ 124 | callback_function: after_response, 125 | valid_responses: trial.choices, 126 | rt_method: 'performance', 127 | persist: false, 128 | allow_held_key: false 129 | }); 130 | } 131 | 132 | // hide stimulus if stimulus_duration is set 133 | if (trial.stimulus_duration !== null) { 134 | jsPsych.pluginAPI.setTimeout(function() { 135 | display_element.querySelector('#jspsych-html-keyboard-response-stimulus').style.visibility = 'hidden'; 136 | }, trial.stimulus_duration); 137 | } 138 | 139 | // end trial if trial_duration is set 140 | if (trial.trial_duration !== null) { 141 | jsPsych.pluginAPI.setTimeout(function() { 142 | end_trial(); 143 | }, trial.trial_duration); 144 | } 145 | 146 | }; 147 | 148 | return plugin; 149 | })(); 150 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-reconstruction.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-reconstruction 3 | * a jspsych plugin for a reconstruction task where the subject recreates 4 | * a stimulus from memory 5 | * 6 | * Josh de Leeuw 7 | * 8 | * documentation: docs.jspsych.org 9 | * 10 | */ 11 | 12 | 13 | jsPsych.plugins['reconstruction'] = (function() { 14 | 15 | var plugin = {}; 16 | 17 | plugin.info = { 18 | name: 'reconstruction', 19 | description: '', 20 | parameters: { 21 | stim_function: { 22 | type: jsPsych.plugins.parameterType.FUNCTION, 23 | pretty_name: 'Stimulus function', 24 | default: undefined, 25 | description: 'A function with a single parameter that returns an HTML-formatted string representing the stimulus.' 26 | }, 27 | starting_value: { 28 | type: jsPsych.plugins.parameterType.FLOAT, 29 | pretty_name: 'Starting value', 30 | default: 0.5, 31 | description: 'The starting value of the stimulus parameter.' 32 | }, 33 | step_size: { 34 | type: jsPsych.plugins.parameterType.FLOAT, 35 | pretty_name: 'Step size', 36 | default: 0.05, 37 | description: 'The change in the stimulus parameter caused by pressing one of the modification keys.' 38 | }, 39 | key_increase: { 40 | type: jsPsych.plugins.parameterType.KEYCODE, 41 | pretty_name: 'Key increase', 42 | default: 'h', 43 | description: 'The key to press for increasing the parameter value.' 44 | }, 45 | key_decrease: { 46 | type: jsPsych.plugins.parameterType.KEYCODE, 47 | pretty_name: 'Key decrease', 48 | default: 'g', 49 | description: 'The key to press for decreasing the parameter value.' 50 | }, 51 | button_label: { 52 | type: jsPsych.plugins.parameterType.STRING, 53 | pretty_name: 'Button label', 54 | default: 'Continue', 55 | description: 'The text that appears on the button to finish the trial.' 56 | } 57 | } 58 | } 59 | 60 | plugin.trial = function(display_element, trial) { 61 | 62 | // current param level 63 | var param = trial.starting_value; 64 | 65 | // set-up key listeners 66 | var after_response = function(info) { 67 | 68 | //console.log('fire'); 69 | 70 | var key_i = (typeof trial.key_increase == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_increase) : trial.key_increase; 71 | var key_d = (typeof trial.key_decrease == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_decrease) : trial.key_decrease; 72 | 73 | // get new param value 74 | if (info.key == key_i) { 75 | param = param + trial.step_size; 76 | } else if (info.key == key_d) { 77 | param = param - trial.step_size; 78 | } 79 | param = Math.max(Math.min(1, param), 0); 80 | 81 | // refresh the display 82 | draw(param); 83 | } 84 | 85 | // listen for responses 86 | var key_listener = jsPsych.pluginAPI.getKeyboardResponse({ 87 | callback_function: after_response, 88 | valid_responses: [trial.key_increase, trial.key_decrease], 89 | rt_method: 'performance', 90 | persist: true, 91 | allow_held_key: true 92 | }); 93 | // draw first iteration 94 | draw(param); 95 | 96 | function draw(param) { 97 | 98 | //console.log(param); 99 | 100 | display_element.innerHTML = '
    '+trial.stim_function(param)+'
    '; 101 | 102 | // add submit button 103 | display_element.innerHTML += ''; 104 | 105 | display_element.querySelector('#jspsych-reconstruction-next').addEventListener('click', endTrial); 106 | } 107 | 108 | function endTrial() { 109 | // measure response time 110 | var endTime =performance.now(); 111 | var response_time = endTime - startTime; 112 | 113 | // clear keyboard response 114 | jsPsych.pluginAPI.cancelKeyboardResponse(key_listener); 115 | 116 | // save data 117 | var trial_data = { 118 | "rt": response_time, 119 | "final_value": param, 120 | "start_value": trial.starting_value 121 | }; 122 | 123 | display_element.innerHTML = ''; 124 | 125 | // next trial 126 | jsPsych.finishTrial(trial_data); 127 | } 128 | 129 | var startTime = performance.now(); 130 | 131 | }; 132 | 133 | return plugin; 134 | })(); 135 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych-vsl-grid-scene.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jsPsych plugin for showing scenes that mimic the experiments described in 3 | * 4 | * Fiser, J., & Aslin, R. N. (2001). Unsupervised statistical learning of 5 | * higher-order spatial structures from visual scenes. Psychological science, 6 | * 12(6), 499-504. 7 | * 8 | * Josh de Leeuw 9 | * 10 | * documentation: docs.jspsych.org 11 | * 12 | */ 13 | 14 | jsPsych.plugins['vsl-grid-scene'] = (function() { 15 | 16 | var plugin = {}; 17 | 18 | jsPsych.pluginAPI.registerPreload('vsl-grid-scene', 'stimuli', 'image'); 19 | 20 | plugin.info = { 21 | name: 'vsl-grid-scene', 22 | description: '', 23 | parameters: { 24 | stimuli: { 25 | type: jsPsych.plugins.parameterType.IMAGE, 26 | pretty_name: 'Stimuli', 27 | array: true, 28 | default: undefined, 29 | description: 'An array that defines a grid.' 30 | }, 31 | image_size: { 32 | type: jsPsych.plugins.parameterType.INT, 33 | pretty_name: 'Image size', 34 | array: true, 35 | default: [100,100], 36 | description: 'Array specifying the width and height of the images to show.' 37 | }, 38 | trial_duration: { 39 | type: jsPsych.plugins.parameterType.INT, 40 | pretty_name: 'Trial duration', 41 | default: 2000, 42 | description: 'How long to show the stimulus for in milliseconds.' 43 | } 44 | } 45 | } 46 | 47 | plugin.trial = function(display_element, trial) { 48 | 49 | display_element.innerHTML = plugin.generate_stimulus(trial.stimuli, trial.image_size); 50 | 51 | jsPsych.pluginAPI.setTimeout(function() { 52 | endTrial(); 53 | }, trial.trial_duration); 54 | 55 | function endTrial() { 56 | 57 | display_element.innerHTML = ''; 58 | 59 | var trial_data = { 60 | "stimulus": JSON.stringify(trial.stimuli) 61 | }; 62 | 63 | jsPsych.finishTrial(trial_data); 64 | } 65 | }; 66 | 67 | plugin.generate_stimulus = function(pattern, image_size) { 68 | var nrows = pattern.length; 69 | var ncols = pattern[0].length; 70 | 71 | // create blank element to hold code that we generate 72 | var html = '
    '; 73 | 74 | // create table 75 | html += ''; 77 | 78 | for (var row = 0; row < nrows; row++) { 79 | html += ''; 80 | 81 | for (var col = 0; col < ncols; col++) { 82 | html += ''; 91 | } 92 | html += ''; 93 | } 94 | 95 | html += '
    '+ 84 | '
    '; 85 | if (pattern[row][col] !== 0) { 86 | html += ''; 88 | } 89 | html += '
    '; 90 | html += '
    '; 96 | html += '
    '; 97 | 98 | return html; 99 | 100 | }; 101 | 102 | return plugin; 103 | })(); 104 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/jspsych.css: -------------------------------------------------------------------------------- 1 | /* 2 | * CSS for jsPsych experiments. 3 | * 4 | * This stylesheet provides minimal styling to make jsPsych 5 | * experiments look polished without any additional styles. 6 | */ 7 | 8 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); 9 | 10 | /* Container holding jsPsych content */ 11 | 12 | .jspsych-display-element { 13 | display: flex; 14 | flex-direction: column; 15 | overflow-y: auto; 16 | } 17 | 18 | .jspsych-display-element:focus { 19 | outline: none; 20 | } 21 | 22 | .jspsych-content-wrapper { 23 | display: flex; 24 | margin: auto; 25 | flex: 1 1 100%; 26 | width: 100%; 27 | } 28 | 29 | .jspsych-content { 30 | max-width: 95%; /* this is mainly an IE 10-11 fix */ 31 | text-align: center; 32 | margin: auto; /* this is for overflowing content */ 33 | } 34 | 35 | .jspsych-top { 36 | align-items: flex-start; 37 | } 38 | 39 | .jspsych-middle { 40 | align-items: center; 41 | } 42 | 43 | /* fonts and type */ 44 | 45 | .jspsych-display-element { 46 | font-family: 'Open Sans', 'Arial', sans-serif; 47 | font-size: 18px; 48 | line-height: 1.6em; 49 | } 50 | 51 | /* Form elements like input fields and buttons */ 52 | 53 | .jspsych-display-element input[type="text"] { 54 | font-family: 'Open Sans', 'Arial', sans-serif; 55 | font-size: 14px; 56 | } 57 | 58 | /* borrowing Bootstrap style for btn elements, but combining styles a bit */ 59 | .jspsych-btn { 60 | display: inline-block; 61 | padding: 6px 12px; 62 | margin: 0px; 63 | font-size: 14px; 64 | font-weight: 400; 65 | font-family: 'Open Sans', 'Arial', sans-serif; 66 | cursor: pointer; 67 | line-height: 1.4; 68 | text-align: center; 69 | white-space: nowrap; 70 | vertical-align: middle; 71 | background-image: none; 72 | border: 1px solid transparent; 73 | border-radius: 4px; 74 | color: #333; 75 | background-color: #fff; 76 | border-color: #ccc; 77 | } 78 | 79 | .jspsych-btn:hover { 80 | background-color: #ddd; 81 | border-color: #aaa; 82 | } 83 | 84 | .jspsych-btn:disabled { 85 | background-color: #eee; 86 | color: #aaa; 87 | border-color: #ccc; 88 | cursor: not-allowed; 89 | } 90 | 91 | /* jsPsych progress bar */ 92 | 93 | #jspsych-progressbar-container { 94 | color: #555; 95 | border-bottom: 1px solid #dedede; 96 | background-color: #f9f9f9; 97 | margin-bottom: 1em; 98 | text-align: center; 99 | padding: 8px 0px; 100 | width: 100%; 101 | line-height: 1em; 102 | } 103 | #jspsych-progressbar-container span { 104 | font-size: 14px; 105 | padding-right: 14px; 106 | } 107 | #jspsych-progressbar-outer { 108 | background-color: #eee; 109 | width: 50%; 110 | margin: auto; 111 | height: 14px; 112 | display: inline-block; 113 | vertical-align: middle; 114 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); 115 | } 116 | #jspsych-progressbar-inner { 117 | background-color: #aaa; 118 | width: 0%; 119 | height: 100%; 120 | } 121 | 122 | /* Control appearance of jsPsych.data.displayData() */ 123 | #jspsych-data-display { 124 | text-align: left; 125 | } 126 | -------------------------------------------------------------------------------- /inst/extdata/jsPsych-6.1.0/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Joshua R. de Leeuw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /inst/extdata/xprmntr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * xprmntr.js 3 | * Danielle Navarro 4 | * 5 | **/ 6 | 7 | // bundle everything into the xprmntr object 8 | var xprmntr = {}; 9 | 10 | // for use in the jsPsych.init() call 11 | xprmntr.save_locally = function() { 12 | var data = jsPsych.data.get().csv(); 13 | var file = "xprmntr_local_name"; 14 | var xhr = new XMLHttpRequest(); 15 | xhr.open('POST', 'submit'); 16 | xhr.setRequestHeader('Content-Type', 'application/json'); 17 | xhr.send(JSON.stringify({filename: file, filedata: data})); 18 | }; 19 | 20 | -------------------------------------------------------------------------------- /man/add_properties.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_experiment.R 3 | \name{add_properties} 4 | \alias{add_properties} 5 | \title{Wrapper to jsPsych.data.addProperty} 6 | \usage{ 7 | add_properties(...) 8 | } 9 | \arguments{ 10 | \item{...}{Name/value pairs} 11 | } 12 | \description{ 13 | Wrapper to jsPsych.data.addProperty 14 | } 15 | -------------------------------------------------------------------------------- /man/add_resources.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_experiment.R 3 | \name{add_resources} 4 | \alias{add_resources} 5 | \title{Construct a resource specification from paths} 6 | \usage{ 7 | add_resources(from, audio = c(".mp3", ".wav", ".aif", ".mid"), 8 | video = c(".mp4", ".mpg", ".mov", ".wmv"), image = c(".jpg", ".png", 9 | ".bmp", ".svg", ".tiff"), script = c(".js"), style = c(".css")) 10 | } 11 | \arguments{ 12 | \item{from}{The paths to files/directories} 13 | 14 | \item{audio}{File extensions assumed to be audio} 15 | 16 | \item{video}{File extensions assumed to be video} 17 | 18 | \item{image}{File extensions assumed to be images} 19 | 20 | \item{script}{File extensions assumed to be scripts} 21 | 22 | \item{style}{File extensions assumed to be stylesheets} 23 | } 24 | \description{ 25 | Construct a resource specification from paths 26 | } 27 | -------------------------------------------------------------------------------- /man/cue_html.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{cue_html} 4 | \alias{cue_html} 5 | \title{Define an HTML cue} 6 | \usage{ 7 | cue_html(stimulus) 8 | } 9 | \arguments{ 10 | \item{stimulus}{HTML} 11 | } 12 | \value{ 13 | An object of class xpt_cue 14 | } 15 | \description{ 16 | Define an HTML cue 17 | } 18 | -------------------------------------------------------------------------------- /man/cue_image.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{cue_image} 4 | \alias{cue_image} 5 | \title{Define an image cue} 6 | \usage{ 7 | cue_image(stimulus, stimulus_height = NULL, stimulus_width = NULL, 8 | maintain_aspect_ratio = TRUE) 9 | } 10 | \arguments{ 11 | \item{stimulus}{Image file, specified using the resource() function} 12 | 13 | \item{stimulus_height}{Image height in pixels (defaults to natural height)} 14 | 15 | \item{stimulus_width}{Image width in pixels (defaults to natural width)} 16 | 17 | \item{maintain_aspect_ratio}{Maintain aspect ratio (default = TRUE)} 18 | } 19 | \value{ 20 | An object of class xpt_cue 21 | } 22 | \description{ 23 | Define an image cue 24 | } 25 | -------------------------------------------------------------------------------- /man/cue_text.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{cue_text} 4 | \alias{cue_text} 5 | \title{Define a text cue} 6 | \usage{ 7 | cue_text(stimulus) 8 | } 9 | \arguments{ 10 | \item{stimulus}{text} 11 | } 12 | \value{ 13 | An object of class xpt_cue 14 | } 15 | \description{ 16 | Define a text cue 17 | } 18 | -------------------------------------------------------------------------------- /man/experiment.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_experiment.R 3 | \name{experiment} 4 | \alias{experiment} 5 | \title{Make the experiment} 6 | \usage{ 7 | experiment(timeline, path, resources = NULL, columns = NULL, ...) 8 | } 9 | \arguments{ 10 | \item{timeline}{tl} 11 | 12 | \item{path}{p} 13 | 14 | \item{resources}{r} 15 | 16 | \item{columns}{columns} 17 | 18 | \item{...}{pass to init} 19 | } 20 | \description{ 21 | Make the experiment 22 | } 23 | -------------------------------------------------------------------------------- /man/jshelpers.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers_js.R 3 | \name{jshelpers} 4 | \alias{jshelpers} 5 | \alias{js_code} 6 | \alias{js_logical} 7 | \alias{js_numeric} 8 | \alias{js_string} 9 | \alias{js_struct} 10 | \alias{js_array} 11 | \title{Manually specify the JavaScript object type} 12 | \usage{ 13 | js_code(x) 14 | 15 | js_logical(x) 16 | 17 | js_numeric(x) 18 | 19 | js_string(...) 20 | 21 | js_struct(...) 22 | 23 | js_array(...) 24 | } 25 | \arguments{ 26 | \item{x}{an object to be coerced} 27 | 28 | \item{...}{objects to be concatenated and coerced} 29 | } 30 | \description{ 31 | Manually specify the JavaScript object type 32 | } 33 | -------------------------------------------------------------------------------- /man/question.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{question} 4 | \alias{question} 5 | \title{Create a survey question} 6 | \usage{ 7 | question(cue, response, required = FALSE, name = NULL) 8 | } 9 | \arguments{ 10 | \item{cue}{the prompt for the question} 11 | 12 | \item{response}{the response type for the question} 13 | 14 | \item{required}{is a response to the question required?} 15 | 16 | \item{name}{a convenient label for the question} 17 | } 18 | \value{ 19 | An object of class xpt_question 20 | } 21 | \description{ 22 | Create a survey question 23 | } 24 | -------------------------------------------------------------------------------- /man/reexports.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers_misc.R 3 | \docType{import} 4 | \name{reexports} 5 | \alias{reexports} 6 | \alias{\%>\%} 7 | \title{Objects exported from other packages} 8 | \keyword{internal} 9 | \description{ 10 | These objects are imported from other packages. Follow the links 11 | below to see their documentation. 12 | 13 | \describe{ 14 | \item{magrittr}{\code{\link[magrittr]{\%>\%}}} 15 | }} 16 | 17 | -------------------------------------------------------------------------------- /man/resource.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/helpers_misc.R 3 | \name{resource} 4 | \alias{resource} 5 | \title{Refers to a resource file} 6 | \usage{ 7 | resource(file) 8 | } 9 | \arguments{ 10 | \item{file}{path} 11 | } 12 | \description{ 13 | Refers to a resource file 14 | } 15 | -------------------------------------------------------------------------------- /man/response_button.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{response_button} 4 | \alias{response_button} 5 | \title{Specify a button response} 6 | \usage{ 7 | response_button(choices, button_html = NULL, margin_vertical = "0px", 8 | margin_horizontal = "8px") 9 | } 10 | \arguments{ 11 | \item{choices}{Character vector with labels for the buttons} 12 | 13 | \item{button_html}{HTML templay specifying the buttons (defaults to jsPsych default)} 14 | 15 | \item{margin_vertical}{Vertical margin of the buttons (default "0px")} 16 | 17 | \item{margin_horizontal}{Horizontal margin of the buttons (default "8px")} 18 | } 19 | \value{ 20 | An object of class xpt_response 21 | } 22 | \description{ 23 | Specify a button response 24 | } 25 | -------------------------------------------------------------------------------- /man/response_freetext.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{response_freetext} 4 | \alias{response_freetext} 5 | \title{Specify a free text response} 6 | \usage{ 7 | response_freetext(placeholder = "", rows = 1, columns = 40) 8 | } 9 | \arguments{ 10 | \item{placeholder}{String specifying the placeholder text} 11 | 12 | \item{rows}{Number of rows spanned by the text box} 13 | 14 | \item{columns}{Number of columns spanned by the text box} 15 | } 16 | \value{ 17 | An object of class xpt_response 18 | } 19 | \description{ 20 | Specify a free text response 21 | } 22 | -------------------------------------------------------------------------------- /man/response_key.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{response_key} 4 | \alias{response_key} 5 | \title{Specify a keyboard response} 6 | \usage{ 7 | response_key(...) 8 | } 9 | \arguments{ 10 | \item{...}{Either single string "any" (default), "none", or characters specifying keys} 11 | } 12 | \value{ 13 | An object of class xpt_response 14 | } 15 | \description{ 16 | Specify a keyboard response 17 | } 18 | -------------------------------------------------------------------------------- /man/response_likert.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{response_likert} 4 | \alias{response_likert} 5 | \title{Specify a Likert response} 6 | \usage{ 7 | response_likert(labels, scale_width = NULL) 8 | } 9 | \arguments{ 10 | \item{labels}{character vector of response labels} 11 | 12 | \item{scale_width}{width of the "slider" in pixels} 13 | } 14 | \value{ 15 | An object of class xpt_response 16 | } 17 | \description{ 18 | Specify a Likert response 19 | } 20 | -------------------------------------------------------------------------------- /man/response_pickone.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{response_pickone} 4 | \alias{response_pickone} 5 | \title{Specify a 'pick one' response} 6 | \usage{ 7 | response_pickone(options, horizontal = FALSE) 8 | } 9 | \arguments{ 10 | \item{options}{character vector of options} 11 | 12 | \item{horizontal}{should radio buttons be laid out horizontally?} 13 | } 14 | \value{ 15 | An object of class xpt_response 16 | } 17 | \description{ 18 | Specify a 'pick one' response 19 | } 20 | -------------------------------------------------------------------------------- /man/response_picksome.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{response_picksome} 4 | \alias{response_picksome} 5 | \title{Specify a 'pick some' response} 6 | \usage{ 7 | response_picksome(options, horizontal = FALSE) 8 | } 9 | \arguments{ 10 | \item{options}{character vector of options} 11 | 12 | \item{horizontal}{should check boxes be laid out horizontally?} 13 | } 14 | \value{ 15 | An object of class xpt_response 16 | } 17 | \description{ 18 | Specify a 'pick some' response 19 | } 20 | -------------------------------------------------------------------------------- /man/response_slider.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{response_slider} 4 | \alias{response_slider} 5 | \title{Specify a slider response} 6 | \usage{ 7 | response_slider(labels = NULL, button_label = "Continue", min = 0, 8 | max = 100, start = 50, step = 1, slider_width = NULL, 9 | require_movement = FALSE) 10 | } 11 | \arguments{ 12 | \item{labels}{Character vector of labels, to be spaced equally along slider} 13 | 14 | \item{button_label}{Text displayed on button at the end (default = "Continue")} 15 | 16 | \item{min}{Minimum value of the slider (default = 0)} 17 | 18 | \item{max}{Maximum value of the slider (default = 100)} 19 | 20 | \item{start}{Starting value of the slider (default = 50)} 21 | 22 | \item{step}{Smallest increment of slider movement (default = 1)} 23 | 24 | \item{slider_width}{Horizontal width of slider (defaults to max width)} 25 | 26 | \item{require_movement}{Does user need to move the slider to continue? (default = FALSE)} 27 | } 28 | \value{ 29 | An object of class xpt_response 30 | } 31 | \description{ 32 | Specify a slider response 33 | } 34 | -------------------------------------------------------------------------------- /man/run_locally.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_api.R 3 | \name{run_locally} 4 | \alias{run_locally} 5 | \title{Run a jspsych experiment} 6 | \usage{ 7 | run_locally(path = ".", port = 8000) 8 | } 9 | \arguments{ 10 | \item{path}{the experiment directory} 11 | 12 | \item{port}{port to use} 13 | } 14 | \description{ 15 | Run a jspsych experiment 16 | } 17 | -------------------------------------------------------------------------------- /man/timeline.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_timeline.R 3 | \name{timeline} 4 | \alias{timeline} 5 | \title{Initialise a timeline} 6 | \usage{ 7 | timeline(...) 8 | } 9 | \arguments{ 10 | \item{...}{trial objects to add to this timeline} 11 | } 12 | \description{ 13 | Initialise a timeline 14 | } 15 | -------------------------------------------------------------------------------- /man/trial.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_timeline.R 3 | \name{trial} 4 | \alias{trial} 5 | \title{Adds an arbitrary trial to the timeline} 6 | \usage{ 7 | trial(type, ...) 8 | } 9 | \arguments{ 10 | \item{type}{the type of trial} 11 | 12 | \item{...}{arguments passed to the trial plugin} 13 | } 14 | \description{ 15 | Adds an arbitrary trial to the timeline 16 | } 17 | -------------------------------------------------------------------------------- /man/trial_simple.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_simple.R 3 | \name{trial_simple} 4 | \alias{trial_simple} 5 | \title{Create a simple trial} 6 | \usage{ 7 | trial_simple(cue, response, prompt = NULL, stimulus_duration = NULL, 8 | trial_duration = NULL, response_ends_trial = TRUE, ...) 9 | } 10 | \arguments{ 11 | \item{cue}{the cue type for the trial} 12 | 13 | \item{response}{the response type for the question} 14 | 15 | \item{prompt}{prompt to be displayed with the stimulus (can include HTML markup)} 16 | 17 | \item{stimulus_duration}{how long to display stimulus in milliseconds? (default is to remain until response)} 18 | 19 | \item{trial_duration}{how long to wait for response in milliseconds? (default is to wait indefinitely)} 20 | 21 | \item{response_ends_trial}{does the trial end with response (default = TRUE) or continue until trial duration reached?} 22 | 23 | \item{...}{arguments to be passed to trial()} 24 | } 25 | \value{ 26 | A trial object 27 | } 28 | \description{ 29 | Create a simple trial 30 | } 31 | -------------------------------------------------------------------------------- /man/trial_survey.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/trial_survey.R 3 | \name{trial_survey} 4 | \alias{trial_survey} 5 | \title{Create a survey trial} 6 | \usage{ 7 | trial_survey(questions, preamble = "", 8 | randomize_question_order = FALSE, button_label = "Continue") 9 | } 10 | \arguments{ 11 | \item{questions}{A question or list of questions} 12 | 13 | \item{preamble}{Text to appear above the questions} 14 | 15 | \item{randomize_question_order}{Should order be randomised?} 16 | 17 | \item{button_label}{Text for the continue button} 18 | } 19 | \value{ 20 | A trial object 21 | } 22 | \description{ 23 | Create a survey trial 24 | } 25 | -------------------------------------------------------------------------------- /man/variable.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_timeline.R 3 | \name{variable} 4 | \alias{variable} 5 | \title{Use a timeline variable} 6 | \usage{ 7 | variable(name) 8 | } 9 | \arguments{ 10 | \item{name}{name of the variable to insert} 11 | } 12 | \description{ 13 | Use a timeline variable 14 | } 15 | -------------------------------------------------------------------------------- /man/with_parameters.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_timeline.R 3 | \name{with_parameters} 4 | \alias{with_parameters} 5 | \title{Attach a timeline variable to timeline object} 6 | \usage{ 7 | with_parameters(timeline, ...) 8 | } 9 | \arguments{ 10 | \item{timeline}{the timeline object} 11 | 12 | \item{...}{name value pairs} 13 | } 14 | \description{ 15 | Attach a timeline variable to timeline object 16 | } 17 | -------------------------------------------------------------------------------- /man/with_variables.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/build_timeline.R 3 | \name{with_variables} 4 | \alias{with_variables} 5 | \title{Attach a timeline variable to timeline object} 6 | \usage{ 7 | with_variables(timeline, ...) 8 | } 9 | \arguments{ 10 | \item{timeline}{the timeline object} 11 | 12 | \item{...}{name value pairs} 13 | } 14 | \description{ 15 | Attach a timeline variable to timeline object 16 | } 17 | -------------------------------------------------------------------------------- /misc/demo1.R: -------------------------------------------------------------------------------- 1 | library(xprmntr) 2 | 3 | 4 | # define trial events ----------------------------------------------------- 5 | 6 | # define a welcome trial 7 | welcome <- trial_html_key( 8 | "Welcome to the experiment! Press any key to continue", 9 | ) 10 | 11 | # define a fixation trial 12 | fixation <- trial_html_key( 13 | stimulus = '
    +
    ', 14 | choices = no_key(), 15 | trial_duration = 500 16 | ) 17 | 18 | # define a test trial 19 | query <- trial_image_key( 20 | stimulus = variable("stimulus"), 21 | prompt = variable("prompt"), 22 | choices = c("y","n") 23 | ) 24 | 25 | # define a survey question 26 | likert1 <- question_likert( 27 | prompt = "How confident were you in your answers?", 28 | labels = c("very unsure", "somewhat unsure", "somewhat sure", "very sure"), 29 | required = TRUE 30 | ) 31 | 32 | # define a survey question 33 | likert2 <- question_likert( 34 | prompt = "How bored were you in this experient?", 35 | labels = c("not at all bored", "somewhat bored", "very bored"), 36 | required = FALSE 37 | ) 38 | 39 | # define a likert survey page 40 | survey1 <- trial_survey_likert( 41 | questions = list(likert1, likert2), 42 | preamble = "We have some questions" 43 | ) 44 | 45 | # define a survey question 46 | multi1 <- question_multi( 47 | prompt = "What gender are you?", 48 | options = c("male", "female", "non-binary", "other"), 49 | required = FALSE 50 | ) 51 | 52 | # define a survey question 53 | multi2 <- question_multi( 54 | prompt = "Do you identify as LGBTIQ?", 55 | options = c("yeah", "nah"), 56 | required = FALSE 57 | ) 58 | 59 | # define a multiple choice survey page 60 | survey2 <- trial_survey_multi_choice( 61 | questions = list(multi1, multi2), 62 | preamble = "We have some more questions" 63 | ) 64 | 65 | # define a survey question 66 | multi3 <- question_multi( 67 | prompt = "Select all that apply", 68 | options = c("lesbian", "gay", "bisexual", "transgender"), 69 | required = FALSE 70 | ) 71 | 72 | # define a multi select page 73 | survey3 <- trial_survey_multi_select( 74 | questions = list(multi3) 75 | ) 76 | 77 | # define a free text page 78 | survey4 <- trial_survey_text( 79 | questions = list( 80 | question_text(prompt = "Anything to add?", rows = 4), 81 | question_text(prompt = "Enter completion code") 82 | ) 83 | ) 84 | 85 | # define an end of experiment trial 86 | finish <- trial_html_key("All done!") 87 | 88 | 89 | 90 | # organise into a structure ----------------------------------------------- 91 | 92 | flag_names <- c("bisexual", "transgender", "LGBT") 93 | flag_files <- c("bisexual.svg", "transgender.svg", "rainbow.svg") 94 | 95 | # testing procedure is a timeline of fixate/query events 96 | testing <- timeline(fixation, query) %>% 97 | with_variables( 98 | prompt = paste("is this the", flag_names, "flag? (y/n)"), 99 | stimulus = resource(flag_files)) %>% 100 | with_parameters(randomize_order = TRUE, repetitions = 2) 101 | 102 | 103 | # overall procedure 104 | all_events <- timeline( 105 | welcome, 106 | testing, 107 | survey1, 108 | survey2, 109 | survey3, 110 | survey4, 111 | finish 112 | ) 113 | 114 | 115 | 116 | 117 | # write the experiment files ---------------------------------------------- 118 | 119 | resources <- add_resources(system.file("extdata", "img", package = "xprmntr")) 120 | 121 | experiment( 122 | timeline = all_events, 123 | path = "~/Desktop/expt", 124 | resources = resources, 125 | default_iti = 250, 126 | on_finish = js_code("xprmntr.save_locally"), 127 | preload_images = resource(flag_files) 128 | ) 129 | 130 | 131 | 132 | 133 | # run the experiment ------------------------------------------------------ 134 | 135 | if(FALSE) { 136 | run_locally( 137 | path = "~/Desktop/expt", 138 | port = 8000 139 | ) 140 | } 141 | -------------------------------------------------------------------------------- /misc/demo1b.R: -------------------------------------------------------------------------------- 1 | library(xprmntr) 2 | 3 | 4 | 5 | # welcome trial ----------------------------------------------------------- 6 | 7 | welcome_trial <- trial_simple( 8 | cue = cue_html("Welcome to the experiment! Press any key to continue"), 9 | response = response_key("any") 10 | ) 11 | 12 | 13 | 14 | 15 | # choice trials ----------------------------------------------------------- 16 | 17 | # define a fixation trial 18 | fixation <- trial_simple( 19 | cue = cue_html('
    +
    '), 20 | response = response_key("none"), 21 | trial_duration = 500 22 | ) 23 | 24 | # define a test trial 25 | query <- trial_simple( 26 | cue = cue_image(stimulus = variable("stimulus")), 27 | response = response_key("y", "n"), 28 | prompt = variable("prompt") 29 | ) 30 | 31 | # define stimuli 32 | flag_names <- c("bisexual", "transgender", "LGBT") 33 | flag_files <- c("bisexual.svg", "transgender.svg", "rainbow.svg") 34 | 35 | # testing procedure is a timeline of fixate/query events 36 | choice_trials <- timeline(fixation, query) %>% 37 | with_variables( 38 | prompt = paste("is this the", flag_names, "flag? (y/n)"), 39 | stimulus = resource(flag_files)) %>% 40 | with_parameters(randomize_order = TRUE, repetitions = 2) 41 | 42 | 43 | 44 | # likert survey ----------------------------------------------------------- 45 | 46 | # define some response scale 47 | confidence <- c("very unsure", "somewhat unsure", "somewhat sure", "very sure") 48 | boredom <- c("not at all bored", "somewhat bored", "very bored") 49 | 50 | # define a survey question 51 | likert_confidence <- question( 52 | cue = cue_text("How confident were you in your answers?"), 53 | response = response_likert(labels = confidence), 54 | required = TRUE 55 | ) 56 | 57 | # define a survey question 58 | likert_bored <- question( 59 | cue = cue_text("How bored were you in your answers?"), 60 | response = response_likert(labels = boredom), 61 | required = FALSE 62 | ) 63 | 64 | # compose a likert survey 65 | survey_likert <- trial_survey( 66 | questions = list(likert_confidence, likert_bored), 67 | preamble = "We have some questions" 68 | ) 69 | 70 | 71 | 72 | # pick one survey --------------------------------------------------------- 73 | 74 | # define a survey question 75 | pickone_gender <- question( 76 | cue = cue_text("What gender are you?"), 77 | response = response_pickone( 78 | options = c("male", "female", "non-binary", "other") 79 | ), 80 | required = FALSE 81 | ) 82 | 83 | # define a survey question 84 | pickone_identity <- question( 85 | cue = cue_text("Do you identify as LGBTIQ?"), 86 | response = response_pickone( 87 | options = c("yes", "no", "maybe") 88 | ), 89 | required = FALSE 90 | ) 91 | 92 | # define a multiple choice survey page 93 | survey_pickone <- trial_survey( 94 | questions = list(pickone_gender, pickone_identity), 95 | preamble = "We have some more questions" 96 | ) 97 | 98 | 99 | 100 | # pick some survey -----------------`--------------------------------------- 101 | 102 | 103 | # define a survey question 104 | picksome_identities <- question( 105 | cue = cue_text("Select all that apply"), 106 | response = response_picksome( 107 | options = c("lesbian", "gay", "bisexual", "transgender", 108 | "intersex", "queer", "other") 109 | ), 110 | required = FALSE 111 | ) 112 | 113 | # define a multi select page 114 | survey_picksome <- trial_survey(picksome_identities) 115 | 116 | 117 | 118 | # free text survey -------------------------------------------------------- 119 | 120 | 121 | 122 | # define a free text page 123 | survey_freetext <- question( 124 | cue_text("Anything to add?"), 125 | response_freetext() 126 | ) %>% 127 | trial_survey() 128 | 129 | 130 | 131 | # finish trial ------------------------------------------------------------ 132 | 133 | finish_trial <- trial_simple( 134 | cue_html("All done!"), 135 | response_key("any") 136 | ) 137 | 138 | 139 | 140 | 141 | # organise into a structure ----------------------------------------------- 142 | 143 | all_events <- timeline( 144 | welcome_trial, 145 | choice_trials, 146 | survey_likert, 147 | survey_pickone, 148 | survey_picksome, 149 | survey_freetext, 150 | finish_trial 151 | ) 152 | 153 | 154 | 155 | 156 | # write the experiment files ---------------------------------------------- 157 | 158 | resources <- add_resources( 159 | system.file("extdata", "img", package = "xprmntr") 160 | ) 161 | 162 | experiment( 163 | timeline = all_events, 164 | path = "~/Desktop/expt", 165 | resources = resources, 166 | default_iti = 250, 167 | on_finish = js_code("xprmntr.save_locally"), 168 | preload_images = resource(flag_files) 169 | ) 170 | 171 | 172 | 173 | 174 | # run the experiment ------------------------------------------------------ 175 | 176 | if(FALSE) { 177 | run_locally( 178 | path = "~/Desktop/expt", 179 | port = 8000 180 | ) 181 | } 182 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/css/jspsych.css: -------------------------------------------------------------------------------- 1 | /* 2 | * CSS for jsPsych experiments. 3 | * 4 | * This stylesheet provides minimal styling to make jsPsych 5 | * experiments look polished without any additional styles. 6 | */ 7 | 8 | @import url(https://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,400,700); 9 | 10 | /* Container holding jsPsych content */ 11 | 12 | .jspsych-display-element { 13 | display: flex; 14 | flex-direction: column; 15 | overflow-y: auto; 16 | } 17 | 18 | .jspsych-display-element:focus { 19 | outline: none; 20 | } 21 | 22 | .jspsych-content-wrapper { 23 | display: flex; 24 | margin: auto; 25 | flex: 1 1 100%; 26 | width: 100%; 27 | } 28 | 29 | .jspsych-content { 30 | max-width: 95%; /* this is mainly an IE 10-11 fix */ 31 | text-align: center; 32 | margin: auto; /* this is for overflowing content */ 33 | } 34 | 35 | .jspsych-top { 36 | align-items: flex-start; 37 | } 38 | 39 | .jspsych-middle { 40 | align-items: center; 41 | } 42 | 43 | /* fonts and type */ 44 | 45 | .jspsych-display-element { 46 | font-family: 'Open Sans', 'Arial', sans-serif; 47 | font-size: 18px; 48 | line-height: 1.6em; 49 | } 50 | 51 | /* Form elements like input fields and buttons */ 52 | 53 | .jspsych-display-element input[type="text"] { 54 | font-family: 'Open Sans', 'Arial', sans-serif; 55 | font-size: 14px; 56 | } 57 | 58 | /* borrowing Bootstrap style for btn elements, but combining styles a bit */ 59 | .jspsych-btn { 60 | display: inline-block; 61 | padding: 6px 12px; 62 | margin: 0px; 63 | font-size: 14px; 64 | font-weight: 400; 65 | font-family: 'Open Sans', 'Arial', sans-serif; 66 | cursor: pointer; 67 | line-height: 1.4; 68 | text-align: center; 69 | white-space: nowrap; 70 | vertical-align: middle; 71 | background-image: none; 72 | border: 1px solid transparent; 73 | border-radius: 4px; 74 | color: #333; 75 | background-color: #fff; 76 | border-color: #ccc; 77 | } 78 | 79 | .jspsych-btn:hover { 80 | background-color: #ddd; 81 | border-color: #aaa; 82 | } 83 | 84 | .jspsych-btn:disabled { 85 | background-color: #eee; 86 | color: #aaa; 87 | border-color: #ccc; 88 | cursor: not-allowed; 89 | } 90 | 91 | /* jsPsych progress bar */ 92 | 93 | #jspsych-progressbar-container { 94 | color: #555; 95 | border-bottom: 1px solid #dedede; 96 | background-color: #f9f9f9; 97 | margin-bottom: 1em; 98 | text-align: center; 99 | padding: 8px 0px; 100 | width: 100%; 101 | line-height: 1em; 102 | } 103 | #jspsych-progressbar-container span { 104 | font-size: 14px; 105 | padding-right: 14px; 106 | } 107 | #jspsych-progressbar-outer { 108 | background-color: #eee; 109 | width: 50%; 110 | margin: auto; 111 | height: 14px; 112 | display: inline-block; 113 | vertical-align: middle; 114 | box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); 115 | } 116 | #jspsych-progressbar-inner { 117 | background-color: #aaa; 118 | width: 0%; 119 | height: 100%; 120 | } 121 | 122 | /* Control appearance of jsPsych.data.displayData() */ 123 | #jspsych-data-display { 124 | text-align: left; 125 | } 126 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/add-to-end-of-timeline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 32 | 33 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/conditional-and-loop-functions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 63 | 64 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/data-add-properties.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/data-as-function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/data-from-timeline.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/data-from-url.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |

    The URL variable should be logged to the console

    9 | 10 | 21 | 22 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/demo-flanker.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flanker Task 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 108 | 109 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/demo-simple-rt-task.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | My experiment 5 | 6 | 7 | 8 | 9 | 10 | 11 | 104 | 105 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/demos/demo_1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 29 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/demos/demo_2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 43 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/demos/demo_3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 15 | 58 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/display-element-to-embed-experiment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 |
    21 |

    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer nec odio. Praesent libero. Sed cursus ante dapibus diam. Sed nisi. Nulla quis sem at nibh elementum imperdiet. Duis sagittis ipsum. Praesent mauris. Fusce nec tellus sed augue semper porta. Mauris massa. Vestibulum lacinia arcu eget nulla.

    22 | 23 |

    Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Curabitur sodales ligula in libero. Sed dignissim lacinia nunc. Curabitur tortor. Pellentesque nibh. Aenean quam. In scelerisque sem at dolor. Maecenas mattis. Sed convallis tristique sem. Proin ut ligula vel nunc egestas porttitor. Morbi lectus risus, iaculis vel, suscipit quis, luctus non, massa.

    24 | 25 |

    Fusce ac turpis quis ligula lacinia aliquet. Mauris ipsum. Nulla metus metus, ullamcorper vel, tincidunt sed, euismod in, nibh. Quisque volutpat condimentum velit. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nam nec ante. Sed lacinia, urna non tincidunt mattis, tortor neque adipiscing diam, a cursus ipsum ante quis turpis. Nulla facilisi. Ut fringilla. Suspendisse potenti. Nunc feugiat mi a tellus consequat imperdiet. Vestibulum sapien. Proin quam. Etiam ultrices.

    26 | 27 |

    Suspendisse in justo eu magna luctus suscipit. Sed lectus. Integer euismod lacus luctus magna. Quisque cursus, metus vitae pharetra auctor, sem massa mattis sem, at interdum magna augue eget diam. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi lacinia molestie dui. Praesent blandit dolor. Sed non quam. In vel mi sit amet augue congue elementum. Morbi in ipsum sit amet pede facilisis laoreet. Donec lacus nunc, viverra nec, blandit vel, egestas et, augue. Vestibulum tincidunt malesuada tellus.

    28 | 29 |

    Ut ultrices ultrices enim. Curabitur sit amet mauris. Morbi in dui quis est pulvinar ullamcorper. Nulla facilisi. Integer lacinia sollicitudin massa. Cras metus. Sed aliquet risus a tortor. Integer id quam. Morbi mi. Quisque nisl felis, venenatis tristique, dignissim in, ultrices sit amet, augue. Proin sodales libero eget ante. Nulla quam.

    30 | 31 | 32 | 33 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/end-active-node.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/end-experiment.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/exclusions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 16 | 17 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/external_html/simple_consent.html: -------------------------------------------------------------------------------- 1 |

    This is a demo consent form. Click the checkbox below to indicate the you 2 | would like to participate in the experiment

    3 |

    I agree to take part in this study.

    4 | 5 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/1.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/10.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/10.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/11.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/11.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/12.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/12.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/2.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/3.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/4.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/5.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/6.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/6.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/7.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/7.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/8.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/8.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/9.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/9.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/of1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/of1.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/of2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/of2.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/of3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/of3.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/om1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/om1.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/om2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/om2.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/om3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/om3.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/yf1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/yf1.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/yf4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/yf4.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/yf5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/yf5.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/ym2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/ym2.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/ym3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/ym3.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/age/ym5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/age/ym5.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/backwardN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/backwardN.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/blue.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/con1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/con1.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/con2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/con2.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/fixation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/fixation.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/happy_face_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/happy_face_1.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/happy_face_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/happy_face_2.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/happy_face_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/happy_face_3.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/happy_face_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/happy_face_4.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/inc1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/inc1.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/inc2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/inc2.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/normalN.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/normalN.gif -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/orange.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/orange.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/redX.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/redX.png -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/ribbon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/ribbon.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/sad_face_1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/sad_face_1.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/sad_face_2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/sad_face_2.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/sad_face_3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/sad_face_3.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/img/sad_face_4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/img/sad_face_4.jpg -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-RDK.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 55 | 56 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-audio-button-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 45 | 46 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-audio-keyboard-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-audio-slider-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-call-function.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 32 | 33 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-categorize-animation.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-categorize-html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-categorize-image.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-form.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-free-sort.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 24 | 25 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-fullscreen.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | 17 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-html-button-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 46 | 47 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-html-keyboard-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-html-slider-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-image-button-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 10 | 11 | 12 | 46 | 47 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-image-keyboard-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-image-slider-response.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 12 | 13 | 14 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-instructions.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 26 | 27 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-reconstruction.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 43 | 44 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-resize.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 34 | 35 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-same-different-html.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-same-different-image.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-serial-reaction-time-mouse.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-serial-reaction-time.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-survey-likert.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 26 | 27 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-survey-multi-choice.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 34 | 35 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-survey-multi-select.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Document 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 33 | 34 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-survey-text.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 27 | 28 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 26 | 27 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-visual-search-circle.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-vsl-animate-occlusion.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/jspsych-vsl-grid-scene.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 41 | 42 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/pause-unpause.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 33 | 34 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/progress-bar.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 13 | 14 | 15 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/hammer.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/hammer.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/sound.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/sound.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/speech_blue.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/speech_blue.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/speech_green.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/speech_green.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/speech_joke.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/speech_joke.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/speech_red.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/speech_red.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/sound/tone.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/sound/tone.mp3 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/timeline-variables-sampling.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 11 | 12 | 13 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/timeline-variables.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 | 20 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/examples/video/sample_video.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/djnavarro/xprmntr/13b5762a22cfc806cf4735c2cf40ff64b5b98130/misc/jspsych-6.0.5/examples/video/sample_video.mp4 -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014-2018 Joshua R. de Leeuw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-call-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-call-function 3 | * plugin for calling an arbitrary function during a jspsych experiment 4 | * Josh de Leeuw 5 | * 6 | * documentation: docs.jspsych.org 7 | * 8 | **/ 9 | 10 | jsPsych.plugins['call-function'] = (function() { 11 | 12 | var plugin = {}; 13 | 14 | plugin.info = { 15 | name: 'call-function', 16 | description: '', 17 | parameters: { 18 | func: { 19 | type: jsPsych.plugins.parameterType.FUNCTION, 20 | pretty_name: 'Function', 21 | default: undefined, 22 | description: 'Function to call' 23 | }, 24 | async: { 25 | type: jsPsych.plugins.parameterType.BOOL, 26 | pretty_name: 'Asynchronous', 27 | default: false, 28 | description: 'Is the function call asynchronous?' 29 | } 30 | } 31 | } 32 | 33 | plugin.trial = function(display_element, trial) { 34 | trial.post_trial_gap = 0; 35 | var return_val; 36 | 37 | if(trial.async){ 38 | var done = function(data){ 39 | return_val = data; 40 | end_trial(); 41 | } 42 | trial.func(done); 43 | } else { 44 | return_val = trial.func(); 45 | end_trial(); 46 | } 47 | 48 | function end_trial(){ 49 | var trial_data = { 50 | value: return_val 51 | }; 52 | 53 | jsPsych.finishTrial(trial_data); 54 | } 55 | }; 56 | 57 | return plugin; 58 | })(); 59 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-external-html.js: -------------------------------------------------------------------------------- 1 | /** (July 2012, Erik Weitnauer) 2 | The html-plugin will load and display an external html pages. To proceed to the next, the 3 | user might either press a button on the page or a specific key. Afterwards, the page get hidden and 4 | the plugin will wait of a specified time before it proceeds. 5 | 6 | documentation: docs.jspsych.org 7 | */ 8 | 9 | jsPsych.plugins['external-html'] = (function() { 10 | 11 | var plugin = {}; 12 | 13 | plugin.info = { 14 | name: 'external-html', 15 | description: '', 16 | parameters: { 17 | url: { 18 | type: jsPsych.plugins.parameterType.STRING, 19 | pretty_name: 'URL', 20 | default: undefined, 21 | description: 'The url of the external html page' 22 | }, 23 | cont_key: { 24 | type: jsPsych.plugins.parameterType.KEYCODE, 25 | pretty_name: 'Continue key', 26 | default: null, 27 | description: 'The key to continue to the next page.' 28 | }, 29 | cont_btn: { 30 | type: jsPsych.plugins.parameterType.STRING, 31 | pretty_name: 'Continue button', 32 | default: null, 33 | description: 'The button to continue to the next page.' 34 | }, 35 | check_fn: { 36 | type: jsPsych.plugins.parameterType.FUNCTION, 37 | pretty_name: 'Check function', 38 | default: function() { return true; }, 39 | description: '' 40 | }, 41 | force_refresh: { 42 | type: jsPsych.plugins.parameterType.BOOL, 43 | pretty_name: 'Force refresh', 44 | default: false, 45 | description: 'Refresh page.' 46 | }, 47 | // if execute_Script == true, then all javascript code on the external page 48 | // will be executed in the plugin site within your jsPsych test 49 | execute_script: { 50 | type: jsPsych.plugins.parameterType.BOOL, 51 | pretty_name: 'Execute scripts', 52 | default: false, 53 | description: 'If true, JS scripts on the external html file will be executed.' 54 | } 55 | } 56 | } 57 | 58 | plugin.trial = function(display_element, trial) { 59 | 60 | var url = trial.url; 61 | if (trial.force_refresh) { 62 | url = trial.url + "?time=" + (new Date().getTime()); 63 | } 64 | 65 | load(display_element, url, function() { 66 | var t0 = (new Date()).getTime(); 67 | var finish = function() { 68 | if (trial.check_fn && !trial.check_fn(display_element)) { return }; 69 | if (trial.cont_key) { display_element.removeEventListener('keydown', key_listener); } 70 | var trial_data = { 71 | rt: (new Date()).getTime() - t0, 72 | url: trial.url 73 | }; 74 | display_element.innerHTML = ''; 75 | jsPsych.finishTrial(trial_data); 76 | }; 77 | 78 | // by default, scripts on the external page are not executed with XMLHttpRequest(). 79 | // To activate their content through DOM manipulation, we need to relocate all script tags 80 | if (trial.execute_script) { 81 | for (const scriptElement of display_element.getElementsByTagName("script")) { 82 | const relocatedScript = document.createElement("script"); 83 | relocatedScript.text = scriptElement.text; 84 | scriptElement.parentNode.replaceChild(relocatedScript, scriptElement); 85 | }; 86 | } 87 | 88 | if (trial.cont_btn) { display_element.querySelector('#'+trial.cont_btn).addEventListener('click', finish); } 89 | if (trial.cont_key) { 90 | var key_listener = function(e) { 91 | if (e.which == trial.cont_key) finish(); 92 | }; 93 | display_element.addEventListener('keydown', key_listener); 94 | } 95 | }); 96 | }; 97 | 98 | // helper to load via XMLHttpRequest 99 | function load(element, file, callback){ 100 | var xmlhttp = new XMLHttpRequest(); 101 | xmlhttp.open("GET", file, true); 102 | xmlhttp.onload = function(){ 103 | if(xmlhttp.status == 200 || xmlhttp.status == 0){ //Check if loaded 104 | element.innerHTML = xmlhttp.responseText; 105 | callback(); 106 | } 107 | } 108 | xmlhttp.send(); 109 | } 110 | 111 | return plugin; 112 | })(); 113 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-fullscreen.js: -------------------------------------------------------------------------------- 1 | /* jspsych-fullscreen.js 2 | * Josh de Leeuw 3 | * 4 | * toggle fullscreen mode in the browser 5 | * 6 | */ 7 | 8 | jsPsych.plugins.fullscreen = (function() { 9 | 10 | var plugin = {}; 11 | 12 | plugin.info = { 13 | name: 'fullscreen', 14 | description: '', 15 | parameters: { 16 | fullscreen_mode: { 17 | type: jsPsych.plugins.parameterType.BOOL, 18 | pretty_name: 'Fullscreen mode', 19 | default: true, 20 | array: false, 21 | description: 'If true, experiment will enter fullscreen mode. If false, the browser will exit fullscreen mode.' 22 | }, 23 | message: { 24 | type: jsPsych.plugins.parameterType.STRING, 25 | pretty_name: 'Message', 26 | default: '

    The experiment will switch to full screen mode when you press the button below

    ', 27 | array: false, 28 | description: 'HTML content to display above the button to enter fullscreen mode.' 29 | }, 30 | button_label: { 31 | type: jsPsych.plugins.parameterType.STRING, 32 | pretty_name: 'Button label', 33 | default: 'Continue', 34 | array: false, 35 | description: 'The text that appears on the button to enter fullscreen.' 36 | }, 37 | delay_after: { 38 | type: jsPsych.plugins.parameterType.INT, 39 | pretty_name: 'Delay after', 40 | default: 1000, 41 | array: false, 42 | description: 'The length of time to delay after entering fullscreen mode before ending the trial.' 43 | }, 44 | } 45 | } 46 | 47 | plugin.trial = function(display_element, trial) { 48 | 49 | // check if keys are allowed in fullscreen mode 50 | var keyboardNotAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element; 51 | if (keyboardNotAllowed) { 52 | // This is Safari, and keyboard events will be disabled. Don't allow fullscreen here. 53 | // do something else? 54 | endTrial(); 55 | } else { 56 | if(trial.fullscreen_mode){ 57 | display_element.innerHTML = trial.message + ''; 58 | var listener = display_element.querySelector('#jspsych-fullscreen-btn').addEventListener('click', function() { 59 | var element = document.documentElement; 60 | if (element.requestFullscreen) { 61 | element.requestFullscreen(); 62 | } else if (element.mozRequestFullScreen) { 63 | element.mozRequestFullScreen(); 64 | } else if (element.webkitRequestFullscreen) { 65 | element.webkitRequestFullscreen(); 66 | } else if (element.msRequestFullscreen) { 67 | element.msRequestFullscreen(); 68 | } 69 | endTrial(); 70 | }); 71 | } else { 72 | if (document.exitFullscreen) { 73 | document.exitFullscreen(); 74 | } else if (document.msExitFullscreen) { 75 | document.msExitFullscreen(); 76 | } else if (document.mozCancelFullScreen) { 77 | document.mozCancelFullScreen(); 78 | } else if (document.webkitExitFullscreen) { 79 | document.webkitExitFullscreen(); 80 | } 81 | endTrial(); 82 | } 83 | } 84 | 85 | function endTrial() { 86 | 87 | display_element.innerHTML = ''; 88 | 89 | jsPsych.pluginAPI.setTimeout(function(){ 90 | 91 | var trial_data = { 92 | success: !keyboardNotAllowed 93 | }; 94 | 95 | jsPsych.finishTrial(trial_data); 96 | 97 | }, trial.delay_after); 98 | 99 | } 100 | 101 | }; 102 | 103 | return plugin; 104 | })(); 105 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-html-keyboard-response.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-html-keyboard-response 3 | * Josh de Leeuw 4 | * 5 | * plugin for displaying a stimulus and getting a keyboard response 6 | * 7 | * documentation: docs.jspsych.org 8 | * 9 | **/ 10 | 11 | 12 | jsPsych.plugins["html-keyboard-response"] = (function() { 13 | 14 | var plugin = {}; 15 | 16 | plugin.info = { 17 | name: 'html-keyboard-response', 18 | description: '', 19 | parameters: { 20 | stimulus: { 21 | type: jsPsych.plugins.parameterType.HTML_STRING, 22 | pretty_name: 'Stimulus', 23 | default: undefined, 24 | description: 'The HTML string to be displayed' 25 | }, 26 | choices: { 27 | type: jsPsych.plugins.parameterType.KEYCODE, 28 | array: true, 29 | pretty_name: 'Choices', 30 | default: jsPsych.ALL_KEYS, 31 | description: 'The keys the subject is allowed to press to respond to the stimulus.' 32 | }, 33 | prompt: { 34 | type: jsPsych.plugins.parameterType.STRING, 35 | pretty_name: 'Prompt', 36 | default: null, 37 | description: 'Any content here will be displayed below the stimulus.' 38 | }, 39 | stimulus_duration: { 40 | type: jsPsych.plugins.parameterType.INT, 41 | pretty_name: 'Stimulus duration', 42 | default: null, 43 | description: 'How long to hide the stimulus.' 44 | }, 45 | trial_duration: { 46 | type: jsPsych.plugins.parameterType.INT, 47 | pretty_name: 'Trial duration', 48 | default: null, 49 | description: 'How long to show trial before it ends.' 50 | }, 51 | response_ends_trial: { 52 | type: jsPsych.plugins.parameterType.BOOL, 53 | pretty_name: 'Response ends trial', 54 | default: true, 55 | description: 'If true, trial will end when subject makes a response.' 56 | }, 57 | 58 | } 59 | } 60 | 61 | plugin.trial = function(display_element, trial) { 62 | 63 | var new_html = '
    '+trial.stimulus+'
    '; 64 | 65 | // add prompt 66 | if(trial.prompt !== null){ 67 | new_html += trial.prompt; 68 | } 69 | 70 | // draw 71 | display_element.innerHTML = new_html; 72 | 73 | // store response 74 | var response = { 75 | rt: null, 76 | key: null 77 | }; 78 | 79 | // function to end trial when it is time 80 | var end_trial = function() { 81 | 82 | // kill any remaining setTimeout handlers 83 | jsPsych.pluginAPI.clearAllTimeouts(); 84 | 85 | // kill keyboard listeners 86 | if (typeof keyboardListener !== 'undefined') { 87 | jsPsych.pluginAPI.cancelKeyboardResponse(keyboardListener); 88 | } 89 | 90 | // gather the data to store for the trial 91 | var trial_data = { 92 | "rt": response.rt, 93 | "stimulus": trial.stimulus, 94 | "key_press": response.key 95 | }; 96 | 97 | // clear the display 98 | display_element.innerHTML = ''; 99 | 100 | // move on to the next trial 101 | jsPsych.finishTrial(trial_data); 102 | }; 103 | 104 | // function to handle responses by the subject 105 | var after_response = function(info) { 106 | 107 | // after a valid response, the stimulus will have the CSS class 'responded' 108 | // which can be used to provide visual feedback that a response was recorded 109 | display_element.querySelector('#jspsych-html-keyboard-response-stimulus').className += ' responded'; 110 | 111 | // only record the first response 112 | if (response.key == null) { 113 | response = info; 114 | } 115 | 116 | if (trial.response_ends_trial) { 117 | end_trial(); 118 | } 119 | }; 120 | 121 | // start the response listener 122 | if (trial.choices != jsPsych.NO_KEYS) { 123 | var keyboardListener = jsPsych.pluginAPI.getKeyboardResponse({ 124 | callback_function: after_response, 125 | valid_responses: trial.choices, 126 | rt_method: 'date', 127 | persist: false, 128 | allow_held_key: false 129 | }); 130 | } 131 | 132 | // hide stimulus if stimulus_duration is set 133 | if (trial.stimulus_duration !== null) { 134 | jsPsych.pluginAPI.setTimeout(function() { 135 | display_element.querySelector('#jspsych-html-keyboard-response-stimulus').style.visibility = 'hidden'; 136 | }, trial.stimulus_duration); 137 | } 138 | 139 | // end trial if trial_duration is set 140 | if (trial.trial_duration !== null) { 141 | jsPsych.pluginAPI.setTimeout(function() { 142 | end_trial(); 143 | }, trial.trial_duration); 144 | } 145 | 146 | }; 147 | 148 | return plugin; 149 | })(); 150 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-reconstruction.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jspsych-reconstruction 3 | * a jspsych plugin for a reconstruction task where the subject recreates 4 | * a stimulus from memory 5 | * 6 | * Josh de Leeuw 7 | * 8 | * documentation: docs.jspsych.org 9 | * 10 | */ 11 | 12 | 13 | jsPsych.plugins['reconstruction'] = (function() { 14 | 15 | var plugin = {}; 16 | 17 | plugin.info = { 18 | name: 'reconstruction', 19 | description: '', 20 | parameters: { 21 | stim_function: { 22 | type: jsPsych.plugins.parameterType.FUNCTION, 23 | pretty_name: 'Stimulus function', 24 | default: undefined, 25 | description: 'A function with a single parameter that returns an HTML-formatted string representing the stimulus.' 26 | }, 27 | starting_value: { 28 | type: jsPsych.plugins.parameterType.FLOAT, 29 | pretty_name: 'Starting value', 30 | default: 0.5, 31 | description: 'The starting value of the stimulus parameter.' 32 | }, 33 | step_size: { 34 | type: jsPsych.plugins.parameterType.FLOAT, 35 | pretty_name: 'Step size', 36 | default: 0.05, 37 | description: 'The change in the stimulus parameter caused by pressing one of the modification keys.' 38 | }, 39 | key_increase: { 40 | type: jsPsych.plugins.parameterType.KEYCODE, 41 | pretty_name: 'Key increase', 42 | default: 'h', 43 | description: 'The key to press for increasing the parameter value.' 44 | }, 45 | key_decrease: { 46 | type: jsPsych.plugins.parameterType.KEYCODE, 47 | pretty_name: 'Key decrease', 48 | default: 'g', 49 | description: 'The key to press for decreasing the parameter value.' 50 | }, 51 | button_label: { 52 | type: jsPsych.plugins.parameterType.STRING, 53 | pretty_name: 'Button label', 54 | default: 'Continue', 55 | description: 'The text that appears on the button to finish the trial.' 56 | } 57 | } 58 | } 59 | 60 | plugin.trial = function(display_element, trial) { 61 | 62 | // current param level 63 | var param = trial.starting_value; 64 | 65 | // set-up key listeners 66 | var after_response = function(info) { 67 | 68 | //console.log('fire'); 69 | 70 | var key_i = (typeof trial.key_increase == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_increase) : trial.key_increase; 71 | var key_d = (typeof trial.key_decrease == 'string') ? jsPsych.pluginAPI.convertKeyCharacterToKeyCode(trial.key_decrease) : trial.key_decrease; 72 | 73 | // get new param value 74 | if (info.key == key_i) { 75 | param = param + trial.step_size; 76 | } else if (info.key == key_d) { 77 | param = param - trial.step_size; 78 | } 79 | param = Math.max(Math.min(1, param), 0); 80 | 81 | // refresh the display 82 | draw(param); 83 | } 84 | 85 | // listen for responses 86 | var key_listener = jsPsych.pluginAPI.getKeyboardResponse({ 87 | callback_function: after_response, 88 | valid_responses: [trial.key_increase, trial.key_decrease], 89 | rt_method: 'date', 90 | persist: true, 91 | allow_held_key: true 92 | }); 93 | // draw first iteration 94 | draw(param); 95 | 96 | function draw(param) { 97 | 98 | //console.log(param); 99 | 100 | display_element.innerHTML = '
    '+trial.stim_function(param)+'
    '; 101 | 102 | // add submit button 103 | display_element.innerHTML += ''; 104 | 105 | display_element.querySelector('#jspsych-reconstruction-next').addEventListener('click', endTrial); 106 | } 107 | 108 | function endTrial() { 109 | // measure response time 110 | var endTime = (new Date()).getTime(); 111 | var response_time = endTime - startTime; 112 | 113 | // clear keyboard response 114 | jsPsych.pluginAPI.cancelKeyboardResponse(key_listener); 115 | 116 | // save data 117 | var trial_data = { 118 | "rt": response_time, 119 | "final_value": param, 120 | "start_value": trial.starting_value 121 | }; 122 | 123 | display_element.innerHTML = ''; 124 | 125 | // next trial 126 | jsPsych.finishTrial(trial_data); 127 | } 128 | 129 | var startTime = (new Date()).getTime(); 130 | 131 | }; 132 | 133 | return plugin; 134 | })(); 135 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-video.js: -------------------------------------------------------------------------------- 1 | /* jspsych-video.js 2 | * Josh de Leeuw 3 | * 4 | * This plugin displays a video. The trial ends when the video finishes. 5 | * 6 | * documentation: docs.jspsych.org 7 | * 8 | */ 9 | 10 | jsPsych.plugins.video = (function() { 11 | 12 | var plugin = {}; 13 | 14 | plugin.info = { 15 | name: 'video', 16 | description: '', 17 | parameters: { 18 | sources: { 19 | type: jsPsych.plugins.parameterType.VIDEO, 20 | pretty_name: 'Sources', 21 | array: true, 22 | default: undefined, 23 | description: 'The video file to play.' 24 | }, 25 | width: { 26 | type: jsPsych.plugins.parameterType.INT, 27 | pretty_name: 'Width', 28 | default: undefined, 29 | description: 'The width of the video in pixels.' 30 | }, 31 | height: { 32 | type: jsPsych.plugins.parameterType.INT, 33 | pretty_name: 'Height', 34 | default: undefined, 35 | description: 'The height of the video display in pixels.' 36 | }, 37 | autoplay: { 38 | type: jsPsych.plugins.parameterType.BOOL, 39 | pretty_name: 'Autoplay', 40 | default: true, 41 | description: 'If true, the video will begin playing as soon as it has loaded.' 42 | }, 43 | controls: { 44 | type: jsPsych.plugins.parameterType.BOOL, 45 | pretty_name: 'Controls', 46 | default: false, 47 | description: 'If true, the subject will be able to pause the video or move the playback to any point in the video.' 48 | }, 49 | prompt: { 50 | type: jsPsych.plugins.parameterType.STRING, 51 | pretty_name: 'Prompt', 52 | default: null, 53 | description: 'Any content here will be displayed below the video content.' 54 | }, 55 | start: { 56 | type: jsPsych.plugins.parameterType.FLOAT, 57 | pretty_name: 'Start', 58 | default: null, 59 | description: 'Time to start the clip.' 60 | }, 61 | stop: { 62 | type: jsPsych.plugins.parameterType.FLOAT, 63 | pretty_name: 'Stop', 64 | default: null, 65 | description: 'Time to stop the clip.' 66 | } 67 | } 68 | } 69 | 70 | 71 | plugin.trial = function(display_element, trial) { 72 | 73 | // display stimulus 74 | var video_html = '" 110 | 111 | //show prompt if there is one 112 | if (trial.prompt !== null) { 113 | video_html += trial.prompt; 114 | } 115 | 116 | display_element.innerHTML = video_html; 117 | 118 | display_element.querySelector('#jspsych-video-player').onended = function(){ 119 | end_trial(); 120 | } 121 | 122 | // event handler to set timeout to end trial if video is stopped 123 | display_element.querySelector('#jspsych-video-player').onplay = function(){ 124 | if(trial.stop !== null){ 125 | if(trial.start == null){ 126 | trial.start = 0; 127 | } 128 | jsPsych.pluginAPI.setTimeout(end_trial, (trial.stop-trial.start)*1000); 129 | } 130 | } 131 | 132 | if(trial.start !== null){ 133 | display_element.querySelector('#jspsych-video-player').currentTime = trial.start; 134 | } 135 | 136 | // function to end trial when it is time 137 | var end_trial = function() { 138 | 139 | // gather the data to store for the trial 140 | var trial_data = { 141 | stimulus: JSON.stringify(trial.sources) 142 | }; 143 | 144 | // clear the display 145 | display_element.innerHTML = ''; 146 | 147 | // move on to the next trial 148 | jsPsych.finishTrial(trial_data); 149 | }; 150 | 151 | }; 152 | 153 | return plugin; 154 | })(); 155 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/jspsych-vsl-grid-scene.js: -------------------------------------------------------------------------------- 1 | /** 2 | * jsPsych plugin for showing scenes that mimic the experiments described in 3 | * 4 | * Fiser, J., & Aslin, R. N. (2001). Unsupervised statistical learning of 5 | * higher-order spatial structures from visual scenes. Psychological science, 6 | * 12(6), 499-504. 7 | * 8 | * Josh de Leeuw 9 | * 10 | * documentation: docs.jspsych.org 11 | * 12 | */ 13 | 14 | jsPsych.plugins['vsl-grid-scene'] = (function() { 15 | 16 | var plugin = {}; 17 | 18 | jsPsych.pluginAPI.registerPreload('vsl-grid-scene', 'stimuli', 'image'); 19 | 20 | plugin.info = { 21 | name: 'vsl-grid-scene', 22 | description: '', 23 | parameters: { 24 | stimuli: { 25 | type: jsPsych.plugins.parameterType.IMAGE, 26 | pretty_name: 'Stimuli', 27 | array: true, 28 | default: undefined, 29 | description: 'An array that defines a grid.' 30 | }, 31 | image_size: { 32 | type: jsPsych.plugins.parameterType.INT, 33 | pretty_name: 'Image size', 34 | array: true, 35 | default: [100,100], 36 | description: 'Array specifying the width and height of the images to show.' 37 | }, 38 | trial_duration: { 39 | type: jsPsych.plugins.parameterType.INT, 40 | pretty_name: 'Trial duration', 41 | default: 2000, 42 | description: 'How long to show the stimulus for in milliseconds.' 43 | } 44 | } 45 | } 46 | 47 | plugin.trial = function(display_element, trial) { 48 | 49 | display_element.innerHTML = plugin.generate_stimulus(trial.stimuli, trial.image_size); 50 | 51 | jsPsych.pluginAPI.setTimeout(function() { 52 | endTrial(); 53 | }, trial.trial_duration); 54 | 55 | function endTrial() { 56 | 57 | display_element.innerHTML = ''; 58 | 59 | var trial_data = { 60 | "stimulus": JSON.stringify(trial.stimuli) 61 | }; 62 | 63 | jsPsych.finishTrial(trial_data); 64 | } 65 | }; 66 | 67 | plugin.generate_stimulus = function(pattern, image_size) { 68 | var nrows = pattern.length; 69 | var ncols = pattern[0].length; 70 | 71 | // create blank element to hold code that we generate 72 | var html = '
    '; 73 | 74 | // create table 75 | html += ''; 77 | 78 | for (var row = 0; row < nrows; row++) { 79 | html += ''; 80 | 81 | for (var col = 0; col < ncols; col++) { 82 | html += ''; 91 | } 92 | html += ''; 93 | } 94 | 95 | html += '
    '+ 84 | '
    '; 85 | if (pattern[row][col] !== 0) { 86 | html += ''; 88 | } 89 | html += '
    '; 90 | html += '
    '; 96 | html += '
    '; 97 | 98 | return html; 99 | 100 | }; 101 | 102 | return plugin; 103 | })(); 104 | -------------------------------------------------------------------------------- /misc/jspsych-6.0.5/plugins/template/jspsych-plugin-template.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Example plugin template 3 | */ 4 | 5 | jsPsych.plugins["PLUGIN-NAME"] = (function() { 6 | 7 | var plugin = {}; 8 | 9 | plugin.info = { 10 | name: "PLUGIN-NAME", 11 | parameters: { 12 | parameter_name: { 13 | type: jsPsych.plugins.parameterType.INT, // BOOL, STRING, INT, FLOAT, FUNCTION, KEYCODE, SELECT, HTML_STRING, IMAGE, AUDIO, VIDEO, OBJECT, COMPLEX 14 | default: undefined 15 | }, 16 | parameter_name: { 17 | type: jsPsych.plugins.parameterType.IMAGE, 18 | default: undefined 19 | } 20 | } 21 | } 22 | 23 | plugin.trial = function(display_element, trial) { 24 | 25 | // data saving 26 | var trial_data = { 27 | parameter_name: 'parameter value' 28 | }; 29 | 30 | // end trial 31 | jsPsych.finishTrial(trial_data); 32 | }; 33 | 34 | return plugin; 35 | })(); 36 | -------------------------------------------------------------------------------- /misc/plumber.R: -------------------------------------------------------------------------------- 1 | # plumber.R 2 | 3 | #* @post /post 4 | function(req) { 5 | print(req$postBody) 6 | } 7 | 8 | #* @assets EXPERIMENTHOME / 9 | list() 10 | -------------------------------------------------------------------------------- /xprmntr.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: No 4 | SaveWorkspace: No 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | PackageRoxygenize: rd,collate,namespace 22 | --------------------------------------------------------------------------------