From 52f59be008f3f7e71b70715212b070bce06f34bc Mon Sep 17 00:00:00 2001 From: vsporeddy Date: Thu, 4 Apr 2024 01:18:30 -0700 Subject: [PATCH] Update script.js --- script.js | 268 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 148 insertions(+), 120 deletions(-) diff --git a/script.js b/script.js index 4ff7f0d..ec633cf 100644 --- a/script.js +++ b/script.js @@ -1,12 +1,13 @@ const nameInput = document.getElementById('nameInput'); const submitButton = document.getElementById('submitButton'); const resultDiv = document.getElementById('result'); +const imageDiv = document.getElementById('image-result'); const bestMatchDiv = document.getElementById('bestMatch'); const timedModeButton = document.getElementById('timedModeButton'); const challengeModeButton = document.getElementById('challengeModeButton'); const timerDisplay = document.getElementById('timer'); const score = document.getElementById('score'); -const timeReward = 3; +const timeReward = 5; const gameDuration = 60; // Time in seconds for timed mode const scoreLimit = 100; // Score limit for challenge mode const timeDisplay = document.getElementById('timeDisplay'); @@ -20,11 +21,9 @@ const genderErrorMessage = const correctMessage = 'You named a woman!'; const fictionalMessage = 'Wikipedia seems to have this person categorized as fictional. If you think this is incorrect, please submit feedback!'; -const repeatMessage = 'You already said '; -const correctRepeatMessage = 'You already got a point for '; let timeRemaining = gameDuration; -let timerInterval; // To store the interval reference +let timerInterval; let currentScore = 0; let isTimedMode = true; // Default to timed mode initially let stopwatchInterval; @@ -34,9 +33,7 @@ const correctNames = new Set(); const incorrectNames = new Set(); const submittedWikidataIds = new Set(); -const womanGenderIds = - new Set(['Q6581072', 'Q1052281', 'Q4676163', 'Q575', 'Q43445', 'Q10675']); -const transManId = 'Q2449503'; +const submissions = {}; window.addEventListener('DOMContentLoaded', initGradient); // After page loads window.addEventListener('resize', updateGradient); // Handle window resizing @@ -75,78 +72,85 @@ function showResultsPopup() { } function copyResults() { - const resultsText = `I named ${correctNames.size} women in a minute!\r\n||${ + const resultsText = `I named ${correctNames.size} women!\r\n${ Array.from(correctNames) .join( - '\r\n')}||\r\n\r\nHow many can you name?\r\nhttps://vsporeddy.github.io/name-a-woman/`; - + '\r\n')}\r\n\r\nHow many can you name?\r\nhttps://nameawoman.us`; navigator.clipboard.writeText(resultsText) .then(() => alert('Results copied!')) .catch(() => alert('Could not copy results')); } -function formatWikiPageTitle(name) { - const parts = name.split(' '); - return parts.map(part => part[0] + part.slice(1)).join('_'); - // const formattedName = name.replace(/[\.\,\-']/g, ''); // Remove '.', ',', - // '-' - return formattedName; -} - -function formatName(name) { - const parts = name.split(' '); - return parts.map(part => part[0].toUpperCase() + part.slice(1)).join(' '); -} - async function handleNameSubmission() { const name = nameInput.value; nameInput.value = ''; resultDiv.innerHTML = 'Searching...'; - - if (submittedNames.has(name)) { - resultDiv.textContent = repeatMessage + formatName(name) + '!'; - return; + // Remove any existing image + const imageElement = imageDiv.querySelector('img'); + if (imageElement) { + imageElement.remove(); } - submittedNames.add(name); + await checkSubmission(name); +} - let firstMatch = await getEntityByName(name); - if (firstMatch.isHuman && firstMatch.isFemale && firstMatch.label && firstMatch.wikiPage) { - handleValidSubmission(name, firstMatch.isDuplicate); - displayBestMatch(firstMatch.label, firstMatch.wikiPage); - return; - } - let searchMatch = await searchByName(name); - if (searchMatch.isHuman && searchMatch.isFemale && searchMatch.label && searchMatch.wikiPage) { - handleValidSubmission(name, searchMatch.isDuplicate); - displayBestMatch(searchMatch.label, searchMatch.wikiPage); +async function checkSubmission(name) { + if (submissions[name]) { + handleRepeatSubmission(submissions[name], name); + displayBestMatch(submissions[name]); return; } - if (firstMatch.isHuman && !firstMatch.isFemale && firstMatch.label && firstMatch.wikiPage) { - handleNonFemaleSubmission(name); - displayBestMatch(firstMatch.label, firstMatch.wikiPage); - return; - } - if (!firstMatch.isHuman && firstMatch.isFemale && firstMatch.label && firstMatch.wikiPage) { - handleFictionalSubmission(name); - displayBestMatch(firstMatch.label, firstMatch.wikiPage); + + const match = await getBestMatch(name); + submissions[name] = match; + displayBestMatch(match); + + if (match.isDuplicate) { + handleRepeatSubmission(match, name); return; } - if (searchMatch.isHuman && !searchMatch.isFemale && searchMatch.label && searchMatch.wikiPage) { - handleNonFemaleSubmission(name); - displayBestMatch(searchMatch.label, searchMatch.wikiPage); + if (match.success) { + resultDiv.innerHTML = + `${correctMessage}`; + correctNames.add(match.label); + incrementScore(); + + if (match.imageUrl) { + // Create image element if it doesn't exist yet: + if (!imageDiv.querySelector('img')) { + const imageElement = document.createElement('img'); + imageElement.id = 'womanImage'; + imageElement.alt = match.label + ' from Wikipedia'; + imageDiv.appendChild(imageElement); + } + + // Update image attributes + const imageElement = imageDiv.querySelector('img'); + imageElement.src = match.imageUrl; + } return; } - if (!searchMatch.isHuman && searchMatch.isFemale && searchMatch.label && searchMatch.wikiPage) { - handleFictionalSubmission(name); - displayBestMatch(searchMatch.label, searchMatch.wikiPage); - return; + if (match.displayable) { + incorrectNames.add(match.label); + if (match.isFemale) { + resultDiv.innerHTML = + `${fictionalMessage}`; + return; + } + if (match.isHuman) { + resultDiv.innerHTML = + `${genderErrorMessage}`; + return; + } } - - displayBestMatch(null, null); - handleInvalidSubmission(name); + incorrectNames.add(name); + resultDiv.innerHTML = `${errorMessage}`; } function containsFemaleAttribute(claims) { + const womanGenderIds = + new Set(['Q6581072', 'Q1052281', 'Q4676163', 'Q575', 'Q43445', 'Q10675']); + const transManId = 'Q2449503'; + let isFemale = false; if (claims && claims.P21) { // Ensure the 'P21' (gender) property exists // Check if any gender IDs match recognized female-identifying IDs @@ -176,31 +180,40 @@ function containsHumanAttribute(claims) { return false; } -async function searchByName(name) { - const searchQueryUrl = - `https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${ - name}&language=en&limit=2&format=json&origin=*`; +async function getBestMatch(name) { + let greedyMatch = await getEntityByName(name); + if (greedyMatch.success) { + return greedyMatch; + } + const searchResults = await searchEntitiesByName(name); + let matches = []; - let data = await fetch(searchQueryUrl).then(response => response.json()); - const results = data.search; - resultsArr = []; - for (const key in results) { - let result = await getEntityById(results[key].id); - if (result.isHuman && result.isFemale) { - return result; + for (const key in searchResults) { + let match = await getEntityById(searchResults[key].id); + + if (match.success) { + return match; } - resultsArr.push(result) + if (match.displayable) { + matches.push(match); + } + } + if (greedyMatch.displayable) { + return greedyMatch; } - if (resultsArr.length === 0) { - return { - isHuman: false, - isFemale: false, - isDuplicate: false, - label: null, - wikiPage: null - }; + if (matches.length > 0) { + return matches[0]; } - return resultsArr[0]; + return getEmptyMatch(); +} + +async function searchEntitiesByName(name) { + const searchLimit = 2; + const searchQueryUrl = + `https://www.wikidata.org/w/api.php?action=wbsearchentities&search=${ + name}&language=en&limit=${searchLimit}&format=json&origin=*`; + let data = await fetch(searchQueryUrl).then(response => response.json()); + return data.search; } function getEntityById(id) { @@ -217,6 +230,30 @@ function getEntityByName(name) { return fetchWikidataResponse(url); } +function getEmptyMatch() { + return { + success: false, + displayable: false, + isHuman: false, + isFemale: false, + isDuplicate: false, + label: null, + wikiPage: null + }; +} + +function getImageUrl(claims) { + let imageUrl = null; + if (claims.P18) { + const imageClaim = claims.P18[0].mainsnak.datavalue.value; + const imageFilename = + imageClaim.replace(/\s/g, '_'); // Replace spaces for URL safety + imageUrl = 'https://commons.wikimedia.org/w/thumb.php?width=200&f=' + + imageFilename; + } + return imageUrl; +} + function fetchWikidataResponse(url) { return fetch(url) .then(response => response.json()) @@ -224,32 +261,33 @@ function fetchWikidataResponse(url) { const entities = data.entities; entityId = Object.keys(entities)[0]; const claims = entities[entityId].claims; - let isDuplicate = submittedWikidataIds.has(entityId); - let isFemale = containsFemaleAttribute(claims); - let isHuman = containsHumanAttribute(claims); - + if (!claims) { + return getEmptyMatch(); + } + const isDuplicate = submittedWikidataIds.has(entityId); + const isFemale = containsFemaleAttribute(claims); + const isHuman = containsHumanAttribute(claims); + const imageUrl = getImageUrl(claims); const enwikiSitelink = entities[entityId].sitelinks.enwiki; - const wikipediaUrl = enwikiSitelink ? enwikiSitelink.url : null; + const wikiPage = enwikiSitelink ? enwikiSitelink.url : null; const label = entities[entityId].labels?.en?.value; submittedWikidataIds.add(entityId); return { + success: (isHuman && isFemale && label && wikiPage) ? true : false, + displayable: ((isHuman || isFemale) && label && wikiPage) ? true : + false, isHuman: isHuman, isFemale: isFemale, isDuplicate: isDuplicate, label: label, - wikiPage: wikipediaUrl + wikiPage: wikiPage, + imageUrl: imageUrl }; }) .catch(error => { console.log(error); - return { - isHuman: false, - isFemale: false, - isDuplicate: false, - label: null, - wikiPage: null - }; + return getEmptyMatch(); }); } @@ -294,7 +332,7 @@ function startStopwatch() { const elapsedTime = Date.now() - startTime; const formattedTime = formatTime(elapsedTime); timerDisplay.textContent = formattedTime; - }, 1000); // Update every 1000 milliseconds (1 second) + }, 1000); } function formatTime(milliseconds) { @@ -315,37 +353,22 @@ function endGame() { showResultsPopup(); } -function handleInvalidSubmission(name) { - resultDiv.innerHTML = `${errorMessage}`; - incorrectNames.add(formatName(name)); -} - -function handleNonFemaleSubmission(name) { - resultDiv.innerHTML = - `${genderErrorMessage}`; - incorrectNames.add(formatName(name)); -} - -function handleFictionalSubmission(name) { - resultDiv.innerHTML = - `${fictionalMessage}`; - incorrectNames.add(formatName(name)); -} - -function handleValidSubmission(name, isDuplicate) { - if (isDuplicate) { - resultDiv.textContent = correctRepeatMessage + formatName(name) + '!'; - return; +function handleRepeatSubmission(match, name) { + if (match.success) { + resultDiv.innerHTML = `You already got a point for ${match.label}!` + } else if (match.displayable) { + resultDiv.innerHTML = + `You already said ${match.label}!` + } else { + resultDiv.innerHTML = `You already said ${name}!` } - resultDiv.innerHTML = `${correctMessage}`; - correctNames.add(formatName(name)); - incrementScore(); } -function displayBestMatch(label, url) { - if (label && url) { - bestMatchDiv.innerHTML = - `The best match we found was ${label}.`; +function displayBestMatch(match) { + if (match.label && match.wikiPage) { + bestMatchDiv.innerHTML = `The best match we found was ${match.label}.`; } else { bestMatchDiv.innerHTML = ``; } @@ -375,8 +398,13 @@ function closeIntroPopup() { function displayIntroPopup() { document.getElementById('introPopup').style.display = 'block'; document.getElementById('overlay').style.display = 'block'; - var availableHeight = window.innerHeight * 0.8; // 80% of screen height + let availableHeight = window.innerHeight * 0.8; // 80% of screen height introPopup.style.maxHeight = availableHeight + 'px'; + + const imageElement = imageDiv.querySelector('img'); + if (imageElement) { + imageElement.remove(); + } } function updateGradient() {