Following the issue #511908: Values from "in_operator" exposed filters are double-escaped (SA-CONTRIB-2009-037 regression), views_handler_filter::exposed_translate does the magic of converting html checkbox input element display values into html select input element display values.

The problem is that html construct is allowed in checkbox display values (labels?), and references|contrib tried to utilized that to link user's name to its user page.

But in exposed filter selectbox it is shown as:

- Any -
<span class="views-field views-field-name"> <span class="field-content"><a href="/users/achry-febrianto" title="View user profile." class="username">Achry Febrianto</a></span> </span>
<span class="views-field views-field-name"> <span class="field-content"><a href="/users/ario-rahardjo" title="View user profile." class="username">Ario Rahardjo</a></span> </span>

Desired result I think is this:

- Any -
Achry Febrianto
Ario Rahardjo

So, maybe we should add strip_tags in there.

Following is the patch.

Notes: I also apply the strip_tags() to the radio thingy, assuming html is also allowed in its display value.

Comments

dawehner’s picture

Status: Active » Needs review

Update status

dawehner’s picture

Status: Needs review » Needs work
+++ b/handlers/views_handler_filter.incundefined
@@ -478,6 +482,10 @@ class views_handler_filter extends views_handler {
+      foreach ($form['#options'] as &$option) {
+        $option = strip_tags($option);

In this part the form element doesn't have to be select, maybe you should better check for select. It is possible that you still have checkboxes. Sorry

dozymoe’s picture

Status: Needs work » Needs review
StatusFileSize
new931 bytes

O M G... I did not see the exception (#no_convert) thrown in there.

Patch summary: the code strips html structure, if #type is "select", which later goes to check_plain() in form_select_options().

Might as well add decode_entities() in to the mix. :3

I'm worried about the last comment in stackoverflow though, that strip_tags() would nuke <b I forgot to close the tag. :S

dawehner’s picture

Don't you actually want to have
strip_tags(html_entity_decode($text, ENT_QUOTES)) ?

By the way the new patch looks much cleaner now!

dozymoe’s picture

I was grepping strip_tags from Drupal core, there's not many of them, I found:

  • check_plain(decode_entities(strip_tags($description))) in includes/common.inc line 1591
  • truncate_utf8(trim(decode_entities(strip_tags($comment_text))), 29, TRUE) from modules/comment/comment.module line 2181

and bunch of others, and took the generalization from there.

dawehner’s picture

Core seems to also just do a strip_tags _options_prepare_options i guess that's what we should do as well.

dozymoe’s picture

StatusFileSize
new1.35 KB

I think I overlook something else, both _options_prepare_options() and form_select_options() takes into account that the display value could be an array.

    // Recurse for optgroups.
    if (is_array($label)) {
      _options_prepare_options($options[$value], $properties);
    }
    if (is_array($choice)) {
      $options .= '<optgroup label="' . $key . '">';
      $options .= form_select_options($element, $choice);
      $options .= '</optgroup>';
    }

In that case the clean up logic should be in its own function, and do a recursive if the display value is an array, like they did with _options_prepare_options() and form_select_options().

On second thought, _options_prepare_options() looks very similar to form_select_options(), what's new is the strip_tags() and filter_xss() call, a clean up logic that should have been done in form_select_options() instead?

My next logical step is to copy _options_prepare_options(), except the filter_xss() part--I think that was meant for radios and checkboxes--in views; or let views depend of field|module for sake of lazyness. :p

Maybe core form.inc omitted strip_tags() on purpose to gain speed?

Hmm, this issue is now outside my comfort zone, should the clean up logic:

  • be a method of views_handler_filter
  • be a function inside file views_handler_filter.inc
  • be a function inside file views.module
  • move the issue to drupal form.inc
dawehner’s picture

Version: 7.x-3.1 » 6.x-3.x-dev
Status: Needs review » Patch (to be ported)
StatusFileSize
new1.55 KB

Changed the code a bit and committed it to 7.x-3.x

Thanks for your patch!
This would be probably helpful for a backport

adelka’s picture

Hi,

I have images as a label for checkboxes (configured in cck field as for example Sodexho|Only local images are allowed.).

When I use this field in exposed views, I cant see images but only html tags.

I tried first one solution and it worked only for radius, not checkboxes.

this one:
if ($form['#type'] == 'radios') {
$form['#type'] = 'select';
// Clean $form['#options'] from html tags.
foreach ($form['#options'] as &$option) {
$option = strip_tags($option);
}
}

When I tried the same for checkboxes (or whole patches) images are not visible (label is not generated, in html code is empty).

I also tried patches but didnt help.

Any clue what can be problem?

dozymoe’s picture

The patch was made with the assumption that only plain text is going to be the label on the options in select. We didn't expect an image as its label. Since we started with that assumption what the patch does is if you have this label before:

<img src="icon.png"> option number one

After it goes through the patched codes would turned in to (with html elements nuked out of existence):

 option number one

Also, as you can see in this dabblet mockup, even if you forced it, the browser isn't going to render the image element, natively.

What you want though is the #no_convert option, that I ran into at #3.

The #no_convert option, forced Views to display the checkbox element as is, in that Views does not convert (er, translate?) it to select element.

  /**
   * Make some translations to a form item to make it more suitable to
   * exposing.
   */
  function exposed_translate(&$form, $type) {
...
    // Checkboxes don't work so well in exposed forms due to GET conversions.
    if ($form['#type'] == 'checkboxes') {
      if (empty($form['#no_convert']) || empty($this->options['expose']['multiple'])) {
        $form['#type'] = 'select';
      }
...

The comment on that code about GET conversions is weird though, dunno what it meant.

adelka’s picture

unfortunately, none of the proposed solutions work :(

I tried last patch (1413750.patch) but I get an error:
Warning: html_entity_decode() expects parameter 1 to be string, object given v decode_entities() (riadok 429 z /data/e/-/e-donaska.sk/web/includes/unicode.inc).

If its not possible to show images, then abstracted text is also great alternative.

dozymoe’s picture

@adelka doesn't look like strip_tags() made an effort to extract alt, or title attribute out of an img element. :(

Also I think you are using core's Field module, as in you are making a Field with the type List (text) and the widget is Check boxes/radio buttons. So I'm quite sure that talking about writing php codes would complicate things.

Is it possible to do this instead:

Sodexho|<img title="Sodexho" src="sodexho.png"><span class="element-invisible">Sodexho</span>

Also for accessibility sake, if you have an image, make sure you have a textual representation of that image, usually in the form of alt attribute, except in this case strip_tags() would nuked it, not good. Naughty strip_tags(). That special visually hidden span element there served the same purpose I think. The title adds context in case someone is not clear of the icon's meaning. Err, but screen reader would read both the image title and the span next to it. Dunno.

Tagging with needs accessibility review (I wonder if that's a bit much :3).

Googling sodexho I found this. :o

Edit: err, the css rules for element-invisible wasn't available in Drupal 6. If you're using one you might need this in your theme css file.

/**
 * Hide elements visually, but keep them available for screen-readers.
 *
 * Used for information required for screen-reader users to understand and use
 * the site where visual display is undesirable. Information provided in this
 * manner should be kept concise, to avoid unnecessary burden on the user.
 * "!important" is used to prevent unintentional overrides.
 */
.element-invisible {
  position: absolute !important;
  clip: rect(1px 1px 1px 1px); /* IE6, IE7 */
  clip: rect(1px, 1px, 1px, 1px);
}

/**
 * The .element-focusable class extends the .element-invisible class to allow
 * the element to be focusable when navigated to via the keyboard.
 */
.element-invisible.element-focusable:active,
.element-invisible.element-focusable:focus {
  position: static !important;
  clip: auto;
}

Or this one from html5 boilerplate (replace visuallyhidden with element-invisible):

/* Hide only visually, but have it available for screenreaders: h5bp.com/v */
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }

/* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: h5bp.com/p */
.visuallyhidden.focusable:active, .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
adelka’s picture

Works amazing! THANK YOU DOZYMOE! :)

dozymoe’s picture

LAAAAATEEE REPLYYYYYYY -.-

skwashd’s picture

Version: 6.x-3.x-dev » 7.x-3.x-dev
Status: Patch (to be ported) » Needs review

The patch from #7 needs a review. Updating the status so it shows up on someone's radar.

Once this lands on 7.x, the patch can be backported to 6.x.

Status: Needs review » Needs work

The last submitted patch, 1413750.patch, failed testing.

skwashd’s picture

Status: Needs work » Fixed

I have tested this with 7.x-3.7 and it works without this patch. Closing.

Automatically closed -- issue fixed for 2 weeks with no activity.

Anonymous’s picture

Issue summary: View changes

Add - Any - to make it clear that the html code element is about select options.