<!-- Tags that define higher level interactive 'widgets' -->

<!-- An enhanced version of Rapid's `<table>` that has support for column sorting, searching and pagination.
  
This tag calls `<table merge-params>`, so the parameters for `<table>` are also available.

An [worked example](/tutorials/agility#improve_the_project_page_with_a_searchable_sortable_table) of this tag is available in the [Agility Tutorial](/tutorials/agility)

-->
<def tag="table-plus" attrs="sort-field, sort-direction, sort-columns" >
  <% sort_field ||= @sort_field; sort_direction ||= @sort_direction; sort_columns ||= {} %>
  <% sort_columns['this'] ||= this.member_class.try.name_attribute %>
  <div class="table-plus" merge-attrs="&attributes - attrs_for(:with_fields) - attrs_for(:table)">
    <div class="header" param="header">
      <div class="search">
        <form param="search-form" method="get" action="">
          <hidden-fields for-query-string skip="page, search"/>
          <span>Search</span>
          <input class="search" type="search" name="search" value="&params[:search]"/>
          <submit label="Go" class="search-button" param="search-submit"/>
        </form>
      </div>
    </div>

    <table merge-attrs="&attributes & (attrs_for(:table) + attrs_for(:with_fields))" empty merge-params>
      <field-heading-row:>
        <with-field-names merge-attrs="&all_attributes & attrs_for(:with_fields)">
          <% col = sort_columns[scope.field_path] || scope.field_path
             sort = sort_field == col && sort_direction == 'asc' ?
                      "-#{col}" : col
             sort_url = url_for(params.merge(:sort => sort) - [:page])
             col_heading_name = this.member_class.try.view_hints.try.field_name(scope.field_name) || scope.field_name.titleize %>
                          
          <th param="#{scope.field-name}-heading">
            <a href="&sort_url" class="column-sort" 
               param="#{scope.field-name}-heading-link"><%= col_heading_name %></a>
            <if test="&col == sort_field">
              <do param="up-arrow" if="&sort_direction == 'desc'">&uarr;</do>
              <do param="down-arrow" if="&sort_direction == 'asc'">&darr;</do>
            </if>
          </th>
        </with-field-names>
        <th if="&all_parameters[:controls]" class="controls"></th>
      </field-heading-row>
    </table>    
    <do param="empty-message" if="empty?">No <collection-name lowercase/> to display</do>

   
    <page-nav param if="&this.respond_to?(:page_count) || this.respond_to?(:total_pages)"/>
  </div>
</def>


<!-- An enhanced version of Rapid's `<collection>` tag that supports drag-and-drop re-ordering. 
  
Each item in the collection has a `<div class="ordering-handle" param="handle">` added, which can be used to drag the item up and down.
  
### Attributes

 - `sortable-options` - a hash of options to pass to the `sortable_elemnt` helper. Default are:

        { :constraint => :vertical,
          :overlap => :vertical,
          :scroll => :window,
          :handle => 'ordering-handle',
          :complete => [visual_effect(:highlight, attributes[:id])] }
          
### Controller support 

This tag assumes the controller has a `reorder` action. This action is added automatically by Hobo's model-controller if the model declares `acts_as_list`. See also [Drag and Drop Reordering](/manual/controllers#drag_and_drop_reordering) in the [Controllers and Routing](/manual/controllers) chapter of the manual.
 -->
<def tag="sortable-collection" attrs="sortable-options"><%
  singular_name = this.member_class.name.underscore
  attributes[:id] ||= "#{singular_name}_ordering"
  route_method = subsite ? "#{subsite}_reorder_#{singular_name.pluralize}_url" : "reorder_#{singular_name.pluralize}_url"
  reorder_url = send(route_method)
%>
  <collection class="sortable" merge>
    <item: id="#{singular_name}_#{this.id}" param>
      <div class="ordering-handle" param="handle" if="&can_edit?">&uarr;<br/>&darr;</div>
      <do param="default"><card param/></do>
    </item:>
  </collection>
  <%= if Hobo::Dryml.last_if
        opts = { :url => reorder_url,
                 :constraint => :vertical,
                 :overlap => :vertical,
                 :scroll => :window,
                 :handle => 'ordering-handle',
                 :complete => [visual_effect(:highlight, attributes[:id])]
                }
        opts.update(sortable_options) if sortable_options
        sortable_element attributes[:id], opts
      end # FIXME: Make unobstrusive
   %>
</def>


<!-- Captures the common pattern of a list of "the first few" cards, along with a link to the rest. -->
<def tag="preview-with-more" attrs="name">
  <% name ||= collection_name.pluralize -%>
  <section class="#{name.gsub(' ', '-').dasherize} preview-with-more" param="default">
    <h3 param="heading"><%= name.titleize %></h3>
    <a param="more">More <type-name plural lowercase/>...</a>
    <collection param/>
  </section>
</def>


<!-- Renders a gravatar (see [gravatar.com](http://gravatar.com)) image in side a link to `this`. Requires `this` to have an `email_address` field. Normally called with a user record in context.

### Attributes 

 - `size` - Size in pixels of the image. Defaults to 80.
 - `rating` - The rating allowed. Defaults to 'g'. See [gravatar.com](http://gravatar.com) for information on ratings.

 -->
<def tag="gravatar" attrs="size, rating">
  <% size ||= 80; rating ||= 'g'; digest = Digest::MD5.hexdigest(this.email_address) -%>
  <a class="gravatar"><img class="gravatar" src="http://www.gravatar.com/avatar/#{digest}?s=#{size}&r=#{rating}" merge-attrs/></a>
</def>


<!-- Provides an ajax-powered *find-as-you-type* live search field which is hooked up to Hobo's site-side search feature. At the moment this tag is not very flexible. It is not easy to use if for anything other than Hobo's site-wide search. -->
<def tag="live-search">
  <div class="search">
    <label for="search-field">Search</label><input type="search" class="live-search"/>
    <spinner id="search-spinner"/>
  </div>
  <section class="hidden" id="search-results-panel">
    <h2>Search Results</h2><div param="close-button">close</div>
    <section id="search-results">&nbsp;</section>
  </section>
</def>

<!-- A `<select>` menu intended to act as a filter for index pages.
  
See [Filtering stories by status](/tutorials/agility#filtering_stories_by_status) in the [Agility Tutorial](/tutorials/agility) for an example.

### Attributes

 - `param-name` - the name of the HTTP parameter to use for the filter
 - `options` - an array of options for the menu. 
 - `no-filter` - The text of the first option which indicates no filter is in effect. Defaults to 'All'
  -->
<def tag="filter-menu" attrs="param-name, options, no-filter, id">
  <% no_filter ||= "All" %>
  <form action="&request.request_uri" method="get" class="filter-menu" merge-attrs="id">
    <div>
      <% selected = options.detect {|o| o.to_s==params[param_name.gsub('-', '_')] } %>
      <select-menu name="&param_name" options="&options" selected="&selected"
                   first-option="&no_filter" merge-params/>
    </div>
  </form>
</def>