WebHost: Expose name groups through the weighted-settings UI (#2327)

* Factor out a common function for building lists

* Expose name groups through the weighted-settings UI

* Fix weighted-settings page

The request for the JSON file that provides the setting data was missed during the rename in #2037, so prior to this the weighted settings page wasn't rendering at all.
This commit is contained in:
Natalie Weizenbaum 2023-10-31 14:25:07 -07:00 committed by GitHub
parent 5726d2f962
commit dc80f59165
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 88 additions and 213 deletions

View File

@ -139,7 +139,13 @@ def create():
weighted_options["games"][game_name] = {} weighted_options["games"][game_name] = {}
weighted_options["games"][game_name]["gameSettings"] = game_options weighted_options["games"][game_name]["gameSettings"] = game_options
weighted_options["games"][game_name]["gameItems"] = tuple(world.item_names) weighted_options["games"][game_name]["gameItems"] = tuple(world.item_names)
weighted_options["games"][game_name]["gameItemGroups"] = [
group for group in world.item_name_groups.keys() if group != "Everything"
]
weighted_options["games"][game_name]["gameLocations"] = tuple(world.location_names) weighted_options["games"][game_name]["gameLocations"] = tuple(world.location_names)
weighted_options["games"][game_name]["gameLocationGroups"] = [
group for group in world.location_name_groups.keys() if group != "Everywhere"
]
with open(os.path.join(target_folder, 'weighted-options.json'), "w") as f: with open(os.path.join(target_folder, 'weighted-options.json'), "w") as f:
json.dump(weighted_options, f, indent=2, separators=(',', ': ')) json.dump(weighted_options, f, indent=2, separators=(',', ': '))

View File

@ -428,13 +428,13 @@ class GameSettings {
const weightedSettingsDiv = this.#buildWeightedSettingsDiv(); const weightedSettingsDiv = this.#buildWeightedSettingsDiv();
gameDiv.appendChild(weightedSettingsDiv); gameDiv.appendChild(weightedSettingsDiv);
const itemPoolDiv = this.#buildItemsDiv(); const itemPoolDiv = this.#buildItemPoolDiv();
gameDiv.appendChild(itemPoolDiv); gameDiv.appendChild(itemPoolDiv);
const hintsDiv = this.#buildHintsDiv(); const hintsDiv = this.#buildHintsDiv();
gameDiv.appendChild(hintsDiv); gameDiv.appendChild(hintsDiv);
const locationsDiv = this.#buildLocationsDiv(); const locationsDiv = this.#buildPriorityExclusionDiv();
gameDiv.appendChild(locationsDiv); gameDiv.appendChild(locationsDiv);
collapseButton.addEventListener('click', () => { collapseButton.addEventListener('click', () => {
@ -734,107 +734,17 @@ class GameSettings {
break; break;
case 'items-list': case 'items-list':
const itemsList = document.createElement('div'); const itemsList = this.#buildItemsDiv(settingName);
itemsList.classList.add('simple-list');
Object.values(this.data.gameItems).forEach((item) => {
const itemRow = document.createElement('div');
itemRow.classList.add('list-row');
const itemLabel = document.createElement('label');
itemLabel.setAttribute('for', `${this.name}-${settingName}-${item}`)
const itemCheckbox = document.createElement('input');
itemCheckbox.setAttribute('id', `${this.name}-${settingName}-${item}`);
itemCheckbox.setAttribute('type', 'checkbox');
itemCheckbox.setAttribute('data-game', this.name);
itemCheckbox.setAttribute('data-setting', settingName);
itemCheckbox.setAttribute('data-option', item.toString());
itemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
if (this.current[settingName].includes(item)) {
itemCheckbox.setAttribute('checked', '1');
}
const itemName = document.createElement('span');
itemName.innerText = item.toString();
itemLabel.appendChild(itemCheckbox);
itemLabel.appendChild(itemName);
itemRow.appendChild(itemLabel);
itemsList.appendChild((itemRow));
});
settingWrapper.appendChild(itemsList); settingWrapper.appendChild(itemsList);
break; break;
case 'locations-list': case 'locations-list':
const locationsList = document.createElement('div'); const locationsList = this.#buildLocationsDiv(settingName);
locationsList.classList.add('simple-list');
Object.values(this.data.gameLocations).forEach((location) => {
const locationRow = document.createElement('div');
locationRow.classList.add('list-row');
const locationLabel = document.createElement('label');
locationLabel.setAttribute('for', `${this.name}-${settingName}-${location}`)
const locationCheckbox = document.createElement('input');
locationCheckbox.setAttribute('id', `${this.name}-${settingName}-${location}`);
locationCheckbox.setAttribute('type', 'checkbox');
locationCheckbox.setAttribute('data-game', this.name);
locationCheckbox.setAttribute('data-setting', settingName);
locationCheckbox.setAttribute('data-option', location.toString());
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
if (this.current[settingName].includes(location)) {
locationCheckbox.setAttribute('checked', '1');
}
const locationName = document.createElement('span');
locationName.innerText = location.toString();
locationLabel.appendChild(locationCheckbox);
locationLabel.appendChild(locationName);
locationRow.appendChild(locationLabel);
locationsList.appendChild((locationRow));
});
settingWrapper.appendChild(locationsList); settingWrapper.appendChild(locationsList);
break; break;
case 'custom-list': case 'custom-list':
const customList = document.createElement('div'); const customList = this.#buildListDiv(settingName, this.data.gameSettings[settingName].options);
customList.classList.add('simple-list');
Object.values(this.data.gameSettings[settingName].options).forEach((listItem) => {
const customListRow = document.createElement('div');
customListRow.classList.add('list-row');
const customItemLabel = document.createElement('label');
customItemLabel.setAttribute('for', `${this.name}-${settingName}-${listItem}`)
const customItemCheckbox = document.createElement('input');
customItemCheckbox.setAttribute('id', `${this.name}-${settingName}-${listItem}`);
customItemCheckbox.setAttribute('type', 'checkbox');
customItemCheckbox.setAttribute('data-game', this.name);
customItemCheckbox.setAttribute('data-setting', settingName);
customItemCheckbox.setAttribute('data-option', listItem.toString());
customItemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
if (this.current[settingName].includes(listItem)) {
customItemCheckbox.setAttribute('checked', '1');
}
const customItemName = document.createElement('span');
customItemName.innerText = listItem.toString();
customItemLabel.appendChild(customItemCheckbox);
customItemLabel.appendChild(customItemName);
customListRow.appendChild(customItemLabel);
customList.appendChild((customListRow));
});
settingWrapper.appendChild(customList); settingWrapper.appendChild(customList);
break; break;
@ -849,7 +759,7 @@ class GameSettings {
return settingsWrapper; return settingsWrapper;
} }
#buildItemsDiv() { #buildItemPoolDiv() {
const itemsDiv = document.createElement('div'); const itemsDiv = document.createElement('div');
itemsDiv.classList.add('items-div'); itemsDiv.classList.add('items-div');
@ -1058,35 +968,7 @@ class GameSettings {
itemHintsWrapper.classList.add('hints-wrapper'); itemHintsWrapper.classList.add('hints-wrapper');
itemHintsWrapper.innerText = 'Starting Item Hints'; itemHintsWrapper.innerText = 'Starting Item Hints';
const itemHintsDiv = document.createElement('div'); const itemHintsDiv = this.#buildItemsDiv('start_hints');
itemHintsDiv.classList.add('simple-list');
this.data.gameItems.forEach((item) => {
const itemRow = document.createElement('div');
itemRow.classList.add('list-row');
const itemLabel = document.createElement('label');
itemLabel.setAttribute('for', `${this.name}-start_hints-${item}`);
const itemCheckbox = document.createElement('input');
itemCheckbox.setAttribute('type', 'checkbox');
itemCheckbox.setAttribute('id', `${this.name}-start_hints-${item}`);
itemCheckbox.setAttribute('data-game', this.name);
itemCheckbox.setAttribute('data-setting', 'start_hints');
itemCheckbox.setAttribute('data-option', item);
if (this.current.start_hints.includes(item)) {
itemCheckbox.setAttribute('checked', 'true');
}
itemCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
itemLabel.appendChild(itemCheckbox);
const itemName = document.createElement('span');
itemName.innerText = item;
itemLabel.appendChild(itemName);
itemRow.appendChild(itemLabel);
itemHintsDiv.appendChild(itemRow);
});
itemHintsWrapper.appendChild(itemHintsDiv); itemHintsWrapper.appendChild(itemHintsDiv);
itemHintsContainer.appendChild(itemHintsWrapper); itemHintsContainer.appendChild(itemHintsWrapper);
@ -1095,35 +977,7 @@ class GameSettings {
locationHintsWrapper.classList.add('hints-wrapper'); locationHintsWrapper.classList.add('hints-wrapper');
locationHintsWrapper.innerText = 'Starting Location Hints'; locationHintsWrapper.innerText = 'Starting Location Hints';
const locationHintsDiv = document.createElement('div'); const locationHintsDiv = this.#buildLocationsDiv('start_location_hints');
locationHintsDiv.classList.add('simple-list');
this.data.gameLocations.forEach((location) => {
const locationRow = document.createElement('div');
locationRow.classList.add('list-row');
const locationLabel = document.createElement('label');
locationLabel.setAttribute('for', `${this.name}-start_location_hints-${location}`);
const locationCheckbox = document.createElement('input');
locationCheckbox.setAttribute('type', 'checkbox');
locationCheckbox.setAttribute('id', `${this.name}-start_location_hints-${location}`);
locationCheckbox.setAttribute('data-game', this.name);
locationCheckbox.setAttribute('data-setting', 'start_location_hints');
locationCheckbox.setAttribute('data-option', location);
if (this.current.start_location_hints.includes(location)) {
locationCheckbox.setAttribute('checked', '1');
}
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
locationLabel.appendChild(locationCheckbox);
const locationName = document.createElement('span');
locationName.innerText = location;
locationLabel.appendChild(locationName);
locationRow.appendChild(locationLabel);
locationHintsDiv.appendChild(locationRow);
});
locationHintsWrapper.appendChild(locationHintsDiv); locationHintsWrapper.appendChild(locationHintsDiv);
itemHintsContainer.appendChild(locationHintsWrapper); itemHintsContainer.appendChild(locationHintsWrapper);
@ -1131,7 +985,7 @@ class GameSettings {
return hintsDiv; return hintsDiv;
} }
#buildLocationsDiv() { #buildPriorityExclusionDiv() {
const locationsDiv = document.createElement('div'); const locationsDiv = document.createElement('div');
locationsDiv.classList.add('locations-div'); locationsDiv.classList.add('locations-div');
const locationsHeader = document.createElement('h3'); const locationsHeader = document.createElement('h3');
@ -1151,35 +1005,7 @@ class GameSettings {
priorityLocationsWrapper.classList.add('locations-wrapper'); priorityLocationsWrapper.classList.add('locations-wrapper');
priorityLocationsWrapper.innerText = 'Priority Locations'; priorityLocationsWrapper.innerText = 'Priority Locations';
const priorityLocationsDiv = document.createElement('div'); const priorityLocationsDiv = this.#buildLocationsDiv('priority_locations');
priorityLocationsDiv.classList.add('simple-list');
this.data.gameLocations.forEach((location) => {
const locationRow = document.createElement('div');
locationRow.classList.add('list-row');
const locationLabel = document.createElement('label');
locationLabel.setAttribute('for', `${this.name}-priority_locations-${location}`);
const locationCheckbox = document.createElement('input');
locationCheckbox.setAttribute('type', 'checkbox');
locationCheckbox.setAttribute('id', `${this.name}-priority_locations-${location}`);
locationCheckbox.setAttribute('data-game', this.name);
locationCheckbox.setAttribute('data-setting', 'priority_locations');
locationCheckbox.setAttribute('data-option', location);
if (this.current.priority_locations.includes(location)) {
locationCheckbox.setAttribute('checked', '1');
}
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
locationLabel.appendChild(locationCheckbox);
const locationName = document.createElement('span');
locationName.innerText = location;
locationLabel.appendChild(locationName);
locationRow.appendChild(locationLabel);
priorityLocationsDiv.appendChild(locationRow);
});
priorityLocationsWrapper.appendChild(priorityLocationsDiv); priorityLocationsWrapper.appendChild(priorityLocationsDiv);
locationsContainer.appendChild(priorityLocationsWrapper); locationsContainer.appendChild(priorityLocationsWrapper);
@ -1188,35 +1014,7 @@ class GameSettings {
excludeLocationsWrapper.classList.add('locations-wrapper'); excludeLocationsWrapper.classList.add('locations-wrapper');
excludeLocationsWrapper.innerText = 'Exclude Locations'; excludeLocationsWrapper.innerText = 'Exclude Locations';
const excludeLocationsDiv = document.createElement('div'); const excludeLocationsDiv = this.#buildLocationsDiv('exclude_locations');
excludeLocationsDiv.classList.add('simple-list');
this.data.gameLocations.forEach((location) => {
const locationRow = document.createElement('div');
locationRow.classList.add('list-row');
const locationLabel = document.createElement('label');
locationLabel.setAttribute('for', `${this.name}-exclude_locations-${location}`);
const locationCheckbox = document.createElement('input');
locationCheckbox.setAttribute('type', 'checkbox');
locationCheckbox.setAttribute('id', `${this.name}-exclude_locations-${location}`);
locationCheckbox.setAttribute('data-game', this.name);
locationCheckbox.setAttribute('data-setting', 'exclude_locations');
locationCheckbox.setAttribute('data-option', location);
if (this.current.exclude_locations.includes(location)) {
locationCheckbox.setAttribute('checked', '1');
}
locationCheckbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
locationLabel.appendChild(locationCheckbox);
const locationName = document.createElement('span');
locationName.innerText = location;
locationLabel.appendChild(locationName);
locationRow.appendChild(locationLabel);
excludeLocationsDiv.appendChild(locationRow);
});
excludeLocationsWrapper.appendChild(excludeLocationsDiv); excludeLocationsWrapper.appendChild(excludeLocationsDiv);
locationsContainer.appendChild(excludeLocationsWrapper); locationsContainer.appendChild(excludeLocationsWrapper);
@ -1224,6 +1022,71 @@ class GameSettings {
return locationsDiv; return locationsDiv;
} }
// Builds a div for a setting whose value is a list of locations.
#buildLocationsDiv(setting) {
return this.#buildListDiv(setting, this.data.gameLocations, this.data.gameLocationGroups);
}
// Builds a div for a setting whose value is a list of items.
#buildItemsDiv(setting) {
return this.#buildListDiv(setting, this.data.gameItems, this.data.gameItemGroups);
}
// Builds a div for a setting named `setting` with a list value that can
// contain `items`.
//
// The `groups` option can be a list of additional options for this list
// (usually `item_name_groups` or `location_name_groups`) that are displayed
// in a special section at the top of the list.
#buildListDiv(setting, items, groups = []) {
const div = document.createElement('div');
div.classList.add('simple-list');
groups.forEach((group) => {
const row = this.#addListRow(setting, group);
div.appendChild(row);
});
if (groups.length > 0) {
div.appendChild(document.createElement('hr'));
}
items.forEach((item) => {
const row = this.#addListRow(setting, item);
div.appendChild(row);
});
return div;
}
// Builds and returns a row for a list of checkboxes.
#addListRow(setting, item) {
const row = document.createElement('div');
row.classList.add('list-row');
const label = document.createElement('label');
label.setAttribute('for', `${this.name}-${setting}-${item}`);
const checkbox = document.createElement('input');
checkbox.setAttribute('type', 'checkbox');
checkbox.setAttribute('id', `${this.name}-${setting}-${item}`);
checkbox.setAttribute('data-game', this.name);
checkbox.setAttribute('data-setting', setting);
checkbox.setAttribute('data-option', item);
if (this.current[setting].includes(item)) {
checkbox.setAttribute('checked', '1');
}
checkbox.addEventListener('change', (evt) => this.#updateListSetting(evt));
label.appendChild(checkbox);
const name = document.createElement('span');
name.innerText = item;
label.appendChild(name);
row.appendChild(label);
return row;
}
#updateRangeSetting(evt) { #updateRangeSetting(evt) {
const setting = evt.target.getAttribute('data-setting'); const setting = evt.target.getAttribute('data-setting');
const option = evt.target.getAttribute('data-option'); const option = evt.target.getAttribute('data-option');

View File

@ -292,6 +292,12 @@ html{
margin-right: 0.5rem; margin-right: 0.5rem;
} }
#weighted-settings .simple-list hr{
width: calc(100% - 2px);
margin: 2px auto;
border-bottom: 1px solid rgb(255 255 255 / 0.6);
}
#weighted-settings .invisible{ #weighted-settings .invisible{
display: none; display: none;
} }