// Noncommercial research materials. This builder only collects responses. // Run createIST10Form() once from script.google.com, in the collecting lab's account. const IST10_VERSION = "IST10-2026-10-23"; const IST10_INSTRUCTIONS = "Please complete each sentence in your own words. Write what you think or feel. There are no right or wrong answers. Work through the sentences in order. You may write as much or as little as you need. If you do not wish to answer a sentence, leave it blank. Please avoid names or details that identify you or other people."; const IST10_ITEMS = [ { "position": 1, "original_item": 6, "stem_id": "stem_06", "stem": "The thing I like about myself is" }, { "position": 2, "original_item": 10, "stem_id": "stem_10", "stem": "When people are helpless" }, { "position": 3, "original_item": 20, "stem_id": "stem_20", "stem": "Men are lucky because" }, { "position": 4, "original_item": 24, "stem_id": "stem_24", "stem": "If I had more money" }, { "position": 5, "original_item": 26, "stem_id": "stem_26", "stem": "When I get mad" }, { "position": 6, "original_item": 27, "stem_id": "stem_27", "stem": "People who step out of line at work" }, { "position": 7, "original_item": 28, "stem_id": "stem_28", "stem": "A husband has a right to" }, { "position": 8, "original_item": 34, "stem_id": "stem_34", "stem": "For a woman a career is" }, { "position": 9, "original_item": 35, "stem_id": "stem_35", "stem": "My conscience bothers me if" }, { "position": 10, "original_item": 9, "stem_id": "stem_09", "stem": "Education" } ]; function createIST10Form() { const properties = PropertiesService.getUserProperties(); const key = IST10_VERSION + '_resources'; const existing = properties.getProperty(key); if (existing) { const resources = JSON.parse(existing); console.log('Existing materials: ' + JSON.stringify(resources)); return resources; } // Unpublished: researcher adds study information and controls respondent access. const form = FormApp.create('Sentence Completion', false); form.setDescription(IST10_INSTRUCTIONS) .setCollectEmail(false).setLimitOneResponsePerUser(false) .setShuffleQuestions(false).setProgressBar(true) .setPublishingSummary(false).setShowLinkToRespondAgain(false) .setConfirmationMessage('Thank you. Your responses have been recorded.'); const participant = form.addTextItem().setTitle('Participant code') .setHelpText('Enter the code supplied by your research team. Please do not enter your name or email address.') .setRequired(false); const itemMap = {}; IST10_ITEMS.forEach((item, index) => { if (index === 6 || index === 12) { form.addPageBreakItem().setTitle('Sentence Completion — continued') .setHelpText('Continue each sentence in your own words. You may leave a sentence blank.'); } const question = form.addParagraphTextItem() .setTitle(item.position + '. ' + item.stem).setRequired(false); itemMap[String(question.getId())] = item; }); const ss = SpreadsheetApp.create('Sentence Completion responses — ' + IST10_VERSION); ss.getSheets()[0].setName('Read me'); form.setDestination(FormApp.DestinationType.SPREADSHEET, ss.getId()); const resources = { formId: form.getId(), spreadsheetId: ss.getId(), editUrl: form.getEditUrl(), respondentUrl: form.getPublishedUrl(), spreadsheetUrl: ss.getUrl(), participantItemId: participant.getId(), itemMap: itemMap }; properties.setProperty(key, JSON.stringify(resources)); const notes = [ ['Sentence Completion research administration', IST10_VERSION], ['Form editor', resources.editUrl], ['Response spreadsheet', resources.spreadsheetUrl], ['Respondent link (after publication)', resources.respondentUrl], ['Status', 'Created unpublished. Add study information/consent and set respondent access before publishing.'], ['Data', 'Responses remain in this Google account. This script sends nothing to the instrument author or an LLM.'], ['Version', 'Keep the exact 18 stems and their order. Record any changes as a modified administration.'], ['Export', 'Run exportIST10Responses() to produce one row per respondent and stem in Scoring export.'], ['Missing answers', 'Optional questions. Export retains blanks as missing; it does not assign scores.'], ['Form copies', 'Use a separate Google Form for each study; copy the participant form, never a sheet containing actual responses.'], ['Citation', 'Madl & Lazar (2026), Robust Assessment of Integrated Self-Transcendence: Contemplative Expression and Concern Preservation.'], ['Access', 'Noncommercial research use; commercial rights reserved. Tamas.madl@ofai.at.'] ]; ss.getSheetByName('Read me').getRange(1,1,notes.length,2).setValues(notes).setWrap(true); ss.getSheetByName('Read me').setColumnWidth(1,260).setColumnWidth(2,700); const map = ss.insertSheet('Items'); const rows = [['Form position','Original item','Response column','Exact stem']] .concat(IST10_ITEMS.map(i=>[i.position,i.original_item,i.stem_id,i.stem])); map.getRange(1,1,rows.length,4).setValues(rows); map.setFrozenRows(1); map.setColumnWidths(1,3,150); map.setColumnWidth(4,420); console.log('Created unpublished form: ' + resources.editUrl); console.log('Linked response Sheet: ' + resources.spreadsheetUrl); return resources; } function exportIST10Responses() { const stored = PropertiesService.getUserProperties().getProperty(IST10_VERSION + '_resources'); if (!stored) throw new Error('Run createIST10Form() first.'); const resources = JSON.parse(stored); const form = FormApp.openById(resources.formId); const responses = form.getResponses(); const output = [['response_id','participant_code','submitted_at','form_version','form_position','original_item','stem_id','stem','completion','complete_sentence']]; // Treat participant text as text, even if it begins with a spreadsheet formula marker. const safeText = value => /^[=+@-]/.test(String(value)) ? "'" + String(value) : String(value); responses.forEach(response => { const answers = {}; response.getItemResponses().forEach(answer => { answers[String(answer.getItem().getId())] = answer.getResponse(); }); const participant = answers[String(resources.participantItemId)] || ''; const answersByStem = {}; Object.keys(resources.itemMap).forEach(id => { answersByStem[resources.itemMap[id].stem_id] = answers[id] || ''; }); IST10_ITEMS.forEach(item => { const text = String(answersByStem[item.stem_id] || ''); output.push([response.getId(),safeText(participant),response.getTimestamp().toISOString(),IST10_VERSION, item.position,item.original_item,item.stem_id,item.stem,safeText(text), safeText(text.trim() ? item.stem + ' ' + text : '')]); }); }); const ss = SpreadsheetApp.openById(resources.spreadsheetId); const sheet = ss.getSheetByName('Scoring export') || ss.insertSheet('Scoring export'); sheet.clearContents(); if (sheet.getMaxRows() < output.length) sheet.insertRowsAfter(sheet.getMaxRows(), output.length-sheet.getMaxRows()); sheet.getRange(1,1,output.length,output[0].length).setNumberFormat('@').setValues(output); sheet.setFrozenRows(1); sheet.setColumnWidths(8,3,350); console.log('Exported ' + responses.length + ' submissions; 18 rows each, including missing responses.'); }