Here's an example of what a sort function might look like that just sorted by name, to illustrate the complexity. (untested) This assumes you have a button to click to start the sort routine. You could set different filters to sort by, but I went with the simplest in this example. Using reduce instead of forEach could make this shorter but would be harder to understand the steps involved. The fields array at the start should include the name of every attribute within the row of the section. const fields = ['name', 'class', 'level'];
on('change:spell_sort', (event) => {
if(!fields.includes(event.newValue)) {
return;
}
getSectionIDs('repeating_spells', idarray => {
const fieldnames = [];
// get the name of EVERY attribute on every row.
idarray.forEach(id => fields.forEach(field => fieldnames.push(`repeating_spells_${id}_${field}`)));
getAttrs([...fieldnames, 'spell_sort'], v => {
const spell_sort = v.spell_sort;
let allrows = [];
// need to go throw every row and get the values, and store them with out the id
idarray.forEach(id => {
// get all the value of every attribute in a row, and story it in object with the field name
const thisrow = {};
fields.forEach(field => thisrow[field] = v[`repeating_spells_${id}_${field}`]);
allrows = [...allrows, thisrow]
});
/* at this point we have all the attributes from the repeating section in an array of objects that looks something like
[
{name: 'a spell', class: 'cleric', level: 3},
{name: 'another spell', class: 'cleric', level: 3},
{name: 'yet another spell', class: 'wizard', level: 1},
]
now we need to sort the array. The Underscore function _.sortBy is easiest here
*/
allrows = _.sortBy(allrows,spell_sort);
// now we create a new output function
const output = {};
allrows.forEach(row => {
//need to create a new id for each row, and create new complete repeating section attribute names for each field
const rowid = generateRowID();
fields.forEach(field => output[`repeating_spells_${rowid}_${field}`] = row[field]);
});
// now we have a sorted copy of the rows we can add to the repeating section. But we also need to delete the old set. idarray.forEach(id => removeRepeatingRow(`repeating_spells_${id}`));
// finally update the sheet. If a connection error happens between the previous row and next row, the entire repeating section is lost forever.
setAttrs(output, {silent:true}});
});
});
}); The data loss possibility does suggest that it would be a good idea to implement an undo function. That adds even more complexity. That said, data loss due to connection error on roll20 almost never happens (I've never experienced it), so I may be overstating the dangers. Its probably robust enough. And I'm assuming that roll20 will create new rows in the order they are in the output object. That should be tested, lol. If it doesn't, then there;s no way to sort via sheet worker at all.