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

Is There a Better Way to Style HTML in Chat Messages?

1594713736

Edited 1594714586
I use a lot of HTML in chat messages to my players, and I'm looking for a better way to do it.  I've tried three methods thus far, one of which works (but is cumbersome and time-consuming to use), and two others that don't. Working Method:  Function Wrappers to apply inline styles to each HTML element This method works, but (A) it requires pumping a lot of code into each chat message, (B) every style has to be individually included in every HTML element, as there is no cascading possible, and (C) it's a real pain to code in a flexible manner. Step 1: Define a bunch of functions for each type of HTML element (e.g. "Block", "Title", "Header", "Body", etc.).  Each function accepts a content parameter and an options object (for changing the default styles).  Here's an example of the "HTML.Title()" function: const   HTML   =  {      Title : ( content ,  options   =  {})  =>  {          // Overwrite the default styles with any passed-in options:          options   =   Object . assign ({              height :  "45px" ,              color :  COLORS . brightred ,              margin :  "0px" ,              fontFamily :  "sexsmith" ,              fontSize :  "32px" ,              lineHeight :  "45px" ,              bgColor :  "transparent" ,              border :  "none"         },  options );          // Then return the assembled HTML element, with inline styles and the content text:          return  `<span style="                     display: block;                     margin: ${ options . margin };                     font-weight: bold;                     color: ${ options . color };                     background-color: ${ options . bgColor };                     text-align: center;                     width: auto;                     font-family: ${ options . fontFamily };                     font-size: ${ options . fontSize };                     height: ${ options . height };                     line-height: ${ options . lineHeight };                     border: ${ options . border };                 ">                     ${ content }                 </span>` . replace ( / \s+ / gu ,  "   " )         }     }; Step 2: Combine it with other element-wrapper functions to assemble and output a chat message: sendChat (      D . RandomString ( 3 ),      "/w Storyteller   "   +        C . HTML . Block ([          C . HTML . Title (              "Testing Inline Styles" ,              { color :  C . COLORS . crimson}         ),          C . HTML . Header (              "I Know This Works" ,               { fontFamily :  "Voltaire" }         ),          C . HTML . Body (              `... but it's a lot of code being posted to Chat each time:                  I have to manually style each element, without any cascading.` ,              { textAlign :  "left" , fontFamily :  "Voltaire" , fontSize :  "14px" , lineHeight :  "16px" }          )     ] . join ( "" )) ); Result: ... which is great, but I'd much rather be able to make use of the cascading benefits of CSS classes.  Plus, consider that every single HTML tag in there has a lengthy "styles=' ... '" value, which is a lot of text being spammed to chat (even though most of it is hidden): How I'm Trying to Improve The Working Method So, yes, the above works, and while I've explained my problems with it, I think the main functionality I want is to be able to take advantage of CSS's ability to cascade styles, and combine multiple styles.  If I want a particular element to be a different font, color or alignment, I want to be able to to do it by simply adding a "font-voltaire" or a "color-red" class, and having it override the default class automatically according to standard CSS precedence rules, rather than having to configure and output the full inline style data for each element. Attempt #1: Add a <style> element with cascading styles on a per-message basis. Instead of inline styles applied to each element, I preempt the code block with a <style> element.  A few things to know: the sandbox automatically prepends each style with "userscript-", to explain the discrepancy in class names I wrapped the entire thing in its own <div> element, just in case isolating the <style> element would help sendChat (      D . RandomString ( 3 ),      "/w Storyteller   "   +     `<div>         <style>             .userscript-Block { ... }             .userscript-Title {                 display: block;                 font-weight: bold;                 color: ${ C . COLORS . mediumRed };                 text-align: center;             }             .userscript-Header { ... }             .userscript-Body { ... }         </style>         <div class="Block">             <div class="Title">                 Testing <style> Tag Styles             </div>             <div class="Header">                 Let's See If This Works             </div>             <div class="Body">                 Hopefully it does!             </div>         </div>     </div>` . replace ( / \s+ / gu ,  "   " ) ); Result: No dice.  Looking at the actual code in the developer console, Roll20 simply strips the <style> element and all of its styles completely. (Incidentally, if you're wondering about that "RandomString" bit, it's to ensure the "(From):" line is always there: If two chat messages are from the same person, the second one won't always include this line.  This is important because I need these lines to be a consistent height, so I can hide them with a "margin-top: -35px;" setting on the top-level Block element (see the result in Method #1).) Attempt #2: Using styles in my Character Sheet's css file. I mean, it works for roll templates, so why not try to get it to work for chat commands sent via sendChat()?  The following was added to the bottom of my character sheet css (along with styles for all of my other elements): .userscript-Title  {      display :  block ;      margin :  0 px ;      font-weight :  bold ;      color :  rgba ( 255 ,  31 ,  34 ,  1 );      background-color :  transparent ;      text-align :  center ;      width :  auto ;      font-family :  'sexsmith' ;      font-size :  32 px ;      height :  45 px ;      line-height :  45 px ;      border :  none ; } ... but, during processing, Roll20 adds ".charsheet" to the front of each one: ... and when I try to mimic this in the chat code, I'm instead calling on a "userscript-charsheet" style: I've tried to cheat this a few ways:  Adding a comma in front of my .userscript declarations in the css merely results in ".charsheet, .charsheet-userscript-Title" in Roll20, and nothing else I've tried seems to work. Conclusion Thanks for getting this far; I wanted to be thorough in describing everything, so apologies for the length.  If you have any ideas of things I might try (e.g. how to mimic the roll template behavior that does seem to bypass these issues, somehow, to apply styles from the character sheet's css to chat messages?  or maybe using pseudoclasses and CSS selectors might help?), I would be very thankful!
1594717168
GiGs
Pro
Sheet Author
API Scripter
Here's a trick I stole from Aaron. You can define styles like this:     const s = (o) => _.map(o, (v, k) => `${k}:${v};`).join(''); const styles = { dice: { 'font-size': '1em', 'border': '1px solid #333', 'border-radius': '.25em', 'height': '1em', 'width': '1em', 'text-align': 'center', 'margin': '1px', 'font-weight': 'bold', 'display': 'inline-block', 'background-color': 'white' }, p: { 'margin-top': '-2px', },     }; Then set up functions to build your output like so     const formatDie = (die) => `<div style="${s(styles.dice)}"><p style="${s(styles.p)}">${die}</p></div>`; It's still pretty clunky, and I've been planning to figure out how to make the handling of html tags more streamlined, but as it is, you can build pretty complex layouts and chain multiple styles together.
1594744836
The Aaron
Roll20 Production Team
API Scripter
1) above is the only viable option currently. I try to make that as painless as possible (like GiGs points out (thanks for saving me from needing to find an example!)).   With spread for objects coming, you can get some pseudo-cascading combinations. I alternate between using individual object properties and pure text strings. I've gotten to where I don't write html directly but rather compose function to build output (you can see that in TokenMod, Bump, etc).  There is a suggestion for API stylesheets, which is love. 
1594748152
Gold
Forum Champion
The Aaron said: There is a suggestion for API stylesheets, which is love.  Anyone know the Voting link? Will toss +1 to this if Arcane Scriptomancer says it would be useful
1594750514
The Aaron
Roll20 Production Team
API Scripter
Hmm.. looks like it predates the current suggestions forum... guess someone should make a new one...
1594823631
Gold
Forum Champion
There is an API in the one-click called HTML Builder, does that help with this? It installs automatically as a dependency when I install another common API script.
1594828681
Ada L.
Marketplace Creator
Sheet Author
API Scripter
Gold said: There is an API in the one-click called HTML Builder, does that help with this? It installs automatically as a dependency when I install another common API script. It wouldn't really help with OP's problem. It basically just does what Aaron's doing to apply styles.
1594852986
Gold
Forum Champion
Stephen, I sure do appreciate yours and The Aaron's API script contributions to the community. Most of the API that I use regularly and recommend to others are created by Stephen or The Aaron. Stephen L. said: Gold said: There is an API in the one-click called HTML Builder, does that help with this? It installs automatically as a dependency when I install another common API script. It wouldn't really help with OP's problem. It basically just does what Aaron's doing to apply styles.
I'm not a coder, nor am I particularly sure if I understand OP's question, but if I do, here's how I've handled it... Earlier this year I built a custom HeroClix platform in Roll20 to host games with my friends. In order to output dial information from the figures I modified PowerCards to accept some custom CSS. Instead of using the one-click install, I grabbed the code off of Github. Around line 1750 in the code you'll find a bunch of replace functions that can add custom HTML and CSS. I duplicated one of the lines, gave it a new replacement value--something unique that wouldn't accidentally show up in the macro--and then added the function into my PowerCards macro as a wrapper. This allowed me to do a variety of CSS styling and include local fonts. The symbols are all a custom font that's called by a replacement wrapper. So, for example, each symbol has 'hci' around the value to display the custom font. The colored boxes are also defined by wrappers, but I use attribute_max calls to make the system dynamic. So @{selected|speed_1|max}@{selected|speed_1}@{selected|speed_1|max} outputs a numerical value for the character's speed at click 1 then it looks at the value stored in speed_1_max to determine what color that box should be. For Superman it's "10" and "Special" (the white box). For Batman it's "9" and "Charge" (the green box). So, again, not sure if this is what you're asking, but it's how I added CSS and HTML to my chat outputs. You'd just have to add the text you're looking to display into a PowerCard macro.
Thanks for all of the replies! One question I have that I only vaguely hinted at in my original post:  Roll templates appear in Chat, and are styled using CSS from the character sheet.  Would it be possible to make a "dummy" roll template that didn't actually display a roll, but simply displayed the text I wanted, thus letting me take advantage of the CSS styles from the character sheet?
1595004611
The Aaron
Roll20 Production Team
API Scripter
You can't create roll templates from the API, they must be part of a character sheet.  You could definitely create Roll Templates and append them to your character sheet with the intent of using them for API messages.
1595005042
GiGs
Pro
Sheet Author
API Scripter
If it's specifically for the script's output, you could create a function in your script that works like a rolltemplate. But it would only work for chat that comes through that script.