Feature request: tag styling addition

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.

3 Likes

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 Like