Layton said: The Aaron said: Neat Script! I'd love to see 5e Shaped support so I could use it. =D Regarding the player pages, here's a little function that returns an array of all the pageids for pages with a player (including the GM) on them: const getActivePages = () => [...new Set([
Campaign().get('playerpageid'),
...Object.values(Campaign().get('playerspecificpages')),
...findObjs({
type: 'player',
online: true
})
.filter((p)=>playerIsGM(p.id))
.map((p)=>p.get('lastpage'))
])
];
Can you teach me a bit about that ellipsis "..." usage, or tell me what it's called? I'm only learning, and I've seen that used in a lot of places but don't know what to Google to learn about it. That function will be extremely handy though, so thanks for the comment - I'll integrate it soon! Shaped functionality is on the way, but because the global save modifiers on the shaped sheets is in the repeating modifiers section the system becomes a whole bundle more complex. Regardless, I'm making progress. Sure! There are two contexts for ... in javascript, Rest and Spread. The code snippet is all Spread usage. Important Note: The current version of the API sandbox only supports Rest and Spread for Arrays. Contrast that to the current version of Javascript that also supports it with Objects. Spread just takes the contents of an Array and expands them as if you'd typed them in directly one after the other: let a = [1,2,3];
let b = [4,5,6];
let c = [...a, ...b]; Is the same as: let a = [1,2,3];
let b = [4,5,6];
let c = [1,2,3,4,5,6]; or you might write it dynamically without spread as: let a = [1,2,3];
let b = [4,5,6];
let c = [];
a.forEach(n => c.push(n));
b.forEach(n => c.push(n)); You'll likely find yourself using Spread most of the time. Rest is only used in argument lists to functions, and collects any remaining parameters into an array. const logall = (label, ...args) => log(`${label}: ${args.join(', ')}`);
logall('Cousins','Bob','Nancy','Sue','Paul','Tom'); Cousins: Bob, Nancy, Sue, Paul, Tom Rest is necessary because Arrow Functions ( => ) don't get passed the arguments pseudo-Array object. In older Javascript, you'd do something like: var logAll = function(label) {
var output = label + ': ';
var sep = '';
for(var i = 1; i < arguments.length; ++i){
output += sep + arguments[i];
sep = ', ';
}
}; (I feel dirty just typing in all those var's and string concatenations!) As you can see, Modern Javascript is getting a whole lot more expressive. =D Some links: Spread: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax</a> Rest: <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters</a> Arrow Functions (Fat Arrow): <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions" rel="nofollow">https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions</a> An article on ES6 functionality I refer to constantly: <a href="https://www.reindex.io/blog/you-might-not-need-underscore" rel="nofollow">https://www.reindex.io/blog/you-might-not-need-underscore</a> Quick commentary on that function: // returns and array of page ids for pages that players are currently on
// Set has the property that only a single copy of any value is retained.
// By building a Set here, we remove duplicate page ids, then use Spread
// to turn the Set back into an array to return
// Note: the argument to Set is an single Array we are building with
// other calls below.
const getActivePages = () => [...new Set([
// Where the ribbon is, i.e. the "easy" case. =D
Campaign().get('playerpageid'),
// Object.values() returns an array of just the values for all properties
// on an object. The playerspecificpages property contains an object
// mapping player ids to page ids. We don't want the player ids, just the
// page ids, so this is an easy way to strip down to just that.
// Using Spread to take the array of page ids and put them in the
// argument array to Set.
...Object.values(Campaign().get('playerspecificpages')),
// Finally, the GM's current page is dictated by the lastpage property on
// the character. There are some eccentricities to this, mostly around
// having more than one view of the game loaded in different browsers at
// the same time, but it will almost always be completely accurate.
// Find all the players,
...findObjs({
type: 'player',
online: true
})
// filter down to only players that are GMs
.filter((p)=>playerIsGM(p.id))
// pluck out the lastpage property
.map((p)=>p.get('lastpage'))
// Spread then adds them to the Set argument array
]) // end of Set
]; // end of array to return
Cheers!