Edgewall Software
Modify

Opened 9 years ago

Closed 6 years ago

#2048 closed enhancement (fixed)

Wiki macros for generating `<div>`s and `<span>`s with classes

Reported by: cboos Owned by: cboos
Priority: high Milestone: 0.11
Component: wiki system Version: devel
Severity: major Keywords: macro wikiprocessor
Cc: dkg-debian.org@…
Release Notes:
API Changes:

Description (last modified by cboos)

My original request was:

I would like to have a wiki notation for highlighting sentences in a page, in a more striking way than just bold or italic.

Typical use cases would be for short words like "FIXME" or "TODO", that should immediately stand out from normal text, so that it would be clear that those are inlined comments to the text itself.

The proposed syntax would be: * TODO *

and would be rendered as: TODO

That particular example will be supported by the th:WikiGoodiesPlugin.

However, this ticket raises the more general concern that Trac core should have a macro that supports generating <div>s and <span>s with classes. This is even more necessary with 0.11, as there, the HTML processor blocks no longer support leaving elements open.

Attachments (4)

2048.patch (1.7 KB) - added by cboos 9 years ago.
patch against 0.9b1 (or close) for the proposed feature
div-span-macro.patch (2.2 KB) - added by cboos 8 years ago.
For the record, the latest version of the div & span macro (for source:trunk@2500)
div_span_macros.diff (7.8 KB) - added by cboos 7 years ago.
Add builtin div and span wiki processors - suggested fix for 0.11
ticket2048-patches.diff (11.8 KB) - added by cboos 6 years ago.
Updated patch - on top of source:/sandbox/context-refactoring@6135

Download all attachments as: .zip

Change History (39)

Changed 9 years ago by cboos

patch against 0.9b1 (or close) for the proposed feature

comment:1 Changed 9 years ago by cmlenz

I think this kind of stuff should be provided as a generic wiki macro, for example:

[[Block(warning)]]
==== Attention ====

Make sure you have PySQLite >= 1.1 installed to use SQLite 3.x.
[[Block]]

and (possibly):

[[Inline(todo)]]FIXME: better explanation[[Inline]]

These would get rendered as opening <div> or <span> tags, with the argument as value of the class attribute. When the macros are used without argument, a closing tag is rendered. Alternatively, we could provide four macros named [[BeginBlock]], [[EndBlock]], [[BeginInline]] and [[EndInline]]. Not sure which is better here (verbosity vs clarity).

I don't think we should be adding any more specific syntax constructs for specialized kinds of blocks. Different folks have very different requirements here, so instead of adding bloat to the core syntax, I'd rather see us adopt a generic solution like the one proposed above.

comment:2 Changed 9 years ago by cboos

For the block syntax, I think I have a good idea: as the macro syntax already accept mimeview processors (e.g. [[html(...)]]), why not make it symmetrical, and allow blocks to call macros:

 {{{
 #!Block(warning)
 ==== Attention ====

 Make sure you have PySQLite >= 1.1 installed to use SQLite 3.x.
 }}} 

As for the notation proposed in this ticket, I think it's really a matter of verbosity vs. usability. Having to specify a todo style for a content saying also TODO would be a bit too verbose for most users. I'd prefer to have something shorter to type (and as expressive):

  • [[Inline(todo)]]TODO[[Inline]] → bad, too verbose
  • [[TODO]] → would be <span class="todo">TODO</span>
  • [[WARNING: don't do that]] → would be <span class="warning">WARNING: don't do that</span>

That notation would feel very similar to the one used for macros.

comment:3 Changed 9 years ago by cmlenz

  • Milestone set to 0.9.1
  • Priority changed from normal to high
  • Summary changed from Add 'notice' style for the Wiki formatting to Wiki macros for generating `<div>`s and `<span>`s with classes

comment:4 Changed 9 years ago by cboos

Another proposal:

[[todo]]
That would create a div with class="todo"
And it could contain a nested 
[[urgent]]
div with class="urgent"
[[/urgent]]
[[/todo]]

and:

[[todo]]That would create a span with class="todo" [[/todo]]

Using XML-like markup like <underline>...</underline> would be another option, but this would introduce backward incompatible changes.

comment:5 Changed 9 years ago by cboos

  • Status changed from new to assigned

Yet another proposal:

[[div(todo, background: #dfc, border: 2px dotted #0d0)]]

That would create a div with class="todo",
and it could contain a nested 

[[div(urgent, font-style: italic)]]
div with [[span(underline)]]class="urgent"[[/span]]
[[/div]]

[[/div]]

which would be rendered:

That would create a div with class="todo", and it could contain a nested

div with class="urgent"

Of course, we should provide a standard set of classes that could be of general use (like todo, warning, … we already have system-message). Additional classes should be added in customized templates, so generally there wouldn't be a need to specify manually the CSS.

And the macro itself:

class DivSpanMacro(Component):
    """
    Begin (`div` or `span`) or end (`/div` or `/span`) a division or a span,
    using the first argument as the class name.
    
    The remaining arguments are optional and allow configuring directly
    the style of the rendered element. Each argument is a `key:value` pair.
    """
    implements(IWikiMacroProvider)

    def get_macros(self):
        for name in ('div', '/div', 'span', '/span'):
            yield name

    def get_macro_description(self, name):
        return inspect.getdoc(DivMacro)

    def render_macro(self, req, name, content):
        # /div or /span: end the block
        if name[0] == '/':
            return '<%s>' % name
        args = content.split(',')
        # div or span: we expect the 1st argument to be a class name
        if len(args) == 0:
            raise Exception("Missing class name.")
        html_class = args[0]
        keyval_re = re.compile('^([-a-z0-9]+):(.*)')
        quoted_re = re.compile("^(?:\"|')(.*)(?:\"|')$")
        style = {}
        for arg in args[1:]:
            arg = arg.strip()
            match = keyval_re.search(arg)
            if match:
                key = match.group(1)
                val = match.group(2)
                m = quoted_re.search(val) # unquote &#34; character "
                if m:
                    val = m.group(1)
                style[key] = val
        styles = '; '.join(['%s:%s' % x for x in style.iteritems()])
        style_attr = styles and ' style="%s"' % styles or ''
        return '<%s class="%s"%s>' % (name, html_class, style_attr)

comment:6 Changed 8 years ago by cmlenz

I don't agree about the builtin styles… if users need divs/spans with custom classes, they should be providing the CSS to do the layout. Also don't like allowing authors to specify inline styles, really.

Also, I still favor an explicit and somewhat more verbose syntax for blocks/divs:

[[BeginBlock(todo)]]
Bla bla bla bla
[[EndBlock]]

(I prefer the “block” to “div” as “block” is clearer about the intent IMHO.)

For spans, how about:

[[Inline(todo, I really need to do [ticket:123 this])]]

i.e. just include the text in the macro parameters.

We could provide [[BeginInline(todo)]] and [[EndInline]] for cases where spans need to be nested, which I think should be a really rare case.

Not stricly opposed to using “/” to end a block/span, need to think about that some more. :-P

comment:7 Changed 8 years ago by cboos

If you want to do:

[[Inline(todo, I really need to do [ticket:123 this])]]

then you'd need a recursive step of parsing, on the arguments. We do that elsewhere too (titles for example) but that's not optimal (also, I wonder if there wouldn't be an alternative solution for parsing titles without recursion).

Not being verbose was precisely what motivated me to fill this ER, because one can already do that being verbose:

[[html(<div class="todo">)]]
Bla bla bla bla
[[html(</div>)]]

So, not sure what do here… looks like a draw :)

Changed 8 years ago by cboos

For the record, the latest version of the div & span macro (for source:trunk@2500)

comment:8 Changed 8 years ago by anonymous

  • Keywords tools added

comment:9 Changed 8 years ago by anonymous

  • Keywords fun added

comment:10 Changed 8 years ago by mgood

  • Keywords tools fun removed

I don't think that those keywords are relevant. Please do not make edits to the tickets here for testing purposes. There is a demo site for that.

comment:11 Changed 8 years ago by cmlenz

  • Milestone changed from 0.9.1 to 0.9.2

comment:12 Changed 8 years ago by Pedro Algarvio <ufs@…>

Have any of you seen WikiTemplates Plugin? I does what you want. Yeah, syntax aint that simple but it has much more potentiality.

comment:13 Changed 8 years ago by cmlenz

  • Milestone changed from 0.9.3 to 1.0

comment:14 Changed 8 years ago by cmlenz

  • Milestone changed from 1.0 to 0.10

comment:15 Changed 8 years ago by Chris Ryland <cpr@…>

I'd vote for something drop-dead simple, such as

[[[ Normal Wiki text block, but formatted in a colored box like but in a different color, perhaps. ]]]

This could serve as pretty much anything: note, warning, todo, etc. Perhaps one could provide a small set of "icons" as called out at the start, e.g.,

[[[ #Note This is important. ]]]

That seems like the least syntax, and is easily remembered as parallel to .

comment:16 Changed 8 years ago by Chris Ryland <cpr@…>

(Whoops, there are some missing triple-curly braces in that previous post.)

I'd vote for something drop-dead simple, such as

[ Normal Wiki text block, but formatted in a colored box like pre-formattet text but in a different color, perhaps. ?]

This could serve as pretty much anything: note, warning, todo, etc. Perhaps one could provide a small set of "icons" as called out at the start, e.g.,

[ #Note This is important. ?]

That seems like the least syntax, and is easily remembered as parallel to pre-formatted text.

comment:17 Changed 8 years ago by cboos

  • Milestone 0.10 deleted
  • Priority changed from high to low

I think I'll move the original request over to my TracHack:WikiGoodiesPlugin …
(i.e. having * TODO * render as TODO)

As for the more general macro, well, I don't know, maybe I'll get a better idea later.

comment:18 Changed 7 years ago by cboos

  • Resolution set to wontfix
  • Status changed from assigned to closed

See above, moved to TracHacks:WikiGoodiesPlugin.

comment:19 follow-up: Changed 7 years ago by cmlenz

  • Milestone set to 0.11
  • Priority changed from low to normal
  • Resolution wontfix deleted
  • Severity changed from minor to normal
  • Status changed from closed to reopened

I do not agree with closing this. Being able to generate custom <div> and <span> elements in wiki text should be a core feature, especially now that HTML processor blocks no longer support leaving elements open!

comment:20 Changed 7 years ago by cboos

Well, I was referring to my original request.

Maybe should start a fresh ticket, don't you think?

comment:21 Changed 7 years ago by cmlenz

Seeing how all the relevant comments are in this ticket, and the summary has been adjusted, I don't think opening a new ticket would do any good.

comment:22 Changed 7 years ago by cboos

  • Description modified (diff)
  • Keywords macro wikiprocessor added

Well, OK, so I'll also adapt the description, to make this clear.

Any new idea on the topic, by the way?

comment:23 Changed 7 years ago by cboos

  • Status changed from reopened to new

Some new ideas: the syntax for generating <span> could be similar to the one of the macro call, but "opened":

 Do the checkout... [[small[[ (See screenshots below 
                               for help when using TortoiseSvn)
                    ]]small]]

(written on multiple lines on purpose, to show it's not a online [[<macro>[[...]]<macro>]] construct, but it doesn't need to be, of course).

That way, spans could be easily nested.

For <div>, one could do something similar using a special div WikiProcessor:

{{{
#!div(note)

'''Warning:''' This is important ...
}}}

Here again, this would easily allow for nesting, and is pretty close to the current way to do it using the html WikiProcessor.

Of course, this needs the ability to add arguments to WikiProcessors, something that was on my TODO list for some time now (e.g. would also give the ability to specify the annotations to be used for renderers).

comment:24 follow-up: Changed 7 years ago by mgood

The argument passing for WikiProcessors is a good idea, but I think I'd still prefer using a standard macro instead of adding a new syntax for [[class[[. Spans are used to do inline formatting, so requiring splitting the delimiters across lines seems counter-intuitive. It also doesn't seem to offer much benefit over [[span(small)]]some text[[/span]].

For <div>s I think we could use macros [[div]] and [[block]]. I like [[block]] myself, but I wouldn't mind providing both. For <span>s [[span]] and either [[inline]] or possibly [[style]]. I'd be +1 for adding macros div, block, and span and we can discuss an appropriate alias for span.

Passing arguments to WikiProcessors can be opened as a separate ticket since it applies beyond just this request, and we can extend these macros to support it once it's been implemented.

comment:25 in reply to: ↑ 24 Changed 7 years ago by cboos

Replying to mgood:

Good points. Thanks for the feedback.

comment:26 in reply to: ↑ 19 Changed 7 years ago by cboos

Replying to cmlenz:

I do not agree with closing this. Being able to generate custom <div> and <span> elements in wiki text should be a core feature, especially now that HTML processor blocks no longer support leaving elements open!

And as such, this solves the problem raised in #2428. But see the discussion there which would apply to the macros we're planning to implement here.

comment:27 Changed 7 years ago by dkg-debian.org@…

  • Cc dkg-debian.org@… added

comment:28 Changed 7 years ago by zimbatm@…

Hello,

most proposed solutions are about using macros. Why not add a class-definition syntax to the parser ? Macros seems a bit too verbose and you need to apply the closing macro correctly. I propose the ".class-name" syntax which mimics the css definition pretty well and which would be applied to the current scope. It could be used in conjunction with other styles. Some examples :

'''Do that !'''.urgent
=> <b class="urgent">Do that !</b>

or

{{{

Alien code

\}}}.green-and-horrible
=> <pre class="green-and-horrible">

Alien code

</pre>
}}}

Also, I would note that allowing css attributes is not a good idea. Since the restrictions made on the HTML processor are here to avoid spam, allowing something like "{{{[[BeginHTML(display:none)]]<a href="some spam link">...}}}" defeats their purpose.

comment:29 Changed 7 years ago by cboos

  • Priority changed from normal to high

Nice proposal, I like it: it's clean, intuitive and easy to implement.

For blocks: (ignore the leading "|", it's just there in order to not mess up the formatting…)

|
| {{{
| ...
| }}}.urgent
|
| {{{
| #!sh
| echo note that this would work with WikiProcessors as well
| }}}.important
|

And for spans, I think we should allow adding .class on {{{...}}} spans only. This will be consistent with the block styling and won't be too troublesome to implement.

Example: {{{TODO}}}.important : TODO

We might even recurse within the {{{...}}} span, e.g. {{{TODO '''urgently'''}}}.important : TODO urgently

Also, with this syntax, it's quite easy to specify multiple classes for a block or a span, by simply chaining them: .class1.class2.

One thing left to do is to specify how the classes are added. Ok for not allowing arbitrary CSS attributes, but how are the CSS rules for those classes specified, and how will the Wiki editors know about the available classes?

For a start, we could define a few hardcoded classes and list them in WikiFormatting.

comment:30 Changed 7 years ago by zimbatm@…

Also, with this syntax, it's quite easy to specify multiple classes for a block or a span, by simply chaining them: .class1.class2.

Yes, I've alread tought of that. I'm not sure that class chaining is a good thing even if it's easily doable. The user has then to cope with CSS definition orders. Like .green.red is not the same as .red.green if both have a background-color attribute.

One thing left to do is to specify how the classes are added. Ok for not allowing arbitrary CSS attributes, but how are the CSS rules for those classes specified, and how will the Wiki editors know about the available classes?

Just edit the template's CSS and document them in the WikiFormatting page. Some default classes could be added or you could think of an admin panel to define those custom CSS but that can be done later.

Some interesting investigation could be done on the relation between the ticket attributes and CSS classes.. would it be useful to link severity or other attributes to CSS styles ?

Cheers,

zimbatm

comment:31 Changed 7 years ago by cboos

  • Milestone changed from 0.11.1 to 0.11

comment:32 Changed 7 years ago by ThurnerRupert

  • Milestone changed from 0.11 to 0.11.1

nobody touched it for 3 months, its not a bug, so it seems to block 0.11 unecessarily …

comment:33 Changed 7 years ago by cmlenz

  • Milestone changed from 0.11.1 to 0.11

This is not a bug per se, but it still needs to be addressed for 0.11, because we're taking away the ability to define "open" HTML blocks using the HTML processor.

Changed 7 years ago by cboos

Add builtin div and span wiki processors - suggested fix for 0.11

Changed 6 years ago by cboos

Updated patch - on top of source:/sandbox/context-refactoring@6135

comment:34 Changed 6 years ago by cboos

  • Status changed from new to assigned

comment:35 Changed 6 years ago by cboos

  • Resolution set to fixed
  • Severity changed from normal to major
  • Status changed from assigned to closed

Update patch applied as a serie of changes in [6177:6182].

Add Comment

Modify Ticket

Change Properties
<Author field>
Action
as closed The owner will remain cboos.
The resolution will be deleted. Next status will be 'reopened'.
to The owner will be changed from cboos to the specified user.
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.