Feature request: tag styling addition

AI-generated summary

The discussion revolves around a feature request to add a tag-nameOfTheTag class to the top <li> element in the composer pane, allowing for easier styling and hiding of specific tags. jack2 explains the current issue, where hiding tags using CSS only works outside of the composer pane, and proposes the addition of the class to resolve this.

maiki questions the use case and suggests that CSS should not be used to visually hide valid elements in a form. jack2 responds with a detailed explanation of the use case and provides a temporary solution using a plugin initializer, which adds the tag-myTagName class to the <li> elements.

This solution allows for the hiding of tags using CSS, but notes that it does not disable the tag, and users can still type the name of the hidden tag and have it saved in the topic.

Being able to hide tags is a useful feature in many situations. Use cases have been discussed before, for example here and here.

This feature is implemented through a tag-nameOfTheTag class added to tags <a> links. For example, this is what you get in the tag dropdown of meta.discourse.org for the markdown tag:

<a href="/tags/markdown" id="ember1195" class="... tag-markdown ...">
   markdown
</a>

Hiding the tag is just a matter of providing a CSS rule of the form:

a.tag-markdown {
   display:none;
}

Using this technic, you can hide a tag everywhere in Discourse, except in the composer pane (input box and list box):

Tags there aren’t displayed through a simple <a>, but with a more complex markup:

<li class="...">    
   <div>
      <a class="tag-mytag ...">mytag</a>
   </div>    
   <a href="#" class="..." tabindex="-1"></a>
</li>

So if you try to hide the tag with CSS, the <a> link is hidden but the rest remains and is displayed.

To solve the problem, I suggest the tag-nameOfTheTag class to be added to the top <li>, in both the input box and the list box:

<li class="... tag-mytag ...">    
   <div>
      <a class="tag-mytag ...">mytag</a>
   </div>    
   <a href="#" class="..." tabindex="-1"></a>
</li>

My gut says CSS shouldn’t be used to visually hide valid elements in a form. I am sure I could find docs to support that.

What is your use case? The two you linked two were very different, one was a code change to the tag system, and the other was a CSS solve to a filtering issue. I can’t figure out what your use is, that isn’t solved by staff-only tags.

4 « J'aime »

Thanks @maiki. I will come back later with a detailed answer.

In the meantime, for those landing here in the future, here is a way to implement the feature in a plugin initializer (EDITED 08-18-2017):

import TagChooser from 'discourse/components/tag-chooser'

// Discourse extension to add tag-myTagName class to <li> elements
// See discussion here:
// https://meta.discourse.org/t/feature-request-tag-styling-addition/67744/3?u=jack2
//
// Implementation based on:
// https://github.com/discourse/discourse/blob/b5cc6851cf28bbaa775a9f8f9ee330ea9cd9cef8/app/assets/javascripts/discourse/components/tag-chooser.js.es6#L56
// https://github.com/select2/select2/issues/2830#issuecomment-75008648
// https://stackoverflow.com/a/25069704/3567351
// https://github.com/discourse/discourse/blob/5dbd6a304bed5400be481d71061d3e3ebb4d6785/vendor/assets/javascripts/select2.js#L1115
TagChooser.reopen({
	didInsertElement() {
		// Call the parent function, in order to actually create the 'select2' 
		// component
		this._super()

		// Get the 'select2' data
		const data = this.$().data('select2')

		// Add the tag-xxxx class to selection items
		// At this stage the selection has already been rendered, so we have to 
		// actually change the DOM
		data.selection.find('a.discourse-tag').each((i, el) => {
			const tagClass = $(el).attr('class').match(/(^|\W)tag-\S+/)
			$(el).closest('li').addClass(tagClass[0])
		})

		// Add the tag-xxxx class to dropdown items
		// At this stage the dropdown has not been rendered yet, so we can 
		// use the 'select2' API
		const fn = data.opts.formatResultCssClass || (() => {})
		data.opts.formatResultCssClass = (data, container) =>
			fn(data, container) + ' tag-' + data.id
	}
})

As mentioned by @maiki, notice that providing a CSS rule with display:none will only hide the tag, not disable it. A user can still type the name of the hidden tag and have it saved in the topic, even though the tag is never displayed.

1 « J'aime »