Currently, if a user does not have create grants for a term, then that term is disabled in term reference fields on the entity edit form. There are a couple issues with this approach:

  1. Having any form element the user cannot select is a usability no-no (per Bojhan).
  2. Since terms are only disabled and never hidden, all fields will list all values, which makes forms larger and more confusing.

Other possible behaviors are to hide some or all of the terms. Hiding all of the disallowed terms is most consistent, but has the following issues:

  1. The apparent taxonomy hierarchy is garbled whenever a parent term is disabled, but its child is not.
  2. Some sites use parent-level taxonomy terms as category labels for child terms.
  3. This method would break dependent dropdown-type widgets if a parent term is disallowed.
  4. The user might not realize there are terms he or she cannot control, or be confused that terms he or she sees listed elsewhere are not listed on the edit form.

Hiding all terms except those needed to maintain a meaningful hierarchy is probably the most desirable behavior. However, it has the following issues:

  1. It is actually complicated to calculate which disabled terms to show and which to hide, in part of taxonomy API limitations (see #1207326: Refactor taxonomy hierarchy API for performance, consistency, and convenience), and it adds overhead, especially for large taxonomies.
  2. Having some disabled terms visible and others hidden might be even more confusing than anything else.
  3. This method re-introduces the problem of non-usable form elements.
  4. This method would be the most difficult to degrade gracefully (see #1209122: Provide better graceful degradation when jQuery is not available.).

I experimented with the third option a bit, and there are technical considerations in addition to the usability question. This method did not work well with non-core widgets (Multiselect was buggy and Hierarchical Select did not work at all). Furthermore, simply applying the jQuery .hide() method to the elements left checkbox labels displayed, and multiselect boxes were not resized (so 2 or 3 terms were visible in a page-long box). More advanced jQuery would be needed.

In either the first case or the third, there should be better visual presentation for disabled elements. Browser CSS support for select options is, unfortunately, limited and inconsistent. However, we could at least provide a class on labels for disabled checkboxes/radios to make it more obvious that they are uneditable.

Another possibility would be to provide configuration allowing the administrator to choose which method is used, either globally or on a per-instance basis.

Comments

In my case I don't want users to be able neither to see nor to edit terms themselves so I'm ending up here with a non-usable form as described above...

#1: The form should still be usable; just awkward if there's numerous disabled items in the field. Other than a list of disabled items, is the form not working?

Yes everything is fine. Sorry I did not point that out clearly. The form is working, it's just a bad user experience having a ui element that cannot be edited in any way.

Just to mention that, this is my personal view on this situation, it's perfectly okay in the context I'm using it at the moment as it shows the editor while editing who else has the permission to update that node.

I just realized that I didn't even consider the case in which no terms in a fieldset had create grants, although this is a common scenario. It sounds from #1 like this is your case? It would be reasonable (and very easy) to hide the field entirely in that instance. Let me know if that sounds right and I'll roll a patch.

Yes. In think in some situations it can be a security risk if a user knows who else has rights on that node. (Maybe even more extensive rights). Another point that speaks for a hidden field is that this behaviour can bypass the list setting, e.g. if we want a user not to be able to see or change any terms on a node he will be able to see them anyway if he's allowed to edit that node in general-

I hope you understand what I mean, my english skills are going south.
However, I'd leave the choice to the user whether to show such "useless" forms or not.

I opened #1214660: Hide term reference field when user cannot edit it for the specific case where no items are editable, since it is much simpler to fix than this larger question. If we add the ability to configure for one option from 1-3 above, we can make that setting control #1214660: Hide term reference field when user cannot edit it as well.

Issue tags:+TAC UX

Tagging.

Forum Access currently does this, hiding all terms that are not editable. It doesn't do everything I want TAC to do of course, but just throwing that out there for someone who wants to develop this more.

Is it possible to disable, but show, disallowed parents; and to hide all other disallowed terms? This would leave hierarchies in place around allowed terms to support showing context, but also hide all other terms that have no functional value.

I also noticed that all of the select items are enclosed in div contexts. Is it possible to put a class on the div contexts so that CSS could be used to hide the disallowed items using 'display:none' ?

The option described in #9 was what I originally pursued for this issue, but I ran into a few, erm, technical limitations with the Form API (and the general lack of browser CSS support for options in general). See also the usability caveats in the issue summary.

Regarding #10, that also has the same caveats, and I think that might have the same problem as using .hide() -- the term select box will still get sized for them and so have weird blank space. It's worth testing, though. Thanks for the suggestion!

Edit: CSS classes and data about which terms are disallowed should already be attached to the form via jQuery, so you might look at TAC's jQuery object and see if you can adjust that to get the behavior you want. I'd love to review a patch for that. :)

Re #10

First, I'm dealing with a stack of radio buttons (only one valid choice). I'm hoping that a setting of 'display:none' will actually collapse the stack as opposed to a 'visibility:hidden' which would, I believe, leave blank space and possibly a floating, dimmed radio button - which I assume is the .hide() effect. I'm not sure what the overall effect would be if I was dealing with a multi-select combo-box.

Second, what I'm seeing on both the allowed and disallowed items is the same class assignments for the enclosing DIV:

class="form-item form-type-radio form-item-field-af-content-domain-und"

There is no distinction between an allowed or a disallowed term. As far as I can see your tac_create.js is modifying the form display by looking up the items based on term ID (tid) references and then modifying the class specification on the 'label' element and setting the 'input' element to disabled. I tried to play with it a little, but unfortunately I can read js easier than I can write it. (I've got an old brain.) What I was trying to do was to reference the enclosing DIV once you had found the correct elements to change. I wanted to put the 'display:none' on the DIV because I don't think it has any effect on the INPUT or LABEL elements, and the DIV should take them both out.

Is the alteration of the correct DIV elements something that can be done in Drupal? Is this part of the problems you were talking about relative to FAPI?

I am also interested in a solution that would add a class to the wrapping div, as recommended in #10 and #12.

In my case I have only one of a series of taxonomy terms that are valid for a given author or editor. I use a radio button list for presentation. I tested using the following changes to the TAC code:

In tac_create.js I inserted the following line of code (marked '+') behind line 31 (repeated below for reference):

      $(selector).attr('disabled','disabled');
+    $(selector).parent().attr('class','tac-disabled');

This should have given the enclosing div a class attribute of 'tac-disabled'

Then I added the following code to taxonomy_access.css:

div.tac-disabled {
display:none;
}

This functioned exactly as desired for the create form. All of my disabled TAC options disappeared as options on the form and the form collapsed to eliminate the dead space. Effectively I was able to eliminate all of the disabled items from view.

I then reviewed the item using the same user, and in the edit form I again only had one item displayed, the only valid item.

I then reviewed the item from another user who had edit but not create permission and that user had the full list of taxonomy terms showing, with the only valid item in normal text and the remaining terms dimmed and in italics (i.e., disabled, but showing).

The general technique of using 'display:none' on the enclosing div appears to work. However, modifying the tac_create.js to achieve the effect has limited value. The changes really need to be made in the PHP code, or the js file needs to be propagated for everyone rather than just those with create permission.

I would think it makes more sense to make the change in the PHP code. My problem is that I don't know how to find and address the enclosing div from the code.

Edit: I need to do a little more testing on this later. I went back again, and it looks like the change may have also worked for the editor role who does not have a create option. This would be the case if the tac_create.js is always being output. I may not have cleared cache before I did my prior test, or I may have had some other residual. If that is the case, then the tac_create.js change may fix the UI for my case.

Is there a way to include this in a hook for inclusion in another module? This would have the benefit of not this not breaking every time the TAC module is updated.

Well, the intention is to fix the issue in TAC. Patches or sponsorship welcome!

I'm not sure how to configure a patch. I'm having success with what I provided above in #14. My suggestion would be to only put the tac_create.js change into TAC. Then leave the CSS change as an exercise for developer/users. Some people want the disallowed terms visible, other want them hidden. Providing for both seems like more work than needed. The js change provides the mechanism to allow the CSS to do the job, but doesn't require it. The CSS change can be done anywhere and doesn't have to be done where it would get trampled by future TAC revisions.

interested

Currently, the list of disallowed terms contains terms without either view or add permission. I think it should be separated into two lists, or an attribute added to terms to show which they are.

If a user has the view permission, but not add, they should be able to see the term, but not select it in lists. If a user has neither add nor view, the term should be hidden from sight.

Also, in the access rules configuration, without view selected, the add check box should be disabled.

Re #19: The third point is very interesting. That would cleanly solve the issue here. It would be a fairly significant change, though, so I need to think more about that.

The disadvantage I can think of with making View tag a prereq for Add tag is this: Often, terms that are disallowed for Add tag are used to create hierarchy headers in the Add tag list. However, if we make view tag control whether they are shown, that means those tags also show up on nodes even if the user wants to hide them. Hmm.

The prerequisite idea is not really necessary. I'm primarily interested in hiding some terms from the select list completely, while allowing some to still display despite not being selectable.

Has any work been done on this? I'm facing the same issue - if the user cannot add or view tag it should be hidden and not disabled...

I have been using the workaround code in #14. Honestly, I think the code in 14 should be committed.

It's a workaround but there is no way to tell the difference between a tag the the user can see but not add and one they can neither see nor add.

Once you make the CSS change in #14 (along with the base change), the disallowed terms no longer show. The CSS change can be made elsewhere as a general CSS override, so you don't have to mess with TAC supplied code if the base change is made to the js file.

What I'm not sure of is how this looks if you are using a hierarchical taxonomy. But without a hierarchy, the disallowed terms do not show.

I have a hierarchical taxonomy and the term simply disappears, all other terms remain with the same number of dashes as if the hidden term were still there. Thats not really a big deal IMHO, so long as they all show, which they do.

@beauz
If they cannot add it, then it shouldn't show up in a list when selecting a term. Otherwise you get asked "why is this one grayed out?"

Depends how you are using it. On my site I have a taxonomy field on the user profile. This controls what articles they can see. However an admin with higher permissions should be able to select on of these terms, so the user can see that it exists but know they do not have access to change it. There is also other terms that should not be viewable at all, which should be disabled but also hidden from view. So I'd expect if they have view tag permissions they should be able to see a tag and if no add tag permission that it's disabled. Otherwise what's the point of separating these two permissions??

I appreciate my case is probably edge case but perhaps we could solve this by adding a setting to toggle it one way or the other? Default might be to hide disabled terms, but it would be great to have an option to keep disabled terms with view permission visible.

Subscribing... seems silly to display terms people can't actually choose. Can't really have "private" forums that way among other things.

Here's the code to add to your favorite _form_alter to disappear the terms that are not supposed to be listed.

<?php
function YOUR_MODULE_form_alter(&$form, &$form_state, $form_id) {
  if (
$form_id == 'forum_node_form') {
    global
$user;
    if (
user_access('administer taxonomy', $user) == false) {
     
$allowed_tids = taxonomy_access_user_list_terms();
      foreach(
$form['taxonomy_forums']['und']['#options'] as $tid => $term_name) {
        if (
is_numeric($tid) && !in_array($tid, $allowed_tids)) {
          unset(
$form['taxonomy_forums']['und']['#options'][$tid]);
        }
      }
    }
  }
}
?>

Naturally, replace YOUR_MODULE with your module :-)

Andrey.

I think this is an important issue and I think the best way would be to have configuration so that admins can choose their required behaviour.

Sometimes I have sites where disabled is a good thing and for others it is really not acceptable for users to be seeing options they aren't allowed to access and removing the options is preferred.