updated based on T's feedback
This commit is contained in:
@@ -74,6 +74,33 @@ import html from '../utils/html.js';
|
||||
}
|
||||
|
||||
display_element.innerHTML = `
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
||||
<style>
|
||||
.key-icon {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-width: 28px;
|
||||
height: 24px;
|
||||
padding: 2px 6px;
|
||||
background: linear-gradient(145deg, #f0f0f0, #e0e0e0);
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 2px rgba(0,0,0,0.1), inset 0 1px 0 rgba(255,255,255,0.6);
|
||||
font-family: 'Segoe UI', Arial, sans-serif;
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin: 0 2px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.key-icon.space {
|
||||
min-width: 60px;
|
||||
}
|
||||
.key-icon i {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<div style="text-align: center; padding: 20px;">
|
||||
<div style="margin: 20px 0;">
|
||||
<audio style="display: none;" id="playback-audio">
|
||||
@@ -83,23 +110,55 @@ import html from '../utils/html.js';
|
||||
|
||||
|
||||
<div style="margin: 30px 0;">
|
||||
<p style="font-weight: bold; margin-bottom: 15px;">Listen to your recording and mark when you would lift:</p>
|
||||
<p style="margin: 10px 0; font-size: 14px; color: #666;">You can use keyboard controls (space and arrow keys) to play and skip the recording.</p>
|
||||
<p style="margin: 10px 0; font-size: 14px; color: #666;">Adjust playback speed for more precise control.</p>
|
||||
<div class="space-y-4 text-sm text-gray-700">
|
||||
<p class="text-base font-semibold text-black">
|
||||
🎧 Listen to your recording and mark where you would lift:
|
||||
</p>
|
||||
|
||||
<ul class="list-disc list-inside space-y-2">
|
||||
<li>
|
||||
Pause the audio at the lift point and click
|
||||
<span class="italic">'Mark this as lifting point'</span> or press
|
||||
<span class="key-icon">ENTER</span> to save it.
|
||||
</li>
|
||||
<li>
|
||||
You can use the keyboard or the buttons below to mark lift points.
|
||||
</li>
|
||||
<li>
|
||||
Keyboard shortcuts:
|
||||
<ul class="list-inside list-disc ml-5 mt-1 space-y-1 text-gray-600">
|
||||
<li><span class="key-icon space">SPACE</span> – Play/Pause</li>
|
||||
<li><span class="key-icon"><i class="fas fa-arrow-left"></i></span> – Skip back 0.1s</li>
|
||||
<li><span class="key-icon"><i class="fas fa-arrow-right"></i></span> – Skip forward 0.1s</li>
|
||||
<li><span class="key-icon">ENTER</span> – Mark lift point</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
Adjust playback speed if you need more precise control.
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div style="max-width: 500px; margin: 0 auto; background: #f9f9f9; padding: 20px; border-radius: 10px;">
|
||||
<div style="margin-bottom: 20px; display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;">
|
||||
<button id="play-pause-btn" style="
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
min-width: 100px;
|
||||
">▶ Play</button>
|
||||
<div style="margin-bottom: 20px; text-align: center;">
|
||||
<div style="margin-bottom: 15px; font-size: 14px; color: #666;">
|
||||
Playing at 0.5x speed
|
||||
</div>
|
||||
|
||||
<div style="display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;">
|
||||
<button id="play-pause-btn" style="
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #4caf50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
min-width: 140px;
|
||||
">▶ Play <span class="key-icon space">SPACE</span></button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div style="display: flex; gap: 5px; align-items: center;">
|
||||
<span style="font-size: 14px; color: #666;">Speed:</span>
|
||||
<button id="speed-025" class="speed-btn" data-speed="0.25" style="
|
||||
@@ -130,6 +189,7 @@ import html from '../utils/html.js';
|
||||
cursor: pointer;
|
||||
">1x</button>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
|
||||
<div style="margin: 20px 0; display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;">
|
||||
@@ -141,7 +201,7 @@ import html from '../utils/html.js';
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
">⏪ Skip Back 5%</button>
|
||||
">⏪ Skip Back 0.1s <span class="key-icon"><i class="fas fa-arrow-left"></i></span></button>
|
||||
|
||||
<button id="skip-forward-btn" style="
|
||||
padding: 8px 16px;
|
||||
@@ -151,9 +211,10 @@ import html from '../utils/html.js';
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
">Skip Forward 5% ⏩</button>
|
||||
">Skip Forward 0.1s <span class="key-icon"><i class="fas fa-arrow-right"></i></span> ⏩</button>
|
||||
</div>
|
||||
|
||||
<!--
|
||||
<div id="current-time-display" style="
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
@@ -167,21 +228,32 @@ import html from '../utils/html.js';
|
||||
<span>Duration: <span id="duration-display">0:00</span></span>
|
||||
<span>Progress: <span id="progress-display">0%</span></span>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div style="font-size: 11px; color: #888; text-align: center; margin-bottom: 15px; line-height: 1.4;">
|
||||
<strong>Keyboard shortcuts:</strong> Spacebar = Play/Pause | ← → = Skip Back/Forward | Enter = Mark Lift Point
|
||||
</div>
|
||||
|
||||
<div style="margin: 20px 0; text-align: center;">
|
||||
<button id="mark-lift-point-btn" style="
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #ff9800;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
">Mark This as Lift Point</button>
|
||||
<div style="margin: 20px 0;">
|
||||
<!-- Progress Bar -->
|
||||
<div style="margin-bottom: 20px;">
|
||||
<div style="display: flex; justify-content: space-between; font-size: 12px; color: #666; margin-bottom: 5px;">
|
||||
<span id="start-time">0:00</span>
|
||||
<span id="current-time">0:00</span>
|
||||
<span id="end-time">0:00</span>
|
||||
</div>
|
||||
<div style="width: 100%; background-color: #ddd; border-radius: 10px; height: 8px; position: relative;">
|
||||
<div id="progress-bar" style="background-color: #007cba; height: 100%; border-radius: 10px; width: 0%; transition: width 0.1s ease;"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div style="text-align: center;">
|
||||
<button id="mark-lift-point-btn" style="
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #ff9800;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
">Mark This as Lift Point <span class="key-icon">ENTER</span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="marked-point-display" style="
|
||||
@@ -220,9 +292,11 @@ import html from '../utils/html.js';
|
||||
setupMarkingEvents(recordingData, audioBlob) {
|
||||
const audio = document.getElementById('playback-audio');
|
||||
const playPauseBtn = document.getElementById('play-pause-btn');
|
||||
const currentTimeDisplay = document.getElementById('current-time-display');
|
||||
const durationDisplay = document.getElementById('duration-display');
|
||||
const progressDisplay = document.getElementById('progress-display');
|
||||
// Progress bar elements
|
||||
const startTimeDisplay = document.getElementById('start-time');
|
||||
const currentTimeDisplay = document.getElementById('current-time');
|
||||
const endTimeDisplay = document.getElementById('end-time');
|
||||
const progressBar = document.getElementById('progress-bar');
|
||||
const skipBackBtn = document.getElementById('skip-back-btn');
|
||||
const skipForwardBtn = document.getElementById('skip-forward-btn');
|
||||
const markLiftPointBtn = document.getElementById('mark-lift-point-btn');
|
||||
@@ -250,15 +324,16 @@ import html from '../utils/html.js';
|
||||
// Update display function
|
||||
const updateDisplay = () => {
|
||||
const currentTime = audio.currentTime;
|
||||
const progress = audioDuration > 0 ? (currentTime / audioDuration * 100).toFixed(1) : 0;
|
||||
const progress = audioDuration > 0 ? (currentTime / audioDuration * 100) : 0;
|
||||
|
||||
currentTimeDisplay.textContent = `Current position: ${formatPreciseTime(currentTime)}`;
|
||||
progressDisplay.textContent = `${progress}%`;
|
||||
currentTimeDisplay.textContent = formatTime(currentTime);
|
||||
progressBar.style.width = `${progress}%`;
|
||||
};
|
||||
|
||||
// Update submit button state
|
||||
let isPlaybackConfirmed = false;
|
||||
const updateSubmitButton = () => {
|
||||
if (liftPointTime !== null) {
|
||||
if (liftPointTime !== null && isPlaybackConfirmed) {
|
||||
submitButton.disabled = false;
|
||||
submitButton.style.opacity = '1';
|
||||
submitButton.style.cursor = 'pointer';
|
||||
@@ -269,6 +344,58 @@ import html from '../utils/html.js';
|
||||
}
|
||||
};
|
||||
|
||||
// Function to play back from marked point for confirmation
|
||||
const playbackFromMarkedPoint = () => {
|
||||
if (liftPointTime === null) return;
|
||||
|
||||
// Store current position to restore later
|
||||
const originalPosition = audio.currentTime;
|
||||
|
||||
// Show confirmation message
|
||||
markedPointDisplay.innerHTML = `
|
||||
<div style="text-align: center; padding: 10px; background: #fff3cd; border: 1px solid #ffd93d; border-radius: 5px; margin: 10px 0;">
|
||||
<p style="margin: 5px 0; color: #856404;">🔊 Playing back from marked point...</p>
|
||||
<p style="margin: 5px 0; font-size: 14px; color: #856404;">If this sounds right, press Submit. Otherwise, choose a new mark point.</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Set audio to marked point and play
|
||||
audio.currentTime = liftPointTime;
|
||||
updateDisplay();
|
||||
|
||||
// Play for a few seconds (3 seconds or until end)
|
||||
const playbackDuration = 3;
|
||||
const endTime = Math.min(liftPointTime + playbackDuration, audioDuration);
|
||||
|
||||
audio.play();
|
||||
|
||||
// Set up event to stop playback after duration and restore position
|
||||
const onTimeUpdate = () => {
|
||||
if (audio.currentTime >= endTime) {
|
||||
audio.pause();
|
||||
audio.removeEventListener('timeupdate', onTimeUpdate);
|
||||
|
||||
// Restore original position
|
||||
audio.currentTime = originalPosition;
|
||||
updateDisplay();
|
||||
|
||||
// Update display to show confirmation
|
||||
markedPointDisplay.innerHTML = `
|
||||
<div style="text-align: center; padding: 10px; background: #d1edff; border: 1px solid #3498db; border-radius: 5px; margin: 10px 0;">
|
||||
<p style="margin: 5px 0; color: #2c3e50;">✓ Lift point marked at: ${formatPreciseTime(liftPointTime)}</p>
|
||||
<p style="margin: 5px 0; font-size: 14px; color: #2c3e50;">Preview completed. Press Submit to confirm, <span class="key-icon">ENTER</span> to play again, or mark a new point.</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Enable submit button
|
||||
isPlaybackConfirmed = true;
|
||||
updateSubmitButton();
|
||||
}
|
||||
};
|
||||
|
||||
audio.addEventListener('timeupdate', onTimeUpdate);
|
||||
};
|
||||
|
||||
// Check if we have a stored duration from the recording
|
||||
const storedDuration = recordingData.audio_duration;
|
||||
|
||||
@@ -282,7 +409,8 @@ import html from '../utils/html.js';
|
||||
// Use stored duration if available and valid
|
||||
if (storedDuration && isFinite(storedDuration) && storedDuration > 0) {
|
||||
audioDuration = storedDuration;
|
||||
durationDisplay.textContent = formatTime(audioDuration);
|
||||
startTimeDisplay.textContent = '0:00';
|
||||
endTimeDisplay.textContent = formatTime(audioDuration);
|
||||
updateDisplay();
|
||||
updateSubmitButton();
|
||||
console.log('Using stored duration:', audioDuration);
|
||||
@@ -292,7 +420,8 @@ import html from '../utils/html.js';
|
||||
// Otherwise try to get duration from audio element
|
||||
if (audio.duration && isFinite(audio.duration) && audio.duration > 0) {
|
||||
audioDuration = audio.duration;
|
||||
durationDisplay.textContent = formatTime(audioDuration);
|
||||
startTimeDisplay.textContent = '0:00';
|
||||
endTimeDisplay.textContent = formatTime(audioDuration);
|
||||
updateDisplay();
|
||||
updateSubmitButton();
|
||||
console.log('Audio controls setup complete, duration:', audioDuration);
|
||||
@@ -305,7 +434,8 @@ import html from '../utils/html.js';
|
||||
// Fallback: estimate duration based on blob size (rough approximation)
|
||||
const estimatedDuration = Math.max(1, audioBlob.size / 8000); // ~8KB per second rough estimate
|
||||
audioDuration = estimatedDuration;
|
||||
durationDisplay.textContent = formatTime(audioDuration) + ' (est)';
|
||||
startTimeDisplay.textContent = '0:00';
|
||||
endTimeDisplay.textContent = formatTime(audioDuration);
|
||||
updateDisplay();
|
||||
updateSubmitButton();
|
||||
console.log('Using estimated duration:', audioDuration);
|
||||
@@ -336,7 +466,8 @@ import html from '../utils/html.js';
|
||||
// Force load the audio
|
||||
audio.load();
|
||||
|
||||
// Speed control buttons
|
||||
// Speed control buttons (commented out - using fixed 0.5x speed)
|
||||
/*
|
||||
const speedButtons = document.querySelectorAll('.speed-btn');
|
||||
speedButtons.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
@@ -354,16 +485,17 @@ import html from '../utils/html.js';
|
||||
console.log('Playback speed set to:', speed);
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
// Skip buttons (5% of total duration)
|
||||
// Skip buttons (0.1 second increments)
|
||||
skipBackBtn.addEventListener('click', () => {
|
||||
const skipAmount = audioDuration * 0.05; // 5% of duration
|
||||
const skipAmount = 0.1; // 0.1 seconds
|
||||
audio.currentTime = Math.max(0, audio.currentTime - skipAmount);
|
||||
updateDisplay();
|
||||
});
|
||||
|
||||
skipForwardBtn.addEventListener('click', () => {
|
||||
const skipAmount = audioDuration * 0.05; // 5% of duration
|
||||
const skipAmount = 0.1; // 0.1 seconds
|
||||
audio.currentTime = Math.min(audioDuration, audio.currentTime + skipAmount);
|
||||
updateDisplay();
|
||||
});
|
||||
@@ -380,14 +512,14 @@ import html from '../utils/html.js';
|
||||
// Audio play event
|
||||
audio.addEventListener('play', () => {
|
||||
isPlaying = true;
|
||||
playPauseBtn.textContent = '⏸ Pause';
|
||||
playPauseBtn.innerHTML = '⏸ Pause <span class="key-icon space">SPACE</span>';
|
||||
playPauseBtn.style.backgroundColor = '#f44336';
|
||||
});
|
||||
|
||||
// Audio pause event
|
||||
audio.addEventListener('pause', () => {
|
||||
isPlaying = false;
|
||||
playPauseBtn.textContent = '▶ Play';
|
||||
playPauseBtn.innerHTML = '▶ Play <span class="key-icon space">SPACE</span>';
|
||||
playPauseBtn.style.backgroundColor = '#4caf50';
|
||||
});
|
||||
|
||||
@@ -414,16 +546,16 @@ import html from '../utils/html.js';
|
||||
|
||||
case 'ArrowLeft':
|
||||
e.preventDefault();
|
||||
// Skip back with left arrow
|
||||
const skipBackAmount = audioDuration * 0.05;
|
||||
// Skip back with left arrow (0.1 seconds)
|
||||
const skipBackAmount = 0.1;
|
||||
audio.currentTime = Math.max(0, audio.currentTime - skipBackAmount);
|
||||
updateDisplay();
|
||||
break;
|
||||
|
||||
case 'ArrowRight':
|
||||
e.preventDefault();
|
||||
// Skip forward with right arrow
|
||||
const skipForwardAmount = audioDuration * 0.05;
|
||||
// Skip forward with right arrow (0.1 seconds)
|
||||
const skipForwardAmount = 0.1;
|
||||
audio.currentTime = Math.min(audioDuration, audio.currentTime + skipForwardAmount);
|
||||
updateDisplay();
|
||||
break;
|
||||
@@ -432,8 +564,9 @@ import html from '../utils/html.js';
|
||||
e.preventDefault();
|
||||
// Mark lift point with Enter
|
||||
liftPointTime = audio.currentTime;
|
||||
markedPointDisplay.textContent = `✓ Lift point marked at: ${formatPreciseTime(liftPointTime)}`;
|
||||
isPlaybackConfirmed = false;
|
||||
updateSubmitButton();
|
||||
playbackFromMarkedPoint();
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -441,8 +574,9 @@ import html from '../utils/html.js';
|
||||
// Mark lift point button
|
||||
markLiftPointBtn.addEventListener('click', () => {
|
||||
liftPointTime = audio.currentTime;
|
||||
markedPointDisplay.textContent = `✓ Lift point marked at: ${formatPreciseTime(liftPointTime)}`;
|
||||
isPlaybackConfirmed = false;
|
||||
updateSubmitButton();
|
||||
playbackFromMarkedPoint();
|
||||
});
|
||||
|
||||
// Submit button
|
||||
|
||||
@@ -90,63 +90,6 @@ import { ParameterType } from 'jspsych';
|
||||
margin: 5px;
|
||||
">Accept Recording</button>
|
||||
</div>
|
||||
<div id="questions-section" style="display: none; margin: 20px; text-align: left; max-width: 600px; margin-left: auto; margin-right: auto;">
|
||||
<audio id="final-playback-audio" controls style="display: block; margin: 10px auto;"></audio>
|
||||
<h3 style="text-align: center; margin-bottom: 20px;">Please answer the following questions:</h3>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="spelling-input" style="display: block; margin-bottom: 5px; font-weight: bold;">How would you spell what you have just recorded?</label>
|
||||
<input type="text" id="spelling-input" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;" required>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="language-select" style="display: block; margin-bottom: 5px; font-weight: bold;">What language is it in?</label>
|
||||
<select id="language-select" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;" required>
|
||||
<option value="">Select a language...</option>
|
||||
<option value="English">English</option>
|
||||
<option value="Spanish">Spanish</option>
|
||||
<option value="French">French</option>
|
||||
<option value="German">German</option>
|
||||
<option value="Italian">Italian</option>
|
||||
<option value="Portuguese">Portuguese</option>
|
||||
<option value="Russian">Russian</option>
|
||||
<option value="Chinese">Chinese</option>
|
||||
<option value="Japanese">Japanese</option>
|
||||
<option value="Korean">Korean</option>
|
||||
<option value="Arabic">Arabic</option>
|
||||
<option value="Hindi">Hindi</option>
|
||||
<option value="Other">Other</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="other-language-section" style="margin-bottom: 15px; display: none;">
|
||||
<label for="other-language-input" style="display: block; margin-bottom: 5px; font-weight: bold;">Please specify the language:</label>
|
||||
<input type="text" id="other-language-input" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div id="translation-section" style="margin-bottom: 15px; display: none;">
|
||||
<label for="translation-input" style="display: block; margin-bottom: 5px; font-weight: bold;">How would you translate it to English?</label>
|
||||
<input type="text" id="translation-input" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;">
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label for="meaning-input" style="display: block; margin-bottom: 5px; font-weight: bold;">Does it have a meaning? If so, write it here in English:</label>
|
||||
<input type="text" id="meaning-input" style="width: 100%; padding: 8px; border: 1px solid #ddd; border-radius: 4px;" placeholder="Write the meaning or 'No meaning' if it doesn't have one">
|
||||
</div>
|
||||
|
||||
<button id="submit-answers-button" style="
|
||||
padding: 12px 24px;
|
||||
font-size: 16px;
|
||||
background-color: #007cba;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
margin: 20px auto;
|
||||
opacity: 0.5;
|
||||
" disabled>Submit Answers</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -295,84 +238,10 @@ import { ParameterType } from 'jspsych';
|
||||
});
|
||||
|
||||
acceptButton.addEventListener("click", () => {
|
||||
document.getElementById("recording-controls").style.display = "none";
|
||||
document.getElementById("questions-section").style.display = "block";
|
||||
|
||||
const finalAudio = document.getElementById("final-playback-audio");
|
||||
const originalAudio = document.getElementById("playback-audio");
|
||||
finalAudio.src = originalAudio.src;
|
||||
|
||||
document.getElementById("recording-status").textContent = "Please answer all questions to continue:";
|
||||
|
||||
this.setupQuestionEvents(trial);
|
||||
this.endTrial(trial);
|
||||
});
|
||||
}
|
||||
|
||||
setupQuestionEvents(trial) {
|
||||
const spellingInput = document.getElementById("spelling-input");
|
||||
const languageSelect = document.getElementById("language-select");
|
||||
const otherLanguageSection = document.getElementById("other-language-section");
|
||||
const otherLanguageInput = document.getElementById("other-language-input");
|
||||
const translationSection = document.getElementById("translation-section");
|
||||
const translationInput = document.getElementById("translation-input");
|
||||
const meaningInput = document.getElementById("meaning-input");
|
||||
const submitButton = document.getElementById("submit-answers-button");
|
||||
|
||||
const validateForm = () => {
|
||||
const spelling = spellingInput.value.trim();
|
||||
const language = languageSelect.value;
|
||||
const otherLanguage = otherLanguageInput.value.trim();
|
||||
const meaning = meaningInput.value.trim();
|
||||
const needsOtherLanguage = language === "Other";
|
||||
const needsTranslation = language && language !== "English";
|
||||
const translation = translationInput.value.trim();
|
||||
|
||||
const isValid = spelling && language && meaning &&
|
||||
(!needsOtherLanguage || otherLanguage) &&
|
||||
(!needsTranslation || translation);
|
||||
|
||||
submitButton.disabled = !isValid;
|
||||
submitButton.style.opacity = isValid ? "1" : "0.5";
|
||||
submitButton.style.cursor = isValid ? "pointer" : "not-allowed";
|
||||
};
|
||||
|
||||
languageSelect.addEventListener("change", () => {
|
||||
const selectedLanguage = languageSelect.value;
|
||||
const isEnglish = selectedLanguage === "English";
|
||||
const isOther = selectedLanguage === "Other";
|
||||
|
||||
translationSection.style.display = isEnglish ? "none" : "block";
|
||||
otherLanguageSection.style.display = isOther ? "block" : "none";
|
||||
|
||||
if (isEnglish) {
|
||||
translationInput.value = "";
|
||||
}
|
||||
if (!isOther) {
|
||||
otherLanguageInput.value = "";
|
||||
}
|
||||
validateForm();
|
||||
});
|
||||
|
||||
[spellingInput, languageSelect, otherLanguageInput, translationInput, meaningInput].forEach(element => {
|
||||
element.addEventListener("input", validateForm);
|
||||
element.addEventListener("change", validateForm);
|
||||
});
|
||||
|
||||
submitButton.addEventListener("click", () => {
|
||||
if (!submitButton.disabled) {
|
||||
const finalLanguage = languageSelect.value === "Other" ?
|
||||
otherLanguageInput.value.trim() :
|
||||
languageSelect.value;
|
||||
|
||||
this.endTrialWithAnswers(trial, {
|
||||
spelling: spellingInput.value.trim(),
|
||||
language: finalLanguage,
|
||||
translation: translationInput.value.trim() || null,
|
||||
meaning: meaningInput.value.trim()
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
startRecording() {
|
||||
try {
|
||||
@@ -396,7 +265,7 @@ import { ParameterType } from 'jspsych';
|
||||
}
|
||||
}
|
||||
|
||||
endTrialWithAnswers(trial, answers) {
|
||||
endTrial(trial) {
|
||||
this.recorder.removeEventListener("dataavailable", this.data_available_handler);
|
||||
this.recorder.removeEventListener("start", this.start_event_handler);
|
||||
this.recorder.removeEventListener("stop", this.stop_event_handler);
|
||||
@@ -412,10 +281,6 @@ import { ParameterType } from 'jspsych';
|
||||
stimulus: trial.stimulus,
|
||||
response: response,
|
||||
estimated_stimulus_onset: this.recorder_start_time ? Math.round(this.stimulus_start_time - this.recorder_start_time) : null,
|
||||
spelling: answers.spelling,
|
||||
language: answers.language,
|
||||
translation: answers.translation,
|
||||
meaning: answers.meaning,
|
||||
audio_duration: this.audio_duration
|
||||
};
|
||||
|
||||
@@ -430,47 +295,11 @@ import { ParameterType } from 'jspsych';
|
||||
stimulus: trial.stimulus,
|
||||
response: null,
|
||||
estimated_stimulus_onset: null,
|
||||
spelling: answers.spelling,
|
||||
language: answers.language,
|
||||
translation: answers.translation,
|
||||
meaning: answers.meaning,
|
||||
audio_duration: this.audio_duration
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
endTrial(display_element, trial) {
|
||||
this.recorder.removeEventListener("dataavailable", this.data_available_handler);
|
||||
this.recorder.removeEventListener("start", this.start_event_handler);
|
||||
this.recorder.removeEventListener("stop", this.stop_event_handler);
|
||||
|
||||
this.jsPsych.pluginAPI.clearAllTimeouts();
|
||||
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener("load", () => {
|
||||
const response = reader.result.split(",")[1];
|
||||
|
||||
let trial_data = {
|
||||
rt: this.stimulus_start_time ? Date.now() - this.stimulus_start_time : null,
|
||||
stimulus: trial.stimulus,
|
||||
response: response,
|
||||
estimated_stimulus_onset: this.recorder_start_time ? Math.round(this.stimulus_start_time - this.recorder_start_time) : null,
|
||||
};
|
||||
|
||||
this.jsPsych.finishTrial(trial_data);
|
||||
});
|
||||
|
||||
if (this.current_recording) {
|
||||
reader.readAsDataURL(this.current_recording);
|
||||
} else {
|
||||
this.jsPsych.finishTrial({
|
||||
rt: null,
|
||||
stimulus: trial.stimulus,
|
||||
response: null,
|
||||
estimated_stimulus_onset: null,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default jsPsychRecordCall;
|
||||
@@ -12,7 +12,7 @@ export const textStimuli = {
|
||||
<p class = "mt-2">Lifting calls are phrases, words or sounds that people say or make when they want to lift a heavy object together with someone else. To build this online collection of lifting calls, we will ask you to record one or more lifting calls that you know. We will also ask you to provide us with a written version of the recorded calls and information about the region and language that the calls are used in.</p>
|
||||
<p class = "mt-2"> We process this data in accordance with the Austrian Forschungsorganisationsgesetz – FOG and Consent under Art 6 (1) (a) GDPR, public interest (e) and (f) legitimate interest. You have the right to withdraw your consent at any time. To do so and to request the deletion of your data, please contact CEU’s data protection officer at privacy@ceu.edu. </p>
|
||||
<p class = "mt-2"> More information about your rights can be found at the controller’s website https://www.ceu.edu/privacy. If you have any questions regarding data protection, please contact CEU's data protection officer at privacy@ceu.edu.
|
||||
In case you are accessing this online form through via Prolific, Prolific acts as a data processor and has access to personal data. You can download Prolific’s full privacy notices here: https://prolific.notion.site/Privacy-and-Legal-at-Prolific-395a0b3414cd4d84a2557566256e3d58
|
||||
In case you are accessing this online form through Prolific, Prolific acts as a data processor and has access to personal data. You can download Prolific’s full privacy notices here: https://prolific.notion.site/Privacy-and-Legal-at-Prolific-395a0b3414cd4d84a2557566256e3d58
|
||||
<p class = "mt-2"> By checking the “I agree” box, you agree to participate in this study. You also confirm you are 18 years or older. To agree: Check the “I agree” box below and then click next to participate in the study. If you do not wish to participate in this study, simply close out of this browser window.</p>
|
||||
</div>
|
||||
<div class="mx-auto my-6">
|
||||
|
||||
Reference in New Issue
Block a user