Forum: Radiant CMS Custom Tags and Code reuse

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Michael J. (Guest)
on 2007-01-16 09:09
(Received via mailing list)
In the standard tags module there is alot of useful code however it's
not encapsulated in classes so I can't really build my custom tags
upon the existing tags.

I would really like access to "children:each" and just pass it an
options hash or something. Am I missing some code somewhere? Is there
some magic way to reference these tags via your own custom tags or
classes?

Also is there some good info on the way Tags work, after spending my
life in methods this syntax seems so odd and I haven't had much luck
trying to hunt down particular methods in the api.

Thanks-
Michael


BTW:
http://radiantcms.org/blog/2006/11/24/how-to-write...
was very helpful for building custom tags via the new extensions
method.
John W. Long (Guest)
on 2007-01-16 15:50
(Received via mailing list)
Michael J. wrote:
> In the standard tags module there is alot of useful code however it's
> not encapsulated in classes so I can't really build my custom tags
> upon the existing tags.
>
> I would really like access to "children:each" and just pass it an
> options hash or something. Am I missing some code somewhere? Is there
> some magic way to reference these tags via your own custom tags or
> classes?

To call out to another tag you can call render on a tag binding:

   tag 'child_urls' do |tag|
     tag.render('children:each', 'limit' => '5') do
       tag.render('url')
     end
   end

> Also is there some good info on the way Tags work, after spending my
> life in methods this syntax seems so odd and I haven't had much luck
> trying to hunt down particular methods in the api.

The basic principles of tag construction are covered in the Radius
quickstart guide:

http://radius.rubyforge.org/files/QUICKSTART.html

--
John L.
http://wiseheartdesign.com
Michael J. (Guest)
on 2007-01-16 21:06
(Received via mailing list)
> To call out to another tag you can call render on a tag binding:
>
>    tag 'child_urls' do |tag|
>      tag.render('children:each', 'limit' => '5') do
>        tag.render('url')
>      end
>    end

Thanks that really helped, one other question:

How do I pass locals into a tag I'm rendering from another tag?

For example I want to create my own custom tag that dynamically
generates the values for the <r:navigation> tag.

It would go something like:

  tag 'navigation_dynamic' do |tag|
    #some code to generate string of urls
    tag.render('navigation', 'urls' => 'url string here')
  end

The 'navigation_dynamic' would have the nested values that the
'navigation' tag expects, but how do I pass those in?

Thanks-
Michael
Sean C. (Guest)
on 2007-01-16 21:39
(Received via mailing list)
Michael,

I believe you can just set tag.locals.whatever inside the do...end
block.

Sean
Michael J. (Guest)
on 2007-01-16 22:46
(Received via mailing list)
> I believe you can just set tag.locals.whatever inside the do...end block.

I tried to set my locals to be the locals of the navigation tag like
this:

 tag 'navigation_dynamic' do |tag|
   tag.render('navigation', {'urls' => 'Resources:
/resources/;Search: /resources/resources-search/;'}) do
       tag.locals.navigation = tag.locals.navigation_dynamic
   end
 end

I got the error about including a 'normal tag', I tried a few
different approaches such as:
tag.locals.navigation = {:normal=>'yo'}

The navigation tag in the standard_tags.rb is kinda trick, could you
explain the first line some?

hash = tag.locals.navigation = {}
tag.expand
   raise TagError.new("`navigation' tag must include a `normal' tag")
unless hash.has_key? :normal

Also, is there a good way to log debugging from the tags?

Thanks-
Michael
Sean C. (Guest)
on 2007-01-16 23:03
(Received via mailing list)
The first line does two things: Assigns a blank Hash to
tag.locals.navigation and also assigns 'tag.locals.navigation' to the
local
variable 'hash'.

Since the next line is 'tag.expand', the block you pass would be
executed at
this point.  The "trick" is that if you re-assign
tag.locals.navigationinside that block, whatever you assigned it would
fall out of scope after
the block ends.

So, to get your values to pass through, you should either merge the
contents
of your navigation_dynamic local in to tag.locals.navigation like so:

tag.locals.navigation.merge! tag.locals.navigation_dynamic

or set each individual key:

tag.locals.navigation[:here] # = something
tag.locals.navigation[:normal] #= something

The 'r:navigation' tag also expects that the elements in that hash will
be
tag-binding Procs (for lack of a better word).

I have a plan for the <r:navigation> tag that I haven't completed yet,
but
it will allow you to have both external links and dynamically generated
menus, so you could have something like:

<r:navigation>
  <r:children:each>
    <r:item>
      <r:label><r:title /></r:label>
      <r:href><r:url /></r:href>
    </r:item>
  </r:children:each>
  <r:normal>...</r:normal>
  ...
</r:navigation>

I also plan to have it support the old style for backwards
compatibility's
sake, or even a combination.

Cheers,

Sean C.

On 1/16/07, Michael J. <removed_email_address@domain.invalid> wrote:
> > I believe you can just set tag.locals.whatever inside the do...end
block.
Michael J. (Guest)
on 2007-01-16 23:25
(Received via mailing list)
Thanks for you help on this, i'm still struggling....

> The first line does two things: Assigns a blank Hash to
> tag.locals.navigation and also assigns 'tag.locals.navigation' to the local
> variable 'hash'.

If we assign a blank hash to navigation and assign that to a variable
called 'hash' how can it contain any values if we assigned a blank
one?

To establish a baseline I tried copying the existing 'navigation' code
into my custom tag (with name edits) and I'm still getting the 'normal
tag not found error'.

snippet:
<r:navigation_dynamic urls="[Resources: /resources/;Search:
/resources/resources-search/;Health: /resources/food-and-health/;]">
<r:normal><a href="<r:url />"><r:title /></a></r:normal>
<r:here><strong><r:title /></strong></r:here>
<r:selected><strong><a href="<r:url />"><r:title
/></a></strong></r:selected>
<r:between> | </r:between>
</r:navigation_dynamic>

head of custom tag;
  tag 'navigation_dynamic' do |tag|
        hash = tag.locals.navigation_dynamic = {}
        tag.expand
        raise TagError.new("`navigation_d' tag must include a `normal'
tag") unless hash.has_key? :normal


error:
`navigation_d' tag must include a `normal' tag

I've dumped my cache and restarted the server a bunch. How can I get
logging to see what is contained in 'tag.locals'?  Can you see what
I'm doing wrong here/

Thanks-
Michael
Sean C. (Guest)
on 2007-01-16 23:31
(Received via mailing list)
> If we assign a blank hash to navigation and assign that to a variable
> called 'hash' how can it contain any values if we assigned a blank
> one?


The tags that are rendered in the 'tag.expand' call set values in the
hash.
Look at their definitions and you'll see it.


> To establish a baseline I tried copying the existing 'navigation' code
> into my custom tag (with name edits) and I'm still getting the 'normal
> tag not found error'.


Make sure that you redefine each of the nested tags in under
'navigation'...
i.e. 'navigation:normal', 'navigation:here', 'navigation:selected',
'navigation:between'; change the prefix (part before the colon) on each
one
to 'navigation_dynamic'.

Sean
Michael J. (Guest)
on 2007-01-17 00:50
(Received via mailing list)
> The tags that are rendered in the 'tag.expand' call set values in the hash.
> Look at their definitions and you'll see it.

I must be missing it, I don't see an expand method anywhere other than
here:
http://radius.rubyforge.org/classes/Radius/TagBind...

And with that I don't see how the 'hash' is passed to that method
inorder to set values in it?
Sean C. (Guest)
on 2007-01-17 01:57
(Received via mailing list)
> I must be missing it, I don't see an expand method anywhere other than here:
> http://radius.rubyforge.org/classes/Radius/TagBind...
>
Ok, looks like I'll have to explain in more detail.  For reference, I'm
looking at
http://dev.radiantcms.org/radiant/browser/branches...
.

The second line inside the tag definition, line 463, calls
'tag.expand'.  This causes any tags nested inside (in the page, mind
you) to be rendered/evaluated.  The tags usually nested inside
<r:navigation> are listed starting at line 489.  Here's their
definitions:

  [:normal, :here, :selected, :between].each do |symbol|
    tag "navigation:#{symbol}" do |tag|
      hash = tag.locals.navigation
      hash[symbol] = tag.block
    end
  end

This generates tag definitions for everything in that array in the first
line of the snippet.  So, for each one, we grab the
'tag.locals.navigation' that was assigned by the *parent tag*
(originally blank), and assign the hash key associated with this tag to
the tag block.  So essentially, you're passing a block/closure/proc back
to the parent tag that can be evaluated contextually (multiple times).

So here's an overview, again:

1) <r:navigation> somewhere in your page invokes the tag definition.
2) We assign a blank Hash to tag.locals.navigation (and also,
incidentally, to a local var called 'hash' -- all variables are just
references/by-reference in Ruby, so they're really the same object)
3) We evaluate the contained block inside <r:navigation> by calling
tag.expand
3.5) Each contained tag of 'normal', 'here', 'selected', 'between'
assigns its contained block to a key in tag.locals.navigation for future
evaluation.
4) <r:navigation> evaluation continues -- parsing the urls/titles,
evaluating various of the passed blocks on each one, depending on URL,
then joining them together for output.

Let me know if I can clear anything else up.

Cheers,

Sean C.
Ruben D. Orduz (Guest)
on 2007-01-17 02:40
(Received via mailing list)
Hmmm this smells like and looks like a great candidate for the
Wiki...or is it just me?
Michael J. (Guest)
on 2007-01-17 03:15
(Received via mailing list)
> Hmmm this smells like and looks like a great candidate for the
> Wiki...or is it just me?

Yeah I agree, Sean has written up some pretty good stuff. I'll be
happy to wikify some notes on this once I figure it out.

Are wiki accounts open to anyone or do I need to get some account info
in order to post? Any special area this should be placed?
Ruben D. Orduz (Guest)
on 2007-01-17 03:29
(Received via mailing list)
Michael,

Anyone can open a Wiki account. If you don't find a good home for the
text, then you can create a page (it will be at the discretion of John
wether to leave it or remove it).
John W. Long (Guest)
on 2007-01-17 03:32
(Received via mailing list)
Michael J. wrote:
> Are wiki accounts open to anyone or do I need to get some account info
> in order to post? Any special area this should be placed?

You presently have to register and login in order to use the wiki.

--
John L.
http://wiseheartdesign.com
Michael J. (Guest)
on 2007-01-17 04:10
(Received via mailing list)
> Let me know if I can clear anything else up.

Whew! I'm finally rolling along on Radiant. Got the dynamic generation
of secondary nav menus worked out and now I'm easily adding my own
custom tags.

Thank you *very much* Sean for such detailed information. I'll get
some wiki info up on this.

The thing that I missed was:

 [:normal, :here, :selected, :between].each do |symbol|
  tag "navigation:#{symbol}" do |tag|
    hash = tag.locals.navigation
    hash[symbol] = tag.block
  end
 end

I didn't even recognize that this was multiple tag definitions, I
needed to make changes in that code.

Thanks-
Michael
Michael J. (Guest)
on 2007-01-17 20:06
(Received via mailing list)
I added a wiki HowTo that contains some of the great information I got
on this thread about the 'Navigation Tag'.

Thanks again for you great indepth explanations Sean. And for a great
CMS John.

http://dev.radiantcms.org/radiant/wiki/HowToUnders...

Cheers-
Michael
Ruben D. Orduz (Guest)
on 2007-01-17 20:56
(Received via mailing list)
Nice Wiki entry, Michael. I'm sure it'll come handy soon to many of
us. If not for the navigation tag itself, but for the tag
customization.
This topic is locked and can not be replied to.