Skip to content
Draft
6 changes: 2 additions & 4 deletions www/editgame
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,6 @@ if ($errMsg) {
scriptSrc('/gridform.js'),
false);

initStarControls();
imageUploadScripts();
?>

Expand Down Expand Up @@ -1037,7 +1036,7 @@ function saveReviewPopup()
rowDisp = "";
}
}
function setExtRevRating(rating)
function setExtRevRating(gameId, rating)
{
document.getElementById("extrevRating").value = rating;
}
Expand Down Expand Up @@ -1737,8 +1736,7 @@ function onComboSelectReviewSite(val)
<input id="extrevSourceUrl" type=text size=80><br><br>

<b>Rating:</b> <?php
echo showStarCtl("extrevStarCtl", 0,
"setExtRevRating", "null");
echo showStarCtl($id, "extrevStarCtl", 0, "setExtRevRating");
?> <br>
<input type=hidden name=extrevRating id=extrevRating value=0>
<span class=details>If the site uses a different rating
Expand Down
46 changes: 35 additions & 11 deletions www/ifdb.css
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ form.sortingControls {
margin: 1em 0 1em 0;
}

/* A box that has the sorting controls and other search result controls */
.searchControls {
display: flex;
align-items: baseline;
column-gap: 5em;
}

/*
The default style for cells within tables. We use the same style
here as in the main page body.
Expand Down Expand Up @@ -564,6 +571,21 @@ td.coverart {
white-space: nowrap;
}

.haveYouPlayed_playedSection {
margin: 1.25ex 0 0.75ex 0;
}

.searchRatingBox {
width: 20rem !important; /* Overrides the 'width: 100%' in '.haveYouPlayed' */
margin-left: auto !important;
margin-right: 100px !important;
}

.searchRatingBox .haveYouPlayed_title,
.searchRatingBox .howLong {
display: none;
}

/*
We use the "authorProfileLink" style for hyperlinks to author profiles,
as shown in the author section of a game listing. We show these without
Expand Down Expand Up @@ -634,27 +656,25 @@ the page.
}

/*
The "gamerightbar" table is the box on a game's listing page,
The "haveYouPlayed" class is the box on a game's listing page,
underneath the Download box, where we display quick rating
input links ("Have you played this game?").
*/
table.gamerightbar {
padding: 0 0 0 0;
margin: 0 0 0 0;
.haveYouPlayed {
padding: 3px;
margin: 0;
background: #F0F0F0;
border: thin dotted #e0e0e0;
width: 100%;
font-size: 80%;
height: fit-content;
}
table.gamerightbar h3 {
.haveYouPlayed h3 {
font: 100%/140% Verdana, Arial, Helvetica, Sans-Serif;
font-weight: bold;
color: #000080;
margin: 0 0 0.5em 0;
}
table.gamerightbar td {
padding: 0 0 0.5em 0;
}
}

/*
Expand All @@ -671,6 +691,10 @@ on the viewgame page
display: none;
}

.submitTimeSection > div {
margin-top: 1px;
}

/*
The "downloads" section is for external links.
*/
Expand Down Expand Up @@ -2239,14 +2263,14 @@ span.sfl-save-autodesc {
#externalLinks.downloads h3 {
color: #d0d0ff;
}
table.gamerightbar {
.haveYouPlayed {
background: #101030;
border: thin dotted #303030;
}
table.gamerightbar td {
.haveYouPlayed {
color: #d8d8d8;
}
table.gamerightbar td h3 {
.haveYouPlayed h3 {
color: #d0d0ff;
}
}
Expand Down
216 changes: 214 additions & 2 deletions www/ifdbutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ function forceDarkMode(force) {
}
}

async function jsonSend(url, statusSpanID, cbFunc, content, silentMode)
async function jsonSend(url, statusSpanID, cbFunc, content, silentMode, cbFuncArgs)
{
if (statusSpanID)
document.getElementById(statusSpanID).innerHTML = "";
Expand Down Expand Up @@ -267,7 +267,7 @@ async function jsonSend(url, statusSpanID, cbFunc, content, silentMode)
+ "Please try again later.");
}
if (cbFunc && response?.ok) {
cbFunc(jsonResponse);
cbFunc(jsonResponse, cbFuncArgs);
}
}

Expand All @@ -280,3 +280,215 @@ async function check_ifid_in_ifwiki(ifid) {
} catch (e) {}
return false;
}

function setStarCtlValue(id, value) {
if (value) {
document.getElementById(`${id}__rating${value}`).checked = true;
} else {
const checked = [...document.querySelectorAll(`#${id} input[type=radio]`)].filter(i => i.checked)[0];
if (checked) checked.checked = false;
}
}

// Used by the have-you-played widget

function ckboxGetObj(id)
{
return document.getElementById('ckBox' + id);
}
function ckboxClick(id, onUpdateFunc)
{
const elem = ckboxGetObj(id);
if (onUpdateFunc)
onUpdateFunc(id, elem.checked);
}
function updateRating(game_id, rating)
{
const submitRating = document.getElementById(`submitRating_${game_id}`);
if (rating) {
if (submitRating.style.display === 'block') return;
} else {
submitRating.style.display = 'none';
}
jsonSend(`setrating?game=${game_id}&rating=${rating}`,
`rating_${game_id}_SaveMsg`);
}
function updatePlayed(id, stat)
{
const elem = ckboxGetObj(id);
const game_id = elem.closest('[data-gameid]').dataset.gameid;
jsonSend(`setplayed?game=${game_id}&played=`
+ (elem.checked ? "1" : "0"),
`${id}_SaveMsg`, (d) => {if (typeof updatePlaylistCount == "function") updatePlaylistCount(d.newCount);});
}
function updateWishlist(id, stat)
{
const elem = ckboxGetObj(id);
const game_id = elem.closest('[data-gameid]').dataset.gameid;
jsonSend(`setwishlist?game=${game_id}&add=`
+ (elem.checked ? "1" : "0"),
`${id}_SaveMsg`, (d) => {if (typeof updateWishlistCount == "function") updateWishlistCount(d.newCount)});
}
function updateUnwishlist(id, stat)
{
const elem = ckboxGetObj(id);
const game_id = elem.closest('[data-gameid]').dataset.gameid;
jsonSend(`setunwishlist?game=${game_id}&add=`
+ (elem.checked ? "1" : "0"),
`${id}_SaveMsg`);
}

// When the user clicks the "Submit Time" button, get the input
// from the hours and minutes fields, validate it, convert it to
// minutes only, and save it to the database (with the note, if present).
function submitTime() {
const gameElem = event.target.closest('[data-gameid]');
const game_id = gameElem.dataset.gameid;

let new_hours = gameElem.querySelector('.timeSection_hours').value;
let new_minutes = gameElem.querySelector('.timeSection_minutes').value;
const time_note = gameElem.querySelector('.timeNote').value.trim();
if (new_hours == "") { // If the hours field was blank, interpret it as 0
new_hours = 0;
}
if (new_minutes == "") { // If the minutes field was blank, interpret it as 0
new_minutes = 0;
}

const saveMsgId = `time_SaveMsg_${game_id}`;
const saveMsgElem = document.getElementById(saveMsgId);

const hours_are_digits = isOnlyDigits(new_hours);
const minutes_are_digits = isOnlyDigits(new_minutes);
if (hours_are_digits == false || minutes_are_digits == false) {
saveMsgElem.innerHTML="Please enter valid numbers.";
return;
}
if (new_hours > 200) { // Negative numbers will hopefully be eliminated by "Digits only"
saveMsgElem.innerHTML="For hours, please enter a number from 0 to 200.";
return;
}
if (new_minutes > 59) {
saveMsgElem.innerHTML="For minutes, please enter a number from 0 to 59.";
return;
}
const new_time = convertToMinutes(new_hours, new_minutes);
if (new_time < 1) {
saveMsgElem.innerHTML="The total time must be at least one minute.";
return;
}
// Time is valid, as far as we can tell.
// If the game isn't already on the user's list of played games, add it.
const played_it_checkbox = document.getElementById(`ckBoxckPlayed_${game_id}`);
if (!played_it_checkbox.checked) {
played_it_checkbox.checked = true;
updatePlayed(`ckPlayed_${game_id}`);
}
// Submit the time.
jsonSend(`settime?game=${game_id}&newtime=${new_time}&note=${encodeURIComponent(time_note)}`, saveMsgId, swapTimeSections, null, false, {'gameid': game_id});
}

// Remove the user's time for this game from the database.
function removeTime() {
const game_id = event.target.closest('[data-gameid]').dataset.gameid;
jsonSend(`settime?game=${game_id}&newtime=0`, `time_SaveMsg_${game_id}`, swapTimeSections, null, false, {'gameid': game_id});
}

// Check whether a string contains only digits.
function isOnlyDigits(a_string) {
if (/^\d+$/.test(a_string)) {
return true;
}
return false;
}


// Take hours and minutes and convert them into just minutes
// so we can store the time as minutes in the database.
function convertToMinutes(hours, minutes) {
// They need to be integers so they don't get concatenated when we're trying to add them
hours = Number(hours);
minutes = Number(minutes);
hours_into_minutes = hours * 60;
total_minutes = hours_into_minutes + minutes;
return total_minutes;
}


// The Estimated Play Time control panel has a "submitTimeSection," a "removeTimeSection," and
// a "timeSavedSection." Only one of the sections should be visible at a time. These functions
// show and hide the sections.

function showSubmitTimeSection(game_id) {
document.querySelector(`[data-gameid='${game_id}'] .submitTimeSection`).style.display = "block";
document.querySelector(`[data-gameid='${game_id}'] .removeTimeSection`).style.display = "none";
document.querySelector(`[data-gameid='${game_id}'] .timeSavedSection`).style.display = "none";
}

function showRemoveTimeSection(game_id) {
document.querySelector(`[data-gameid='${game_id}'] .submitTimeSection`).style.display = "none";
document.querySelector(`[data-gameid='${game_id}'] .removeTimeSection`).style.display = "block";
document.querySelector(`[data-gameid='${game_id}'] .timeSavedSection`).style.display = "none";
}

function showTimeSavedSection(game_id) {
document.querySelector(`[data-gameid='${game_id}'] .submitTimeSection`).style.display = "none";
document.querySelector(`[data-gameid='${game_id}'] .removeTimeSection`).style.display = "none";
document.querySelector(`[data-gameid='${game_id}'] .timeSavedSection`).style.display = "block";
}

// After successfully submitting or removing a time, hide or show
// the appropriate sections of the estimated play time control panel.
function swapTimeSectionsEventListener(event) {
const game_id = event.target.closest('[data-gameid]').dataset.gameid;
swapTimeSections(null, {'gameid': game_id});
}

function swapTimeSections(_response, args) {
const game_id = args.gameid;

if (document.getElementById(`time_SaveMsg_${game_id}`).innerHTML == "Saved") {
if (document.querySelector(`[data-gameid='${game_id}'] .submitTimeSection`).style.display == "block") {
//The submit time section is visible, which means we just successfully saved a new time.
showTimeSavedSection(game_id);
} else if (document.querySelector(`[data-gameid='${game_id}'] .removeTimeSection`).style.display == "block") {
//The remove time section is visible, which means we just successfully removed our time.
showSubmitTimeSection(game_id);
}
} // Don't swap the time controls if there was an error saving.
}

function prepareHaveYouPlayedBox(game_id) {
// Set up star rating control so it submits as soon as a star is clicked
const arrowKeys = new Set(['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown']);
const ratingStars = document.getElementById(`ratingStars_${game_id}`);
const submitRating = document.getElementById(`submitRating_${game_id}`);
ratingStars.addEventListener('keydown', e => {
if (arrowKeys.has(e.key)) submitRating.style.display = 'block';
});
submitRating.addEventListener('click', () => {
submitRating.style.display = 'none';
updateRating(game_id, ratingStars.querySelector('input:checked').value);
});

// Attach the submitTime function to the "Submit Time" button.
document.querySelector(`[data-gameid='${game_id}'] .submitTimeButton`).addEventListener("click", submitTime);


// Attach the removeTime function to the Remove Time button.
document.querySelector(`[data-gameid='${game_id}'] .removeTimeButton`).addEventListener("click", removeTime);


// Attach the swapTimeSections function to the timeVoteControls div.
document.querySelector(`[data-gameid='${game_id}'] .timeVoteControls`).addEventListener("load", swapTimeSectionsEventListener);


// Show the relevant time controls based on whether the user has a time already stored for this game.
// To find out, we check whether there's a message displaying the user's time.
const your_time_message = document.querySelector(`[data-gameid='${game_id}'] .yourTime`).innerHTML;
if (your_time_message == "") {
showSubmitTimeSection(game_id);
} else {
showRemoveTimeSection(game_id);
}
}
Loading