Using CSS to suppress vote options from view results with zero votes


(Danny Goodall) #1

Hi meta, Help please!

tl;dr I’ve wracked my (limited) brain on this but with no joy. Can someone tell me how I can hide the non-chosen poll items once you’ve participated in a poll?

For example, here is a screenshot of a poll where two people have voted:

What I would like to do, once there are results to view (i.e. I’ve taken part in the poll), is to remove the entries that have not received any votes (3. and 4. in this example).

Like this.

Now, I’ll concede that I’m far from being a CSS expert, but I’ve tried everything I can think of to target the elements that represent the options that have no votes.

Here’s the HTML I’m dealing with.

<div class="cooked">
    <p>Here is my poll</p>
    <div data-poll-name="poll2" data-poll-type="regular" class="poll">
        <div>
            <div class="poll-container">
                <ul class="results">
                    <li class="">
                        <div class="option">
                            <p>
                                <span class="percentage">50%</span>
                                <span>This one is too (but by somebody else)</span>
                            </p>
                        </div>
                        <div class="bar-back">
                            <div style="width:50%" class="bar">
                            </div>
                        </div>
                        <ul class="poll-voters-list">
                            <div class="poll-voters">
                                <li><a class="trigger-user-card " data-user-card="DanG"><img alt="" width="20"
                                            height="20" src="/letter_avatar_proxy/v2/letter/d/bc79bd/20.png" title="DanG"
                                            class="avatar"></a> </li>
                            </div>
                        </ul>
                    </li>
                    <li class="chosen">
                        <div class="option">
                            <p><span class="percentage">50%</span><span>This will be chosen</span></p>
                        </div>
                        <div class="bar-back">
                            <div style="width:50%" class="bar"></div>
                        </div>
                        <ul class="poll-voters-list">
                            <div class="poll-voters">
                                <li><a class="trigger-user-card " data-user-card="DanAdmin"><img alt="" width="20"
                                            height="20" src="blah"
                                            title="DanAdmin" class="avatar"></a> </li>
                            </div>
                        </ul>
                    </li>
                    <li class="">
                        <div class="option">
                            <p><span class="percentage">0%</span><span>And nor has this</span></p>
                        </div>
                        <div class="bar-back">
                            <div style="width:0%" class="bar"></div>
                        </div>
                        <ul class="poll-voters-list">
                            <div class="poll-voters"></div>
                        </ul>
                    </li>
                    <li class="">
                        <div class="option">
                            <p><span class="percentage">0%</span><span>But this one has not been selected by anyone</span></p>
                        </div>
                        <div class="bar-back">
                            <div style="width:0%" class="bar"></div>
                        </div>
                        <ul class="poll-voters-list">
                            <div class="poll-voters"></div>
                        </ul>
                    </li>
                </ul>
            </div>
            <div class="poll-info">
                <p><span class="info-number">2</span><span class="info-label">voters</span></p>
            </div>
            <div class="poll-buttons"><button class="widget-button btn btn toggle-results btn-icon-text" aria-label="Back to your votes"
                    title="Back to your votes"><svg class="fa d-icon d-icon-eye-slash svg-icon svg-node" aria-hidden="true">
                        <use xlink:href="#far-eye-slash"></use>
                    </svg><span class="d-button-label">Hide results</span></button><button class="widget-button btn btn toggle-status btn-danger btn-icon-text"
                    aria-label="Close the poll" title="Close the poll"><svg class="fa d-icon d-icon-lock svg-icon svg-node"
                        aria-hidden="true">
                        <use xlink:href="#lock"></use>
                    </svg><span class="d-button-label">Close</span></button></div>
        </div>
    </div>
</div>

What have I tried?

Theme component CSS

I’ve tried creating a theme component with CSS to target the elements I don’t want to display and applying display: none.

The issue, for my very limited CSS skills, is that I want to remove the li child elements of ul.results only if the embedded ul.poll-voters-list contains an :empty div.poll-voters.

i.e. I want to apply display: none to the li based on whether a grandchild div is empty.

li                        -> Hide this...
  ul.poll-voters-list 
    div.poll-voters       -> ...if this has no children

So my selector to get to the empty div is something like this:

.poll .results div.poll-voters:empty {
  display: none;
}

That works fine, but I need to target the display: none on the li element two levels up.

See <!-- comments --> below:

<div class="poll"...
.
.
.
  <ul class="results">
      <li class=""> <!-- I want to display this because the embedded div.poll-voters is not empty-->
          <div class="option">...</div>
          <div class="bar-back">...</div>
          <ul class="poll-voters-list">
              <div class="poll-voters"> <!-- NOT EMPTY-->
                  <li><a class="trigger-user-card " data-user-card="DanG"><img alt="" width="20"
                              height="20" src="blah" title="DanG"
                              class="avatar"></a> </li>
              </div>
          </ul>
      </li>
      <li class="chosen"> <!-- I want to display this because the embedded div.poll-voters is not empty-->
          <div class="option">...</div>
          <div class="bar-back">...</div>
          <ul class="poll-voters-list">
              <div class="poll-voters"> <!-- NOT EMPTY-->
                  <li><a class="trigger-user-card " data-user-card="DanAdmin"><img alt="" width="20"
                              height="20" src="blah"
                              title="DanAdmin" class="avatar"></a> </li>
              </div>
          </ul>
      </li>
      <li class=""> <!-- I want to TARGET with display: none this because it is not empty-->
          <div class="option">...</div>
          <div class="bar-back">...</div>
          <ul class="poll-voters-list">
              <div class="poll-voters"></div><!-- EMTPY! -->
          </ul>
      </li>
  </ul>
.
.
.
</div>

I’m sure someone with CSS/ SCSS expertise would have been able to set me right on this, but I soldiered on.

I spent a couple of days Googling and learning and found some kindred spirits who each lamented the omission of a parent selector in CSS. The general consensus seemed to be that JavaScript was the way to go.

Theme Component JavaScript / JQuery

I did a bit of mucking around with JQuery many years ago and thought I’d be able to get what I wanted with this. I soon realised that I’m not dealing with a ‘typical’ web page in Discourse. Instead new posts are added to topics dynamically as we scroll.

So a simply JQuery might work as long as the poll was not ‘off screen’ when the page was first rendered, but as soon as a new poll was scrolled into view, my JQuery code wouldn’t fire.

So, I dug around meta and found and read the excellent Developer’s Guide to Discourse Themes and realised I could jump on the back of the api.decorateCooked function to get the div.cooked structure each time it is added to the page.

I set out to write some code to target a div that is :empty with a class of poll-voters inside the div.poll structure, jump back up two .parents() and .addClass('bletch') so that I could then target that class with some simple CSS…

.bletch {
    display: none;
}

Well, to cut a VERY long story short, I had some fun, learned a lot but it LOOKS LIKE, the div.cooked structure that gets sent to the api.decorateCooked function for polls only includes the first level of the poll. Perhaps this is due to the dynamic nature of polls?

This made for a very frustrating time at the keyboard. Chrome’s dev tools were showing the structure and I’m looking at my code and can’t work out why I’m not able to target the elements that I can see in Chrome’s debugger!

To try to regain my sanity, I added this code to the </head> section of the theme component…

$( document ).ready(function() {
    e = $('.poll .results div.poll-voters:empty');
    e.parent().parent().addClass('bletch');
}

and sure enough I see this…

image

Some questions

Is it the case that the api.decorateCooked() function isn’t getting the entire polls structure but that it is instead fleshed out some time after the api.decorateCooked() function is invoked?

Is there another function I can sit on, perhaps called after new posts have been added to the topic?

Is there a function that is called once the polls are ‘cooked’?

If any JavaScript whizzes can put my right on this I’d be very grateful.

Or, hopefully, more likely someone can suggest a simple CSS selector that would get what I want?

Any advice gratefully received.

B


(Jeff Atwood) #2

I am unclear why you would want to do this in the first place? What does this accomplish?


(Danny Goodall) #3

I’m using polls to collect data for a behaviour management system at the school I work at. You’d be surprised how well Discourse works for collecting quantitative data intermingled with narrative.

As it is simply data capture about a single discrete event, in effect the first vote closes the poll.

Some of the polls have upto 60 options - when I’m asking for the minutes past the hour when an incident happened.
If the poll hasn’t been submitted I am able to use CSS to display the options inline so they don’t take up too much vertical space.

However, when there are poll results, the polls are very deep.


(Danny Goodall) #4

Any ideas Discourse community?