Good Afternoon, I am trying to make a few buttons that will reorder a repeating field used for storing spells using sheetworkers. The intended functionality is to be able to click a button to reorder alphabetically, by mana cost, or by school. Once I have it working, I will expand it outward to work for other spell tiers. While I try to write some of my own code, this was a little above my current skill level, so I have been going back and forth with chatGPT. I realize that AI has limitations, especially as related to roll20, but I find it tends to be useful for specific javascript functionality in a limited context. In this case, after correcting for several errors, the code almost seems to work, based on the final console.log output. But, it doesn't actually implement the change. What I eventually reached is that maybe setSectionOrder may not actually work with roll20 (which of course the AI did not realize initially, but eventually said). Is there an alternative method for this, or am I largely out of luck on this one? The code is below. As an aside, I can consider using an API based solution instead, if that is all that is available. However, due to unrelated issues, I am unable to use the API at present, so that is more of a long term solution. Relevant HTML Code: <!-- BASIC SPELLS -->
<div class="sheet-section-spellsbasic">
<h2 style="text-align: center">Basic Spells</h2>
<br/>
<!-- BASIC SPELLS 2COLROW -->
<div class="sheet-2colrow">
<!-- BASIC SPELLS LEFT COLUMN -->
<div class="sheet-col">
<fieldset class="repeating_spellsbasic">
<table class="proficiency_table">
<thead>
<tr>
<th>
Prep
</th>
<th>
Bon
</th>
<th>
Sig
</th>
<th>
School
</th>
<th>
Cost
</th>
<th>
Roll
</th>
</tr>
</thead>
<tr>
<td>
<input type="checkbox" class="combat_text_input" name="attr_prepared" value="1" title="Check this if this spell is prepared. This must be checked for this spell to appear on your spell list in combat. @{prepared}" />
</td>
<td>
<input type="checkbox" class="combat_text_input" name="attr_bonus" value="1" title="Check this if this spell does not count against your total number of prepared spells. @{bonus}" />
</td>
<td>
<input type="checkbox" class="combat_text_input" name="attr_signature" value="1" title="Check this if this spell is a signature spell. @{signature}" />
</td>
<td>
<input type="text" class="proficiency_input" name="attr_school" value="0" title="What school this spell belongs to. @{school}" readonly />
</td>
<td>
<input type="text" class="proficiency_input" name="attr_mana_cost" value="0" title="The mana cost of this spell. @{mana_cost}" readonly />
</td>
<td>
<button type="roll" name="roll_castspellbutton" value="@{link}" title="Click this button to cast this spell. You will still need to select your character (in all cases) and the target (when necessary) for this to work. @{castspellbutton}"></button>
</td>
</tr>
<tr>
<td colspan=6>
<input type="text" class="proficiency_input" name="attr_input" value="Spell Name" title="Place the spell name here." />
</td>
</tr>
<tr hidden >
<td colspan=6>
<input type="text" class="proficiency_input" name="attr_feedback" value="No feedback generated yet." title="The status of your last attempt to enter this feature. @{feedback}" readonly />
</td>
</tr>
<tr hidden >
<td colspan=6>
<input type="text" class="proficiency_input" name="attr_link" value="Spell Link" title="A link to the spell should be here." readonly />
</td>
</tr>
</table>
<br/>
</fieldset>
</div>
<!-- END OF BASIC SPELLS LEFT COLUMN style="display: none;" -->
<!-- BASIC SPELLS RIGHT COLUMN -->
<div class="sheet-col">
<table class="proficiency_table">
<thead>
<tr>
<th>
Known
</th>
<th>
Ready
</th>
<th>
Prepared
</th>
<th>
Roll
</th>
</tr>
</thead>
<tr>
<td>
<input class="skill_input" type="text" name="attr_known_basic_spells_count" value="0" title="How many basic spells you currently know. @{known_basic_spells_count}" readonly />
</td>
<td>
<input class="skill_input" type="text" name="attr_ready_basic_spells_count" value="0" title="How many basic spells you currently have prepared. @{ready_basic_spells_count}" readonly />
</td>
<td>
<input class="skill_input" type="text" name="attr_prepared_basic_spells_count" value="0" title="How many tier basic you currently have prepared. @{prepared_basic_spells_count}" readonly />
</td>
<td>
<button type="roll" name="roll_castspellbasicbutton" value="/w gm &{template:spell} {{name=@{selected|token_name}'s Basic Spells}} {{description=@{selected|basic_spells}}}" title="Click this button to roll all basic spells to chat. You will still need to select your character (in all cases) and the target (when necessary) for this to work. @{castspellbasicbutton}"></button>
</td>
</tr>
</table>
<textarea name="attr_basic_spells" value="Class Features" title="@{basic_spells}" style="width:98%; resize:vertical; height:34ex;" readonly ></textarea>
<br/>
<br/>
<h3 style="text-align: center">Sort Basic Spells</h3>
<br/>
<table class="proficiency_table">
<thead>
<tr>
<th>
Alphabetic
</th>
<th>
Mana Cost
</th>
<th>
School
</th>
</tr>
</thead>
<tr>
<td>
<button type="action" name="act_alphabeticsortspellbasicbutton" title="Click this button to alphabetize your basic spells. @{alphabeticsortspellbasicbutton}"></button>
</td>
<td>
<button type="action" name="act_manasortspellbasicbutton" title="Click this button to sort your basic spells by mana cost. Variable spells will be listed together. Spells with the same cost will be alphabetized within that cost. @{manasortspellbasicbutton}"></button>
</td>
<td>
<button type="action" name="act_schoolsortspellbasicbutton" title="Click this button to sort your basic spells by spell school. Spells with the same school will be alphabetized within that school. @{schoolsortspellbasicbutton}"></button>
</td>
</tr>
</table>
<br/>
<br/>
</div>
<!-- END OF BASIC SPELLS RIGHT COLUMN -->
</div>
<!-- END OF BASIC SPELLS 2COLROW -->
</div>
<!-- END OF BASIC SPELLS --> Sorting Basic Spells Sheetworker: /* Sort Basic Spells Sheetworker */
on("clicked:alphabeticsortspellbasicbutton clicked:manasortspellbasicbutton clicked:schoolsortspellbasicbutton", function(eventInfo) {
const buttonClicked = eventInfo.triggerName;
const sectionName = "repeating_spellsbasic"; // <-- adjust if needed
console.log(`Basic spell sort triggered: ${buttonClicked}`);
getSectionIDs(sectionName, function(ids) {
if (!ids.length) {
console.log("No repeating entries found.");
return;
}
// Build a list of all attributes to fetch
const attrNames = [];
ids.forEach(id => {
attrNames.push(`${sectionName}_${id}_spellname`);
attrNames.push(`${sectionName}_${id}_manacost`);
attrNames.push(`${sectionName}_${id}_school`);
});
// Fetch data
getAttrs(attrNames, function(values) {
const spells = ids.map(id => ({
id,
name: (values[`${sectionName}_${id}_spellname`] || "").trim(),
mana: (values[`${sectionName}_${id}_manacost`] || "").trim(),
school: (values[`${sectionName}_${id}_school`] || "").trim()
}));
// Sorting logic
if (buttonClicked === "clicked:alphabeticsortspellbasicbutton") {
spells.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
}
else if (buttonClicked === "clicked:manasortspellbasicbutton") {
spells.sort((a, b) => {
// Extract leading number if present
const numA = parseInt(a.mana);
const numB = parseInt(b.mana);
// Handle "Variable" or non-numeric cases
const isNumA = !isNaN(numA);
const isNumB = !isNaN(numB);
if (isNumA && isNumB) return numA - numB || a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
if (isNumA && !isNumB) return -1; // numbers before non-numeric
if (!isNumA && isNumB) return 1; // non-numeric after numbers
return a.mana.localeCompare(b.mana, undefined, { sensitivity: "base" }) || a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
});
}
else if (buttonClicked === "clicked:schoolsortspellbasicbutton") {
spells.sort((a, b) => a.school.localeCompare(b.school, undefined, { sensitivity: "base" }) || a.name.localeCompare(b.name, undefined, { sensitivity: "base" }));
}
// Apply the new order
const order = spells.map(s => `${sectionName}_${s.id}`);
setSectionOrder(sectionName, order);
console.log(`Reordered ${sectionName}:`, order);
});
});
});
/* End of Sort Basic Spells Sheetworker */