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 it possible to use jquery in repeating sections?

December 21 (2 years ago)

Edited December 21 (2 years ago)

I'm trying to make an edit button to show/hide selects and textbox editors in my repeating sections (while always displaying the values in a <span> section). 

I've made an edit button that only changes the "editing?" boolean in the specific repeating section. And an event that listens  changes in the "repeating_abilities:editing" value. Still, while that means the getAttrs calls are automatically scoped to that repeating section, the jquery functions

 $20('.abilitySource').toggleClass("hidden");

still aren't scoped to that specific section, so clicking one edit button toggles the changes for every repeating section. Unfortunately because of the structure of the sections, that isn't acceptable -- choosing a "source" for your ability shows a second dropdown to choose a "type" specific to that source, and 

$20('.abilityType.' + values.repeating_abilities_abilitySource).toggleClass("hidden");

creates all kinds of chaos as a result, as it shows/hides the incorrect dropdown in other abilities with a different source.

Is there a css selector unique to repeating sections that I can pass to this function to target the jquery to just the elements within that section? Or an alternative solution I can use to show/hide specific elements within repeating sections?

My next thought would be to just hardcode in 100 or so "repeating sections" with unique IDs that stay invisible until they're turned on instead of using the built in repeating section functionality -- wouldn't be too hard since I already have a python script that dynamically writes the HTML/JavaScript for the sheet from a google sheet with information about the system since it's still in active development with some friends of mine -- but I can't imagine that there wouldn't be an "official" solution for this.

December 21 (2 years ago)

Edited December 21 (2 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

The character sheet implementation of jquery is useless when it comes to repeating sections. My preferred method for doing an edit mode like this is to use a checkbox:

HTML

<fieldset class="repeating_my-section">
  <input type="checkbox" name="attr_collapse" class="collapse" value="1">
  <span>
    Look ma I can always be seen
  </span>
  <span class="expanded">
    Look ma I hide
  </span>
</fieldset>

SCSS

Showing SCSS cause it's what I have the code in on my system.

.collapse-container,.repitem {
  position: relative;
}

.repitem,
.collapse-container {
  &:hover {
    .collapse{
      opacity: 1;
    }
  }

  .collapse {
    opacity: 0;
    position: absolute;
    right: -10px;
    top: 0px;
    border: 0px solid black;
    border-radius: 0;
    color: var(--selectedColor);
    text-transform: none;
    background-color: transparent;

    &:before {
      content: 'y';
      font-family: pictos;
    }

    &:checked {
      color: var(--unselectedColor1);
      background-color: transparent;

      ~.expanded,
      ~.collapse-container .expanded {
        display: none !important;
      }

      ~.expanded--empty:is(:not([value]), [value=''])+*,
      ~.collapse-container~.expanded--empty:is(:not([value]), [value=''])+* {
        display: none !important;
      }
    }

    &:not(:checked) {

      ~.collapsed,
      ~.collapse-container .collapsed {
        display: none !important;
      }
    }

    &:hover {
      color: var(--selectedColor);
    }
  }
}

.repcontainer.editmode {
  .collapse {
    display: none;
  }
}
December 21 (2 years ago)


Scott C. said:

The character sheet implementation of jquery is useless when it comes to repeating sections. My preferred method for doing an edit mode like this is to use a checkbox:

HTML

<fieldset class="repeating_my-section">
  <input type="checkbox" name="attr_collapse" class="collapse" value="1">
  <span>
    Look ma I can always be seen
  </span>
  <span class="expanded">
    Look ma I hide
  </span>
</fieldset>

SCSS

Showing SCSS cause it's what I have the code in on my system.

.collapse-container,.repitem {
  position: relative;
}

.repitem,
.collapse-container {
  &:hover {
    .collapse{
      opacity: 1;
    }
  }

  .collapse {
    opacity: 0;
    position: absolute;
    right: -10px;
    top: 0px;
    border: 0px solid black;
    border-radius: 0;
    color: var(--selectedColor);
    text-transform: none;
    background-color: transparent;

    &:before {
      content: 'y';
      font-family: pictos;
    }

    &:checked {
      color: var(--unselectedColor1);
      background-color: transparent;

      ~.expanded,
      ~.collapse-container .expanded {
        display: none !important;
      }

      ~.expanded--empty:is(:not([value]), [value=''])+*,
      ~.collapse-container~.expanded--empty:is(:not([value]), [value=''])+* {
        display: none !important;
      }
    }

    &:not(:checked) {

      ~.collapsed,
      ~.collapse-container .collapsed {
        display: none !important;
      }
    }

    &:hover {
      color: var(--selectedColor);
    }
  }
}

.repcontainer.editmode {
  .collapse {
    display: none;
  }
}



Thank you for the detailed response, it's a good one. I think macgyvering my own implementation of a "repeating section" will probably still work better for my purposes, as I'll probably end up needing to use jQuery to selectively hide elements "behind the scenes"/based on other calculations in the JavaScript, but I'll keep this solution in mind as well for the future. It's also good to get confirmation that the jQuery won't work for roll20's implementation of these sections. 

December 21 (2 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

Unfortunately, there's really no way to get repeating section behavior without actually using a repeating section. You can just make a ton of elements to have 100 or so "repeating items", but that will cause your sheet to suffer from attribute bloat and inevitably, you can't hard code in a number of elements to match what some player is going to want to do with their character.

The better option for conditionally showing/hiding elements of a repeating section is to simply expand on that collapse technique and create an attribute (attributes) to track the status of the things that can affect what is displayed. Then simply control the display of the item based on the value of the control attribute.

December 23 (2 years ago)

Edited December 23 (2 years ago)


Scott C. said:

Unfortunately, there's really no way to get repeating section behavior without actually using a repeating section. You can just make a ton of elements to have 100 or so "repeating items", but that will cause your sheet to suffer from attribute bloat and inevitably, you can't hard code in a number of elements to match what some player is going to want to do with their character.

The better option for conditionally showing/hiding elements of a repeating section is to simply expand on that collapse technique and create an attribute (attributes) to track the status of the things that can affect what is displayed. Then simply control the display of the item based on the value of the control attribute.

Thanks! I figured it out.

In case anyone like me with no background knowledge of css comes across this with the same issue, a simplified version of this based on attribute/input values would be:

<fieldset class =repeating_abilities>
    <input type="hidden" value="true" name="attr_editing" class="editing"/> // value modified by custom button in my case, but a checkbox also works

    <div class="editor">
        Source: <select name="attr_ability-source" class ="source"> //a dropdown list with a few options that you want to show/hide sections based on
            <option value="Divine">Divine</option>
            <option value="Profane">Profane</option>
            <option value="Arcane">Arcane</option>
        </select>

        <span class = "Divine"> //span elements with classes that describe what you want to show/hide
            <select name="attr_ability-type-divine" class="divine">
                <option value="Divination">Divination</option>
                <option value="Rejuvenation">Rejuvenation</option>
            </select>
        </span>
        <span class = "Profane">
            <select name="attr_ability-type-profane">
                <option value="Cataclysm">Cataclysm</option>
                <option value="Scourge">Scourge</option>
            </select>
        </span>
        <span class = "Arcane">
            <select name="attr_ability-type-arcane">
                <option value="Magisprudence">Magisprudence</option>
                <option value="Illusion">Illusion</option>
            </select>
        </span>
    </div>
</fieldset>

And then css:

.charsheet input.editing[value="false"] ~ div.editor {//don't display the "editor" div when editing=false
    display: none
}

.charsheet select.source:not([value="Divine"]) ~ span.divine {//when value is not "divine", hide the "divine" span
    display: none
}


.charsheet select.source:not([value="Profane"]) ~ span.profane {
    display: none
}

.charsheet select.source:not([value="Arcane"]) ~ span.arcane {
    display: none
}

Also note: select.source refers to a select with the css class "source" and similarly input.editing refers to an input (the hidden input) with the css class "editing", not the name "attr_editing", for clarity. Also, the tilde (~) is called a subsequent sibling combinator, it checks the condition on the left (cssSelector[value="someValue"]) and then applies the styling in the brackets to the "sibling" (other element with the same parent) on the right. So input.editing[value="false"] is asking 'is the value of the input with the class="editing" tag equal to "false"?' and if the answer is yes, it applies {display: none} to div.editor.

The wiki page about this is https://wiki.roll20.net/CSS_Wizardry and I would just search the page for "[value" to find the relevant sections. But I figured I'd include the above explanation as well because the examples don't always contain everything needed to follow them + some of this symbol-syntax is difficult to google because google ignores symbols in searches.


Edit: actually I appear to still be missing a component here, as it is still causing issues where changed to one repeating element affects the others. Not sure if that's caused by this or by other functions in my sheet. will continue troubleshooting.

December 23 (2 years ago)

Edited December 23 (2 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

I'll note that your select.source stuff is not actually doing anything. You can't interrogate the values of selects directly with css. You have to make a hidden or checkbox version and then check it with [value] or :checked respectively.

December 23 (2 years ago)

Edited December 23 (2 years ago)


Scott C. said:

I'll note that your select.source stuff is not actually doing anything. You can't interrogate the values of selects directly with css. You have to make a hidden or checkbox version and then check it with [value] or :checked respectively.


That's odd, because it's working as intended in that regard. The main thing I'm still struggling to figure out is how to get it scoped to a single repeating element (all the css syntax for the repcontainer stuff). Right now selecting "divine" does bring up the correct span and hide all the others. It just does that for every repeating_ability item. Maybe I need to go back and make sure I don't have any leftover stuff setting the classes with jquery.


Edit: yep, leftover jquery. Deleted that and wrote a script that sets the value of a hidden input to the value of the select. Now it doesn't work but at least it doesn't work correctly haha.

.charsheet  input.editing[value="false"] ~ div.editor { //this works (closes editor div)
    display: none
}

.charsheet  input.source[value="divine"] ~ div.editor {//this works (closes editor div)
    display: none
}

.charsheet  input.source[value="divine"] ~ .editor {//this works (closes editor div)
    display: none
}
.charsheet  input.source[value="divine"] ~ span.divine {//this doesn't? (doesn't close divine span
    display: none
}
Edit 2: I'm a little slow but I got there eventually. It wasn't working because ~ looks for an element with the same parent element. Therefore, ~ div.editor > span.divine is necessary.
December 23 (2 years ago)

Edited December 23 (2 years ago)

So, this appears to be the actual working solution to what I was trying to do (for posterity):

Html/javascript

<fieldset class =repeating_abilities>
    <input type="hidden" value="true" name="attr_editing" class="editing"/> // value modified by custom button in my case, but a checkbox also works
    <input type="hidden" value="true" name="attr_source" class="source"/> // value modified by the javascript, equal to the value of the source <select>

    <div class="editor">
        Source: <select name="attr_select-source" class ="source"> //a dropdown list with a few options that you want to show/hide sections based on
            <option value="Divine">Divine</option>
            <option value="Profane">Profane</option>
            <option value="Arcane">Arcane</option>
        </select>

        <span class = "Divine"> //span elements with classes that describe what you want to show/hide
            <select name="attr_ability-type-divine">
                <option value="Divination">Divination</option>
                <option value="Rejuvenation">Rejuvenation</option>
            </select>
        </span>
        <span class = "Profane">
            <select name="attr_ability-type-profane">
                <option value="Cataclysm">Cataclysm</option>
                <option value="Scourge">Scourge</option>
            </select>
        </span>
        <span class = "Arcane">
            <select name="attr_ability-type-arcane">
                <option value="Magisprudence">Magisprudence</option>
                <option value="Illusion">Illusion</option>
            </select>
        </span>
    </div>
</fieldset>

<script type="text/worker">
    on("change:repeating_abilities:select-source", function() {//code that sets a <input type="hidden"/> to the value of the select so it can be read by css
        getAttrs(["repeating_abilities_select-source"], function(values) {
            setAttrs({"repeating_abilities_source":values.repeating_abilities_select-source});
        })
    });
</script>

css:
.charsheet  input.editing[value="false"] ~ div.editor {
    display: none
}

.charsheet  input.source:not([value="Divine"]) ~ div.editor > span.Divine {
    display: none
}

.charsheet  input.source:not([value="Profane"]) ~ div.editor > span.Profane {
    display: none
}

.charsheet  input.source:not([value="Arcane"]) ~ div.editor > span.Arcane {
    display: none
}

The ~ selector is sufficient for scoping the changes to the same repeating item, but > may be necessary if you've nested elements with div/span elements. 


Also I think the inclusion of the "~" symbol is causing a "Potential CSS security violation; character sheet template styling thrown out." error to print to my console, as in this thread, but it doesn't cause any actual issues with the functionality.

December 24 (2 years ago)
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator

That won't cause the security issue. The issue is likely caused by a word that contains a "dangerous" word like eval. The classic example is medieval. There are other possible causes, but the sibling selector definitely isn't it.

As for getting your select source into the hidden input. No need for JavaScript, just name the hidden the same and the r20 backend will take care of it.