Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Request for Assistance] Unable to label Horizontally

1630193552

Edited 1630195384
Toby
Pro
Alright, so I have a small problem with making my css do as I want.&nbsp; The image below shows how the page currently appears, its kinda nice and I'd be mostly happy with it, however as you can see the sheet goes off the screen with the default loading width of the character sheet.&nbsp; Not ideal and very much sets off my--and probably everyone elses' OCD.&nbsp; It is also my second choice as I gave up trying to force the label for each row to display above and centered.&nbsp; So.. my problem.. As can be seen the label takes up far too much room.&nbsp; And the following would be a whole heck of a lot better: Obviously I had to use paint to put the label above each section.&nbsp; But that is basically how I want it to display.&nbsp; Ideally, I would have the words "Difficulty Modifiers" and "Dice Pool" visible always and when you click on it it expands the section below.&nbsp; But I'll settle for it simply being a label for now.&nbsp; Assistance in this matter would be greatly appreciated. The code I am using so far is located at&nbsp;<a href="https://github.com/TobyFox2002/WoD20Unified" rel="nofollow">https://github.com/TobyFox2002/WoD20Unified</a>.
1630208581

Edited 1630294524
Oosh
Sheet Author
API Scripter
One of the more experienced sheet authors might disagree with me on this (and definitely listen to them instead of me if they do), but I've found CSS much easier by making free use of &lt;div&gt; elements around many of the functional elements. Some of them, like buttons, inputs and labels, do not freely respond to all CSS, so wrapping them inside a &lt;div&gt; gives you much greater control over them. This may or may not be the problem you're running into. In terms of turning that label into a function collapse button, you could try doing this with your HTML: This is starting from around line 335 of your code, where the Alertness &lt;ul&gt; section starts (commented out): &lt;!--&nbsp;&lt;ul&gt;&nbsp;section&nbsp;above&nbsp;&lt;/ul&gt;&nbsp;--&gt; &lt; div &nbsp; class = "abilBuffs" &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_collapse-flag-abilBuffs" &nbsp; value = "0" &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt;!--&nbsp;Button&nbsp;wrapped&nbsp;in&nbsp;a&nbsp;div&nbsp;gives&nbsp;you&nbsp;more&nbsp;CSS&nbsp;freedom&nbsp;to&nbsp;play&nbsp;with&nbsp;borders,&nbsp;padding&nbsp;etc.&nbsp;--&gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; div &nbsp; class = "collapse-button" &gt; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; button &nbsp; name = "act_collapse-abilBuffs" &nbsp; type = "action" &gt; Difficulty&nbsp;Modifier: &lt;/ button &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt;/ div &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; div &nbsp; class = "collapse-details&nbsp;abilBuffs" &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;!--&nbsp;abilBuffs&nbsp;collapsable&nbsp;section&nbsp;here&nbsp;--&gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt;/ div &gt; &lt;/ div &gt; You can target the button and surrounding &lt;div&gt; with CSS to make it look un-buttony if that's the effect you're after. If you stick to a naming convention for your hidden input (collapse-flag-&lt;section name&gt;), button (act_collapse-&lt;section name&gt;) and class (collapse-details &lt;section-name&gt;), it allows you to write a single function for all your collapsable sections. Note that you can still use the section name as the second class in your CSS to target specific classes if they need some differences. Anyway, the listener, and a helper function to do a 0 =&gt; 1 toggle. I've omitted any error handling for brevity, but you'd probably want to have something in there (for example, I generally have a helper.toArray(input) function that ensures a variable is an array before it gets passed to each getAttrs). I've added some extra 'clicked:' sections just to illustrate the ease of adding more buttons to it: on ( 'clicked:collapse-abilBuffs&nbsp;clicked:collapse-otherSection&nbsp;clicked:collapse-yetAnotherSection' ,&nbsp;( ev )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; section &nbsp;=&nbsp; ev . triggerName . match ( /collapse- ( . * ) / )[ 1 ]; &nbsp;&nbsp;&nbsp;&nbsp; toggleAttr ([ `collapse-flag- ${ section } ` ]); }) //&nbsp;Helper&nbsp;function&nbsp;to&nbsp;toggle&nbsp;1&nbsp;and&nbsp;0.&nbsp;Uses&nbsp;lazy&nbsp;==&nbsp;compare,&nbsp;which&nbsp;some&nbsp;people&nbsp;don't&nbsp;like.&nbsp;You&nbsp;can&nbsp;parseInt&nbsp;if&nbsp;you&nbsp;wish const &nbsp; toggleAttr &nbsp;=&nbsp;( target ,&nbsp; log = false )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; getAttrs ( target ,&nbsp;( val )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; outVal &nbsp;=&nbsp;(! val [ target ]&nbsp;||&nbsp; val [ target ]&nbsp;==&nbsp; 0 )&nbsp;?&nbsp; 1 &nbsp;:&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs ({ [ target ]: &nbsp; outVal }); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if &nbsp;( log )&nbsp; console . log ( `Toggle&nbsp;Helper:&nbsp; ${ target } &nbsp;switched&nbsp;to&nbsp;" ${ outVal } "` ); &nbsp;&nbsp;&nbsp;&nbsp;}); } Then finally, your CSS would be something like: .collapse-details &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; display : none ; } input [ type = "hidden" ][ name *= "collapse-flag" ][ value = "1" ]&nbsp;~&nbsp; .collapse-details &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; display : block ; } Toggling display gives and instant fold/unfold. If you'd like something prettier, you can use a transition effect on the height property or something similar for a smooth transition. Edit - I've only written one sheet, and all of it using the async/await framework. Removed some async references... hopefully I didn't mess up the vanilla getAttrs :)
I am sorry to say, I'm quite lost.&nbsp; I think I can see what is supposed to happen.&nbsp; But, I am not sure how I can put my code into this.&nbsp; I mean, if I have to get rid of my &lt;ul&gt; sections, it definitely cant work.&nbsp; You have it commented out, but I don't really see how that's gonna work as that section above is needed. And as for the sheet workers, my understanding of them is almost non-existent, so I don't understand whats supposed to be happening except that somehow it mimics the old checkbox show hide somehow?&nbsp; Is that something close?&nbsp; I'll take another look tomorrow.&nbsp; I've been sitting here trying to write this reply for the better part of 40 mins cause I don't want to sound like an ass, cause I'm not trying to be.
1630242445
GiGs
Pro
Sheet Author
API Scripter
Oosh said: One of the more experienced sheet authors might disagree with me on this (and definitely listen to them instead of me if they do), but I've found CSS much easier by making free use of &lt;div&gt; elements around many of the functional elements. Hehe, i can imagine many experienced with HTML and CSS hissing and recoiling from the screen at this suggestion. There's a term called divitus invented to describe people who over use containers like divs. This kind of thing is not generally recommended: &lt;div&nbsp;class="collapse-button"&gt;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;button&nbsp;name="act_collapse-abilBuffs"&nbsp;type="action"&gt;Difficulty&nbsp;Modifier:&lt;/button&gt; &nbsp;&nbsp;&nbsp;&nbsp;&lt;/div&gt; when you can just do &lt;button&nbsp;class="collapse-button" name="act_collapse-abilBuffs"&nbsp;type="action"&gt;Difficulty&nbsp;Modifier:&lt;/button&gt; and have whatever CSS is applying to the container div apply directly to the button itself. Generally speaking, you should only use containers like divs when there are multiple elements you want to group together, not for single elements. To the OP, unfortunately we don't have control over the size of the opening character sheet frame, so if you want everything to appear neatly within it, you have to change the size of your elements or reorganise them in some way. That is honestly the most painful part of working with CSS IMO - the constant fiddling with element sizes to make things fit where you want them to. But looking at your design, it seems like you should be able to do that (also I'd extend the box size for temp mod so that label all appears on one line)
I have just awoken... and re-reading my post.&nbsp; I should probably refrain from posting when I am that exhausted.&nbsp; It makes my already lousy people skills worse.&nbsp; I am very sorry to those I probably offended.&nbsp; With that out of the way. I do like the idea of being able to individually allow the user to minimize/maximize each skill (ability) individually.&nbsp; One of the reasons, I didn't even try for that was the massive amount of css required to create unique show/hide elements.&nbsp; From what I am understsanding of the css/SheetWorker interaction is that you can dynamically handle that without creating a unquie class for each ability?&nbsp; Sounds very interesting, unfortunately I don't really have enough of an understanding on how the Javascript works to pull that off at this time. Most of the code that was used was entirely greek to me, though I think I understsood some of he logic involved, and I saw the compare syntax with "foo : foo2 ? foo3".&nbsp; But that is about the limit of my understanding in that regard. What I didnt understand with the OP was how to place my code into his example, and I still am a little confused.&nbsp; When ever I try it seems to constrain it to the width of one &lt;li&gt; element dispite being a direct child of the &lt;ul&gt; which should span it across an entire row.&nbsp; Maybe it has to do with how the flex is functioning. P.S., @GiGi Were you saying I have divitus or the OP?&nbsp; I am certainly guilty of using a lot of &lt;divs&gt; in my code.&nbsp; Though, I have to say working with buttons, checkboxes, and radio buttons you do need ALOT of divs, the browsers just dont properly handle css for those elements very well.
1630247882
GiGs
Pro
Sheet Author
API Scripter
Toby said: P.S., @GiGi Were you saying I have divitus or the OP?&nbsp; I am certainly guilty of using a lot of &lt;divs&gt; in my code.&nbsp; Though, I have to say working with buttons, checkboxes, and radio buttons you do need ALOT of divs, the browsers just dont properly handle css for those elements very well. I was responding to Oosh's comment about using divs liberally. I wasn't referring to your code because I haven't looked at it :)
1630288358

Edited 1630288430
Toby
Pro
Well, I've added the code, or at least I think I had, but it still really isn't functioning. &lt;div class="border"&gt;&lt;!-- Alertness ~ Mage | Werewolf | Vampire | Changeling | Shen | Mummy | Hunter | Bygone --&gt; &lt;ul&gt; &lt;li&gt;Alertness&lt;button type="roll" name="roll_Alertness-Check" value="[QUERY]" title="%{selected|Alertness-Check} Tokenless Roll (No Token Select Required for this Roll)" &gt;&lt;/button&gt;&lt;/li&gt; &lt;li class="dicepool"&gt;&lt;input type="checkbox" class="610-skills" name="attr_show-10d-skills" hidden /&gt; &lt;input type="radio" class="hd zero" name="attr_Alertness" value="0" checked /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd" name="attr_Alertness" value="1" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd" name="attr_Alertness" value="2" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd" name="attr_Alertness" value="3" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd" name="attr_Alertness" value="4" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd" name="attr_Alertness" value="5" /&gt;&lt;span&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;input type="radio" class="hd show-10d-skills" name="attr_Alertness" value="6" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd show-10d-skills" name="attr_Alertness" value="7" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd show-10d-skills" name="attr_Alertness" value="8" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd show-10d-skills" name="attr_Alertness" value="9" /&gt;&lt;span&gt;&lt;/span&gt; &lt;input type="radio" class="hd show-10d-skills" name="attr_Alertness" value="10" /&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt; &lt;/ul&gt; &lt;input type="checkbox" name="attr_abil-min-show" class="collapse-show" value="1" hidden&gt; &lt;input type="hidden" name="collapse-flag-abilBuffs" value="0"&gt; &lt;div class="collapse-button"&gt;&lt;button name="act_collapse-abilBuffs" type="action"&gt;Difficulty Modifier:&lt;/button&gt;&lt;/div&gt; &lt;div class="abilBuffs collapse-details" style="border: 1px dotted black; padding: .3em;"&gt; &lt;label class="ability-optGroup1" title="Add or Subtract default difficulty"&gt;Diff&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-DiffPerm" value="0" /&gt;&lt;br&gt;&lt;span&gt;Perm&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-DiffMerFl" value="0" /&gt;&lt;br&gt;&lt;span&gt;Merit/Flaw&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-DiffShapeShf" value="0" /&gt;&lt;br&gt;&lt;span&gt;Form&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-DiffBuffs" value="0" disabled /&gt;&lt;br&gt;&lt;span title="Reserved for Future Use."&gt;Buffs&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-DiffTotal" value="@{Alert-DiffTemp} + @{Alert-DiffPerm} + @{Alert-DiffBuffs} + @{Alert-DiffMerFl} + @{Alert-DiffShapeShf}" disabled /&gt;&lt;br&gt;&lt;span&gt;Total&lt;/span&gt;&lt;/label&gt; &lt;/div&gt; &lt;div class="abilBuffs collapse-details" style="border: 1px dotted black; padding: .3em;"&gt; &lt;label class="ability-optGroup2" title="Add or Subtract from for the number of dice being rolled."&gt;Dice Pool&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-TempMod" value="0" /&gt;&lt;br&gt;&lt;span&gt;Temp&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="number" class="2dig" name="attr_Alert-PermMod" value="0" /&gt;&lt;br&gt;&lt;span&gt;Perm&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;select class="skAttrSz" title="@{Alertness-Ability}" name="attr_Alertness-Ability"&gt; &lt;option value="0"&gt;• None&lt;/option&gt; &lt;option value="@{Str-Total}"&gt;STR&lt;/option&gt;&lt;option value="@{Dex-Total}"&gt;DEX&lt;/option&gt;&lt;option value="@{Stm-Total}"&gt;STM&lt;/option&gt; &lt;option value="@{Cha-Total}"&gt;CHA&lt;/option&gt;&lt;option value="@{Man-Total}"&gt;MAN&lt;/option&gt;&lt;option value="@{App-Total}"&gt;APP&lt;/option&gt; &lt;option value="@{Per-Total}" selected&gt;PER&lt;/option&gt;&lt;option value="@{Int-Total}"&gt;INT&lt;/option&gt;&lt;option value="@{Wit-Total}"&gt;WIT&lt;/option&gt; &lt;/select&gt;&lt;br&gt;&lt;span class="SkPoolLabel"&gt;Attribute&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="text" name="attr_Alert-Buffs" value="0" class="3dig" disabled&gt;&lt;br&gt;&lt;span title="Reserved for Future Use."&gt;Buffs&lt;/span&gt;&lt;/label&gt; &lt;label class="smlabel"&gt;&lt;input type="text" name="attr_Alert-Total" value="@{Alertness} + @{Alertness-Ability} + @{Alert-TempMod} + @{Alert-PermMod}" class="3dig" disabled&gt;&lt;br&gt;&lt;span&gt;Total&lt;/span&gt;&lt;/label&gt;&lt;br&gt; &lt;/div&gt; &lt;label class="smlabel collapse-details"&gt;&lt;input type="text" name="attr_Alert-Spec" placeholder="Alertness Specialization" /&gt;&lt;br&gt;&lt;span&gt;Specialization&lt;/span&gt;&lt;/label&gt; &lt;/div&gt;&lt;!-- End of Skill --&gt; with&nbsp; on('clicked:collapse-abilBuffs clicked:collapse-otherSection clicked:collapse-yetAnotherSection', (ev) =&gt; { let section = ev.triggerName.match(/collapse-(.*)/)[1]; toggleAttr([`collapse-flag-${section}`]); }) // Helper function to toggle 1 and 0. Uses lazy == compare, which some people don't like. You can parseInt if you wish const toggleAttr = (target, log=false) =&gt; { getAttrs(target, (val) =&gt; { let outVal = (!val[target] || val[target] == 0) ? 1 : 0; setAttrs({[target]: outVal}); if (log) console.log(`Toggle Helper: ${target} switched to "${outVal}"`); }); } as my sheet workers.&nbsp; And the css added into my style.&nbsp; Nothing happens.&nbsp; Though the button does fit and if I do some padding shenanigans it does span across the rows as desired, so I can possibly use this and leave the sheet workers for a later time so thats a positive. Edit: How did he do that code formating, Oosh was so much nicer looking than mine...
Hm.. Looking at the console.&nbsp; The sheet worker isn't even being triggered.&nbsp; As the console.log output isnt appearing at all.&nbsp; I am getting a number of warnings regarding disabled fields being out of bounds.&nbsp; But those fields seem to be displaying and updating properly and they are not using sheet workers for their math so... I don think thats really relevant (also, they were in the console log even before I made these changes, so.. obviously they cant be part of this. I am also getting some weird error that I haven't a clue about which has been persistent for a while: I dont really know if its related to this issue or not, my sheet seems to otherwise work perfectly fine and I dont know what it means by "property 'replace' of undefined" so..
1630290859

Edited 1630291652
Oosh
Sheet Author
API Scripter
Edit - looks like you posted while I was typing... could you post your whole script block? Sorry for any misunderstanding - I wasn't suggesting getting rid of any of your code, just omitting it since I wasn't changing any of it and trying to use the // commented sections to show where it should go. The code snippets are pasted straight from VS Code, with the syntax highlighting intact - no real tricks required there (apart from setting up VS Code with ESLint which can be challenging for those of us with no coding background), you can paste it straight into Roll20. Sorry for the lack of explanation - from the quick look I had at the code it looked like you had a pretty good handle on the whole coding part, so I tried to leave it fairly brief with just the general structure I was suggesting. If the HTML/CSS is somewhere near where you want it, I'll just suggest a new version of the JS with more logging - it's possible the sheetworker section isn't running at all since I didn't really put any error checking or logging in there. This has a bit more logging and got rid of the fictional sections - the console should indicate where the process is going wrong: on ( 'clicked:collapse-abilBuffs' ,&nbsp;( ev )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; section &nbsp;=&nbsp;( ev . triggerName . match ( /collapse- ( . * ) / )&nbsp;||&nbsp;[])[ 1 ]; &nbsp;&nbsp;&nbsp;&nbsp; console . info ( `Collapse&nbsp;event&nbsp;triggered&nbsp;on&nbsp;section:&nbsp;" ${ section } "` ,&nbsp; ev ); &nbsp;&nbsp;&nbsp;&nbsp; toggleAttr ( `collapse-flag- ${ section } ` ,&nbsp; true ); }); //&nbsp;Helper&nbsp;function&nbsp;to&nbsp;toggle&nbsp;1&nbsp;and&nbsp;0.&nbsp;Uses&nbsp;lazy&nbsp;==&nbsp;compare,&nbsp;which&nbsp;some&nbsp;people&nbsp;don't&nbsp;like.&nbsp;You&nbsp;can&nbsp;parseInt&nbsp;if&nbsp;you&nbsp;wish const &nbsp; toggleAttr &nbsp;=&nbsp;( target ,&nbsp; log = false )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; target &nbsp;=&nbsp;( Array . isArray ( target ))&nbsp;?&nbsp; target &nbsp;:&nbsp;[ target ]; &nbsp;&nbsp;&nbsp;&nbsp; getAttrs ( target ,&nbsp;( val )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if &nbsp;( log )&nbsp; console . log ( `Toggle&nbsp;Helper:&nbsp; ${ target } &nbsp;initial&nbsp;value:&nbsp;" ${ val [ target ] } "` ); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; outVal &nbsp;=&nbsp;(! val [ target ]&nbsp;||&nbsp; val [ target ]&nbsp;==&nbsp; 0 )&nbsp;?&nbsp; 1 &nbsp;:&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs ({ [ target ]: &nbsp; outVal }); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if &nbsp;( log )&nbsp; console . log ( `Toggle&nbsp;Helper:&nbsp; ${ target } &nbsp;switched&nbsp;to&nbsp;" ${ outVal } "` ); &nbsp;&nbsp;&nbsp;&nbsp;}); }; Give that a go with the browser console open and see what comes up when the button is clicked. If nothing at all is happening, there's probably a serious error somewhere in the script block stopping the whole thing from running. GiGs said: Hehe, i can imagine many experienced with HTML and CSS hissing and recoiling from the screen at this suggestion. There's a term called divitus invented to describe people who over use containers like divs. This kind of thing is not generally recommended. Good to know my condition has a name! :) So how would you approach the above screenshot? It seems to me that the label might look better with a thin top &amp; bottom border stretching full width of the outer section, but personally I'd only want the text to be a clickable button. Is a single button inside a div a bad way to do this? Having the two elements also leaves the option to leave a border or background on your button (just around the text) and full width border to separate the sections above and below. But if there's a better way to do it that'll start the healing process on my divitus - I'm always happy to learn :)
1630293886

Edited 1630294343
Toby
Pro
Edit - looks like you posted while I was typing... could you post your whole script block? What do you mean the whole script block? Sorry for the lack of explanation - from the quick look I had at the code it looked like you had a pretty good handle on the whole coding part, so I tried to leave it fairly brief with just the general structure I was suggesting. Well thanks for the complement, the truth is I am fairly good with html (up to version 4 html 5 confuses me, I prefer it remain a markup language, animating using it seems wrong.) CSS1, 2 and a little bit of 3.&nbsp; I get very confused when using selectors and with complex hierarchical mix and matching.&nbsp; I am just begining to study flex and and making code cross compatable with multiple screen sizes (which I am trying to do for this sheet).&nbsp; My knowledge of javascript is quite limited.&nbsp; I understand the logic well enough, as long as it doesnt start to use all kinds of wierd commands and sticks to absolute basics.&nbsp; I am still trying to learn.&nbsp; But I learn best by copy/paste and from practical examples with real-language explanations.&nbsp; Not with programmer-jargon filled lessons. If an example or lesson is just a task for the sake of demonstrating a concept... They might as well be speaking a foreign language cause I'll not retain it.&nbsp; Makes also makes it difficult to learn sheetWorkers, cause their really isnt much of that for me to pick apart that doesnt have extra junk in it. Give that a go with the browser console open and see what comes up when the button is clicked. If nothing at all is happening, there's probably a serious error somewhere in the script block stopping the whole thing from running. Thats what it looks like, cause nothing happens when I press the button, nothing in the console at all.&nbsp; No message of any kind. Good to know my condition has a name! :) To be fair, when dealing with check boxes, radio buttons, dropdown lists and buttons css support is rather trash.&nbsp; And there is alot of CSS wizardry that can be done by wrapping the element in other elements.&nbsp; Moreso when you can create different styles by adding sheetworkers, I've seen examples of people creating checkboxes, use sheet workers to test for state and add images based on the state of the check box.&nbsp; Can do some really neat things with that, probably..&nbsp; Most commonly this uses either &lt;label&gt;...&lt;/label&gt; or &lt;div&gt;&lt;/div&gt; or &lt;span&gt;&lt;/span&gt;.&nbsp; I tend to use &lt;div&gt; for block level and &lt;span&gt; for inline. There is also the fact that I used to rely heavily on using divs and spans to mimic table based layouts.&nbsp; I really never understood why people said not to use tables when they would just reinvent the wheel by making DIVS and SPANS have the display property of tables.&nbsp; Seemed rather silly, but I guess that is the syntax now. Also, as for how your question on how it handles, see for your self.. This example shows 10 dots for NPC's, bygones and Elders.&nbsp; I need to figure out how to change width of the surrounding container for the radio buttons (which are actually check boxes using some fancy code) so they line up.&nbsp; But thats a different issue.&nbsp; I dont need to hold everything up for that because I know that all that would be required is creating some conditionals in the css.&nbsp; I just dont know how to do that off the top of my head. EDIT: I forgot to add in that I updated the GITHUB with the new code..&nbsp;&nbsp;<a href="https://github.com/TobyFox2002/WoD20Unified" rel="nofollow">https://github.com/TobyFox2002/WoD20Unified</a>
1630295310

Edited 1630295993
Oosh
Sheet Author
API Scripter
Ah OK, I've had a proper look now, and there's a few problems. Firstly, I forgot the attr_ prefix on those collapse flags. Secondly, I didn't even look at the CSS and notice it's using Legacy - the classes will need the "sheet-" prefix. Third, I didn't notice you wanted two different collapsible sections which are siblings - the general sibling selector won't work since the top button will be collapsing both the difficulty modifier and dice pool sections. You've also changed the names of the action buttons without updating the javascript, which means the event won't fire at all. Also bear in mind that Roll20 attributes are case-insensitive most of the time - using capital letters can lead to some confusion later if trying to do an exact compare in your sheetworkers - the capitalised HTML attribute names will not match the ones you get from a getAttrs() function - they'll all be dropped to lower case. With that in mind, here is a fixed-up example. If you really want the capital letters in there, add them back in - the sheetworker will need to be updated to match the case exactly in the 'clicked:buttonName' part, as those events use the exact HTML and aren't converted to lower case by Roll20 . Never mind, it's working with both capitals and lower case. I'm not sure why it wasn't firing before - must have been another issue. The HTML - rearranged to put the hidden input immediately before the collapsible content: &lt;!--&nbsp;&lt;input&nbsp;type="checkbox"&nbsp;name="attr_abil-min-show"&nbsp;class="collapse-show"&nbsp;value="1"&nbsp;hidden&gt;&nbsp;--&gt; &lt; button &nbsp; type = "action" &nbsp; class = "collapse-button" &nbsp; name = "act_collapse-abil-diffmods" &nbsp; &gt; Difficulty&nbsp;Modifier &lt;/ button &gt; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_collapse-flag-abil-diffmods" &nbsp; value = "1" &gt; &lt; div &nbsp; class = "abilBuffs&nbsp;collapse-details" &nbsp; style = " border:&nbsp;1px&nbsp;dotted&nbsp;black;&nbsp;padding:&nbsp;.3em; " &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-DiffPerm" &nbsp; value = "0" &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Perm &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-DiffMerFl" &nbsp; value = "0" &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Merit/Flaw &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-DiffShapeShf" &nbsp; value = "0" &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Form &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-DiffBuffs" &nbsp; value = "0" &nbsp; disabled &nbsp; /&gt;&lt; br &gt;&lt; span &nbsp; title = "Reserved&nbsp;for&nbsp;Future&nbsp;Use." &gt; Buffs &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-DiffTotal" &nbsp; value = "@{Alert-DiffPerm}&nbsp;+&nbsp;@{Alert-DiffBuffs}&nbsp;+&nbsp;@{Alert-DiffMerFl}&nbsp;+&nbsp;@{Alert-DiffShapeShf}" &nbsp; disabled &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Total &lt;/ span &gt;&lt;/ label &gt; &lt;/ div &gt; &lt; button &nbsp; type = "action" &nbsp; class = "collapse-button" &nbsp; name = "act_collapse-abil-dicepool" &nbsp; &gt; Dice&nbsp;Pool &lt;/ button &gt; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_collapse-flag-abil-dicepool" &nbsp; value = "1" &gt; &lt; div &nbsp; class = "abilBuffs&nbsp;collapse-details" &nbsp; style = " border:&nbsp;1px&nbsp;dotted&nbsp;black;&nbsp;padding:&nbsp;.3em; " &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-TempMod" &nbsp; value = "0" &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Temp &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "number" &nbsp; class = "2dig" &nbsp; name = "attr_Alert-PermMod" &nbsp; value = "0" &nbsp; /&gt;&lt; br &gt;&lt; span &gt; Perm &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; select &nbsp; class = "skAttrSz" &nbsp; title = "@{Alertness-Ability}" &nbsp; name = "attr_Alertness-Ability" &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; option &nbsp; value = "0" &gt; •&nbsp;None &lt;/ option &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; option &nbsp; value = "@{Str-Total}" &gt; STR &lt;/ option &gt;&lt; option &nbsp; value = "@{Dex-Total}" &gt; DEX &lt;/ option &gt;&lt; option &nbsp; value = "@{Stm-Total}" &gt; STM &lt;/ option &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; option &nbsp; value = "@{Cha-Total}" &gt; CHA &lt;/ option &gt;&lt; option &nbsp; value = "@{Man-Total}" &gt; MAN &lt;/ option &gt;&lt; option &nbsp; value = "@{App-Total}" &gt; APP &lt;/ option &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt; option &nbsp; value = "@{Per-Total}" &nbsp; selected &gt; PER &lt;/ option &gt;&lt; option &nbsp; value = "@{Int-Total}" &gt; INT &lt;/ option &gt;&lt; option &nbsp; value = "@{Wit-Total}" &gt; WIT &lt;/ option &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt;/ select &gt;&lt; br &gt;&lt; span &nbsp; class = "SkPoolLabel" &gt; Attribute &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "text" &nbsp; name = "attr_Alert-Buffs" &nbsp; value = "0" &nbsp; class = "3dig" &nbsp; disabled &gt;&lt; br &gt;&lt; span &nbsp; title = "Reserved&nbsp;for&nbsp;Future&nbsp;Use." &gt; Buffs &lt;/ span &gt;&lt;/ label &gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; label &nbsp; class = "smlabel" &gt;&lt; input &nbsp; type = "text" &nbsp; name = "attr_Alert-Total" &nbsp; value = "@{Alertness}&nbsp;+&nbsp;@{Alertness-Ability}&nbsp;+&nbsp;@{Alert-TempMod}&nbsp;+&nbsp;@{Alert-PermMod}" &nbsp; class = "3dig" &nbsp; disabled &gt;&lt; br &gt;&lt; span &gt; Total &lt;/ span &gt;&lt;/ label &gt;&lt; br &gt; &lt;/ div &gt; The updated script block to account for the name changes: &lt;!--&nbsp;Sheet&nbsp;Workers&nbsp;--&gt; &nbsp;&nbsp;&nbsp;&nbsp; &lt; script &nbsp; type = "text/worker" &gt; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;buttonlist&nbsp;=&nbsp;["core","combat","abilities",&nbsp;"advantages",&nbsp;"details","biography","config"]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;buttonlist.forEach(button&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;on(`clicked:${button}`,&nbsp;function()&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sheetTab:&nbsp;button &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;on('clicked:collapse-abil-diffmods&nbsp;clicked:collapse-abil-dicepool',&nbsp;(ev)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;section&nbsp;=&nbsp;(ev.triggerName.match(/collapse-(.*)/i)&nbsp;||&nbsp;[])[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.info(`Collapse&nbsp;event&nbsp;triggered&nbsp;on&nbsp;section:&nbsp;"${section}"`,&nbsp;ev); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;toggleAttr(`collapse-flag-${section}`,&nbsp;true); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//&nbsp;Helper&nbsp;function&nbsp;to&nbsp;toggle&nbsp;1&nbsp;and&nbsp;0.&nbsp;Uses&nbsp;lazy&nbsp;==&nbsp;compare,&nbsp;which&nbsp;some&nbsp;people&nbsp;don't&nbsp;like.&nbsp;You&nbsp;can&nbsp;parseInt&nbsp;if&nbsp;you&nbsp;wish &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;const&nbsp;toggleAttr&nbsp;=&nbsp;(target,&nbsp;log=false)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target&nbsp;=&nbsp;(Array.isArray(target))&nbsp;?&nbsp;target&nbsp;:&nbsp;[target]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;getAttrs(target,&nbsp;(val)&nbsp;=&gt;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(log)&nbsp;console.log(`Toggle&nbsp;Helper:&nbsp;${target}&nbsp;initial&nbsp;value:&nbsp;"${val[target]}"`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;let&nbsp;outVal&nbsp;=&nbsp;(!val[target]&nbsp;||&nbsp;val[target]&nbsp;==&nbsp;0)&nbsp;?&nbsp;1&nbsp;:&nbsp;0; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setAttrs({[target]:&nbsp;outVal}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(log)&nbsp;console.log(`Toggle&nbsp;Helper:&nbsp;${target}&nbsp;switched&nbsp;to&nbsp;"${outVal}"`); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp; &lt;/ script &gt; And the CSS rule... I've never used Legacy sanitization by the way - but my understanding is you just bang a "sheet-" in front of the class names :) input [ name *= "collapse-flag" ][ value = "0" ]&nbsp;+&nbsp; .sheet-collapse-details &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; display :&nbsp; none ; } And obviously you'll need to remove those CSS rules from before. This worked when I tested it, though when you collapse both parts, the width of the column changes - this probably needs to have a minimum width or something set on the parent.
Honestly, the parent one would just be used to collapse ALL abilities at once instead of each ability one at a time, which is what I was doing before because I didn't really think I could do what you assisted me in achieving without a huge amount of unneeded code. The next question is how to I add this to function with each ability down the list.&nbsp; What do I add in the sheetworkers and how do I modify the html/css.
So after trying it, there is a slight problem.&nbsp; When pressed, it expands and collapses for ALL abilities not just each one individually.&nbsp; Obviously not what was intended.
1630303263

Edited 1630304029
Oosh
Sheet Author
API Scripter
Ah OK - have you added more of the buttons/hidden inputs? If so, what are their names? If they're still abil-diffmods and abil-dicepool, it's going to cause the issue you're describing. The other problem could be if the old CSS rules are still there - though, I don't think they should be doing much since I forgot the "sheet-" prefix for Legacy on those ones. It's probably just the names that are the problem - "abil" is pretty generic, it's probably better to use the skill name of the section. So in the above HTML, the &lt;input&gt; and &lt;button&gt; names would change to use "alert" instead of "abil": &lt; button &nbsp; type = "action" &nbsp; class = "collapse-button" &nbsp; name = "act_collapse-alert-diffmods" &nbsp; &gt; Difficulty&nbsp;Modifier &lt;/ button &gt; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_collapse-flag-alert-diffmods" &nbsp; value = "1" &gt; and &lt; button &nbsp; type = "action" &nbsp; class = "collapse-button" &nbsp; name = "act_collapse-alert-dicepool" &nbsp; &gt; Dice&nbsp;Pool &lt;/ button &gt; &lt; input &nbsp; type = "hidden" &nbsp; name = "attr_collapse-flag-alert-dicepool" &nbsp; value = "1" &gt; The event listener then needs to change accordingly: on ( 'clicked:collapse-alert-diffmods&nbsp;clicked:collapse-alert-dicepool' ,&nbsp;( ev )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; section &nbsp;=&nbsp;( ev . triggerName . match ( /collapse- ( . * ) / i )&nbsp;||&nbsp;[])[ 1 ]; &nbsp;&nbsp;&nbsp;&nbsp; console . info ( `Collapse&nbsp;event&nbsp;triggered&nbsp;on&nbsp;section:&nbsp;" ${ section } "` ,&nbsp; ev ); &nbsp;&nbsp;&nbsp;&nbsp; toggleAttr ( `collapse-flag- ${ section } ` ,&nbsp; true ); }); As a quick explanation of the event listener: Roll20 events are fired when specific things happen - an attribute change, a button is clicked etc. If you register an event listener, the specified function will run when the event occurs. Roll20 will also generate an event object containing some information on what happened to trigger the event. The (ev) parameter before the start of the function is short for 'event', and passes the event data into the function below. This event object will contain different data depending on the triggering event - for example, an attribute change event will include the previous &amp; the new values of the attribute. The only thing we're interested in here is the name of the button that was clicked - and that's only because we're registering multiple buttons at once, so we need to know which one triggered an event. If you only had a single button registered in the listener, you wouldn't need the event object, as there's no ambiguity about what triggered the event. The second line uses a regular expression match to pinch the section name from the triggering event data that Roll20 gave us. So when the button named "act_collapse-alert-diffmods" is clicked, the triggerName property passed through in the event object will be "clicked:collapse-alert-diffmods" (Roll20 drops the "act_" prefix which denotes an action button name). As long as we follow the same naming convention for all buttons, 'act_collapse-&lt;section name&gt;', we're only interested in the section name part - that's what the regex match is grabbing. So in this case, we've defined a variable 'section' which now has the value 'alert-diffmods'. (for the sake of completeness, the || [ ] part after the .match() function is a bit of error handling. If the match() function fails and returns 'undefined', the logical OR operator will return the value on the right instead, which is an empty Array [ ]. The next instruction is [1], which references the second value in an Array (which is the value we want if the match() function is successful). This will cause a crash when passed on 'undefined', while it won't when passed on an empty Array. While the match() *shouldn't* fail provided the button names are all correct, it's nice to prevent nasty errors where it doesn't take much typing) The third line logs what's just happened - that's where we can check if something is wrong with the event object, or the regex match, if the function is not working. Finally, the fourth line calls our other function to do a simple 0 =&gt; 1 or 1 =&gt; 0 toggle. It passes through a value by using a template literal : `collapse-flag-${section}`. This creates a new string from the "collapse-flag-" literal text, and inserts the value of our 'section' variable into the ${} enclosed part. Again, as long as we stick to the naming convention of 'collapse-flag-&lt;section name&gt;', where the section name is an exact match of the &lt;button&gt;'s section name, this function will turn the button name, into the attribute name we require for toggling the section. Now, on to adding more buttons. The simplest way is to just keep adding 'clicked' events. So for 'awareness' you would add the &lt;input&gt; and &lt;button&gt; HTML to your section so it's the same as the 'alert' section, but with the &lt;button&gt; and &lt;input&gt; names changed to 'act_collapse-awareness-diffmods' and 'collapse-flag-awareness-diffmods' for the diffmods part, and 'act_collapse-awareness-dicepool', 'collapse-flag-awareness-dicepool' for the dicepool. Then change the top line of the event listener to include the new Awareness button: on ( 'clicked:collapse-alert-diffmods&nbsp;clicked:collapse-alert-dicepool&nbsp;clicked:collapse-awareness-diffmods&nbsp;clicked:collapse-awareness-dicepool' ,&nbsp;( ev )&nbsp; =&gt; &nbsp;{ Now, this is clearly going to end up a very long line if you're adding a bunch of sections. So using a transform is a good option here. First, store all of your skill/ability names in an array. This is immensely useful if you're adding more code - you don't want to be spelling out long lists of skills/attributes/abilities any more than you have to: The names you use here need to match the attribute names, not the display text. So, to match what's in your HTML, the start would be: const &nbsp; abilities &nbsp;=&nbsp;[ 'Art' ,&nbsp; 'Awareness' ,&nbsp; 'Alert' ,&nbsp; 'AnimalKen' ]; (as a side note, underscores to denote a space in attribute names are useful - they allow you to use a simple function to turn an attribute name into a display name. While you can do this by inserting a space before capital letters, it's trickier). You can then use Javascript .map() to transform your skill list into the required text very easily: let &nbsp; abilityButtonEvents &nbsp;=&nbsp; abilities . map ( ability &nbsp; =&gt; &nbsp; `clicked:collapse- ${ ability } -diffmods&nbsp;clicked:collapse- ${ ability } -dicepool` ); The expected output of the above .map() function: ['clicked:collapse-art-diffmods clicked:collapse-art-dicepool', 'clicked:collapse-awareness-diffmods clicked:collapse-awareness-dicepool', 'clicked:collapse-alert-diffmods clicked:collapse-alert-dicepool', 'clicked:collapse-animalken-diffmods clicked:collapse-animalken-dicepool'] This is still an Array, which is no good for the event listener line. So we'd use join() to join the array parts back into a single string before handing it to Roll20's on() event listener, taking care to insert a space between the array parts to stop them running into each other. So you first line now become much more readable: on ( abilityButtonEvents . join ( '&nbsp;' ),&nbsp;( ev )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;rest&nbsp;of&nbsp;function&nbsp;in&nbsp;here }); You can then add more sections to your 'abilities' Array quickly and easily. Using .map() to generate the button names also cuts down on the potential for typos. I've linked w3schools above as it's pretty easy to understand. As you get more comfortable with Javascript, the MDN documentation is much better - but it can be pretty overwhelming when you're new to JS.
Hrm, sounds good I'll give it a shot when I get some sleep.&nbsp; I have seen something like this before, I had some help one one of my previous sheets a custom pathfinder sheet and sheet workers were used to do the calculations for all the math.&nbsp; I'm fairly certain this was used to eliminate the need for a new function for each and every single skill. Also, with so much concern over capitalization when it comes to handling matching and such, would a string function to transform everything to lowercase before handling the eval be wise?&nbsp; I prefer to keep the CamelCaps because of its ease to read and because _underscore in names is a very bad idea while the -hyphen is also not great because it prevents me from being able to double click on the name to highlight for copy/paste. I want to thank you for your help on this issue.&nbsp; I'll play around with this when i wake.
Sweet!&nbsp; That works perfectly and functions as expected.&nbsp; Also, it turns out I had been using a similar version of this for the Top of sheet navigation bar.&nbsp; The same sort of array based chicainery to hide the sections of the character sheet, though the meat of the code is slightly different, I think does roughly the same thing. I will say however, the console does seem to spit out something strange.&nbsp; After the console log prints the expected result (as written into the script.&nbsp; It does give more details with a lot of&nbsp; sourceAttribute: undefined, sourceType: undefined ..&nbsp; I was wondering if that was normal.&nbsp; Normally things being undefined is not good. If that perfectly ignoreable I'll move on to adapting this to the rest of my code and perhaps try and build on this.&nbsp; I think I might be able to manage as a self-learning project creating a loop that allows a single button to expand/collapse all at once as a shortcut.&nbsp; Also, perhaps a string manipulation function to add a whitespace just before a capital letter when it appears in the middle of a word. I think that would probably use a strCount and a regEx to parse.&nbsp; As I mentioned earlier, I have reasons for going with the CamelNotation because it makes it easier for me to edit and maintain. Thank you again.&nbsp; This helps make my character sheet look much nicer as well as allowing for ease of use.
1630377855

Edited 1630378129
Oosh
Sheet Author
API Scripter
Glad it's somewhat working :) By all means, stick to camelCase (or UpperCamelCase) if you prefer - don't let a beginner like me tell you what to do!. Just be aware of the fact that roll20 won't recognise it internally for attribute names. All those attribute names will be lowercase once they're processed by a sheetworker: myAttr and myattr will be treated as the same attribute by Roll20 when updating the sheet, but not by your Javascript. You can already see the difference in that screenshot of your console log - the event Object has a capital letter in the htmlAttributes.name value, but the triggerName value has all come back as lowercase. As long as you're aware of the differences, you shouldn't have any massive issues - just remember that many of Javascript's String functions are case sensitive by default. Speaking of the event Object - the 'undefined' for sourceAttribute and sourceType are fine for this event type - for other events, sourceType will tell you whether a sheetworker or player initiated the event (like an attribute change coming from keyboard input, or modified by code), sourceAttribute will give you the name of the attribute which triggered the event. Roll20 ignores sourceType for a click event, since no currently available code can trigger a mouse click - it's always user input. Roll20 also ignores sourceAttribute for action buttons which aren't in a repeating section - I think this is probably a bug/oversight. While you can still get the button name from triggerName, it should still be populating sourceAttribute for the sake of consistency. As for the hyphens vs. underscores: provided you remember the places you can't use underscores on Roll20 (only one underscore when defining a "repeating_section-name", same for "act_action-button-names" in repeating sections), don't be afraid to use them. They improve readability considerably, and they're a pretty standard word-delimiter when dealing with lower case. Personally, I would find collapse_academics-diffmods and collapse-flag_academics-diffmods more readable as the underscore is splitting each name into the functional part, and the sheet section. That comes with the big caveat that collapse_academics-diffmods is a button name, so this naming convention wouldn't work in a repeating section. Finally, depending on the software you're using to edit your HTML/JS, you might be able to add your own word delimiters. That was one of the first things I did when I started using VS Code - add the hyphen as a delimiter for both HTML and JS, so double clicking the first part of academics-diffmods will select "academics". Also, perhaps a string manipulation function to add a whitespace just before a capital letter when it appears in the middle of a word. Yep, there's a bunch of ways to approach it. Here's a lazy one-liner (ignore if you wanted to solve it yourself) const &nbsp; addSpaces &nbsp;=&nbsp;( inputString )&nbsp; =&gt; &nbsp; inputString . replace ( / ([ A-Z ]) / g ,&nbsp; `&nbsp;$1` ). trim (); let &nbsp; attrName &nbsp;=&nbsp; `IsAThing` ; console . log ( addSpaces ( attrName )); //&nbsp;Expected&nbsp;output:&nbsp;Is&nbsp;A&nbsp;Thing
1630378749
GiGs
Pro
Sheet Author
API Scripter
I generally recommend avoiding hyphens in attribute names, because of the way it forces you to use different syntax for those attributes in sheet workers. You can use them fine if you know what you're doing, but given that I mainly help beginners here, where it causes a lot of people to trip up, I've developed an aversion to it :) I also recommend lower case attribute names (though that's a rule I break often myself as I like camelCase too), because if you have any upper case letters in attribute names, you have to remember to lower-case them on the On() event line, and it's another thing that causes unnecessary confusion when helping newbies. I would use underscores everywhere, including multiple times in the same attribute name, if not for the action button and repeating section names problems that Oosh points out.
LOL... I was literally in the process of writing a PM to you when I saw you had made a reply.&nbsp; Amazing timing. I was going to ask if you could point me to a number of examples for sheet workers code.&nbsp; The first example I am looking for is one where I can loop through each element in an array... so for example I wanted to also have a button on the page where it expanded and collapsed all of them at once.&nbsp; I am assuming the way to do this is pretty much the same code command as before but using a loop or or iteration for the array and assigning the true/false to the flag for each. I wanted to kinda play with it and figure it out on my own (or try to) as a learning experience, but I cant find any examples of this in practice. The second one you partially answered, I'm wanting to create a function that essentially works as you posted. The code I had was very similar because I worked on a project with a friend at school (they did the php/mysql) and I did the graphic design.&nbsp; And I remember this exact thing came up and it was very easy.&nbsp; From what they told me, this function was extremely common in database ux design to take internal field names and use them to create labels. I still had some of the code from that project and this was what was used.&nbsp; I am not entirely sure on the RegEx code, cause well, regEx is kinda a pain in the neck and I avoid it whereever possible :p.&nbsp; But I think it checks for any capitalized letters that immediately follow a lowercase letter and is not at the start of or end of a line.&nbsp; Then adds a whitespace between while preserving the capitalization using title caps.&nbsp; It will also ignore ALL CAPS for acryonyms so ACME wont be written as "A C M E". function insertSpaces ( string ) { string = string. replace ( /([a-z])([A-Z])/g , '$1 $2' ); string = string. replace ( /([A-Z])([A-Z][a-z])/g , '$1 $2' ) return string; } But the question I have is how can I set this up in a sheet worker so I can use it anywhere.&nbsp; Basically I want to be able use the function as a variable or to be able to print it to the console log.&nbsp; I can't really find any examples of how that might be achieved. So using the above, I'd like to be able to have something like: console.log("This section is called: " + insertSpaces(${target}) + "."); and get something like: This section is called: Animal Ken. Obviously, the syntax isn't correct.&nbsp; I tried using above, and it obviously failed.&nbsp; Or I wouldn't be asking. Thank you very much again for all your help, and for some examples of code.&nbsp; I attempting, once again to learn java script better and am currently in the process of watching some videos on skillshare.&nbsp; So hopefully over the next few days or weeks, I should be able to understand the code a little better and more importantly, understand explanations without having my hand-held for each and every step.
1630380962
Oosh
Sheet Author
API Scripter
GiGs said: I also recommend lower case attribute names (though that's a rule I break often myself as I like camelCase too), because if you have any upper case letters in attribute names, you have to remember to lower-case them on the On() event line, and it's another thing that causes unnecessary confusion when helping newbies. Strange, that's what I thought too. One of the posts above I mentioned that, and then put strikethrough on the advice because it appears to be wrong. This output is from 3 on('clicked') listeners and 3 on('change') listeners, identical apart from the uppercase: They're all triggered at once, regardless of case. Could this have changed with the recent getAttrs/setAttrs differences? It seems like one of the issues with using camel case in the HTML is no longer applying? Oh, and code snippet, just so you know I didn't forget to change the case in the actual parameter :) on ( 'clicked:testroll' ,&nbsp;( ev )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; console . log ( `Triggered&nbsp;"clicked:testroll"` ); &nbsp;&nbsp;&nbsp;&nbsp; //doubleRoll(); }); on ( 'clicked:TESTROLL' ,&nbsp;( ev )&nbsp; =&gt; &nbsp; console . log ( `Triggered&nbsp;"clicked:TESTROLL` )); on ( 'cliCKEd:TesTROLL' ,&nbsp;( ev )&nbsp; =&gt; &nbsp; console . log ( `Triggered&nbsp;"cliCKEd:TesTROLL` )); on ( 'change:stamina' ,&nbsp;( ev )&nbsp; =&gt; &nbsp; console . log ( `Triggered:&nbsp;"change:stamina"` )); on ( 'change:sTAMina' ,&nbsp;( ev )&nbsp; =&gt; &nbsp; console . log ( `Triggered:&nbsp;"change:sTAMina"` )); on ( 'Change:Stamina' ,&nbsp;( ev )&nbsp; =&gt; &nbsp; console . log ( `Triggered:&nbsp;"Change:Stamina"` ));
1630384091

Edited 1630384223
Oosh
Sheet Author
API Scripter
Toby said: LOL... I was literally in the process of writing a PM to you when I saw you had made a reply.&nbsp; Amazing timing. I was going to ask if you could point me to a number of examples for sheet workers code.&nbsp; The first example I am looking for is one where I can loop through each element in an array... so for example I wanted to also have a button on the page where it expanded and collapsed all of them at once.&nbsp; I am assuming the way to do this is pretty much the same code command as before but using a loop or or iteration for the array and assigning the true/false to the flag for each. The wiki has plenty of code examples you can look through. If a specific sheet has something you like, you can help yourself to the code at the repo (unless it's an Official Roll20 sheet). In terms of the "expand all" button, you're correct - you basically want to iterate over an Array with all the section/skill names you're trying to collapse, which should be the same as the one used for generating the event listener line. So with the Array of abilities, const = ['AnimalKen', 'Art', 'Awareness' .... ] containing every section you want to collapse. The difference is you'll need to pass this into the setAttrs() sheetworker, which requires an Object. You can still use .map() like before, but we don't need the return value that .map() provides (as it's an Array, and we need a normal Object), so it's slightly more efficient to use .forEach() - it does almost the same thing (iterates over an Array), but it doesn't return a value: const &nbsp; collapseAll &nbsp;=&nbsp;()&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;Initialise&nbsp;an&nbsp;empty&nbsp;object &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; output &nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;Iterate&nbsp;over&nbsp;the&nbsp;abilities&nbsp;to&nbsp;create&nbsp;all&nbsp;flag&nbsp;attribute&nbsp;names &nbsp;&nbsp;&nbsp;&nbsp; abilities . forEach ( abil &nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output [ `collapse-flag- ${ abil } -diffmods` ]&nbsp;=&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output [ `collapse-flag- ${ abil } -dicepool` ]&nbsp;=&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp; console . log ( output ); &nbsp;&nbsp;&nbsp;&nbsp; /* &nbsp;&nbsp;&nbsp;&nbsp;Expected&nbsp;output: &nbsp;&nbsp;&nbsp;&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-AnimalKen-dicepool:0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-AnimalKen-diffmods:0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-Art-dicepool:0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-Art-diffmods:0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-Awareness-dicepool:0 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;collapse-flag-Awareness-diffmods:0&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;&nbsp;&nbsp;*/ &nbsp;&nbsp;&nbsp;&nbsp; setAttrs ( output ); } This creates an Object that can be passed straight into setAttrs to set every flag to 0. It's important here to do the iteration before we invoke setAttrs(). Everything before setAttrs() is occurring within the browser instance on your local PC, and is extremely fast. setAttrs() sends the changes to the remote database, and introduces a heap of lag - if you put it inside the .forEach() loop, it'll be invoked many times and introduce a massive amount of lag when using the sheet - you almost never want setAttrs() to run more than once form a user action. Note we also don't use a getAttrs() in this case - we don't care what the inital value of the flag is, as we're just collapsing everything. By introducing a parameter, you can also turn the function into a collapse all / expand all. You'll still want two separate buttons obviously, but they can invoke the same function in different ways: const &nbsp; collapseExpandAll &nbsp;=&nbsp;( collapse )&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;Defaulting&nbsp;to&nbsp;"expand"&nbsp;(1)&nbsp;means&nbsp;if&nbsp;it&nbsp;bugs&nbsp;out,&nbsp;at&nbsp;least&nbsp;the&nbsp;whole&nbsp;sheet&nbsp;is&nbsp;visible! &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; flagValue &nbsp;=&nbsp; 1 ; &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;If&nbsp;any&nbsp;truthy&nbsp;parameter&nbsp;is&nbsp;supplied&nbsp;to&nbsp;the&nbsp;function,&nbsp;it&nbsp;will&nbsp;collapse&nbsp;everything &nbsp;&nbsp;&nbsp;&nbsp; if &nbsp;( collapse )&nbsp; flagValue &nbsp;=&nbsp; 0 ; &nbsp;&nbsp;&nbsp;&nbsp; let &nbsp; output &nbsp;=&nbsp;{}; &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;We&nbsp;now&nbsp;reference&nbsp;'flagValue'&nbsp;instead&nbsp;of&nbsp;the&nbsp;hard-coded&nbsp;0&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; abilities . forEach ( abil &nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output [ `collapse-flag- ${ abil } -diffmods` ]&nbsp;=&nbsp; flagValue ; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; output [ `collapse-flag- ${ abil } -dicepool` ]&nbsp;=&nbsp; flagValue ; &nbsp;&nbsp;&nbsp;&nbsp;}); &nbsp;&nbsp;&nbsp;&nbsp; setAttrs ( output ); } //&nbsp;Now&nbsp;we&nbsp;just&nbsp;need&nbsp;the&nbsp;event&nbsp;listeners&nbsp;to&nbsp;invoke&nbsp;the&nbsp;function&nbsp;the&nbsp;required&nbsp;way //&nbsp;As&nbsp;this&nbsp;is&nbsp;a&nbsp;single&nbsp;button,&nbsp;you&nbsp;can&nbsp;ignore&nbsp;the&nbsp;event&nbsp;object&nbsp;if&nbsp;you&nbsp;wish on ( 'clicked:collapseAll' ,&nbsp;()&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; console . log ( `Collapsing&nbsp;all...` ); &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;You&nbsp;can&nbsp;supply&nbsp;almost&nbsp;anything&nbsp;here&nbsp;as&nbsp;a&nbsp;truthy&nbsp;value&nbsp;-&nbsp;'I&nbsp;love&nbsp;collapsing',&nbsp;124908,&nbsp;true,&nbsp;'true',&nbsp;1 &nbsp;&nbsp;&nbsp;&nbsp; collapseExpandAll ( true ); }); on ( 'clicked:expandAll' ,&nbsp;()&nbsp; =&gt; &nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp; console . log ( `Expanding&nbsp;all...` ); &nbsp;&nbsp;&nbsp;&nbsp; //&nbsp;Any&nbsp;falsy&nbsp;value&nbsp;-&nbsp;false,&nbsp;undefined,&nbsp;null,&nbsp;0&nbsp;(but&nbsp;not&nbsp;"0")&nbsp;or&nbsp;completely&nbsp;empty &nbsp;&nbsp;&nbsp;&nbsp; collapseExpandAll (); }); Toby said: So using the above, I'd like to be able to have something like: console.log("This section is called: " + insertSpaces(${target}) + "."); and get something like: This section is called: Animal Ken. Obviously, the syntax isn't correct.&nbsp; I tried using above, and it obviously failed.&nbsp; Or I wouldn't be asking. You're very close - a template literal needs to be enclosed with `backticks` - unlike most JS strings, single and double apostrophes won't work. This is by design, so you can freely use apostrophes and quotes within a template literal without breaking anything. You'll also need to call your function inside the ${} code section - everything outside this is treated as text. console . log ( `This&nbsp;section&nbsp;is&nbsp;called:&nbsp;" ${ insertSpaces ( target ) } "` ); I'd highly recommend getting VSCode with ESLint up and running if you're going to delve into the JS side of things - or another IDE &amp; linter if you prefer. The error checking, syntax highlighting are invaluable in weeding out errors. For example, if I'd messed up the template literal with a a parenthesis instead of a brace, I'd know straight away because the function call is the wrong colour: console . log ( `This&nbsp;section&nbsp;is&nbsp;called:&nbsp;"$(insertSpaces(target)}"` );
My program of choice is Notepad++ is that acceptable?&nbsp; It does have a good deal of syntax highlighting for nearly any code or language.&nbsp; Although, I wish it had proper color for HeroLabs Parsing and Twine 2.0 SugarCube (a cyoa builder).
1630415080

Edited 1630415317
GiGs
Pro
Sheet Author
API Scripter
Oosh said: GiGs said: I also recommend lower case attribute names (though that's a rule I break often myself as I like camelCase too), because if you have any upper case letters in attribute names, you have to remember to lower-case them on the On() event line, and it's another thing that causes unnecessary confusion when helping newbies. Strange, that's what I thought too. One of the posts above I mentioned that, and then put strikethrough on the advice because it appears to be wrong. This output is from 3 on('clicked') listeners and 3 on('change') listeners, identical apart from the uppercase: The problem is it's inconsistent. Sometimes (maybe most of the time) using mixed case works on the ON() event line, but sometimes it won't. And when it doesn't, it's a pain to track down the error until you remember, "oh I used an upper case letter on that line" and suddenly things work magically. The official guidance is to always use lower case there, and if you don't, you will have problems - you just won't notice them immediately. Take it from a veteran who has encountered this problem too many times to mention - if you don't use lower case in the On event line, it will bite you in the ass sooner or later. But it'll creep up on you and you might not see it coming :)
Grr!&nbsp; I spent 30mins trying to type a reply only for the system to throw me a 404 error for this page and clear all my work typing..&nbsp; Eff IT!&nbsp; No niceities.. No preamble. I feel I have a basic understanding of the expand/collapse code.&nbsp; I've played around a bit and gotten it to work elsewhere in my sheet.&nbsp; However, I don't even know how to begin adapting it to work within a repeating section.&nbsp; I have updated my code on GitHub (<a href="https://github.com/TobyFox2002/WoD20Unified" rel="nofollow">https://github.com/TobyFox2002/WoD20Unified</a>).&nbsp; The new version of the HTML is _002c.&nbsp; Cause I wanted to save what I was working on once I moved from one section of the page to the next. I also figured out how to get some version of syntax highlighting to function as copy/paste.&nbsp; It is not as nice looking as the examples above, as it doesn't use dark mode.&nbsp; I'll have to see if I can get Notepad++ to do so.&nbsp; As for JSLint, apparently there is a version of Notepad with that.&nbsp; But I haven't figured out how to to install it. So, the specific repeating section is as follows: span { font-family: 'Courier New'; font-size: 10pt; color: #000000; } .sc0 { font-weight: bold; } .sc1 { color: #0000FF; } .sc3 { color: #FF0000; } .sc6 { font-weight: bold; color: #8000FF; } .sc8 { } .sc9 { color: #008000; } .sc10 { font-style: italic; background: #FEFDE0; } .sc11 { color: #0000FF; } &lt;div class = "repeating-container" &gt; &lt;fieldset class = "repeating_abilities repstyle-abilites" &gt; &lt;div class = "border" &gt; &lt;!-- Athletics ~ Mage | Werewolf | Vampire | Changeling | Shen | Mummy | Hunter | Bygone --&gt; &lt;ul&gt; &lt;!-- proll will be used for public rolls, gmroll will be used for rolls that are visable to the storyteller and the player * * and apiroll is for rolls using an api script or external helper such as power cards or blind whisper --&gt; &lt;li class = "rep-proll" &gt;&lt;button type = "roll" name = "roll_ability-proll" value = "proll [QUERY]" title = "%{selected|ability-proll}" &gt;&lt;/button&gt;&lt;/li&gt; &lt;li class = "rep-gmroll" &gt;&lt;button type = "roll" name = "roll_ability-gmroll" value = "gmroll [QUERY]" title = "%{selected|ability-gmroll}" &gt;&lt;/button&gt;&lt;/li&gt; &lt;li class = "rep-apiroll" &gt;&lt;button type = "roll" name = "roll_ability-apiroll" value = "apiroll [QUERY]" title = "%{selected|ability-apiroll}" &gt;&lt;/button&gt;&lt;/li&gt; &lt;li&gt;&lt;label class = "smlabel collapse-details" &gt;&lt;input type = "text" name = "attr_abilityName" /&gt; &lt;br&gt;&lt;span&gt; Abiltiy Name &lt;/span&gt;&lt;/label&gt;&lt;/li&gt; &lt;li class = "dicepool" &gt;&lt;input type = "checkbox" class = "610-skills" name = "attr_show-10d-skills" hidden /&gt; &lt;input type = "radio" class = "hd zero" name = "attr_abilityDots" value = "0" checked /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "1" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "2" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "3" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "4" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "5" /&gt; &lt;span&gt;&lt;/span&gt; &amp;nbsp;&amp;nbsp; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "6" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "7" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "8" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "9" /&gt; &lt;span&gt;&lt;/span&gt; &lt;input type = "radio" class = "hd" name = "attr_abilityDots" value = "10" /&gt; &lt;span&gt;&lt;/span&gt;&lt;/li&gt; &lt;li&gt;&lt;label class = "smlabel collapse-details" &gt;&lt;input type = "text" name = "attr_abilitySpec" placeholder = "Specialization" /&gt; &lt;br&gt;&lt;span&gt; Specialization &lt;/span&gt;&lt;/label&gt;&lt;/li&gt; &lt;/ul&gt; &lt;!-- &lt;input type="checkbox" name="attr_abil-min-show" class="collapse-show" value="1" hidden&gt; --&gt; &lt;button type = "action" class = "collapse-button" name = "act_collapse-ability-diffmods" /&gt; Difficulty Modifier &lt;/button&gt; &lt;input type = "hidden" name = "attr_collapse-flag-ability-diffmods" value = "1" &gt; &lt;div class = "abilBuffs collapse-details" &gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-DiffPerm" value = "0" /&gt; &lt;br&gt;&lt;span&gt; Perm &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-DiffMerFl" value = "0" /&gt; &lt;br&gt;&lt;span&gt; Merit/Flaw &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-DiffShapeShf" value = "0" /&gt; &lt;br&gt;&lt;span&gt; Form &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-DiffBuffs" value = "0" disabled /&gt; &lt;br&gt;&lt;span title = "Reserved for Future Use." &gt; Buffs &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-DiffTotal" value = "@{ability-DiffPerm} + @{ability-DiffBuffs} + @{ability-DiffMerFl} + @{ability-DiffShapeShf}" disabled /&gt; &lt;br&gt;&lt;span&gt; Total &lt;/span&gt;&lt;/label&gt; &lt;/div&gt; &lt;button type = "action" class = "collapse-button" name = "act_collapse-ability-dicepool" &gt; Dice Pool &lt;/button&gt; &lt;input type = "hidden" name = "attr_collapse-flag-ability-dicepool" value = "1" &gt; &lt;div class = "abilBuffs collapse-details" &gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-TempMod" value = "0" /&gt; &lt;br&gt;&lt;span&gt; Temp &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "number" class = "2dig" name = "attr_ability-PermMod" value = "0" /&gt; &lt;br&gt;&lt;span&gt; Perm &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;select class = "skAttrSz" name = "attr_ability-attribute" title = "@{ability-attribute}" &gt; &lt;option value = "0" &gt; • None &lt;/option&gt; &lt;option value = "@{Str-Total}" &gt; STR &lt;/option&gt;&lt;option value = "@{Dex-Total}" &gt; DEX &lt;/option&gt;&lt;option value = "@{Stm-Total}" &gt; STM &lt;/option&gt; &lt;option value = "@{Cha-Total}" &gt; CHA &lt;/option&gt;&lt;option value = "@{Man-Total}" &gt; MAN &lt;/option&gt;&lt;option value = "@{App-Total}" &gt; APP &lt;/option&gt; &lt;option value = "@{Per-Total}" selected &gt; PER &lt;/option&gt;&lt;option value = "@{Int-Total}" &gt; INT &lt;/option&gt;&lt;option value = "@{Wit-Total}" &gt; WIT &lt;/option&gt; &lt;/select&gt;&lt;br&gt;&lt;span class = "SkPoolLabel" &gt; Attribute &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "text" class = "3dig" name = "attr_ability-Buffs" value = "0" disabled &gt;&lt;br&gt;&lt;span title = "Reserved for Future Use." &gt; Buffs &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "text" class = "3dig" name = "attr_ability-Total" value = "@{abilityDots} + @{ability-Attribute} + @{ability-TempMod} + @{ability-PermMod}" disabled &gt;&lt;br&gt;&lt;span&gt; Total &lt;/span&gt;&lt;/label&gt;&lt;br&gt; &lt;/div&gt; &lt;button type = "action" class = "collapse-button" name = "act_collapse-ability-advanced" &gt; Advanced Details &lt;/button&gt; &lt;input type = "hidden" name = "attr_collapse-flag-ability-advanced" value = "1" &gt; &lt;div class = "abilBuffs collapse-details" &gt; &lt;label class = "smlabel" &gt;&lt;input type = "text" name = "attr_ability-infolink" placeholder = "http://" /&gt; &lt;br&gt;&lt;span title = "URL link to information on this ability." &gt; Info Link &lt;/span&gt;&lt;/label&gt; &lt;label class = "smlabel" &gt;&lt;input type = "text" name = "attr_ability-refID" disabled /&gt; &lt;br&gt;&lt;span title = "Repeating section ROW ID for use in macro buttons." &gt; Repeating Section ID &lt;/span&gt;&lt;/label&gt; &lt;/div&gt; &lt;input type = "hidden" name = "attr_collapse-flag-ability-advanced" value = "1" &gt; &lt;div class = "abilBuffs collapse-details" &gt; &lt;label class = "smlabel" &gt;&lt;textarea name = "attr_description" class = "sheet-desc" title = "@{repeating_abilities_$X_description}" &gt;&lt;/textarea&gt;&lt;br&gt;&lt;span title = "Allows text to be added for a desscription of the secondary ability. This will be displayed when the ability is rolled." &gt; Description &lt;/span&gt;&lt;/label&gt; &lt;/div&gt; &lt;input type = "hidden" name = "attr_collapse-flag-ability-advanced" value = "1" &gt; &lt;div class = "abilBuffs collapse-details" &gt; &lt;label class = "smlabel" &gt;&lt;textarea name = "attr_notes" class = "sheet-desc" title = "@{repeating_abilities_$X_notes}" &gt;&lt;/textarea&gt;&lt;br&gt;&lt;span title = "Allows text to be added for any user notes on the secondary ability. This will be displayed when the ability is rolled." &gt; Notes &lt;/span&gt;&lt;/label&gt; &lt;/div&gt; &lt;/div&gt; &lt;!-- End of Skill --&gt; &lt;/fieldset&gt; &lt;/div&gt; I haven't fully finished polishing it off.&nbsp; I intend to add in counting 0., 01, 02... and so on in the upper right hand corner.&nbsp; And some more style to the roll buttons based on config options.&nbsp; Not to mention I want to create code to display the row_id in the disabled text input field at the bottom (ease of user access). Not to mention some css wizardry to one button expand/collapse, a lock button to prevent size changes and a minimize mode that compresses it to the normal 3 column layout used by WoD with Talents on the left, skills in the middle and knowledge on the right.&nbsp; None of those are immediately important and I can do those gradually after the sheet is complete. Anyways, thanks again for continuing to assist.
Yikes, it took me three days and four browsers to to post my above post.&nbsp; FFS..&nbsp; I think there are some nasty browser compatability issues going on behind the scenes.