<!-- Core Rapid tags and tags that don't belong anywhere else. -->

<!-- Renders a table with one row per field, where each row contains a `<th>` with the field name, and a `<td>` with (by default)
     a `<view>` of the field.

### Attributes

 - fields: Comma separated list of field names to display. Defaults to the fields returned by the `standard_fields` helper. That is, all fields apart from IDs and timestamps.

 - force-all: All non-viewable fields will be skipped unless this attribute is given

 - skip: Comma separated list of fields to exclude

 - tag: The name of a tag to use inside the `<td>` to display the value. Defaults to `view`

 - no-edit: Controls the behavior of `<input>` tags when the user doesn't have edit permission for a field.
   - view: render the current value using the `<view>` tag
   - disable: render the input as normal, but add HTML's `disabled` attribute
   - skip: render nothing at all. This will omit the entire row (including the label)
   - ignore: render the input normally. That is, don't even perform the edit check.

 - no-blanks: (boolean) Controls the behavior of `<view>` tags. The entire row (including the label) will be omitted if `this` is blank. Default false.

### Example

    <field-list fields="first-name, last-name, city">
      <first-name-label:>Given Name</first-name-label:>
      <last-name-label:>Family Name</last-name-label:>
      <city-view:><name-one/></city-view:>
    </field-list>

-->
<def tag="field-list" attrs="tag, no-edit, no-blanks">
  <% tag ||= scope.in_form ? "input" : "view"; no_edit ||= "skip" %>
  <labelled-item-list merge-attrs="&attributes - attrs_for(:with_fields)">
    <with-fields merge-attrs="&attributes & attrs_for(:with_fields)">
    <% field_name = this_field_name
       input_attrs = {:no_edit => no_edit} if tag == "input"
    -%>
      <labelled-item unless="&(tag == 'input' && no_edit == 'skip' && !can_edit?) || (tag == 'view' && no_blanks && this.blank?)">
        <item-label param="#{scope.field_name.to_s.sub('?', '').gsub('.', '-')}-label" unless="&field_name.blank?">
          <do param="label"><%= field_name %></do>
        </item-label>
        <item-value param="#{scope.field_name.to_s.sub('?', '').gsub('.', '-')}-view" colspan="&2 if field_name.blank?">
          <do param="view"><call-tag tag="&tag" param="#{scope.field_name.to_s.sub('?', '').gsub('.', '-')}-tag" merge-attrs="&input_attrs"/></do>
          <div param="input-help" if="&tag.to_sym == :input && !this_field_help.blank?"><%= this_field_help %></div>
        </item-value>
      </labelled-item>
    </with-fields>
  </labelled-item-list>
</def>

<!-- Used to render nil values. By default renders "(Not Available)"

### Usage

Redefine in your app to have nil values displayed differently, e.g.:

    <def tag="nil-view">-</def>

-->
<def tag="nil-view"><%= scope.nil_view || "(Not Available)" %></def>

<!--
`<table>` is extended in Rapid to provide a shorthand way to output a set of fields for a given collection. This is enabled using the `field` attribute (without the `field` attribute this is just the regular HTML `<table>` tag)

### Usage

If the context is an array of blog posts...

    <table fields="name, created_at, description"/>

This will output a header row containing "Name", "Created At" and "Description" followed by a row for each record in the collection. By default, the `<view/>` tag is called for each field in the row. This can be altered with the `field-tag` attribute, e.g.

    <table fields="name, created_at, description" field-tag="input"/>

This will use `<input/>` as the tag in each table cell instead of `<view/>`

### Additional Notes

* `<table>` provides parameters based on the names of the fields which can be used to further customise the output. For each field a heading parameter is provided, e.g. name-heading, created-at-heading, description-heading. These can be used to customise the headings:

        <table fields="name, created_at, description">
          <created-at-heading:>Creation Date</created-at-heading:>
        </table>
* Similarly, "view" parameters are provided as an additional way to customise the table cells of the table body, e.g. `name-view`, `created-at-view`, `description-view`:

        <table fields="name, created_at, description">
          <created-at-view:><view format="%d %B %Y"/></created-at-view:>
        </table>
* By adding an empty `control` parameter, the default control column is enable adding an edit link and delete button for each table row:

        <table fields="name, created_at, description">
          <controls:/>
        </table>

    The controls can be further customised using the "edit-link" and "delete-button" parameters:

        <table fields="name, created_at, description">
          <controls:/>
          <delete-button: label="Nuke Me"/>
        </table>

    or by providing completely new content for the control column:

        <table fields="name, created_at, description">
          <controls:>my controls!</controls:>
        </table>
-->
<def tag="table" attrs="fields, field-tag, empty">
  <if test="&!(fields || all_parameters.tr?)">
    <%= element("table", attributes, all_parameters.default) %>
  </if>
  <else>
    <% field_tag ||= "view" %>
    <unless test="&this.empty? && !empty">
      <% element "table", attributes - attrs_for(:with_fields) do %>
      <thead if="&all_parameters[:thead] || fields" param>
        <tr param="field-heading-row">
          <with-field-names merge-attrs="&all_attributes & attrs_for(:with_fields)">
            <th param="#{scope.field_name}-heading"><%= this.member_class.human_attribute_name(scope.field_name) if scope %></th>
          </with-field-names>
          <th if="&all_parameters[:controls]" class="controls" param="controls-heading"/>
        </tr>
      </thead>
      <tbody param>
        <repeat>
          <tr param if="&can_view?"
              class="#{scope.even_odd} #{this_type.name.underscore} #{model_id_class}">
            <if test="&fields">
              <with-fields merge-attrs="&all_attributes & attrs_for(:with_fields)" force-all>
                <td param="#{scope.field_name.to_s.sub('?', '').gsub('.', '-')}-view"><call-tag tag="&field_tag"/></td>
              </with-fields>
              <td class="controls" param="controls" if="&all_parameters[:controls]">
                <a param="edit-link" action="edit" if="&can_edit?">
                  <t key="hobo.actions.edit_control">Edit</t>
                </a>
                <delete-button param/>
              </td>
            </if>
          </tr>
        </repeat>
      </tbody>
      <tfoot if="&all_parameters[:tfoot]" param/>
      <% end %>
    </unless>
  </else>
</def>

<!--
Provides a short hand way of displaying images in public/images

### Usage

    <image src="hobo.png"/> -> <img src="/images/hobo.png"/>
    <image src="blog/funny.jpg" alt="Funny Scene"/> -> <img src="/images/blog/funny.jpg" alt="Funny Scene"/>
-->
<def tag="image" attrs="src">
  <img src="#{base_url}/images/#{src}" merge-attrs/>
</def>


<!-- Renders an ajax-progress 'spinner' using `spinner.gif` from the current theme, with a `class='hidden'` -->
<def tag="spinner">
  <img src="#{base_url}/hobothemes/#{Hobo.current_theme}/images/spinner.gif" class="hidden" merge-attrs/>
</def>


<!-- Renders some standard JavaScript code that various features of the Rapid library rely on. This tag would typicallu be called from your `<page>` tag. The default Rapid pages include this already. -->
<def tag="hobo-rapid-javascripts">
  <script type="text/javascript" param="default"><%=
     res = 'var hoboParts = {};'
     # FIXME: This should interrogate the model-router - not the models
     unless Hobo::Model.all_models.empty?
       # Tell JS code how to pluralize names, unless they follow the simple rule
       names = Hobo::Model.all_models.map do |m|
                 m = m.name.underscore
                 "#{m}: '#{m.pluralize}'" unless m.pluralize == m + 's'
               end.compact
       res << "var pluralisations = {#{names * ', '}}; "
     end
     base = [base_url, subsite].compact.join("/")
     res << "urlBase = '#{base}'; hoboPagePath = '#{CGI.escape(request.fullpath)}'"
     if protect_against_forgery?
       res << "; formAuthToken = { name: '#{request_forgery_protection_token}', value: '#{form_authenticity_token}' }"
     end
     res.html_safe
  %></script>
</def>


<def tag="part-contexts-javascripts">
  <% unless (storage = part_contexts_storage).blank? %>
    <script type="text/javascript"><%=
      storage
    %></script>
  <% end %>
</def>

<!-- Renders the name of the current context using a variety of methods.

### Details

 - Equivalent to `<nil-view>` if `this` is nil
 - Equivalent to `<count>` if `this` is an Array
 - Equivalent to `<type-name>` if `this` is a class
 - If the context has a `name_attribute` defined, equivalent to `<view:abc/>` (where `abc` is the name attribute)
 - Finally falls back to `this.to_s` (html escaped), but only if the user has view permission for `this`

### Attributes

 - if-present: if given, nothing at all will be rendered for nil values (as opposed to rendering `<nil-view>`)

-->
<def tag="name" attrs="if-present"><%=
  if this.nil?
    nil_view unless if_present
  else
    if this.is_a?(Array)
      count
    elsif this.is_a?(Class)
      type_name(attributes)
    elsif (name_attr = this.class.try.name_attribute) && can_view?(this, name_attr)
      view(merge_attrs(attributes, {:field => name_attr}))
    elsif can_view?(this)
      h this.to_s
    end
  end
%></def>


<!-- Renders a human readable version of the type of the context

### Details

 - If `this` is already a class, the name of that class is used
 - Otherwise, first `this.member_class` (for collections), then `this.class` are tried
 - By default the name is titleised and singular.

### Attributes

 - plural: pluralise the name
 - lowercase: render the name in all lower case
 - dasherize: render the name in lower case with dashes instead of spaces.

-->
<def tag="type-name" attrs="plural, lowercase, dasherize"><%=
  type ||= (this if this.is_a?(Class)) || this.try.member_class || this.class

  name = type.respond_to?(:model_name) ? type.model_name.human : type.name
  name = dasherize ? name.underscore.dasherize : name.titleize
  name = name.pluralize if plural
  name = name.downcase if lowercase
  name
%></def>


<!-- Renders a human readable name of a collection

Use this tag for en locale only. Use human-collection-name for i18n.

### Details

 - Uses `this.origin_attribute` as the name.
 - Falls back to `<type-name>` otherwise.
 - By default the name is titleised and plural.

### Attributes

 - singular: singularise the name
 - lowercase: render the name in all lower case
 - dasherize: render the name in lower case with dashes instead of spaces.

-->
<def tag="collection-name" attrs="singular, lowercase, dasherize"><%=
  if (attr = this.try.origin_attribute)
    name = attr.to_s
    name = dasherize ? name.underscore.dasherize : name.titleize
    name = name.singularize if singular
    name = name.downcase if lowercase
    name
  else
    type_name(:plural => !singular, :lowercase => lowercase, :dasherize => dasherize)
  end
%></def>

<!--
`<a>` is extended in Rapid to automatically provide URLs for Hobo model routes

### Usage

The tag behaves as a regular HTML link or anchor if either the href or name attribute is given:

    <a href="/admin">Admin</a> -> Output is exactly as provided, untouched by Rapid

If no href or name is given then the _context_ is used to determine the link URL.
The helper method `object_url` is used to construct the URL using restful routing:

If the context is a class then the link will be an index page:

    <a with="&BlogPost">My Blog</a> -> <a href="/blog_posts">My Blog</a>

If the context is a hobo model instance then the link will be a show page:

    <% blog_post = BlogPost.find(1) %>
    <a with="&blog_post">My Blog Post</a> -> <a href="/blog_posts/1">My Blog Post</a>

An action can be provided for an alternative show page:

    <a with="&blog_post" action="edit">Edit Post</a> -> <a href="/blog_posts/1/edit">Edit Post</a>

Or a new page if the context is a class:

    <a with="&BlogPost" action="new">New Blog Post</a> -> <a href="/blog_posts/new">New Blog Post</a>

### Additional Features

* If the constructed route does not exist then the link will not be created, but the content of the link will still be output. E.g. when `/blog_posts` does not exist (because the hobo model controller does not exist or the index action is disabled):

        <a with="&BlogPost">My Blog</a> -> My Blog

    when the show action `/blog_posts/:id` does not exist:

        <a with="&blog_post">My Blog Post</a> -> My Blog Post
* If no content text is provided then `<a>` will use the name method on the context to provide the text. E.g.

        <a with="&blog_post"/> -> <a href="/blog_posts/1">My First Blog Post</a>`
        <a with="&BlogPost"/> -> <a href="/blog_posts">Blog Posts</a>`
* If `action="new"` then `<a>` will check that the current user has permission to create the object
* Several useful classes are added automatically to the output `<a>`.

### Attributes

* action:  If "new", triggers the special behaviour listed above.  Otherwise, contains the action to be performed on the context.   If neither `action` nor `method` are specified, the action will be "index" or "show", as appropriate.

* to:  Use this item as the target instead of the current context.

* params, query-params:  These are appended to the target as a query string after a "?".  Params are passed as a ruby hash.  Example: `params="&{id=>17, name=>'joe'}"`

* href, name:  If either of these attributes are present, the smart features of this tag are turned off.

* format: this adds ".#{format}" to the end of the url

* subsite: routes the URL using the subsite

* force: overrides the permission check if `action` is "new"

* method: "get", "put", "post" or "delete".  "get" is the default

-->
<def tag="a" attrs="action, to, params, query-params, href, format, subsite, force"><%=
  content = parameters.default

  params = self.query_params.merge(params || HashWithIndifferentAccess.new) if query_params

  if href || attributes[:name]
    # Regular link
    href += "?" + params.map { |n, v| "#{n}=#{v}" }.join('&') if !params.blank?
    element(:a, attributes.update(:href => href), content)
  else
    target = to || this

    if target.nil?
      Dryml.last_if = false
      nil_view
    elsif action == "new"
      # Link to a new object form
      new_record = target.new
      new_record.set_creator(current_user)
      href = object_url(target, "new", params._?.merge(:subsite => subsite))

      if href && (force || can_create?(new_record))
        new_class_name = if target.respond_to?(:proxy_reflection)
                           target.proxy_reflection.klass.name
                         else
                           target.name
                         end

        add_classes!(attributes, "new-#{new_class_name.underscore}-link")
        content = "New #{new_class_name.titleize}" if content.blank?
        Dryml.last_if = true
        element(:a, attributes.update(:href => href), content)
      else
        Dryml.last_if = false
        ""
      end
    else
      # Link to an existing object

      content = name if content.blank?

      href = object_url(target, action, (params || {}).merge(:subsite => subsite)) unless (action.nil? && target.try.new_record?)
      if href.nil?
        # This target is registered with Hobo::Routes as not linkable
        content
      else
        css_class = target.try.origin_attribute || target.class.name.underscore.dasherize
        add_classes!(attributes, "#{css_class}-link")

        href.sub!(/\?|$/, ".#{format}\\0") unless format.blank?

        # Set default link text if none given
        element(:a, attributes.update(:href => href), content)
      end
    end
  end
%></def>

<!--
Provides a read-only view tailored to the type of the object being viewed. `<view>` is a _polymorphic_ tag which means that there are a variety of definitions, each one written for a particular type. For example there are views for `Date`, `Time`, `Numeric`, `String` and `Boolean`. The type specific view is enclosed in a wrapper tag (typically a `<span>` or `<div>`) with some useful classes automatically added.

### Usage

Assuming the context is a blog post...

* Viewing a DateTime field:

        <view:created_at/> -> <span class="view blog-post-created-at">June 09, 2008 15:36</span>
* Viewing a String field:

        <view:title/> -> <span class="view blog-post-title">My First Blog Post</span>
* Viewing an Integer field:

        <view:comment_count/> -> <span class="view blog-post-comment-count">4</span>
* Viewing the blog post itself results in a link to the blog post (using Rapid's `<a>` tag):

        <view/> -> <span class="view model:blog-post-1"><a href="/blog_posts/1">My First Blog Post</a></span>

### Additional Notes

* The wrapper tag is `<span>` unless the field type is `Text` (different to `String`) where it is `<div>`. Use the `inline` or `block` attributes to force a `<span>` or a `<div>`, e.g.

        <view:body/> -> <div class="view blog-post-body">This is my blog post body</div>

        <view:body inline/> -> <span class="view blog-post-body">This is my blog post body</span>

        <view:created_at block/> -> <div class="view blog-post-created-at">June 09, 2008 15:36</div>
* Use the `no-wrapper` attribute to remove the wrapper tag completely. e.g.

        <view:created_at no-wrapper/> -> June 09, 2008 15:36
-->
<def tag="view" attrs="inline, block, if-blank, no-wrapper, truncate"><%=
  raise Hobo::PermissionDeniedError, "view of non-viewable field '#{this_field}' of #{this_parent.typed_id rescue this_parent}" unless
    can_view?

  res = if this.nil? && if_blank.nil?
          this_type.is_a?(Class) && this_type <= String ? "" : nil_view
        elsif (refl = this_field_reflection) && refl.macro == :has_many
          collection_view(attributes)
        else
          view_tag = find_polymorphic_tag("view")

          if view_tag == "view" # i.e. it didn't find a type specific tag
            if this.respond_to?(:to_html)
              this.to_html(scope.xmldoctype)
            else
              this.to_s
            end
          else
            attrs = add_classes(attributes, "view", type_and_field._?.dasherize, model_id_class)

            view_attrs = attrs_for(view_tag)
            the_view = send(view_tag, attrs & view_attrs)

            the_view = if_blank if if_blank && the_view.blank?

            truncate = 30 if truncate == true
            the_view = self.truncate(the_view, :length => truncate.to_i) if truncate
            the_view = the_view.html_safe? ? the_view.strip.html_safe : the_view.strip

            if no_wrapper
              the_view
            else
              wrapper = if inline
                          :span
                        elsif block || this_type <= HoboFields::Types::Text
                          :div
                        else
                          :span
                        end
              element(wrapper, attrs - view_attrs, the_view)
            end
          end
        end
   Dryml.last_if = !res.blank?
   res
%></def>

<!-- `<view>` calls this tag when called for a `has_many` collection. By default calls `<links-for-collection/>` -->
<def tag="collection-view" polymorphic><links-for-collection merge-attrs/></def>

<!-- Renders a comma separated list of links (`<a>`), or "(none)" if the list is empty -->
<def tag="links-for-collection"><%= this.empty? ? "(none)" : context_map { a }.safe_join(", ") %></def>

<!-- Renders `this` in localized :default format. `format` can be a symbol representing a locale key or a standard format string (see strftime) -->
<def tag="view" for="date" attrs="format"><%= this && (format||= :default) && I18n.backend.localize(I18n.locale, this, format) %></def>

<!-- Renders `this` in localized :default format. `format` can be a symbol representing a Time::DATE_FORMATS or a standard format string (see strftime) -->
  <def tag="view" for="time" attrs="format"><%= this && (format||= :time) && (format.is_a?(Symbol) ? this.to_s(format) : this.strftime(format) ) %></def>

<!-- Renders `this` in localized :default format. `format` can be a symbol representing a locale key or a standard format string (see strftime) -->
<def tag="view" for="datetime" attrs="format"><%= this && (format||= :default) && I18n.backend.localize(I18n.locale, this, format) %></def>

<!-- Renders localized `number_with_delimiter this`, or `format % this` if the `format` attribute is given -->
<def tag="view" for="Numeric" attrs="format"><%= format ? format % this : number_with_delimiter(this) %></def>

<!-- If `this.html_safe?`, returns this unchanged.  Otherwise renders `this` with HTML escaping and newlines replaced with `<br>` tags -->
<def tag="view" for="string"><%=
  if this.html_safe?
    this
  elsif !(this.class == String) && this.respond_to?(:to_html) # workaround for Maruku which adds String#to_html : (
    this.to_html(scope.xmldoctype)
  else
    h(this).gsub("\n", "<br#{scope.xmldoctype ? ' /' : ''}>").html_safe
  end
%></def>

<!-- Renders 'Yes' for true and 'No' for false -->
<def tag="view" for="boolean"><%= this ? t('hobo.boolean_yes', :default => 'Yes') : t('hobo.boolean_no', :default => 'No') %></def>

<!-- Renders a link (`<a>`) to `this` -->
<def tag="view" for="ActiveRecord::Base"><a merge-attrs/></def>


<!--
A convenience tag used to output a count summary with a correctly localized and pluralised label. Works with any kind of collection such as an `ActiveRecord` association or an array.

### Usage

    <count:comments/> -> <span class="count">1 Comment</span>

    <count:viewings/> -> <span class="count">3 Viewings</span>

The label can be customised using the `label` attribute, e.g.

    <count:comments label="blog post comment"/> -> <span class="count">12 blog post comments</span>

You can pass a summary attribute, which will generate a complete localized sentence. It allows 2 options:

- boolean (e.g. `<count summary/>`): it will lookup the 'tags.count.default' key in the locale file. If the lookup fails, it will fallback to the english default sentences consistent with the count.
- String (e.g. `<count summary="offer"/>`): it will lookup the 'tags.count.offer' key in the locale file.  If the lookup fails, it will fallback to the english default sentences consistent with the count.

### Examples

    it:
      tags:
        count:
          default:
            zero: "Non ci sono {{label}}"
            one: "C'è solo 1 {{label}}"
            other: "Ci sono {{count}} {{label}}"
          choice:
            zero: "Non ci sono {{label}} da scegliere"
            one: "Puoi scegliere solo una {{label}}"
            other: "Puoi scegliere tra {{count}} {{label}}"

with :en locale and boolean summary (internal defaults)

    <count:comments summary/> -> <span class="count">There is 1 Comment</span>
    <count:viewings summary/> -> <span class="count">There are 3 Viewings</span>

(note: just add the locale english strings to use like the following examples)

with :it locale and boolean summary (key "tags.count.default")

    <count:comments summary/>
    -> count => 0 -> <span class="count">Non ci sono Commenti</span>
    -> count => 1 -> <span class="count">C'è solo 1 Commento</span>
    -> count => 5 -> <span class="count">Ci sono 5 Commenti</span>

with :it locale and summary="choice" (key "tags.count.choice")

    <count:comments summary="choice"/>
    -> count => 0 -> <span class="count">Non ci sono Commenti da scegliere</span>
    -> count => 1 -> <span class="count">Puoi scegliere solo 1 Commento</span>
    -> count => 5 -> <span class="count">Puoi scegliere tra 5 Commenti</span>

### Additional Notes

* The `prefix` attribute is deprecated: use summary instead.

* Use the `lowercase` attribute to force the generated label to be lowercase:

        <count:comments lowercase/> -> <span class="count">1 comment</span>
* Use the `if-any` attribute to output nothing if the count is zero. This can be followed by an `<else>` tag to handle the empty case:

        <count:comments if-any/><else>There are no comments</else>
-->
<def tag="count" attrs="summary, label, if-any, lowercase, prefix"><span class="count"><%=
  raise Exception.new("asked for count of a string") if this.is_a?(String)
  Rails.logger.warn('The "prefix" attribute is deprecated: please, use a locale string') unless prefix.blank?

  c = collection_count

  # generated label will be pluralized
  label ||= case
            when this.is_a?(Class)
              this.model_name.human(:count=>c)
            when (attr = this.try.origin_attribute)
              (this_parent || this.origin).class.human_attribute_name(attr, :count=>c)
            else
              this.member_class.model_name.human(:count=>c)
            end

  label = label.downcase if lowercase

  Dryml.last_if = c > 0 if if_any
  if if_any && c == 0
    ""
  else
    if summary.blank?  # old behaviour
      main = label.blank? ? c : "#{c} #{label}"
      if prefix.in? %w(are is)
        prefix = c == 1 ? "is" : "are"
      end
      (prefix ? "#{prefix} #{main}" : main.to_s)
    else
      key = summary.kind_of?(String) ? summary : "default"
      default = c == 1 ? "There is 1 #{label}" : "There are #{c} #{label}"
      t "tags.count.#{key}", {:count=>c, :label=>label, :default=>default}.merge(attributes)
    end
  end
%></span></def>

<!-- Equivalent to `<you capitalize/>`-->
<def tag="You"><you merge capitalize/></def>

<!-- Renders a `<link rel="Stylesheet" type="text/css">` to include the default stylesheet for the selected theme (select with `<set-theme>`). Included in the default pages.
-->
<def tag="theme-stylesheet" attrs="name">
  <% name ||= Hobo.current_theme -%>
  <link href="#{base_url}/hobothemes/#{Hobo.current_theme}/stylesheets/#{name}.css"
        media="all" rel="Stylesheet" type="text/css" merge/>
</def>

<!-- Convenience tag to help with the common situation where you need to address the current user as "you", and refer to other users by name

### Usage

The context should be a user object. If `this == current_user` the "you" form is rendered, otherwise the form with the user's name:

- `<you have/> new mail` -> "you have new mail" or "Jim has new mail"
- `<you are/> now an admin` -> "you are now an admin" or "Jim is now an admin"
- `<you do/>n't want to go there` -> "you don't want to go there" or "Jim doesn't want to go there"

The tag is also localized in the namespaces "tags.you.current_user" and "tags.you.other_user".
Each namespace can contain the legacy keys "have", "are", "do" used for the respective attributes,
and "nothing" used when no attribute is passed. But you can also use your own keys, providing
that you add the keys in the correct namespaces.

### Examples

    it:
      tags:
        you:
          current_user:
            nothing: "Tu"
            have: "Hai"
            are: "sei"
            can: "Puoi"
          other_user:
            nothing: "{{name}}"
            have: "{{name}} ha"
            are: "{{name}} è"
            can: "{{name}} può"

- `<you have/> un nuovo messaggio.` -> "Hai un nuovo messaggio." or "Jim ha un nuovo messaggio."
- `Adesso <you are/> amministratore.` -> "Adesso sei amministratore." or "Adesso Jim è amministratore."
- `<you can/> scrivere.` -> "Puoi scrivere." or "Jim può scrivere."

(note: :name is added by default as an interpolable variable)

### Attributes

- capitalize: the first letter of the resulting sentence will be capitalized


### Additional Notes

The "titleize" attribute is deprecated: use "capitalize" instead.

-->
<def tag="you" attrs="titleize, capitalize">
  <% Rails.logger.warn "'titleize' is a deprecated attribute of the 'you' tag. Please, use 'capitalize' instead." -%>
  <% raise ArgumentError, "You can add only one attribute-key to the 'you' tag." if attributes.size > 1 -%>
  <% k = case
         when attributes[:have] then 'have'
         when attributes[:are] then 'are'
         when attributes[:do] then 'do'
         end -%>
  <if test="&this == current_user">
    <%= s = t("tags.you.current_user.#{k || attributes.keys.first || 'default'}",:default=>"you #{k}")
       (titleize||capitalize) ? s.sub(/^./){|c| c.upcase} : s %>
  </if>
  <else>
    <do param="default">
      <%= s = t("tags.you.other_user.#{k || attributes.keys.first || 'default'}", :name=>name(:no_wrapper => true),
          :default=>"#{name(:no_wrapper => true)} #{'has' if attributes[:have]}#{'is' if attributes[:are]}#{'does' if attributes[:do]}")
          (titleize||capitalize) ? s.sub(/^./){|c| c.upcase} : s %>
    </do>
  </else>
</def>

<!-- Equivalent to `<your ... capitalize/>`-->
<def tag="Your"><your merge capitalize/></def>

<!-- Similar to `<you>`, but renders "Your" or "Fred's" or equivalent localized strings

### Attributes

- capitalize: the first letter of the resulting sentence will be capitalized
- count: used in pluralization. If omitted it will be set to 1.
- key: used to lookup the translation in the locale file. It allows 3 different options:
   - single key like 'message': simple translation in 'tags.your.message.current_user'
     or 'tags.your.message.other_user'
   - composite key like 'any.namespace.message': translation as for the previous case, but it will
     translate also the 'any.namespace.message' and will interpolate the variable `<key>` (in this case :message)
     in the translation
   - when key is omitted it will be set to "default" and will do the translation with that key.
     Pass other meaningful attributes to achieve a dynamic usage
- any other attribute passed to the tag will be used as a variable for interpolation

Notes

- The :name variable is added by default as an interpolable variable
- If no translation is found an automatic (only english) default is generated:
   the Your/Jim's string, joined to the tag content.
   If you pass an explicit 'default' attribute you will override the automatic default.


### Examples

    it:
      tags:
        your:
          message:
            current_user:
              one: "Tuo Messaggio"
              other: "Tuoi Messaggi"
            other_user:
              one: "Messaggio di {{name}}"
              other: "Messaggi di {{name}
          entry:
            current_user:
              one: "Tua {{entry}}"
              other: "Tue {{entry}}"
            other_user: "{{entry}} di {{name}}"

- `<your key="message" count=>"&messages.count"/>`:

 - count => 1: "Tuo Messaggio" or "Messaggio di Jim"
 - count => 5: "Tuoi Messaggi" or "Messaggi di Jim"

- `<your key="activerecord.models.entry" count=>"&this.entries.count"/>`:

 - count => 1: "Tua Entrata" or "Entrata di Jim"
 - count => 5: "Tue Entrate" or "Entrate di Jim"

- `<your>Posts</your>`: "your Posts" or "Jim's Posts"
 -->
<def tag="your" attrs="key, capitalize, name"><%=
   key ||= 'default'
   name ||= name(:no_wrapper => true)
   # prepare symbolized attributes for merging
   attrs = {}
   attributes.each_pair{|k,v| attrs[k.to_sym] = v}
   d = "#{h name}'#{'s' unless name.ends_with?('s')} #{all_parameters.default}"
   options = {:default=>[d], :count=>(attrs[:count]||1), :name=>name}
   your_key = key.split('.').last
   unless key.eql?(your_key) || attrs.has_key?(your_key.to_sym)
     options[your_key.to_sym] = t(key, :count=>options[:count], :default=>your_key.titleize)
   end
   s = if this == current_user
         options[:default].unshift :"tags.your.default.current_user"
         t("tags.your.#{your_key}.current_user", options.merge(attrs))
       else
         options[:default].unshift :"tags.your.default.other_user"
         t("tags.your.#{your_key}.other_user", options.merge(attrs))
       end
   (capitalize ? s.sub(/^./){|c| c.upcase} : s).html_safe
%></def>

<!-- Capitalised version of `<a-or-an>` -->
<def tag="A-or-An" attrs="word"><%=
  (word =~ /^[aeiou]/i ? "An " : "A ") + word
%></def>

<!-- Deprecated. It's harder than you think to do this (e.g. an umbrealla, an user)
-->
<def tag="a-or-an" attrs="word"><%=
  (word =~ /^[aeiou]/i ? "an " : "a ") + word
%></def>


<!-- Renders a collection of string joined with ", ", or some other string passed in the `join` attribute -->
<def tag="comma-list" attrs="join"><%= this.join(join || ", ") %></def>


<!-- Development mode only - a menu to change the `current_user` -->
<def tag="dev-user-changer">
  <set user="&Hobo::Model::UserBase.default_user_model"/>
  <select-menu if="&user && Rails.env.development?"
               first-option="#{t('hobo.dev_user_changer.guest', {:default=>'Guest'})}" options="&user.all(:limit => 30).*.login"
               onchange="location.href = '#{dev_support_path :action=>:set_current_user}?login=' + encodeURIComponent(this.options[this.selectedIndex].value)"
               selected="#{current_user.login}"
               class="dev-user-changer"
               merge-attrs/>
</def>