From 878f6bc5c1916e775819e2b4002782aebe7f0226 Mon Sep 17 00:00:00 2001 From: Winter Mason Date: Thu, 31 Jan 2013 00:01:22 -0500 Subject: [PATCH 1/7] Added missing output file for Race --- templates/Race/output/blank.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 templates/Race/output/blank.txt diff --git a/templates/Race/output/blank.txt b/templates/Race/output/blank.txt new file mode 100644 index 0000000..e69de29 From 388baca77a479852312bc39738ad390c5a2310ab Mon Sep 17 00:00:00 2001 From: Winter Mason Date: Fri, 1 Feb 2013 00:24:16 -0500 Subject: [PATCH 2/7] Added analysis script and missing directory in Science template --- IATanalysis.R | 35 ++++++++++++++++++++++++++++++++ templates/Science/img/none.png | 0 templates/Science/summarized.csv | 3 +++ 3 files changed, 38 insertions(+) create mode 100644 IATanalysis.R create mode 100644 templates/Science/img/none.png create mode 100644 templates/Science/summarized.csv diff --git a/IATanalysis.R b/IATanalysis.R new file mode 100644 index 0000000..daa384a --- /dev/null +++ b/IATanalysis.R @@ -0,0 +1,35 @@ +# Set the path to the IAT folder here (be sure to include trailing slash) +base.dir = "~/Documents/Research/IAT/" +# base.dir = "C:\Users\winteram\Documents\IAT\" + +# File delimiter = '/' for Unix/Max, '\' for Windows +fd = '/' + +# Set the template you want to analyze here +template.name = "Science" +output.dir = paste(base.dir,"templates",fd,template.name,fd,"output",fd,sep="") + +setwd(output.dir) +output.files = list.files() +data.list = lapply(output.files, read.table, sep = ",") +summarized <- data.frame(matrix(ncol=9,nrow=length(data.list))) +names(summarized) <- c("Id","Date","Block4.m","Block4.sd","Block7.m","Block7.sd","diff","full.sd",'d') + +for(i in 1:length(data.list)) +{ + filename = strsplit(output.files[i],'-') + id = filename[[1]][2] + iat.date = paste(filename[[1]][4],"-",filename[[1]][5],"-",filename[[1]][3]," ",filename[[1]][6],":",substr(filename[[1]][7],1,2),sep="") + block4.m = mean(subset(data.list[[i]], V1==3 & V6>300 & V6 < 3000, select="V6")) + block7.m = mean(subset(data.list[[i]], V1==6 & V6>300 & V6 < 3000, select="V6")) + block4.sd = sd(subset(data.list[[i]], V1==3 & V6>300 & V6 < 3000, select="V6")) + block7.sd = sd(subset(data.list[[i]], V1==6 & V6>300 & V6 < 3000, select="V6")) + full.sd = sd(subset(data.list[[i]], (V1==6 | V1==3) & V6>300 & V6 < 3000, select="V6")) + diff = block7.m - block4.m + d = diff / full.sd + summarized[i,] = c(id, iat.date, block4.m, block4.sd, block7.m, block7.sd, diff, full.sd, d) +} +rm(block4.m,block4.sd,block7.m,block7.sd,d,data.list,diff,filename,full.sd,i,iat.date,id,output.files) + +setwd(paste(base.dir,"templates",fd,template.name,sep="")) +write.csv(summarized, "summarized.csv") \ No newline at end of file diff --git a/templates/Science/img/none.png b/templates/Science/img/none.png new file mode 100644 index 0000000..e69de29 diff --git a/templates/Science/summarized.csv b/templates/Science/summarized.csv new file mode 100644 index 0000000..f8eca82 --- /dev/null +++ b/templates/Science/summarized.csv @@ -0,0 +1,3 @@ +"","Id","Date","Block4.m","Block4.sd","Block7.m","Block7.sd","diff","full.sd","d" +"1","c1nm9ESIBB","01-16-2013 10:15","444.7","28.4458858370175","441.5625","52.1523010038867","-3.13749999999999","40.0926209416178","-0.0782562957051064" +"2","hoouH19DHR","01-16-2013 10:49","456.714285714286","53.4304621514196","457.176470588235","33.2682943921793","0.462184873949582","44.9644794217928","0.0102788885781156" From a599fbaa3634b9a04e6e9262394f3bb8e9a620be Mon Sep 17 00:00:00 2001 From: Winter Mason Date: Fri, 1 Feb 2013 00:25:01 -0500 Subject: [PATCH 3/7] removed useless file --- templates/Science/img/none.png | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 templates/Science/img/none.png diff --git a/templates/Science/img/none.png b/templates/Science/img/none.png deleted file mode 100644 index e69de29..0000000 From f151c0042f77d19e0bdca14c1ef7423632f0e3ed Mon Sep 17 00:00:00 2001 From: Winter Mason Date: Tue, 5 Feb 2013 08:47:36 -0500 Subject: [PATCH 4/7] Attributed Steven for work --- README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README b/README index dde249f..8c28aac 100644 --- a/README +++ b/README @@ -1,6 +1,7 @@ ********************************************************** * project: Open Source, Web-based IAT -* author: Winter Mason (m@winteram.com) +* authors: Winter Mason (m@winteram.com) +* Steven Allon * source: https://github.com/winteram/IAT ********************************************************** From c78fe6b96e08316edade24d0d3828d22ac7fcebc Mon Sep 17 00:00:00 2001 From: Winter Mason Date: Tue, 19 Feb 2013 10:03:44 -0500 Subject: [PATCH 5/7] Added variation that inserts Google Form before results --- core/js/IAT_gform.js | 683 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 683 insertions(+) create mode 100644 core/js/IAT_gform.js diff --git a/core/js/IAT_gform.js b/core/js/IAT_gform.js new file mode 100644 index 0000000..e515a44 --- /dev/null +++ b/core/js/IAT_gform.js @@ -0,0 +1,683 @@ +template = {}; +sub = ''; +clearform = true; + +// replace this with the link to the google form +gframe = 'https://docs.google.com/forms/d/1alFGZ2_tkQTsGf5CXI7dyzQPTipsELUMQU6G1v-pdLE/viewform'; + +function randomString(length) { + var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + var result = ''; + for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))]; + return result; +} + +// Loads the input file and starts introduction +function initialize() +{ + // get active template & load data into global variable + $.getJSON("templates/active.txt", function(input) { + document.title = input.active + " IAT"; + $.getJSON("templates/"+input.active+"/input.txt", function(data) { + template = data; + $.get("core/instruct0.html", function(data) { + $("#instructions").html(data); + $("#subID").val(randomString(10)); + }); + }); + }); +} + +function loadInstructions(stage) +{ + switch(stage) + { + case 'one': + sub = $("#subID").val(); + if(sub.search('/[^a-zA-Z0-9]/g')==-1) + { + $.get("core/instruct1.html", function(data) { + $("#instructions").html(data); + $(".IATname").html(template.name); + if( template.catA.itemtype == "img" || + template.catB.itemtype == "img" || + template.cat1.itemtype == "img" || + template.cat2.itemtype == "img") + { + $("#andpics").html(" and pictures "); + } + }); + } + else + { + alert("Please enter a valid subject ID"); + } + break; + case 'two': + $.get("core/instruct2.html", function(data) { + $("#instructions").html(data); + + $("#clabel1").html(template.cat1.label); + $("#clabel2").html(template.cat2.label); + $("#clabelA").html(template.catA.label); + $("#clabelB").html(template.catB.label); + if (template.cat1.itemtype == "txt") + { $("#citems1").html(template.cat1.items.join(", ")); } + else if (template.cat1.itemtype == "img") + { $("#citems1").html("Images of "+template.cat1.label); } + if (template.cat2.itemtype == "txt") + { $("#citems2").html(template.cat2.items.join(", ")); } + else if (template.cat2.itemtype == "img") + { $("#citems2").html("Images of "+template.cat2.label); } + if (template.catA.itemtype == "txt") + { $("#citemsA").html(template.catA.items.join(", ")); } + else if (template.catA.itemtype == "img") + { $("#citemsA").html("Images of "+template.catA.label); } + if (template.catB.itemtype == "txt") + { $("#citemsB").html(template.catB.items.join(", ")); } + else if (template.catB.itemtype == "img") + { $("#citemsB").html("Images of "+template.catB.label); } + }); + break; + case 'IAT': + $.get("core/IAT.html", function(data) { + $('body').html(data); + document.onkeypress = keyHandler; + startIAT(); + }); + break; + } +} + +// Initialize variables, build page & data object, display instructions +function startIAT() +{ + currentState = "instruction"; + session = 0; + roundnum = 0; + + // default to show results to participant + if (!('showResult' in template)) + { + template.showResult = "show"; + } + + // make the target or association words green + if (Math.random() < 0.5) + { + openA = ""; + closeA = ""; + open1 = ""; + close1 = ""; + } + else + { + open1 = ""; + close1 = ""; + openA = ""; + closeA = ""; + } + buildPage(); + roundArray = initRounds(); + instructionPage(); +} + +// Adds all images to page (initially hidden) so they are pre-loaded for IAT +function buildPage() +{ + if (template.catA.itemtype == "img") + { + for (i in template.catA.items) + { + var itemstr = ''; + $("#exp_instruct").after(itemstr); + } + } + if (template.catB.itemtype == "img") + { + for (i in template.catB.items) + { + var itemstr = ''; + $("#exp_instruct").after(itemstr); + } + } + if (template.cat1.itemtype == "img") + { + for (i in template.cat1.items) + { + var itemstr = ''; + $("#exp_instruct").after(itemstr); + } + } + if (template.cat2.itemtype == "img") + { + for (i in template.cat2.items) + { + var itemstr = ''; + $("#exp_instruct").after(itemstr); + } + } +} + +// Round object +function IATround() +{ + this.starttime = 0; + this.endtime = 0; + this.itemtype = "none"; + this.category = "none"; + this.catIndex = 0; + this.correct = 0; + this.errors = 0; +} + +// Create array for each session & round, with pre-randomized ordering of images +function initRounds() +{ + var roundArray = []; + // for each session + for (var i=0; i<7; i++) + { + roundArray[i] = []; + switch (i) + { + case 0: + case 4: + stype = "target"; + numrounds = 20; + break; + case 1: + stype = "association"; + numrounds = 20; + break; + case 2: + case 3: + case 5: + case 6: + stype = "both"; + numrounds = 40; + break; + + } + prevIndexA = -1; prevIndex1 = -1; + for (var j = 0; jor
'+open1+template.cat1.label+close1); + $("#right_cat").html(openA+template.catB.label+closeA+'
or
'+open1+template.cat2.label+close1); + break; + case 4: + $("#left_cat").html(openA+template.catB.label+closeA); + $("#right_cat").html(openA+template.catA.label+closeA); + break; + case 5: + case 6: + $("#left_cat").html(openA+template.catB.label+closeA+'
or
'+open1+template.cat1.label+close1); + $("#right_cat").html(openA+template.catA.label+closeA+'
or
'+open1+template.cat2.label+close1); + break; + } + if (session == 7) + { + $("#left_cat").html(""); + $("#right_cat").html(""); + $("#exp_instruct").html(""); + WriteFile(); + //if('insertForm' in template) + if(true) + { + resulttext = ''; + $("#experiment_frame").html(resulttext); + } + else + { + if(template.showResult == "show") + { + calculateIAT(); + } + else + { + resulttext = "
Thanks for participating!
"; + $("#picture_frame").html(resulttext); + } + } + } + else + { + $.get("core/gInstruct"+(session+1)+".html", function(data) { $('#exp_instruct').html(data); }); + } +} + +function clearForm(toggle) +{ + clearform = clearform ^ toggle; + if(clearform) + { + $('#experiment_frame').html('
'); + if(template.showResult == "show") + { + calculateIAT(); + } + else + { + resulttext = "
Thanks for participating!
"; + $("#picture_frame").html(resulttext); + } + } +} + +// Calculates estimate of effect size to present results to participant +function calculateIAT() +{ + // calculate mean log(RT) for first key trial + compatible = 0; + for (i=1; i 3000) { score = 3000; } + compatible += Math.log(score); + } + compatible /= (roundArray[3].length - 1); + + // calculate mean log(RT) for second key trial + incompatible = 0; + for (i=1; i 3000) { score = 3000; } + incompatible += Math.log(score); + } + incompatible /= (roundArray[6].length - 1); + + // calculate variance log(RT) for first key trial + cvar = 0; + for (i=1; i 3000) { score = 3000; } + cvar += Math.pow((Math.log(score) - compatible),2); + } + + // calculate variance log(RT) for second key trial + ivar = 0; + for (i=1; i 3000) { score = 3000; } + ivar += Math.pow((Math.log(score) - incompatible),2); + } + + // calculate t-value + tvalue = (incompatible - compatible) / Math.sqrt(((cvar/39) + (ivar/39))/40); + + // determine effect size from t-value and create corresponding text + if (Math.abs(tvalue) > 2.89) { severity = " much more than "; } + else if (Math.abs(tvalue) > 2.64) { severity = " more than "; } + else if (Math.abs(tvalue) > 1.99) { severity = " a little more than "; } + else if (Math.abs(tvalue) > 1.66) { severity = " just slightly more than "; } + else { severity = ""; } + + // put together feedback based on direction & magnitude + if (tvalue < 0 && severity != "") + { + resulttext = "
You associate "+openA+template.catB.label+closeA+" with "+open1+template.cat1.label+close1; + resulttext += " and "+openA+template.catA.label+closeA+" with "+open1+template.cat2.label+close1+severity; + resulttext += "you associate "+openA+template.catA.label+closeA+" with "+open1+template.cat1.label+close1; + resulttext += " and "+openA+template.catB.label+closeA+" with "+open1+template.cat2.label+close1+".
"; + // resulttext += "
incompatible: "+incompatible+" ("+(ivar/39)+"); compatible: "+compatible+" ("+(cvar/39)+"); tvalue: "+tvalue+"
"; + } + else if (tvalue > 0 && severity != "") + { + resulttext = "
You associate "+openA+template.catA.label+closeA+" with "+open1+template.cat1.label+close1; + resulttext += " and "+openA+template.catB.label+closeA+" with "+open1+template.cat2.label+close1+severity; + resulttext += "you associate "+openA+template.catB.label+closeA+" with "+open1+template.cat1.label+close1; + resulttext += " and "+openA+template.catA.label+closeA+" with "+open1+template.cat2.label+close1+".
"; + // resulttext += "
incompatible: "+incompatible+" ("+(ivar/39)+"); compatible: "+compatible+" ("+(cvar/39)+"); tvalue: "+tvalue+"
"; + } + else + { + resulttext = "
You do not associate "+openA+template.catA.label+closeA; + resulttext += " with "+open1+template.cat1.label+close1+" any more or less than you associate "; + resulttext += openA+template.catB.label+closeA+" with "+open1+template.cat1.label+close1+".
"; + // resulttext += "
incompatible: "+incompatible+" ("+(ivar/39)+"); compatible: "+compatible+" ("+(cvar/39)+"); tvalue: "+tvalue+"
"; + } + $("#picture_frame").html(resulttext); +} + +// not currently used +function groupEvaluations() +{ + $('#demoglist').after( + "Please rate how warm or cold you feel toward the following groups:\ +
\ + (0 = coldest feelings, 5 = neutral, 10 = warmest feelings)\ +
    \ +
  1. \ +

    "+template.catA.label+"

    \ +

    \ + \ +

    \ +
  2. \ +
  3. \ +

    "+template.catB.label+"

    \ +

    \ + \ +

    \ +
  4. \ +
\ + "); +} + +function IsNumeric(input) +{ + return (input - 0) == input && input.length > 0; +} + +// not currently used +function checkDemographics() +{ + gender = $("input[name=gender]:checked").val(); + age = $("#age option:selected").val(); + loc = $("#loc option:selected").val().replace(/[^A-Za-z0-9,]/g,' '); + races = []; + $("input[name=race]:checked").each(function() { races.push($(this).val()); }); + income = $("#income").val(); + education = $("#edu option:selected").val(); + + // alert(income+"\n"+parseFloat(income)+"\n"); + // $.get('getLocation.php', + // { 'q': loc}, + // function(data) { + // alert(data); + // }); + + // Do validation of input + var error = false; + var errmsg = ""; + + if(gender==null) + { + error=true; + errmsg += "
Please choose an option for gender
"; + } + if(age=="unselected") + { + error=true; + errmsg += "
Please state the year you were born
"; + } + if(loc.length == 0) + { + error=true; + errmsg += "
Please indicate your current location
"; + } + if(races==null) + { + error=true; + errmsg += "
Please indicate your ethnicity
"; + } + if(income==null || $.trim(income) != income.replace(/[^0-9$.,]/g,'') || !IsNumeric(income.replace(/[^0-9.]/g,''))) + { + error=true; + errmsg += "
Please enter a valid number for income
"; + } + if(education=="unselected") + { + error=true; + errmsg += "
Please indicate your highest level of education
"; + } + if(sub.length == 0) + { + error=true; + errmsg += "
Please enter a valid identifier
"; + } + // Output error message if input not valid + if(error==false) + { + subject = sub; + var demos = gender+'\t'; + demos += age+'\t'; + demos += loc+'\t'; + demos += races.join(',')+'\t'; + demos += income.replace(/[^0-9.]/g,'')+'\t'; + demos += education+'\n'; + $.post("core/writeFile.php", { 'subject': subject, 'src': "survey", 'data': demos }, function() {location.href = 'instruct2.php?sub='+sub;}); + } + else + { + $('#error-1').html(errmsg); + } +} + + +// Converts the data for each session and round into a comma-delimited string +// and passes it to writeFile.php to be written by the server +function WriteFile() +{ + var subject = sub; + subject = subject.length==0 ? "unknown" : subject; + var str = ""; + for (i=0; i Date: Sat, 16 Mar 2013 21:42:01 -0500 Subject: [PATCH 6/7] Solved issue #2 ('save' button issue), etc. -'Save' button fixed to work when template name contains space -Updated delete function to work when template name contains space --- core/fileManager.php | 14 +- core/js/experimenter.js | 1959 ++++++++++++++++++++------------------- experimenter.php | 71 +- 3 files changed, 1023 insertions(+), 1021 deletions(-) diff --git a/core/fileManager.php b/core/fileManager.php index 3f911cd..ed92a73 100644 --- a/core/fileManager.php +++ b/core/fileManager.php @@ -171,14 +171,14 @@ function writeoutput($output) } else { $errors = ""; - // template name is set, has only alphanumeric characters, and is < 30 characters + // template name is set and is < 30 characters if(!isset($form["template-name"]) || - strlen($form["template-name"]) > 30 || - $form["template-name"] != preg_replace('/[^A-Za-z0-9]+/','',$form["template-name"])) + strlen($form["template-name"]) > 30 /*|| + $form["template-name"] != preg_replace('/[^A-Za-z0-9]+/','',$form["template-name"])*/) { $errors .= "
  • "; - $errors .= "Please input a valid template name (less than 30 alphanumeric characters only) "; - $errors .= "
  • "; + $errors .= "Please input a valid template name (less than 30 characters)"; + $errors .= ""; } else { @@ -358,10 +358,10 @@ function writeoutput($output) // else if template name has changed else if ($_REQUEST['oldname'] != $form["template-name"]) { - // check for template-name conflict happened earlier, so this is safe + // checked for template-name conflict happened earlier, so this is safe rename("../templates/".$_REQUEST['oldname'],"../templates/".$form["template-name"]); - // check if old name is currently active, if so, change? + // check if old name is currently active, if so, change // also need to rename in active.txt $optArr = array('oldName' => $_REQUEST['oldname'], 'newName' => $form['template-name'], diff --git a/core/js/experimenter.js b/core/js/experimenter.js index 9567720..dfc6a29 100644 --- a/core/js/experimenter.js +++ b/core/js/experimenter.js @@ -1,980 +1,981 @@ -var templates = {}; -var catlistnames = ["catA","catB","cat1","cat2"]; -var catfullnames = ["Category A","Category B","Category 1","Category 2"]; - -$.fn.hookToInput = function(selector) -{ - if(typeof selector == "string") - { - selector = $(selector); - } - - this.each(function(i) - { - var $this = $(this); - var assocInput = $($.isFunction(selector) ? selector($this) - : selector.get(i)); - - assocInput.keyup(function() - { - $this.html(assocInput.val() || "[Untitled]"); - }); - }); -} - -$.fn.toSerializedJSON = function() -{ - var $this = $(this); - var params = $this.serialize().split("&"); - var json = "{"; - - for(var i = 0, l = params.length; i 0; - - /* If current template has unsaved changes, prompt user to - * save before closing. - * - * Store unsaved data in cookies to prompt user with on - * return to experimenter - */ - if(hasUnsavedTemplate) - { - var templateId = $(".template-selected").data("templateid"); - $.cookie("unsaved_templateid",templateId); - $.cookie("unsaved_data",$("#template-form").toSerializedJSON()); - - return "Note: You have unsaved changes to " + templateId + "."; - } -} - -function showUnsavedChangesFromPrevious() -{ - var templateId = $.cookie("unsaved_templateid"); - var templateData = $.cookie("unsaved_data"); - if(templateId && templateData) - { - /*$("#alert-window").html("Do you want to recover unsaved changes to " + templateId + "?"); - $("#alert-window").dialog({ - title: "

    Unsaved Changes:" + templateId + "

    ", - modal: true, - buttons: { - Yes: function() - { - $(this).dialog("close"); - }, - No: function() - { - $(this).dialog("close"); - } - } - });*/ - - clearUnsavedChangesFromPrevious(); - } -} - -function clearUnsavedChangesFromPrevious() -{ - // Clear unsaved changes from previous visit - $.removeCookie("unsaved_templateid"); - $.removeCookie("unsaved_data"); -} - -function clearUnsavedTemplate() -{ - var unsavedTemplate = $(".template-unsaved"); - - unsavedTemplate.find(".save-item").remove(); - unsavedTemplate.data("ischanged", false) - .removeClass("template-unsaved"); -} - -function renderTemplateViewerItem(templateId) -{ - // Update :: added data-templateid attribute to avoid - // errors resulting from selecting .template-item elements - // with illegal characters in ID attribute - - $(".active-selector").append("
    " + templateId + "
    "); -} - -function showTemplates(input) -{ - // Save currently selected template (if any) - var currTemplateId = $("#template-name").val(); - - // Removes previously created DOM for templates - // before updating with new content - $(".user-template").remove(); - - var numTemplates = input.available.length; - var numTemplatesLoaded = 0; - - // Generate DOM elements for each template in - // .selector-frame and populate templates object - for (var template in input.available) - { - if(input.available[template] != "Empty") - { - renderTemplateViewerItem(input.available[template]); - } - - // Retrieve current template configuration from external resource - FileMgr.getJSON(FileMgr.getInputPath(input.available[template]), function(data) - { - templates[data["name"]] = data; - - numTemplatesLoaded++; - if(numTemplatesLoaded == numTemplates) - { - readyTemplates(input); - } - }); - } - - // Re-attach .template-selected class to current template - var currTemplateObj = $(".template-item[data-templateid='" + currTemplateId + "']"); - if(currTemplateObj.length > 0) - { - currTemplateObj.addClass("template-selected"); - } - - // Attach event handler for changing templates - $(".template-item").unbind("click").click(selectTemplate); -} - - -function verifyDelete(templateId) -{ - if($(".exp-header-active").html() == templateId) - { - $( "#alert-window" ).html(templateId+" is currently active. Please make another template active before deleting this template."); - $( "#alert-window" ).dialog({ - title: "

    Template Currently Active

    ", - modal: true, - buttons: { - Ok: function() { - $( this ).dialog( "close" ); - } - } - }); - } - else - { - $( "#alert-window" ).html("
    Are you sure you want to delete template '"+templateId+"'? This will delete all associated files, including existing data!!
    "); - $( "#alert-window" ).dialog({ - title: "

    Confirm Delete

    ", - modal: true, - buttons: { - Delete: function() { - FileMgr.post(FileMgr.getFileMgrPath(), {"op":"deleteTemplate", "template":templateId}, function(data) { - if (data.slice(0,5) == "Error") - { - alert(data); - } - else - { - $("#exp-content").empty(); - FileMgr.getJSON(FileMgr.getActivePath(),showTemplates); - } - }); - $(this).dialog("close"); - }, - Cancel: function() { - $(this).dialog("close"); - } - } - }); - } -} - -function selectTemplate() -{ - var $this = $(this); - - // Prevent reloading of current template so - // altered data not overwritted - if($this.hasClass("template-selected")) { - return false; - } - - // Prompt user to save changes to active template - // before changing to selected template - var currTemplateObj = $(".template-selected"); - var currTemplate = currTemplateObj.text(); - - // If new, unsaved template, adjust its title - if(currTemplateObj.attr("id") == "create-new") - { - currTemplate = ($("#template-name").val() != "Empty") ? $("#template-name").val() - : "Untitled"; - } - - if(currTemplateObj.hasClass("template-unsaved")) - { - $("#alert-window").html("Do you want to save changes to \"" + currTemplate +"\"?") - .dialog({ - title: "

    Unsaved Changes

    ", - modal: true, - close: clearUnsavedTemplate, - buttons: { - Save: function() - { - saveTemplate(function(data) - { - repaintTemplates(data); - changeTemplate({ - templateObj: $this, - isReloadActive: true - }); - $("#alert-window").dialog("close"); // Note the closure :: $(this) != $("#alert-window") - },showSaveError); - }, - Discard: function() - { - currTemplateObj.find(".template-item-label").html(currTemplateObj.data("templateid")); // Restore original template name - changeTemplate({ - templateObj: $this, - isReloadActive: false - }); - $(this).dialog("close"); - } - } - }); - } - else - { - changeTemplate({ - templateObj: $this, - isReloadActive: false - }); - } - - -} - -function changeTemplate(options) -{ - // isReloadActive indicates whether template inputs should - // be redownloaded with updates - isReloadActive = options.isReloadActive || false; - var $this = options.templateObj; - - // Change selected template - $(".template-selected").removeClass("template-selected"); - $this.addClass("template-selected"); - - if($this.attr("id") != "create-new") - { - $("#set-active").button("option","disabled", false); - } - - // Put form html into exp-content frame - FileMgr.get(FileMgr.getTemplateFormPath(), function(data) { - - renderTemplateForm(data); - attachTemplateFormEventHandlers(); - - if(isReloadActive) - { - // Update templates object with new data (so oldname is fixed on next run) - FileMgr.getJSON(FileMgr.getActivePath(),showTemplates); - } - - }); -} - -function renderTemplateForm(data) -{ - var templateId; - if($(".template-selected").attr("id") == "create-new") - { - templateId = "Empty"; - } - else - { - templateId = $(".template-selected").attr("id"); - } - - $("#exp-content").html(data); - $("#template-name").val(templateId); - $("#category-selector").tabs(); - - // Enable buttons to select between 2-cat and 1-cat IAT - $( "#IAT-type" ).buttonset(); - // set initial value from template - if(templates[templateId].IATtype == "two") - { - $("#IAT-standard").attr("checked",true); - $("#IAT-type").buttonset('refresh'); - } - else - { - $("#IAT-single").attr("checked",true); - $("#IAT-type").buttonset('refresh'); - } - // Change on click - $( "#IAT-type :radio" ).click(function(e) { - $( "#IAT-type :radio" ).attr("checked",false); - $(this).attr("checked",true); - }); - // Hide IAT type until IAT is ready for it - $( "#IAT-type").hide(); - - // Enable buttons for showing results at end or not - $( "#show-results" ).buttonset(); - if(templates[templateId].showResult == "show") - { - $("#show").attr("checked",true); - $("#show-results").buttonset('refresh'); - } - else - { - $("#noshow").attr("checked",true); - $("#show-results").buttonset('refresh'); - } - // Change on click - $( "#show-results :radio" ).click(function(e) { - $( "#show-results :radio" ).attr("checked",false); - $(this).attr("checked",true); - }); - - var categoryTabs = $("#category-list a"); - for(var j=1; j<5; j++) - { - // create references - tabname = "tabs" + j; - catname = catlistnames[j-1]; - - // Update category tab with name - $(categoryTabs.get(j - 1)).html(templates[templateId][catname].label); - - // Set up Category Tab - $( "#"+tabname+"-toi-selector" ).buttonset(); - - // Change from img to text on click - $( "#"+tabname+"-toi-selector :radio" ).click(function(e) { - idx = parseInt($(this).attr("id").slice(-5,-4)); - tabname = "tabs" + idx; - catname = catlistnames[idx-1]; - $( "#"+tabname+"-toi-selector :radio" ).attr("checked",false); - - if($(this).attr("id").slice(-3) == "txt") - { - $(this).attr("checked",true); - $(".img-item-"+catname).hide(); - } - else - { - $(this).attr("checked",true); - $(".img-item-"+catname).show(); - updateImages(idx); - } - $('#'+tabname+'-toi-selector').buttonset('refresh') - }); - - // add category label name - $("#"+tabname+"-catlabel-input").val(templates[templateId][catname].label); - - // add data label name - $("#"+tabname+"-datalabel-input").val(templates[templateId][catname].datalabel); - - // Show options for each tab - for (var i=0; i"; - // preview - if(templates[templateId][catname].itemtype == "txt") - { - itemstring += ""; - } - else - { - itemstring += ""; - } - // input for filename - itemstring += ""; - itemstring += ""; - $("#"+tabname+"-catitems").append(itemstring); - } - itemstring = ""; - $("#"+tabname+"-catitems").append(itemstring); - - itemstring = "
    "; - $("#"+tabname+"-catitems").append(itemstring); - - // update images button - itemstring = ""; - $("#"+tabname+"-catitems").append(itemstring); - - // decide if showing or not - if(templates[templateId][catname].itemtype == "txt") - { - // Set text / image selection - $("#"+tabname+"-txt").attr('checked', "checked"); - $("#"+tabname+"-toi-selector").buttonset('refresh'); - $(".img-item-"+catname).hide(); - } - else - { - // Set text / image selection - $("#"+tabname+"-img").attr('checked', "checked"); - $("#"+tabname+"-toi-selector").buttonset('refresh'); - $(".img-item-"+catname).show(); - } - - } - - if($(".template-selected").attr("id") == "create-new") - { - $("#template-name").val("").focus(); - } -} - -function attachTemplateFormEventHandlers() -{ - $("input[type=button]").button(); - - // Listen for changes to template to update templates object - $("#template-form input").unbind("change").on("change",updateTemplateState); - - // Event handler for save icon in template viewer - $("#save-template").unbind("click").click(function() { - saveTemplate(repaintTemplates,showSaveError) - }); - - // Event hook to update category tab labels with category - $("#category-list a").hookToInput(".catlabel-input"); - - // Event hook to update template viewer labels when template name changes - $(".template-selected .template-item-label").hookToInput(function(x) { - return "#template-name"; - }); -} - -function repaintTemplates() -{ - var templateName = $("#template-name").val(); - - - if($(".template-selected").attr("id") == "create-new") - { - $(".template-selected").removeClass("template-selected"); - $("#exp-content").empty(); - } - else - { - $(".template-selected").attr("id",templateName) - .data("templateid",templateName); - } - - //update images - for(var j=1; j<5; j++) - { - tabname = "tabs" + j; - // clear errors - $("#"+tabname + "-catitems > div.catitem").removeClass("erroritem"); - - if ($("#tabs"+j+"-toi-selector :radio:checked").attr("id") == "tabs"+j+"-img") - { - // update images - catitemimgs = $("#"+tabname + "-catitems > div.catitem > img"); - catitemtxts = $("#"+tabname + "-catitems > div.catitem > input:text"); - for (var imgidx=0; imgidxTemplate saved", - modal: true, - buttons: { - Ok: function() { - $( this ).dialog( "close" ); - } - } - }); - });*/ -} - -function showSaveError(data) -{console.log(data); - /*res = eval('('+data+')'); - $("#alert-window").html("
      "+res['errors']+"
    "); - for(var j=1; j<5; j++) - { - tabname = "tabs" + j; - if ($("#tabs"+j+"-toi-selector :radio:checked").attr("id") == "tabs"+j+"-img") - { - // update images - catitemimgs = $("#"+tabname + "-catitems > div.catitem > img"); - filesrcs = res['images'][tabname].split(","); - numitems = filesrcs.length; - // put image sources in files - for (var imgidx=0; imgidxProblems with template", - modal: true, - buttons: { - Ok: function() { - $( this ).dialog( "close" ); - } - } - }); - });*/ -} - -function updateTemplateState(e) -{ - var currTemplateObj = $(".template-selected"); - - if(!currTemplateObj.hasClass("template-unsaved")) - { - // Subtle hint: CSS (.template-unsaved .template-item-label:after) appends "*" to template name - currTemplateObj.data("ischanged", true) - .addClass("template-unsaved"); - - // Subtle hint: add save icon to template viewer item - var baseHtml = currTemplateObj.html(); - currTemplateObj.html(baseHtml + ""); - } -} - -function addItem(catnum) -{ - if($(".template-selected").attr("id") == "create-new") - { - var templateId = "Empty"; - } - else - { - var templateId = $(".template-selected").attr("id"); - } - tabname = "tabs" + catnum; - catname = catlistnames[catnum-1]; - var lastitem = $("#max-"+catname).prev(); - var lasttext = lastitem.children("input:text").attr("id"); - var idx = parseInt(lasttext.slice(-5,-4)) + 1; - - itemstring = "
    "; - // delete button - itemstring += ""; - // preview - itemstring += ""; - // input for filename - itemstring += ""; - itemstring += "
    "; - $("#max-"+catname).before(itemstring); - // check currently selected option - if($("#"+tabname+"-toi-selector :radio:checked").attr("id") == tabname+"-txt") - { - $(".img-item-"+catname).hide() - } - // update maximum number of items - $("#max-"+catname).val(idx); -} - -function updateImages(catidx) -{ - if($(".template-selected").attr("id") == "create-new") - { - var templateId = "Empty"; - } - else - { - var templateId = $(".template-selected").attr("id"); - } - tabname = "tabs" + catidx; - catname = catlistnames[catidx-1]; - - // clear errors - $("#"+tabname + "-catitems > div.catitem").removeClass("erroritem"); - - // get file sources from input fields - catitemtxts = $("#"+tabname + "-catitems > div.catitem > input:text"); - imgsources = [] - for (var imgidx=0; imgidx div.catitem > img"); - filesrcs = data.split(","); - if (filesrcs.length == catitemimgs.length - 1) - { - // put image sources in files - for (var imgidx=0; imgidxActive Template Updated", - modal: true, - buttons: { - Ok: function() { - $( this ).dialog( "close" ); - } - } - }); - } - else if(data.slice(0,5) == "Error") - { - alert(data); - } - }); - -} - -function saveTemplate(successCallback, errorCallback) -{ - var templateId, oldName; - if($(".template-selected").attr("id") == "create-new") - { - templateId = $("#template-name").val(); - oldName = "Empty"; - } - else - { - templateId = $("#template-name").val(); - oldName = templates[$(".template-selected").data("templateid")].name; - } - var formString = $("form").serialize(); - // console.log(formString); - - FileMgr.post(FileMgr.getFileMgrPath(), - { "op": "saveTemplate", "template": templateId, "oldname": oldName, "form": formString}, - function(saveData) { - if (saveData == "success") - { - // Remove save icon from unsaved template viewer item - clearUnsavedTemplate(); - - clearUnsavedChangesFromPrevious(); - - $(".template-selected") - .data("templateid",templateId) - .attr("id",templateId); - - // Update template object with saved data - FileMgr.getJSON(FileMgr.getInputPath(templateId), function(templateData) - { - templates[templateId] = templateData; - successCallback(saveData); - }); - } - else if (saveData.slice(0,5) == "Error") - { - alert(saveData); // Should call errorCallback as well? (Probably) - } - else - { - errorCallback(saveData); - } - }); - -} - -function loadCreateForm() { - // $(".template-selected").removeClass("template-selected"); - $("#set-active").button("option","disabled",true); - // $("#view-stats").attr("disabled","disabled"); - - // selectTemplate(); - - // Make edits to group name live - // $("#group-name-field").ready(function() { - // $("#group-name-field").keyup(changeGroupName); - // }); -} - -function loadActiveStats(input) -{ - $(".exp-header-active").html(input.active); - - // Get completed output - // $.getJSON("core/fileManager.php", - // {"op":"getstats","root":input.root,"output":input.output}, - // buildStatsPage); -} - -function viewStats() { - // Get selected template - - // Verify data for template exists - - // Build stats page -} - - -function buildStatsPage(input) -{ - - // Number completed - - // Bar chart - - // Aggregate & Save button - - // Change active IAT +var templates = {}; +var catlistnames = ["catA","catB","cat1","cat2"]; +var catfullnames = ["Category A","Category B","Category 1","Category 2"]; + +$.fn.hookToInput = function(selector) +{ + if(typeof selector == "string") + { + selector = $(selector); + } + + this.each(function(i) + { + var $this = $(this); + var assocInput = $($.isFunction(selector) ? selector($this) + : selector.get(i)); + + assocInput.keyup(function() + { + $this.html(assocInput.val() || "[Untitled]"); + }); + }); +} + +$.fn.toSerializedJSON = function() +{ + var $this = $(this); + var params = $this.serialize().split("&"); + var json = "{"; + + for(var i = 0, l = params.length; i 0; + + /* If current template has unsaved changes, prompt user to + * save before closing. + * + * Store unsaved data in cookies to prompt user with on + * return to experimenter + */ + if(hasUnsavedTemplate) + { + var templateId = $(".template-selected").data("templateid"); + $.cookie("unsaved_templateid",templateId); + $.cookie("unsaved_data",$("#template-form").toSerializedJSON()); + + return "Note: You have unsaved changes to " + templateId + "."; + } +} + +function showUnsavedChangesFromPrevious() +{ + var templateId = $.cookie("unsaved_templateid"); + var templateData = $.cookie("unsaved_data"); + if(templateId && templateData) + { + /*$("#alert-window").html("Do you want to recover unsaved changes to " + templateId + "?"); + $("#alert-window").dialog({ + title: "

    Unsaved Changes:" + templateId + "

    ", + modal: true, + buttons: { + Yes: function() + { + $(this).dialog("close"); + }, + No: function() + { + $(this).dialog("close"); + } + } + });*/ + + clearUnsavedChangesFromPrevious(); + } +} + +function clearUnsavedChangesFromPrevious() +{ + // Clear unsaved changes from previous visit + $.removeCookie("unsaved_templateid"); + $.removeCookie("unsaved_data"); +} + +function clearUnsavedTemplate() +{ + var unsavedTemplate = $(".template-unsaved"); + + unsavedTemplate.find(".save-item").remove(); + unsavedTemplate.data("ischanged", false) + .removeClass("template-unsaved"); +} + +function renderTemplateViewerItem(templateId) +{ + // Update :: added data-templateid attribute to avoid + // errors resulting from selecting .template-item elements + // with illegal characters in ID attribute + + $(".active-selector").append("
    " + templateId + "
    "); +} + +function showTemplates(input) +{ + // Save currently selected template (if any) + var currTemplateId = $("#template-name").val(); + + // Removes previously created DOM for templates + // before updating with new content + $(".user-template").remove(); + + var numTemplates = input.available.length; + var numTemplatesLoaded = 0; + + // Generate DOM elements for each template in + // .selector-frame and populate templates object + for (var template in input.available) + { + if(input.available[template] != "Empty") + { + renderTemplateViewerItem(input.available[template]); + } + + // Retrieve current template configuration from external resource + FileMgr.getJSON(FileMgr.getInputPath(input.available[template]), function(data) + { + templates[data["name"]] = data; + + numTemplatesLoaded++; + if(numTemplatesLoaded == numTemplates) + { + readyTemplates(input); + } + }); + } + + // Re-attach .template-selected class to current template + var currTemplateObj = $(".template-item[data-templateid='" + currTemplateId + "']"); + if(currTemplateObj.length > 0) + { + currTemplateObj.addClass("template-selected"); + } + + // Attach event handler for changing templates + $(".template-item").unbind("click").click(selectTemplate); +} + + +function verifyDelete(templateId) +{ + if($(".exp-header-active").html() == templateId) + { + $( "#alert-window" ).html(templateId+" is currently active. Please make another template active before deleting this template."); + $( "#alert-window" ).dialog({ + title: "

    Template Currently Active

    ", + modal: true, + buttons: { + Ok: function() { + $( this ).dialog( "close" ); + } + } + }); + } + else + { + $( "#alert-window" ).html("
    Are you sure you want to delete template '"+templateId+"'? This will delete all associated files, including existing data!!
    "); + $( "#alert-window" ).dialog({ + title: "

    Confirm Delete

    ", + modal: true, + buttons: { + Delete: function() { + FileMgr.post(FileMgr.getFileMgrPath(), {"op":"deleteTemplate", "template":templateId}, function(data) { + if (data.slice(0,5) == "Error") + { + alert(data); + } + else + { + $("#exp-content").empty(); + FileMgr.getJSON(FileMgr.getActivePath(),showTemplates); + } + }); + $(this).dialog("close"); + }, + Cancel: function() { + $(this).dialog("close"); + } + } + }); + } +} + +function selectTemplate(e) +{ + var $this = $(this); + + // Prevent reloading of current template so + // altered data not overwritted + if(!$this.hasClass("template-selected")) { + // Prompt user to save changes to active template + // before changing to selected template + var currTemplateObj = $(".template-selected"); + var currTemplate = currTemplateObj.text(); + + // If new, unsaved template, adjust its title + if(currTemplateObj.attr("id") == "create-new") + { + currTemplate = ($("#template-name").val() != "Empty") ? $("#template-name").val() + : "Untitled"; + } + + if(currTemplateObj.hasClass("template-unsaved")) + { + $("#alert-window").html("Do you want to save changes to \"" + currTemplate +"\"?") + .dialog({ + title: "

    Unsaved Changes

    ", + modal: true, + close: clearUnsavedTemplate, + buttons: { + Save: function() + { + saveTemplate(function(data) + { + repaintTemplates(data); + changeTemplate({ + templateObj: $this, + isReloadActive: true + }); + $("#alert-window").dialog("close"); // Note the closure :: $(this) != $("#alert-window") + },showSaveError); + }, + Discard: function() + { + currTemplateObj.find(".template-item-label").html(currTemplateObj.data("templateid")); // Restore original template name + changeTemplate({ + templateObj: $this, + isReloadActive: false + }); + $(this).dialog("close"); + } + } + }); + } + else + { + changeTemplate({ + templateObj: $this, + isReloadActive: false + }); + } + } +} + +function changeTemplate(options) +{ + // isReloadActive indicates whether template inputs should + // be redownloaded with updates + isReloadActive = options.isReloadActive || false; + var $this = options.templateObj; + + // Change selected template + $(".template-selected").removeClass("template-selected"); + $this.addClass("template-selected"); + + if($this.attr("id") != "create-new") + { + $("#set-active").button("option","disabled", false); + } + + // Put form html into exp-content frame + FileMgr.get(FileMgr.getTemplateFormPath(), function(data) { + + renderTemplateForm(data); + attachTemplateFormEventHandlers(); + + if(isReloadActive) + { + // Update templates object with new data (so oldname is fixed on next run) + FileMgr.getJSON(FileMgr.getActivePath(),showTemplates); + } + + }); +} + +function renderTemplateForm(data) +{ + var templateId; + if($(".template-selected").attr("id") == "create-new") + { + templateId = "Empty"; + } + else + { + templateId = $(".template-selected").attr("id"); + } + + $("#exp-content").html(data); + $("#template-name").val(templateId); + $("#category-selector").tabs(); + + // Enable buttons to select between 2-cat and 1-cat IAT + $( "#IAT-type" ).buttonset(); + // set initial value from template + if(templates[templateId].IATtype == "two") + { + $("#IAT-standard").attr("checked",true); + $("#IAT-type").buttonset('refresh'); + } + else + { + $("#IAT-single").attr("checked",true); + $("#IAT-type").buttonset('refresh'); + } + // Change on click + $( "#IAT-type :radio" ).click(function(e) { + $( "#IAT-type :radio" ).attr("checked",false); + $(this).attr("checked",true); + }); + // Hide IAT type until IAT is ready for it + $( "#IAT-type").hide(); + + // Enable buttons for showing results at end or not + $( "#show-results" ).buttonset(); + if(templates[templateId].showResult == "show") + { + $("#show").attr("checked",true); + $("#show-results").buttonset('refresh'); + } + else + { + $("#noshow").attr("checked",true); + $("#show-results").buttonset('refresh'); + } + // Change on click + $( "#show-results :radio" ).click(function(e) { + $( "#show-results :radio" ).attr("checked",false); + $(this).attr("checked",true); + }); + + var categoryTabs = $("#category-list a"); + for(var j=1; j<5; j++) + { + // create references + tabname = "tabs" + j; + catname = catlistnames[j-1]; + + // Update category tab with name + $(categoryTabs.get(j - 1)).html(templates[templateId][catname].label); + + // Set up Category Tab + $( "#"+tabname+"-toi-selector" ).buttonset(); + + // Change from img to text on click + $( "#"+tabname+"-toi-selector :radio" ).click(function(e) { + idx = parseInt($(this).attr("id").slice(-5,-4)); + tabname = "tabs" + idx; + catname = catlistnames[idx-1]; + $( "#"+tabname+"-toi-selector :radio" ).attr("checked",false); + + if($(this).attr("id").slice(-3) == "txt") + { + $(this).attr("checked",true); + $(".img-item-"+catname).hide(); + } + else + { + $(this).attr("checked",true); + $(".img-item-"+catname).show(); + updateImages(idx); + } + $('#'+tabname+'-toi-selector').buttonset('refresh') + }); + + // add category label name + $("#"+tabname+"-catlabel-input").val(templates[templateId][catname].label); + + // add data label name + $("#"+tabname+"-datalabel-input").val(templates[templateId][catname].datalabel); + + // Show options for each tab + for (var i=0; i"; + // preview + if(templates[templateId][catname].itemtype == "txt") + { + itemstring += ""; + } + else + { + itemstring += ""; + } + // input for filename + itemstring += ""; + itemstring += ""; + $("#"+tabname+"-catitems").append(itemstring); + } + itemstring = ""; + $("#"+tabname+"-catitems").append(itemstring); + + itemstring = "
    "; + $("#"+tabname+"-catitems").append(itemstring); + + // update images button + itemstring = ""; + $("#"+tabname+"-catitems").append(itemstring); + + // decide if showing or not + if(templates[templateId][catname].itemtype == "txt") + { + // Set text / image selection + $("#"+tabname+"-txt").attr('checked', "checked"); + $("#"+tabname+"-toi-selector").buttonset('refresh'); + $(".img-item-"+catname).hide(); + } + else + { + // Set text / image selection + $("#"+tabname+"-img").attr('checked', "checked"); + $("#"+tabname+"-toi-selector").buttonset('refresh'); + $(".img-item-"+catname).show(); + } + + } + + if($(".template-selected").attr("id") == "create-new") + { + $("#template-name").val("").focus(); + } +} + +function attachTemplateFormEventHandlers() +{ + $("input[type=button]").button(); + + // Listen for changes to template to update templates object + $("#template-form input").unbind("change").on("change",updateTemplateState); + + // Event handler for save icon in template viewer + $("#save-template").unbind("click").click(function() { + saveTemplate(repaintTemplates,showSaveError) + }); + + // Event hook to update category tab labels with category + $("#category-list a").hookToInput(".catlabel-input"); + + // Event hook to update template viewer labels when template name changes + $(".template-selected .template-item-label").hookToInput(function(x) { + return "#template-name"; + }); +} + +function repaintTemplates() +{ + var templateName = $("#template-name").val(); + + + if($(".template-selected").attr("id") == "create-new") + { + $(".template-selected").removeClass("template-selected"); + $("#exp-content").empty(); + } + else + { + $(".template-selected").attr("id",templateName) + .data("templateid",templateName); + } + + //update images + for(var j=1; j<5; j++) + { + tabname = "tabs" + j; + // clear errors + $("#"+tabname + "-catitems > div.catitem").removeClass("erroritem"); + + if ($("#tabs"+j+"-toi-selector :radio:checked").attr("id") == "tabs"+j+"-img") + { + // update images + catitemimgs = $("#"+tabname + "-catitems > div.catitem > img"); + catitemtxts = $("#"+tabname + "-catitems > div.catitem > input:text"); + for (var imgidx=0; imgidxTemplate saved", + modal: true, + buttons: { + Ok: function() { + $( this ).dialog( "close" ); + } + } + }); + });*/ +} + +function showSaveError(data) +{console.log(data); + /*res = eval('('+data+')'); + $("#alert-window").html("
      "+res['errors']+"
    "); + for(var j=1; j<5; j++) + { + tabname = "tabs" + j; + if ($("#tabs"+j+"-toi-selector :radio:checked").attr("id") == "tabs"+j+"-img") + { + // update images + catitemimgs = $("#"+tabname + "-catitems > div.catitem > img"); + filesrcs = res['images'][tabname].split(","); + numitems = filesrcs.length; + // put image sources in files + for (var imgidx=0; imgidxProblems with template", + modal: true, + buttons: { + Ok: function() { + $( this ).dialog( "close" ); + } + } + }); + });*/ +} + +function updateTemplateState(e) +{ + var currTemplateObj = $(".template-selected"); + + if(!currTemplateObj.hasClass("template-unsaved")) + { + // Subtle hint: CSS (.template-unsaved .template-item-label:after) appends "*" to template name + currTemplateObj.data("ischanged", true) + .addClass("template-unsaved"); + + // Subtle hint: add save icon to template viewer item + var baseHtml = currTemplateObj.html(); + currTemplateObj.html(baseHtml + ""); + } +} + +function addItem(catnum) +{ + if($(".template-selected").attr("id") == "create-new") + { + var templateId = "Empty"; + } + else + { + var templateId = $(".template-selected").attr("id"); + } + tabname = "tabs" + catnum; + catname = catlistnames[catnum-1]; + var lastitem = $("#max-"+catname).prev(); + var lasttext = lastitem.children("input:text").attr("id"); + var idx = parseInt(lasttext.slice(-5,-4)) + 1; + + itemstring = "
    "; + // delete button + itemstring += ""; + // preview + itemstring += ""; + // input for filename + itemstring += ""; + itemstring += "
    "; + $("#max-"+catname).before(itemstring); + // check currently selected option + if($("#"+tabname+"-toi-selector :radio:checked").attr("id") == tabname+"-txt") + { + $(".img-item-"+catname).hide() + } + // update maximum number of items + $("#max-"+catname).val(idx); +} + +function updateImages(catidx) +{ + if($(".template-selected").attr("id") == "create-new") + { + var templateId = "Empty"; + } + else + { + var templateId = $(".template-selected").attr("id"); + } + tabname = "tabs" + catidx; + catname = catlistnames[catidx-1]; + + // clear errors + $("#"+tabname + "-catitems > div.catitem").removeClass("erroritem"); + + // get file sources from input fields + catitemtxts = $("#"+tabname + "-catitems > div.catitem > input:text"); + imgsources = [] + for (var imgidx=0; imgidx div.catitem > img"); + filesrcs = data.split(","); + if (filesrcs.length == catitemimgs.length - 1) + { + // put image sources in files + for (var imgidx=0; imgidxActive Template Updated", + modal: true, + buttons: { + Ok: function() { + $( this ).dialog( "close" ); + } + } + }); + } + else if(data.slice(0,5) == "Error") + { + alert(data); + } + }); + +} + +function saveTemplate(successCallback, errorCallback) +{ + var templateId, oldName; + if($(".template-selected").attr("id") == "create-new") + { + templateId = $("#template-name").val(); + oldName = "Empty"; + } + else + { + templateId = $("#template-name").val(); + oldName = templates[$(".template-selected").data("templateid")].name; + } + var formString = $("form").serialize(); + // console.log(formString); + + FileMgr.post(FileMgr.getFileMgrPath(), + { "op": "saveTemplate", "template": templateId, "oldname": oldName, "form": formString}, + function(saveData) { + if (saveData == "success") + { + // Remove save icon from unsaved template viewer item + clearUnsavedTemplate(); + + clearUnsavedChangesFromPrevious(); + + $(".template-selected") + .data("templateid",templateId) + .attr("id",templateId); + + // Update template object with saved data + FileMgr.getJSON(FileMgr.getInputPath(templateId), function(templateData) + { + templates[templateId] = templateData; + successCallback(saveData); + }); + } + else if (saveData.slice(0,5) == "Error") + { + alert(saveData); // Should call errorCallback as well? (Probably) + } + else + { + errorCallback(saveData); + } + }); + +} + +function loadCreateForm() { + // $(".template-selected").removeClass("template-selected"); + $("#set-active").button("option","disabled",true); + // $("#view-stats").attr("disabled","disabled"); + + // selectTemplate(); + + // Make edits to group name live + // $("#group-name-field").ready(function() { + // $("#group-name-field").keyup(changeGroupName); + // }); +} + +function loadActiveStats(input) +{ + $(".exp-header-active").html(input.active); + + // Get completed output + // $.getJSON("core/fileManager.php", + // {"op":"getstats","root":input.root,"output":input.output}, + // buildStatsPage); +} + +function viewStats() { + // Get selected template + + // Verify data for template exists + + // Build stats page +} + + +function buildStatsPage(input) +{ + + // Number completed + + // Bar chart + + // Aggregate & Save button + + // Change active IAT } \ No newline at end of file diff --git a/experimenter.php b/experimenter.php index ce35548..20366c9 100644 --- a/experimenter.php +++ b/experimenter.php @@ -1,36 +1,37 @@ - - -IAT Experimenter Page - - - - - - - - - - - -
    -
    -
    Active:
    -
    None
    -
    -
    -
    Templates
    -
    -
    - [New Template] -
    -
    -
    - - -
    -
    -
    -
    + + + +IAT Experimenter Page + + + + + + + + + + + +
    +
    +
    Active:
    +
    None
    +
    +
    +
    Templates
    +
    +
    + [New Template] +
    +
    +
    + + +
    +
    +
    +
    \ No newline at end of file From 970ec6d482308a986ce4f6f4324446b790805d61 Mon Sep 17 00:00:00 2001 From: Steven Allon Date: Thu, 9 May 2013 16:55:51 -0500 Subject: [PATCH 7/7] Solves issue #5 Fixed issue with randomString() function that generated "undefined" participant codes in IE 7-9. --- core/instruct0.html | 2 +- core/js/IAT.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/core/instruct0.html b/core/instruct0.html index ef237b5..52e1d53 100644 --- a/core/instruct0.html +++ b/core/instruct0.html @@ -3,4 +3,4 @@

    Please enter a unique subject identifier; No more than 30 characters, alphanumeric only.

    - + diff --git a/core/js/IAT.js b/core/js/IAT.js index 8cd3717..3ebedd1 100644 --- a/core/js/IAT.js +++ b/core/js/IAT.js @@ -4,7 +4,7 @@ sub = ''; function randomString(length) { var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; var result = ''; - for (var i = length; i > 0; --i) result += chars[Math.round(Math.random() * (chars.length - 1))]; + for (var i = length; i > 0; --i) result += chars.charAt(Math.floor(Math.random() * (chars.length - 1))); return result; }