Problem with variable substitution to create a class

Hello everyone.

I’m trying to use a single macro to create all the Admonitions variants that require six macros in the add-on I created.
To do this, I created two additional parameters: styles (whose values ​​would be lateral or lateralb) and dropdown (with the value details).
Following @Scott_sauyet’s advice, I transformed the macro into a procedure, and everything seems to work except I can’t get the class to have the value I want. This also happens with the normal macro.
This is the code I’m using:

\procedure callout2(type:"note", src, title, width:"100%", class)
<$let theme-class   = {{{ [[$:/palette]get[text]get[color-scheme]else[light]addprefix[theme-]] }}} 
      callout-title = {{{ [<title>!is[blank]] :else[<type>titlecase[]]  }}}
      callout-style = {{{ [<style>!is[blank]then[<style>]] }}}
      icon-tiddler  = {{{ [all[tiddlers+shadows]tag[$:/tags/TimitAdmonitions/Image]contains:callout-type<type>]
                          :else[[$:/plugins/timit/admonitions/images/note]] }}}
      source        = {{{ [<src>get[text]else<src>] }}} >
<div class=<<theme-class>> style=`width:$(width)$`>
<div data-callout=<<type>> class=`callout <<callout-style>>`>
<div class="callout-title">
<div class="callout-icon"><$transclude tiddler=<<icon-tiddler>> field=text/></div>
<div class="callout-title-inner"><<callout-title>></div>
</div>
<$list filter="[<src>!is[blank]]" variable=ignore>
<div class="callout-content">
<$transclude tiddler=<<source>> field=title mode=block />
</div>
</$list>
</div>
</div>
</$let>
\end callout2

In this example, I’m just using one new parameter, callout-styles.

For some reason, it doesn’t create the class correctly. I’ve tried everything: ``, " ", {{{ }}}, using +[join[]], etc…, but it always ends up wrong.

class=`callout <<callout-style>>`>

If I separate callout from callout-style in this code: class="callout <> ", the admonition appears, but with the callout class, if I put it all together, the admonition doesn’t get any style.

I’m sure it’s something obvious, but I can’t figure it out. I’ve been reviewing the documentation, but I’m getting really confused and can’t figure anything out. The AI ​​tells me everything’s fine, but I know it’s failing a lot…
Does anyone know what I’m doing wrong?

Best regards, and thanks.

The backtick syntax used for substituted attribute values uses a special format for variables. You’d need to use this instead:

class=`callout $(callout-style)$`

This is a crucial difference because “normal” variables like <<callout-style>> don’t get replaced with their values in this context, so <<callout-style>> would be treated as a literal value referring to a (non-existent) class .<<callout-style>>.

But you also have some issues with your <<callout-style>> definition:

  • Syntax: {{{ [<style>!is[blank]then[<style>]] }}} has extra brackets: then[<style>] means “then use the literal value<style>” (rather than the value of the <<style>> variable)”. then<style> would be correct, but you don’t actually need it here at all: {{{ [<style>!is[blank]] }}} will produce the same result.
    • … and in fact, since the filter is so simple, you don’t really need callout-style = {{{ [<style>!is[blank]then[<style>]] }}} at all: you could get the same results and save a line of code by using the following instead:
class=`callout $(style)$`
  • Variable names: You’re using the variable <<style>> (or $(style)$) in your code, but you haven’t actually defined it anywhere in your procedure. On the other hand, you do have a procedure parameter class which you don’t seem be using anywhere, so I’d recommend replacing <<style>> and $(style)$ with <<class>> and $(class)$ respectively.
    • In theory, you could alternatively keep the <<style>> variable and change class to style in your procedure parameters. But to me, style implies an inline CSS rule like border: 3px solid red;, and that won’t work in this context.
class=`callout $(style)$`
   would be transformed to
class="callout border: 3px solid red;" --> doesn't work

So IMO, it’s better to use class as it clarifies the sort of values you should be giving the parameter.

4 Likes

Just for the record, I don’t believe I actually suggested the transformation, although I did offer advice on how to do it. I see a good reason to use procedures and other modern tools for new work (although see @EricShulman’s good arguments for the opposite point of view) so I would support doing this, especially as this is fresh development. But the differences are small and the advantage fairly minor. I wouldn’t do this change except when I was in the process of making other changes.

And all the advice from @etardiff is excellent, even if I might choose differently between “style” and “class”. (I might even pull out a thesaurus to find an alternative free of other implications, but that’s just me.)

1 Like

Hi Emily.

First of all, I apologize for being so overwhelmed with code testing yesterday that I ended up sending you the wrong one. That’s why the styles parameter (which I’ve now named model) wasn’t there, and the variable’s syntax was incorrect when creating the class.

I’ve created two variables; there’s only one in this code, since all admonitions models begin with callout, and the variants are made up of “-” + “name.” E.g., callout-lateral.
With the other parameter, which I don’t have in this code yet, it will be the same, except in this case it will be “-” + “details.” E.g., callout-lateral-details.
With these variables, I’ll be able to code all the admonitions models I have in a single procedure, or so I think.

That’s why the callout-model variable in the code has “then” and then “else.” Additionally, I’ll have to figure out how to code the state of the “details” element later, but for now, I want to focus on this small problem.

I changed the variables in the procedure from <<__varName__>>/[<__varName__>] to <<varName>>/[<varName>]. I assume this is correct.

This is the code I should have posted yesterday, but it’s not working for me:

\procedure callout2(type:"note", model, src, title, width:"100%", class)
<$let theme-class   = {{{ [[$:/palette]get[text]get[color-scheme]else[light]addprefix[theme-]] }}} 
      callout-title = {{{ [<title>!is[blank]] :else[<type>titlecase[]]  }}}
      callout-model = {{{ [<model>!is[blank]then[-<model>] :else[]] }}}
      icon-tiddler  = {{{ [all[tiddlers+shadows]tag[$:/tags/TimitAdmonitions/Image]contains:callout-type<type>]
                          :else[[$:/plugins/timit/admonitions/images/note]] }}}
      source        = {{{ [<src>get[text]else<src>] }}} >
<div class=<<theme-class>> style=`width:$(width)$`>
<div data-callout=$(type)$ class=`callout$(callout-model)$`>
<div class="callout-title">
<div class="callout-icon"><$transclude tiddler=<<icon-tiddler>> field=text/></div>
<div class="callout-title-inner"><<callout-title>></div>
</div>
<$list filter="[<src>!is[blank]]" variable=ignore>
<div class="callout-content">
<$transclude tiddler=<<source>> field=title mode=block />
</div>
</$list>
</div>
</div>
</$let>
\end callout2

I think the problem is in how this line is processed, but I’m not sure how to fix it. callout-model = {{{ [<model>!is[blank]then[-<model>] :else[]] }}}

Thank you very much for your help.

1 Like

Hi Scott.

Don’t think I felt pressured by your suggestion.

I’d already seen some discussion about using procedures over the original macros and wanted to test what switching from one to the other would be like.

The truth is, I’m not sure it offers any advantages for what I’m doing, but I also don’t have the programming knowledge to say for sure. My impression is, no.

What I appreciate is your idea of ​​unifying the generation of the different callouts into a single macro. It’s much more functional as you suggest, but at first, with what little I know, it seemed most reasonable to replicate the original codes. Now I think I’m capable of going a step further.

Best regards.

You have a missing close square bracket in the first filter run, and I don’t think that -<model> is going to work anyway.

Try this instead:

callout-model = {{{ [<model>!is[blank]addprefix[-]] }}}
callout-detail = {{{ [<detail>!is[blank]addprefix[-]] }}}

then you can use these variables to construct your callout classname, like this:

<div data-callout=$(type)$ class=`callout$(callout-model)$$(callout-detail)$`>

Hope this helps,
-e

2 Likes

Thanks, Eric.

It worked perfectly just as you said. But I have a question. If, when calling the macro, instead of “details,” I had “folded” as a parameter and its value, if set, was “yes.”

Could this code work to convert it to “-details”? callout-folded = {{{ [<folded>is[yes]]then[-detail] :else[] }}}

There is no is[yes] operator. use match[yes] to compare the <folded> variable with a literal yes text value.

Also, be careful to check your square brackets…
you have an extra bracket here: [yes]],
and a missing bracket here: [-detail]

callout-folded = {{{ [<folded>match[yes]then[-detail]] }}}

which you would use like this:

<div ... class=`callout$(callout-model)$$(callout-folded)$`>

-e

2 Likes

Hi Eric.

I’ll keep this in mind next time I need to use something similar. I wasn’t familiar with Mach. And I also have to be more careful with brackets; I always forget one. :man_facepalming:

Now I’ve been doing the same thing with the original macro (not a procedure) and I get an error when applying the format. The error must be in how the class is applied (I think, since the rest hasn’t changed). How do I get the callouts-details value to be applied here?

How can I get the value of the callout-model variable to be processed in this part of the code? <div data-callout=<<__type__>> class="callout<<callout-model>>">
If it were part of the macro’s parameters, I know I could use $callout-model$, but this isn’t the case…

I tried this but it didn’t work for me either: <div data-callout=<<__type__>> class="[callout <<callout-model>> +join[]]">

Here’s the full code, in case it helps:

\define callout(type:"note", model, src, title, width:"100%", class)
<$let theme-class   = {{{ [[$:/palette]get[text]get[color-scheme]else[light]addprefix[theme-]] }}} 
      callout-title = {{{ [<__title__>!is[blank]] :else[<__type__>titlecase[]]  }}}
      callout-model = {{{ [<__model__>!is[blank]addprefix[-]] }}}
      icon-tiddler  = {{{ [all[tiddlers+shadows]tag[$:/tags/TimitAdmonitions/Image]contains:callout-type<__type__>]
                          :else[[$:/plugins/timit/admonitions/images/note]] }}}
      source        = {{{ [<__src__>get[text]else<__src__>] }}} >
<div class=<<theme-class>> style="width:$width$;">
<div data-callout=<<__type__>> class="callout<<callout-model>>">
<div class="callout-title">
<div class="callout-icon"><$transclude tiddler=<<icon-tiddler>> field=text/></div>
<div class="callout-title-inner"><<callout-title>></div>
</div>
<$list filter="[<__src__>!is[blank]]" variable=ignore>
<div class="callout-content">
<$transclude tiddler=<<source>> field=title mode=block />
<$log message="Valor style:" output=<<__style__>>/>
</div>
</$list>
</div>
</div>
</$let>
\end callout

Thank you so much.

You can still use the substituted attribute value (backtick) syntax, even with the older \define macro:

<div ... class=`callout$(callout-model)$`>

Note that before the backtick syntax was available, a “filtered transclusion” would have been used to achieve the same result:

<div ... class={{{ [[callout]addsuffix<callout-model>] }}}>
or
<div ... class={{{ callout [<callout-model>] +[join[]] }}}>

-e

3 Likes

Hi Eric.

When I saw your first solution, I thought it couldn’t be true since I’d already tried it (I made a bunch of variations to see if any were correct… :sweat_smile:). I’ve re-created it and it doesn’t work, I don’t know why.

The last two work perfectly. :grin:

The error can’t be in the definition of the callout-model variable, otherwise the other two solutions wouldn’t work…

Umm… I was wrong (gasp!) about using substituted attribute syntax inside an old-style \define macro.

The problem is that unlike the newer \procedure syntax, the old-style macro syntax does some “pre-processing” to replace instances of $param$ with passed in parameter values and also replaces instances of $(variable)$ with values from variables defined OUTSIDE the macro definition.

As a result, $(callout-model)$ was being replaced with a blank value instead of performing the backtick substitution processing, while using the older “filtered transclusion” syntax works because it doesn’t use $(variable)$ syntax.

-e

1 Like

Thanks, Eric. I think Emily mentioned this to me in some thread, but I can’t quite remember.
Anyway, now that I have the other method you suggested, it’s working for me.

Again, I’m grateful to both of you for your advice and solutions.

I’ve already completed phase one of the plugin remodel. Now let’s move on to phase two. Let’s see if I can do it… :sweat_smile:

Best regards.

1 Like