Index: openacs-4/packages/acs-templating/tcl/list-procs.tcl =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-templating/tcl/list-procs.tcl,v diff -u -r1.61 -r1.62 --- openacs-4/packages/acs-templating/tcl/list-procs.tcl 17 Nov 2015 23:33:01 -0000 1.61 +++ openacs-4/packages/acs-templating/tcl/list-procs.tcl 7 Aug 2017 23:48:02 -0000 1.62 @@ -57,26 +57,26 @@ } { Defines a list to be diplayed in a template. The list works in conjunction with a multirow, which contains the data for the list. The list is output using the <listtemplate> and <listfilters> templating tags, with the help of <listelement> and <listrow>. - +

Here's an example of a fairly simple standard list.

-    template::list::create \ 
-        -name order_lines \ 
-        -multirow order_lines \ 
-        -key item_id \ 
-        -actions [list "Add item" [export_vars -base item-add {order_id}] "Add item to this order"] \ 
+    template::list::create \
+        -name order_lines \
+        -multirow order_lines \
+        -key item_id \
+        -actions [list "Add item" [export_vars -base item-add {order_id}] "Add item to this order"] \
         -bulk_actions {
             "Remove" "item-remove" "Remove checked items"
             "Copy" "item-copy" "Copy checked items to clipboard"
-        } \ 
+        } \
         -bulk_action_method post \
         -bulk_action_export_vars {
             order_id
-        } \ 
-        -row_pretty_plural "order items" \ 
+        } \
+        -row_pretty_plural "order items" \
         -elements {
             quantity {
                 label "Quantity"
@@ -99,11 +99,11 @@
 
     db_multirow -extend { item_url } order_lines select_order_lines {
         select l.item_id,
-               l.quantity,
-               i.name as item_name,
-               i.price as item_price
+        l.quantity,
+        i.name as item_name,
+        i.price as item_price
         from   order_lines l,
-               items i
+        items i
         where  l.order_id = :order_id
         and    i.item_id = l.item_id
     } {
@@ -119,65 +119,65 @@
 
 
     @param  name           The name of the list you want to build.
-    
+
     @param  multirow       The name of the multirow which you want to loop over. Defaults to name of the list.
 
-    @param  key            The name of the column holding the primary key/unique identifier for each row. 
-                           Must be a single column, which must be present in the multirow. 
-                           This switch is required to have bulk actions.
-    
+    @param  key            The name of the column holding the primary key/unique identifier for each row.
+    Must be a single column, which must be present in the multirow.
+    This switch is required to have bulk actions.
+
     @param  pass_properties
-                           A list of variables in the caller's namespace, which should be avilable to the display_template
-                           of elements.
-    
-    @param  actions        A list of action buttons to display at the top of 
-                           the list in the form (label1 url1 title1 label2 url2 title2 ...).
-                           The action button will be a simple link to the url.
-    
+    A list of variables in the caller's namespace, which should be available to the display_template
+    of elements.
+
+    @param  actions        A list of action buttons to display at the top of
+    the list in the form (label1 url1 title1 label2 url2 title2 ...).
+    The action button will be a simple link to the url.
+
     @param  bulk_actions   A list of bulk action buttons, operating on the checked rows,
-                           to display at the bottom of 
-                           the list. The format is (label1 url1 title1 label2 url2 title2 ...).
-                           A form will be submitted to the url, containing a list of the key values of the checked rows.
-                           For example, if 'key' is 'message_id', and rows with message_id 2 4 and 9 are chcked, the 
-                           page will get variables message_id=2&message_id=4&message_id=9. The receiving page
-                           should declare message_id:naturalnum,multiple in its ad_page_contract. Note that the 'message_id' 
-                           local variable will the be a Tcl list.
+    to display at the bottom of
+    the list. The format is (label1 url1 title1 label2 url2 title2 ...).
+    A form will be submitted to the url, containing a list of the key values of the checked rows.
+    For example, if 'key' is 'message_id', and rows with message_id 2 4 and 9 are chcked, the
+    page will get variables message_id=2&message_id=4&message_id=9. The receiving page
+    should declare message_id:naturalnum,multiple in its ad_page_contract. Note that the 'message_id'
+    local variable will the be a Tcl list.
 
     @param  bulk_action_method should a bulk action be a "get" or "post"
 
-    @param  bulk_action_export_vars 
-                           A list of additional variables to pass to the receving page, along with the other variables for 
-                           the selected keys. This is typically useful if the rows in this list are all hanging off of 
-                           one row in a parent table. For example, if this list contains the order lines of one particular 
-                           order, and the primary key of the order lines table is 'order_id, item_id', the key would be 
-                           'item_id', and bulk_action_export_vars would be 'order_id', so together they constitute the 
-                           primary key.
-    
+    @param  bulk_action_export_vars
+    A list of additional variables to pass to the receiving page, along with the other variables for
+    the selected keys. This is typically useful if the rows in this list are all hanging off of
+    one row in a parent table. For example, if this list contains the order lines of one particular
+    order, and the primary key of the order lines table is 'order_id, item_id', the key would be
+    'item_id', and bulk_action_export_vars would be 'order_id', so together they constitute the
+    primary key.
+
     @param  selected_format
-                           The currently selected display format. See the 'formats' option.
+    The currently selected display format. See the 'formats' option.
 
     @param  has_checkboxes Set this flag if your table already includes the checkboxes for the bulk actions.
-                           If not, and your list has bulk actions, we will add a checkbox column for you as the first column.
+    If not, and your list has bulk actions, we will add a checkbox column for you as the first column.
 
     @param  checkbox_name  You can explicitly name the checkbox column here, so you can refer to it and place it where you
-                           want it when you specify display formats. Defaults to 'checkbox'. See the 'formats' option.
+    want it when you specify display formats. Defaults to 'checkbox'. See the 'formats' option.
 
     @param  row_pretty_plural
-                           The pretty name of the rows in plural. For example 'items' or 'forum postings'. This is used to 
-                           auto-generate the 'no_data' message to say "No (row_pretty_plural)." Defaults to 'data'. See 'no_data' below.
+    The pretty name of the rows in plural. For example 'items' or 'forum postings'. This is used to
+    auto-generate the 'no_data' message to say "No (row_pretty_plural)." Defaults to 'data'. See 'no_data' below.
 
     @param  no_data        The message to display when the multirow has no rows. Defaults to 'No data.'.
 
-    @param  main_class     The main CSS class to be used in the output. The CSS class is constructed by combining the 
-                           main_class and the sub_class with a dash in between. E.g., main_class could be 'list', and 
-                           sub_class could be 'narrow', in which case the resuling CSS class used would be 'list-narrow'.
+    @param  main_class     The main CSS class to be used in the output. The CSS class is constructed by combining the
+    main_class and the sub_class with a dash in between. E.g., main_class could be 'list', and
+    sub_class could be 'narrow', in which case the resuling CSS class used would be 'list-narrow'.
 
     @param  sub_class      The sub-part of the CSS class to use. See 'main_class' option.
 
     @param  class          Alternatively, you can specify the CSS class directly. If specified, this overrides main_class/sub_class.
 
-    @param  html           HTML attributes to be output for the table tag, e.g. { align right style "background-color: yellow;" }. 
-                           Value should be a Tcl list with { name value name value }
+    @param  html           HTML attributes to be output for the table tag, e.g. { align right style "background-color: yellow;" }.
+    Value should be a Tcl list with { name value name value }
 
     @param caption         Caption tag that appears right below the table tag. Required for AA. Added 2/27/2007
 
@@ -186,55 +186,55 @@
     @param  page_size_variable_p Displays a selectbox to let the user change the number of rows to display on each page. If specified, the list will be paginated.
 
     @param  page_groupsize The page group size for the paginator. See template::paginator::create for more details.
-                           
 
+
     @param  page_query     The query to get the row IDs and contexts for the entire result set. See template::paginator::create for details.
 
-    @param  page_query_name 
-                           Alternatively, you can specify a query name. See template::paginator::create for details.
+    @param  page_query_name
+    Alternatively, you can specify a query name. See template::paginator::create for details.
 
-    @param  ulevel         The number of levels to uplevel when doing subst on values for elements, filters, groupbys, orderbys 
-                           and formats below. Defaults to one level up, which means the caller of template::list::create's scope.
+    @param  ulevel         The number of levels to uplevel when doing subst on values for elements, filters, groupbys, orderbys
+    and formats below. Defaults to one level up, which means the caller of template::list::create's scope.
 
-    @param elements        The list elements (columns). 
-                           The value should be an array-list of (element-name, spec) pairs, like in the example above. Each spec, in turn, is an array-list of 
-                           property-name/value pairs, where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are
-                           'subst'ed in the multirow context.
-                           See template::list::element::create for details.
+    @param elements        The list elements (columns).
+    The value should be an array-list of (element-name, spec) pairs, like in the example above. Each spec, in turn, is an array-list of
+    property-name/value pairs, where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are
+    'subst'ed in the multirow context.
+    See template::list::element::create for details.
 
-    @param  filters        Filters for the list. Typically used to slice the data, for example to see only rows by a particular user. 
-                           Array-list of (filter-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs, 
-                           where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are 'subst'ed in the multirow context.
-                           In order for filters to work, you have to specify them in your page's ad_page_contract, typically as filter_name:optional.
-                           The list builder will find them from there,
-                           by grabbing them from your page's local variables.
-                           See template::list::filter::create for details.
+    @param  filters        Filters for the list. Typically used to slice the data, for example to see only rows by a particular user.
+    Array-list of (filter-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs,
+    where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are 'subst'ed in the multirow context.
+    In order for filters to work, you have to specify them in your page's ad_page_contract, typically as filter_name:optional.
+    The list builder will find them from there,
+    by grabbing them from your page's local variables.
+    See template::list::filter::create for details.
 
-                           filters are also the mechanism to export state variables which need to be preserved.  If for example you needed user_id to be 
-                           maintained for the filter and sorting links you would add -filters {user_id {}}
+    filters are also the mechanism to export state variables which need to be preserved.  If for example you needed user_id to be
+    maintained for the filter and sorting links you would add -filters {user_id {}}
 
-    @param  groupby        Things you can group by, e.g. day, week, user, etc. Automatically creates a filter called 'groupby'. 
-                           Single array-list of property-name/value pairs, where the value is 'subst'ed in the caller's environment.
-                           Groupby is really just a filter with a fixed name, so see above for more details.
-                           See template::list::filter::create for details.
+    @param  groupby        Things you can group by, e.g. day, week, user, etc. Automatically creates a filter called 'groupby'.
+    Single array-list of property-name/value pairs, where the value is 'subst'ed in the caller's environment.
+    Groupby is really just a filter with a fixed name, so see above for more details.
+    See template::list::filter::create for details.
 
-    @param  orderby        Things you can order by. You can also specify ordering directly in the elements. Automatically creates a filter called 'orderby'. 
-                           Array-list of (orderby-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs, 
-                           where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are 'subst'ed in the multirow context.
-                           If the name of your orderby is the same as the name of an element, that element's header will be made a link to sort by that column.
-                           See template::list::orderby::create for details.
+    @param  orderby        Things you can order by. You can also specify ordering directly in the elements. Automatically creates a filter called 'orderby'.
+    Array-list of (orderby-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs,
+    where the value is 'subst'ed in the caller's environment, except for the *_eval properties, which are 'subst'ed in the multirow context.
+    If the name of your orderby is the same as the name of an element, that element's header will be made a link to sort by that column.
+    See template::list::orderby::create for details.
 
-    @param  orderby_name   The page query variable name for the selected orderby is normally named 'orderby', but if you want to, you can 
-                           override it here.
+    @param  orderby_name   The page query variable name for the selected orderby is normally named 'orderby', but if you want to, you can
+    override it here.
 
-    @param  formats        If no formats are specified, a default format is created. Automatically creates a filter called 'format'. 
-                           Array-list of (format-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs, 
-                           where the value is 'subst'ed in the caller's environment.
-                           See template::list::format::create for details.
+    @param  formats        If no formats are specified, a default format is created. Automatically creates a filter called 'format'.
+    Array-list of (format-name, spec) pairs, like elements. Each spec, in turn, is an array-list of property-name/value pairs,
+    where the value is 'subst'ed in the caller's environment.
+    See template::list::format::create for details.
 
     @param filter_form     Whether or not we create the form data structure for the listfilters-form tag to dynamically generate a form to specify filter criteria. Default 0 will not generate form. Set to 1 to generate form to use listfilters-form tag.
-    @param bulk_action_click_functon Javascript function name to call when bulk action buttons are clicked. 
-    
+    @param bulk_action_click_functon Javascript function name to call when bulk action buttons are clicked.
+
     @see template::list::element::create
     @see template::list::filter::create
     @see template::list::orderby::create
@@ -244,57 +244,57 @@
 
     # Get an upvar'd reference to list_properties
     get_reference -create -name $name
-    
+
     # Setup some list defaults
     array set list_properties {
+        actions {}
+        bulk_action_click_function {}
+        bulk_action_export_vars {}
+        bulk_actions {}
+        caption {}
+        class {}
+        html {}
         key {}
+        main_class {list}
         multirow {}
-        style {}
-        page_size {}
-        page_size_variable_p {}
+        orderby_name {orderby}
+        page_flush_p {}
         page_groupsize {}
         page_query {}
         page_query_name {}
-        page_flush_p {}
-        main_class {list}
+        page_size {}
+        page_size_variable_p {}
+        style {}
         sub_class {}
-        class {}
-        html {}
-	caption {}
-        actions {}
-        bulk_actions {}
-        bulk_action_export_vars {}
-        orderby_name {orderby}
-	bulk_action_click_function {} 
     }
 
     # These are defauls for internally maintained properties
     array set list_properties {
-        elements {}
-        element_refs {}
+        aggregates_p 0
+        bulk_action_export_chunk {}
         display_elements {}
-        filters {}
-        filters_export {}
+        dynamic_cols_p 0
+        element_refs {}
+        element_select_clauses {}
+        element_where_clauses {}
+        elements {}
         filter_refs {}
+        filter_select_clauses {}
         filter_where_clauses {}
-	from_clauses {}
-	filter_select_clauses {}
-	element_select_clauses {}
-	element_where_clauses {}
-        dynamic_cols_p 0
-        aggregates_p 0
+        filters {}
+        filters_export {}
+        format_refs {}
+        from_clauses {}
         groupby {}
         groupby_label {}
-        format_refs {}
-        row_template {}
         orderby_refs {}
-        orderby_selected_name {}
         orderby_selected_direction {}
-        ulevel {}
+        orderby_selected_name {}
         output {}
-        bulk_action_export_chunk {}
-	page_size_export_chunk {}
-	url {}
+        page_size_export_chunk {}
+        row_template {}
+        ulevel {}
+        url {}
     }
 
     # Set default for no_data
@@ -304,29 +304,30 @@
     set list_properties(ulevel) "\#[expr {[info level] - $ulevel}]"
 
     # Set properties from the parameters passed
-    foreach elm { 
-        name
-        key
-        multirow
-        pass_properties
+    foreach elm {
         actions
-        bulk_actions
-        bulk_action_method
+        bulk_action_click_function
         bulk_action_export_vars
-        row_pretty_plural
-        no_data
-        main_class
-        sub_class
+        bulk_action_method
+        bulk_actions
+        caption
         class
         html
-	caption
-        page_size
+        key
+        main_class
+        multirow
+        name
+        no_data
+        orderby_name
+        page_flush_p
         page_groupsize
         page_query
         page_query_name
-        page_flush_p
-        orderby_name
-	bulk_action_click_function
+        page_size
+        page_size_variable_p
+        pass_properties
+        row_pretty_plural
+        sub_class
     } {
         set list_properties($elm) [set $elm]
     }
@@ -338,22 +339,40 @@
 
     # Default 'multirow' to list name
     if { $list_properties(multirow) eq "" } {
-	set list_properties(multirow) $name
+        set list_properties(multirow) $name
     }
 
     # Set up automatic 'checkbox' element as the first element
     if { !$has_checkboxes_p && [llength $bulk_actions] > 0 } {
-	if { $key eq "" } {
-	    error "You cannot have bulk_actions without providing a key for list '$name'"
-	}
+        if { $key eq "" } {
+            error "You cannot have bulk_actions without providing a key for list '$name'"
+        }
         # Create the checkbox element
+        set label [subst {
+            
+        }]
+        template::add_event_listener \
+            -id $name-bulkaction-control \
+            -preventdefault=false \
+            -script [subst {acs_ListCheckAll('[ns_quotehtml $name]', this.checked);}]
+        template::add_event_listener \
+            -id $name-bulkaction-control \
+            -event keypress \
+            -preventdefault=false \
+            -script [subst {acs_ListCheckAll('[ns_quotehtml $name]', this.checked);}]
+
+        if {[info exists ::__csrf_token]} {
+            append label [subst {}]
+        }
+        
         # We only ulevel 1 here, because we want the subst to be done in this namespace
         template::list::element::create \
             -list_name $name \
             -element_name $checkbox_name \
             -spec {
-                label {}
-                display_template {}
+                label $label
+                display_template {}
                 sub_class {narrow}
                 html { align center }
             }
@@ -368,7 +387,7 @@
             -list_name $name \
             -element_name $elm_name \
             -spec $elm_spec \
-            -ulevel 2 
+            -ulevel 2
     }
     set reserved_filter_names { groupby orderby format page }
 
@@ -385,7 +404,7 @@
     }
 
     # Groupby (this is also a filter, but a special one)
-    if { [llength $groupby] > 0 } { 
+    if { [llength $groupby] > 0 } {
         template::list::filter::create \
             -list_name $name \
             -filter_name "groupby" \
@@ -409,7 +428,7 @@
                     -ulevel 2
             }
         }
-        
+
         template::list::filter::set_property \
             -list_name $name \
             -filter_name $list_properties(orderby_name) \
@@ -430,7 +449,7 @@
                                        -ulevel 2]
         }
         set filter_spec [list label [_ acs-templating.Formats] values $filter_values has_default_p 1]
-        
+
         template::list::filter::create \
             -list_name $name \
             -filter_name "format" \
@@ -440,7 +459,7 @@
 
     # Pagination
     if { $list_properties(page_size_variable_p) == 1 } {
-	# Create a filter for the variable page size
+        # Create a filter for the variable page size
         template::list::filter::create \
             -list_name $name \
             -filter_name "page_size" \
@@ -494,7 +513,7 @@
 
     prepare_filters \
         -name $name
-    
+
     # Split the current ordering info into name and direction
     # name is the string before the comma, order (asc/desc) is what's after
     if { [info exists list_properties(filter,$list_properties(orderby_name))] } {
@@ -504,10 +523,16 @@
         set list_properties(orderby_selected_name) $orderby_name
 
         if { $orderby_direction eq "" } {
-            template::list::orderby::get_reference \
-                -list_name $name \
-                -orderby_name $orderby_name
-    
+
+            if {[catch {
+                template::list::orderby::get_reference \
+                    -list_name $name \
+                    -orderby_name $orderby_name
+            } errorMsg]} {
+                ad_page_contract_handle_datasource_error $errorMsg
+                ad_script_abort
+            }
+
             set orderby_direction $orderby_properties(default_direction)
         }
         set list_properties(orderby_selected_direction) $orderby_direction
@@ -517,7 +542,7 @@
     prepare_elements \
         -name $name \
         -ulevel [expr {$ulevel + 1}]
-    
+
     # Make groupby information available to templates
     if { [exists_and_not_null list_properties(filter,groupby)] } {
         set list_properties(groupby) $list_properties(filter,groupby)
@@ -526,10 +551,10 @@
         set list_properties(groupby_label) $list_properties(filter_label,groupby)
     }
 
-    # Create the paginator 
+    # Create the paginator
     if { $list_properties(page_size_variable_p) == 1 } {
-	set list_properties(page_size) $list_properties(filter,page_size)
-	set list_properties(url) [ad_conn url]
+        set list_properties(page_size) $list_properties(filter,page_size)
+        set list_properties(url) [ad_conn url]
         set list_properties(page_size_export_chunk) [uplevel $list_properties(ulevel) [list export_vars -form -exclude {page_size page} $list_properties(filters_export)]]
     }
 
@@ -543,7 +568,7 @@
             # We need to uplevel subst it so we get the filters evaluated
             set list_properties(page_query_substed) \
                 [uplevel $list_properties(ulevel) \
-                    [list subst -nobackslashes $list_properties(page_query)]]
+                     [list subst -nobackslashes $list_properties(page_query)]]
         }
 
         # Use some short variable names to make the expr readable
@@ -555,12 +580,12 @@
         set last_row [expr {$first_row + ($groupsize + 1) * $page_size - 1}]
         set page_offset [expr {($page_group - 1) * $groupsize}]
 
-	# Antonio Pisano 2015-11-17: From now on, the original query 
-	# will be tampered with the limit information, so this is our 
-	# last chance to save it and use it to get the full row count in
-	# the paginator.
-	set list_properties(page_query_original) $list_properties(page_query_substed)
-	
+        # Antonio Pisano 2015-11-17: From now on, the original query 
+        # will be tampered with the limit information, so this is our 
+        # last chance to save it and use it to get the full row count in
+        # the paginator.
+        set list_properties(page_query_original) $list_properties(page_query_substed)
+        
         # Now wrap the provided query with the limit information
         set list_properties(page_query_substed) [db_map pagination_query]
 
@@ -587,12 +612,12 @@
         # We need this uplevel so that the bind variables in the query
         # will get bound at the caller's level
         # we pass in a dummy query name because the query text was
-        # already retreived previously with db_map so this call
+        # already retrieved previously with db_map so this call
         # always passes the full query text and not the query name
         # this was failing if the template::list call contained a
-        # page_query with an empty page_query_name 
+        # page_query with an empty page_query_name
         uplevel $ulevel [list template::paginator create \
-			     --dummy--query--name-- \
+                             --dummy--query--name-- \
                              $list_properties(paginator_name) \
                              $list_properties(page_query_substed) \
                              -pagesize $list_properties(page_size) \
@@ -626,21 +651,21 @@
 
     @param name Name of the variable at the template parse level.
     @param local_name Name of the local variable to bind the reference to, default
-           "list_properties".
+    "list_properties".
     @param create Boolean which if true suppresses the "not found" error return, for
-           instance when you're building the reference in order to create a new
-           list.
+    instance when you're building the reference in order to create a new
+    list.
 
 } {
     if {$name eq ""} {
-	error "Attempt to get reference to an empty name."
-    } 
+        error "Attempt to get reference to an empty name."
+    }
     set refname [get_refname -name $name]
-    
+
     if { !$create_p && ![uplevel \#[template::adp_level] [list info exists $refname]] } {
         error "List '$name' not found"
     }
-    
+
     uplevel upvar #[template::adp_level] $refname $local_name
 }
 
@@ -650,7 +675,7 @@
     {-exclude ""}
 } {
     Build a URL for the current page with query variables set for the various filters
-    active for the named list.  
+    active for the named list.
 
     @param name The name of the list
     @param override Values that export_vars should override
@@ -682,17 +707,17 @@
     if { [llength $list_properties(filter_from_clauses)] == 0 } {
         return {}
     }
-    
+
     set result {}
     if { $comma_p } {
         append result ", "
     }
     append result [join $list_properties(filter_from_clauses) "\n , "]
-    
+
     return $result
 }
 
- ad_proc -public template::list::filter_select_clauses {
+ad_proc -public template::list::filter_select_clauses {
     -name:required
     -comma:boolean
 } {
@@ -704,13 +729,13 @@
     if { [llength $list_properties(filter_select_clauses)] == 0 } {
         return {}
     }
-    
+
     set result {}
     if { $comma_p } {
         append result ", "
     }
     append result [join $list_properties(filter_select_clauses) "\n , "]
-    
+
     return $result
 }
 
@@ -736,19 +761,19 @@
     set i 0
     foreach elm $list_properties(from_clauses) {
 
-	if {([string trim $elm] ne "" && ![string match "left*" [string trim $elm]]) \
-		&& ($comma_p || $i > 0)} {
-	    append results ","
-	}
-	append result " $elm"
-	incr i
+        if {([string trim $elm] ne "" && ![string match "left*" [string trim $elm]]) \
+                && ($comma_p || $i > 0)} {
+            append results ","
+        }
+        append result " $elm"
+        incr i
     }
-#    append result [join $list_properties(from_clauses) "\n , "]
-    
+    #    append result [join $list_properties(from_clauses) "\n , "]
+
     return $result
 }
 
- ad_proc -public template::list::element_select_clauses {
+ad_proc -public template::list::element_select_clauses {
     -name:required
     -comma:boolean
 } {
@@ -760,13 +785,13 @@
     if { [llength $list_properties(element_select_clauses)] == 0 } {
         return {}
     }
-    
+
     set result {}
     if { $comma_p } {
         append result ", "
     }
     append result [join $list_properties(element_select_clauses) "\n , "]
-    
+
     return $result
 }
 
@@ -782,7 +807,7 @@
     if { [llength $list_properties(filter_where_clauses)] == 0 } {
         return {}
     }
-    
+
     set result {}
     if { $and_p } {
         append result "and "
@@ -803,13 +828,13 @@
     if { [llength $list_properties(element_where_clauses)] == 0 } {
         return {}
     }
-    
+
     set result {}
     if { $and_p } {
         append result "and "
     }
     append result [join $list_properties(element_where_clauses) "\n and "]
-    
+
     return $result
 }
 
@@ -819,17 +844,17 @@
     {-key}
 } {
     @param  and     Set this flag if you want the result to start with an 'and' if the list of where clauses returned is non-empty.
-    
-    @param key      Specify the name of the primary key to be used in the query's where clause, 
-                    if different from the list builder's key.
+
+    @param key      Specify the name of the primary key to be used in the query's where clause,
+    if different from the list builder's key.
 } {
     # Get an upvar'd reference to list_properties
     get_reference -name $name
 
     if { $list_properties(page_size) eq "" || $list_properties(page_size) == 0 } {
         return {}
     }
-    
+
     set result {}
 
     if { $and_p } {
@@ -839,7 +864,7 @@
     if { (![info exists key] || $key eq "") } {
         set key $list_properties(key)
     }
-    
+
     append result "$key in ([page_get_ids -name $name])"
 
     return $result
@@ -854,7 +879,7 @@
 } {
     # Get an upvar'd reference to list_properties
     get_reference -name $name
-    
+
     switch $list_properties(output) {
         csv {
             write_csv -name $name
@@ -876,12 +901,12 @@
     -name:required
 } {
     Writes a CSV to the connection
-} { 
+} {
     # Creates the '_eval' columns and aggregates
     template::list::prepare_for_rendering -name $name
- 
+
     get_reference -name $name
-    
+
     set __list_name $name
     set __output {}
     set __groupby $list_properties(groupby)
@@ -892,53 +917,53 @@
     set __csv_labels [list]
 
     foreach __element_name $list_properties(elements) {
-	template::list::element::get_reference -list_name $name -element_name $__element_name
+        template::list::element::get_reference -list_name $name -element_name $__element_name
         if {!$element_properties(hide_p)} {
-	    lappend __csv_cols $__element_name
-	    lappend __csv_labels [csv_quote $element_properties(label)]
-	}
+            lappend __csv_cols $__element_name
+            lappend __csv_labels [csv_quote $element_properties(label)]
+        }
     }
     append __output "\"[join $__csv_labels "\",\""]\"\n"
 
     set __rowcount [template::multirow size $list_properties(multirow)]
     set __rownum 0
     # Output rows
     template::multirow foreach $list_properties(multirow) {
-	set group_lastnum_p 0
-	if {$__groupby ne ""} {
-	    if {$__rownum < $__rowcount} {
-		# check if the next row's group column is the same as this one
-		set next_group [template::multirow get $list_properties(multirow) [expr {$__rownum + 1}] $__groupby]
-		if {[set $__groupby] ne $next_group} {
-		    set group_lastnum_p 1
-		}
-	    } else {
-		set group_lastnum_p 1
-	    }
-	    incr __rownum
-	}
-	
-	if {$__groupby eq "" \
-	    || $group_lastnum_p} {
-        set __cols [list]
+        set group_lastnum_p 0
+        if {$__groupby ne ""} {
+            if {$__rownum < $__rowcount} {
+                # check if the next row's group column is the same as this one
+                set next_group [template::multirow get $list_properties(multirow) [expr {$__rownum + 1}] $__groupby]
+                if {[set $__groupby] ne $next_group} {
+                    set group_lastnum_p 1
+                }
+            } else {
+                set group_lastnum_p 1
+            }
+            incr __rownum
+        }
 
-	    foreach __element_name $__csv_cols {
-		if {![string match "*___*_group" $__element_name]} {
-		    template::list::element::get_reference \
-			-list_name $__list_name \
-			-element_name $__element_name \
-			-local_name __element_properties
-		    if { [info exists $__element_properties(csv_col)] } {
-			lappend __cols [csv_quote [set $__element_properties(csv_col)]]
-		    } else {
-			lappend __cols [csv_quote [set $__element_name]]
-		    }
-		} {
-		    lappend __cols [csv_quote [set $__element_name]]
-		}
-	    }
-	    append __output "\"[join $__cols "\",\""]\"\n"
-	}
+        if {$__groupby eq "" \
+                || $group_lastnum_p} {
+            set __cols [list]
+
+            foreach __element_name $__csv_cols {
+                if {![string match "*___*_group" $__element_name]} {
+                    template::list::element::get_reference \
+                        -list_name $__list_name \
+                        -element_name $__element_name \
+                        -local_name __element_properties
+                    if { [info exists $__element_properties(csv_col)] } {
+                        lappend __cols [csv_quote [set $__element_properties(csv_col)]]
+                    } else {
+                        lappend __cols [csv_quote [set $__element_name]]
+                    }
+                } {
+                    lappend __cols [csv_quote [set $__element_name]]
+                }
+            }
+            append __output "\"[join $__cols "\",\""]\"\n"
+        }
     }
     set oh [ns_conn outputheaders]
     ns_set put $oh Content-Disposition "attachment; filename=${__list_name}.csv"
@@ -951,16 +976,16 @@
     -tcl_list:boolean
 } {
     @param  name     Name of the list builder list for which you want the IDs of the current page.
-    @param  tcl_list Set this option if you want the IDs as a Tcl list. Otherwise, they'll be returned as a 
-                     quoted SQL list, ready to be included in an "where foo_id in (...)" expression.
+    @param  tcl_list Set this option if you want the IDs as a Tcl list. Otherwise, they'll be returned as a
+    quoted SQL list, ready to be included in an "where foo_id in (...)" expression.
 } {
     # Get an upvar'd reference to list_properties
     get_reference -name $name
 
     if { $list_properties(page_size) eq "" || $list_properties(page_size) == 0 } {
         return {}
     }
-    
+
     set ids [template::paginator get_row_ids $list_properties(paginator_name) $list_properties(filter,page)]
 
     if { $tcl_list_p } {
@@ -969,11 +994,11 @@
         if { [llength $ids] == 0 } {
             return NULL
         }
-	set quoted_ids [list]
-	foreach one_id $ids {
-	    lappend quoted_ids "'[DoubleApos $one_id]'"
-	}
-	return [join $quoted_ids ","]
+        set quoted_ids [list]
+        foreach one_id $ids {
+            lappend quoted_ids "'[DoubleApos $one_id]'"
+        }
+        return [join $quoted_ids ","]
     }
 }
 
@@ -990,30 +1015,30 @@
     if { $list_properties(page_size) eq "" || $list_properties(page_size) == 0 } {
         return {}
     }
-    
+
     return [template::paginator get_row_count $list_properties(paginator_name)]
 }
 
 ad_proc -public template::list::get_rowcount {
     -name:required
 } {
     Gets the full number of rows retrieved from this template::list. This number can
-    exceed number_of_pages * rows_per_page. If list is not paginated, size of the 
-    multirow will be returned. Multirow must exist for count to succeed on a not 
+    exceed number_of_pages * rows_per_page. If list is not paginated, size of the
+    multirow will be returned. Multirow must exist for count to succeed on a not
     paginated list.
 
     @param  name     Name of the list builder list for which you want the full number of rows.
 } {
     # Get an upvar'd reference to list_properties
     get_reference -name $name
-    
+
     if { $list_properties(page_size) eq "" || $list_properties(page_size) == 0 } {
         if {![template::multirow exists {*}$list_properties(multirow)]} {
-	    return {}
-	}
-	return [template::multirow size {*}$list_properties(multirow)]
+            return {}
+        }
+        return [template::multirow size {*}$list_properties(multirow)]
     }
-    
+
     return [template::paginator get_full_row_count $list_properties(paginator_name)]
 }
 
@@ -1026,33 +1051,38 @@
 
     @param name List name
 
-    @param  orderby     If this is specified, this proc will also spit out the "order by" part, so it can be used directly 
-                        in the query without saying 'order by' yourself.
-                 
+    @param  orderby     If this is specified, this proc will also spit out the "order by" part, so it can be used directly
+    in the query without saying 'order by' yourself.
+
 } {
     # Get an upvar'd reference to list_properties
     get_reference -name $name
 
     if { $list_properties(orderby_selected_name) eq "" } {
         return {}
     }
-    
+
     set result {}
     template::list::orderby::get_reference -list_name $name -orderby_name $list_properties(orderby_selected_name)
-    
+
+    if {![info exists orderby_properties(orderby_$list_properties(orderby_selected_direction))]} {
+        ad_page_contract_handle_datasource_error "invalid value for orderby: $list_properties(orderby_selected_direction)"
+        ad_script_abort
+    }
     set result $orderby_properties(orderby_$list_properties(orderby_selected_direction))
+
     if { $orderby_p && $result ne "" } {
         set result "order by $result"
     }
-    
+
     return $result
 }
 
 ad_proc -public template::list::multirow_cols {
     -name:required
 } {
     Get the list of columns to order by, if ordering in web server. Otherwise returns empty string.
-    
+
     @param name List name
 } {
     # Get an upvar'd reference to list_properties
@@ -1061,7 +1091,7 @@
     if { $list_properties(orderby_selected_name) eq "" } {
         return {}
     }
-    
+
     template::list::orderby::get_reference -list_name $name -orderby_name $list_properties(orderby_selected_name)
 
     set result [list]
@@ -1074,16 +1104,16 @@
     return $result
 }
 
-ad_proc -private template::list::template { 
+ad_proc -private template::list::template {
     {-name:required}
-    {-style ""} 
+    {-style ""}
 } {
     Process a list template with the special hacks into becoming a
     'real' ADP template, as if it was included directly in the page.
     Will provide that template with a multirow named 'elements'.
-} { 
+} {
     set level [template::adp_level]
-    
+
     # Get an upvar'd reference to list_properties
     get_reference -name $name
 
@@ -1094,7 +1124,7 @@
     # Manually construct a multirow by setting the relevant variables
     foreach type { actions bulk_actions } {
         set ${type}:rowcount 0
-        
+
         foreach { label url title } $list_properties(${type}) {
             incr ${type}:rowcount
             set "${type}:[set "${type}:rowcount"](label)" $label
@@ -1121,8 +1151,8 @@
             incr elements:rowcount
 
             # get a reference by index for the multirow data source
-            upvar #$level $element_ref elements:${elements:rowcount} 
-            
+            upvar #$level $element_ref elements:${elements:rowcount}
+
             # Also set the rownum pseudocolumn
             set "elements:${elements:rowcount}(rownum)" ${elements:rowcount}
         }
@@ -1135,35 +1165,30 @@
     # Find the list template
     #
 
-    if {$style eq {}} { 
+    if {$style eq {}} {
         set style $list_properties(style)
     }
 
-    if {$style eq {}} { 
-      set style [parameter::get \
-                     -package_id [ad_conn subsite_id] \
-                     -parameter DefaultListStyle \
-                     -default [parameter::get \
-                                   -package_id [apm_package_id_from_key "acs-templating"] \
-                                   -parameter DefaultListStyle \
-                                   -default "table"]]
+    if {$style eq {}} {
+        set style [parameter::get \
+                       -package_id [ad_conn subsite_id] \
+                       -parameter DefaultListStyle \
+                       -default [parameter::get \
+                                     -package_id [apm_package_id_from_key "acs-templating"] \
+                                     -parameter DefaultListStyle \
+                                     -default "table"]]
     }
-    
-    # Added support for storing form templates outside acs-templating
-    if {[regexp {^/(.*)} $style path]} {
-        set file_stub "$::acs::rootdir$path"
-    } else {
-        set file_stub [template::get_resource_path]/lists/$style  
-    }
 
+    set file_stub [template::resource_path -type lists -style $style]
+
     # ensure that the style template has been compiled and is up-to-date
     template::adp_init adp $file_stub
 
     # get result of template output procedure into __adp_output
     # the only data source on which this template depends is the "elements"
     # multirow data source.  The output of this procedure will be
     # placed in __adp_output in this stack frame.
-   
+
     template::code::adp::$file_stub
 
     return $__adp_output
@@ -1183,7 +1208,7 @@
     # This one is named __list_properties to avoid getting scrambled by below multirow
     get_reference -name $name -local_name __list_properties
 
-    # Sort in webserver layer, if requested to do so    
+    # Sort in webserver layer, if requested to do so
     set __multirow_cols [template::list::multirow_cols -name $__list_properties(name)]
     if { $__multirow_cols ne "" } {
         template::multirow sort {*}$__list_properties(multirow) {*}$__multirow_cols
@@ -1200,13 +1225,13 @@
 
     # TODO: If we want to be able to sort by display_eval'd element values,
     # we'll have to do those in a separate run from doing the aggregates.
-    
+
     if { $__list_properties(dynamic_cols_p) || $__list_properties(aggregates_p) } {
         foreach __element_ref $__list_properties(element_refs) {
             # We don't need to prefix it with __ to become __element_properties here
             # because we're not doing the multirow foreach loop yet.
             upvar #$__level $__element_ref element_properties
-            
+
             # display_eval, link_url_eval
             foreach __eval_property { display link_url } {
                 if { [exists_and_not_null element_properties(${__eval_property}_eval)] } {
@@ -1238,9 +1263,9 @@
                 set __agg_group_sum($element_properties(name)) 0
             }
         }
-      set __have_groupby [expr { [info exists $__list_properties(groupby)] && [set $__list_properties(groupby)] ne "" }]
-		
+        set __have_groupby [expr { [info exists $__list_properties(groupby)] && [set $__list_properties(groupby)] ne "" }]
 
+
         # This keeps track of the value of the group-by column for sub-totals
         set __last_group_val {}
 
@@ -1251,7 +1276,7 @@
                 # because we are inside the multirow foreach loop yet.
                 # LARS: That means we should probably also __-prefix element_ref, eval_property, and others.
                 upvar #$__level $__element_ref __element_properties
-                
+
                 # display_eval, link_url_eval
                 foreach __eval_property { display link_url } {
                     if { [exists_and_not_null __element_properties(${__eval_property}_eval)] } {
@@ -1265,8 +1290,8 @@
                     incr __agg_counter($__element_properties(name))
                     if {$__element_properties(aggregate) eq "sum" } {
                         set __agg_sum($__element_properties(name)) \
-                            [expr {$__agg_sum($__element_properties(name)) + 
-				   ([set $__element_properties(name)] ne "" ? [set $__element_properties(name)] : 0)} ]
+                            [expr {$__agg_sum($__element_properties(name)) +
+                                   ([set $__element_properties(name)] ne "" ? [set $__element_properties(name)] : 0)} ]
                     }
 
                     # Check if the value of the groupby column has changed
@@ -1279,49 +1304,49 @@
                         # Update subtotals
                         incr __agg_group_counter($__element_properties(name))
                         set __agg_group_sum($__element_properties(name)) \
-                            [expr {$__agg_group_sum($__element_properties(name)) + 
-				   ([string is double [set $__element_properties(name)]] ? [set $__element_properties(name)] : 0)}]
+                            [expr {$__agg_group_sum($__element_properties(name)) +
+                                   ([string is double [set $__element_properties(name)]] ? [set $__element_properties(name)] : 0)}]
                     }
-		    
+
                     switch $__element_properties(aggregate) {
                         sum {
-			  set $__element_properties(aggregate_col) $__agg_sum($__element_properties(name))
-			  if { $__have_groupby } {
-			    set $__element_properties(aggregate_group_col) $__agg_group_sum($__element_properties(name))
-			  }
+                            set $__element_properties(aggregate_col) $__agg_sum($__element_properties(name))
+                            if { $__have_groupby } {
+                                set $__element_properties(aggregate_group_col) $__agg_group_sum($__element_properties(name))
+                            }
                         }
                         average {
-			  set $__element_properties(aggregate_col) \
-			      [expr {$__agg_sum($__element_properties(name)) / $__agg_counter($__element_properties(name))}]
-			  if { $__have_groupby } {
-			    set $__element_properties(aggregate_group_col) \
-				[expr {$__agg_sum($__element_properties(name)) / $__agg_group_counter($__element_properties(name))}]
-			  }
+                            set $__element_properties(aggregate_col) \
+                                [expr {$__agg_sum($__element_properties(name)) / $__agg_counter($__element_properties(name))}]
+                            if { $__have_groupby } {
+                                set $__element_properties(aggregate_group_col) \
+                                    [expr {$__agg_sum($__element_properties(name)) / $__agg_group_counter($__element_properties(name))}]
+                            }
                         }
                         count {
-			  set $__element_properties(aggregate_col) [expr {$__agg_counter($__element_properties(name))}]
-			  if { $__have_groupby } {
-			    set $__element_properties(aggregate_group_col) \
-				[expr {$__agg_group_counter($__element_properties(name))}]
-			  }
+                            set $__element_properties(aggregate_col) [expr {$__agg_counter($__element_properties(name))}]
+                            if { $__have_groupby } {
+                                set $__element_properties(aggregate_group_col) \
+                                    [expr {$__agg_group_counter($__element_properties(name))}]
+                            }
                         }
                         default {
                             error "Unknown aggregate function '$__element_properties(aggregate)'"
                         }
                     }
-                    
-                    set $__element_properties(aggregate_group_col) [lc_numeric [set $__element_properties(aggregate_group_col)]] 
-                    set $__element_properties(aggregate_col) [lc_numeric [set $__element_properties(aggregate_col)]] 
+
+                    set $__element_properties(aggregate_group_col) [lc_numeric [set $__element_properties(aggregate_group_col)]]
+                    set $__element_properties(aggregate_col) [lc_numeric [set $__element_properties(aggregate_col)]]
                 }
             }
 
             # Remember this value of the groupby column
-            if { $__have_groupby } { 
+            if { $__have_groupby } {
                 set __last_group_val [set $__list_properties(groupby)]
             }
         }
     }
-}    
+}
 
 
 ad_proc -private template::list::render {
@@ -1338,7 +1363,7 @@
     @return HTML suitable for display by your favorite browser.
 } {
     set level [template::adp_level]
-    
+
     # Creates the '_eval' columns and aggregates
     template::list::prepare_for_rendering -name $name
 
@@ -1348,22 +1373,22 @@
     # This gets and actually compiles the dynamic template into the template to use for the output
     # Thus, we need to do the dynamic columns above before this step
     set __adp_output [template -name $name -style $style]
-    
+
     # set __adp_stub so includes work. Only fully qualified includes will work with this
     set __list_code {
-	set __adp_stub ""
+        set __adp_stub ""
     }
 
     # compile the template (this is the second compilation, if we're using a dynamic template -- I think)
     append __list_code [template::adp_compile -string $__adp_output]
 
     # Paginator
     if { $list_properties(page_size_variable_p) == 1 } {
-	template::util::list_to_multirow page_sizes {{name 10 value 10} {name 20 value 20} {name 50 value 50} {name 100 value 100}}
+        template::util::list_to_multirow page_sizes {{name 10 value 10} {name 20 value 20} {name 50 value 50} {name 100 value 100}}
     }
 
     if { $list_properties(page_size) ne "" && $list_properties(page_size) != 0 } {
-        
+
         set current_page $list_properties(filter,page)
 
         template::paginator get_display_info $list_properties(paginator_name) paginator $current_page
@@ -1381,7 +1406,7 @@
         # Use this if you want to display the pages around the currently selected page,
         # with num_pages pages before and num_pages after the currently selected page.
         # This is an alternative to 'groups' of pages, and should eventually be built
-        # into paginator, should we decide that this is a nicer way to do things 
+        # into paginator, should we decide that this is a nicer way to do things
         # (I stole the idea from Google).
         # However, for now, it's just commented out with an if 0 ... block.
         if 0 {
@@ -1404,7 +1429,7 @@
             $pages
 
         # Add URL to the pages
-        template::multirow -local extend paginator_pages url 
+        template::multirow -local extend paginator_pages url
 
         template::multirow -local foreach paginator_pages {
             set url [get_url -name $list_properties(name) -override [list [list page $page]]]
@@ -1449,7 +1474,7 @@
 
     # compile the template (this is the second compilation, if we're using a dynamic template -- I think)
     set __list_code [template::adp_compile -string $__adp_output]
-    
+
     # Get the multirow upvar'd to this namespace
     template::multirow upvar $list_properties(multirow)
 
@@ -1459,14 +1484,14 @@
     }
 
     # Get the list definition upvar'd to this namespace
-    upvar #$level [get_refname -name $name] [get_refname -name $name] 
+    upvar #$level [get_refname -name $name] [get_refname -name $name]
     foreach element_ref $list_properties(element_refs) {
         upvar #$level $element_ref $element_ref
     }
 
     # evaluate the code and return the rendered HTML for the list
     set output [template::adp_eval __list_code]
-    
+
     return $output
 }
 
@@ -1508,36 +1533,36 @@
             }
         }
 
-	# support dynamic coluumns
-	if {!$element_properties(hide_p)} {
-	    if {$element_properties(from_clause_eval) ne ""} {
-		set evaluated_from_clause [uplevel $list_properties(ulevel) $element_properties($property)]
-                if {[lseach $list_properties(from_clauses) $evaluated_from_clause] < 0} {
+        # support dynamic coluumns
+        if {!$element_properties(hide_p)} {
+            if {$element_properties(from_clause_eval) ne ""} {
+                set evaluated_from_clause [uplevel $list_properties(ulevel) $element_properties($property)]
+                if {[lsearch $list_properties(from_clauses) $evaluated_from_clause] < 0} {
                     lappend list_properties(from_clauses) $evaluated_from_clause
                 }
-	    } elseif {$element_properties(from_clause) ne "" \
+            } elseif {$element_properties(from_clause) ne "" \
                           && [lsearch $list_properties(from_clauses) $element_properties(from_clause)] < 0} {
-		lappend list_properties(from_clauses) $element_properties(from_clause)
-	    }
-	    # get the select clause
-	    if {$element_properties(select_clause_eval) ne "" \
-		    && [lsearch $list_properties(element_select_clauses) [string trim  [uplevel $list_properties(ulevel) $element_properties(select_clause_eval)]]] < 0} {
-		lappend list_properties(element_select_clauses) [uplevel $list_properties(ulevel) $element_properties(select_clause_eval)]
-	    } elseif {$element_properties(select_clause) ne "" \
-			  && [lsearch $list_properties(element_select_clauses) [string trim $element_properties(select_clause)]] < 0} {
-		lappend list_properties(element_select_clauses) $element_properties(select_clause)
-	    }
-	    # get the where clause
-	    if {$element_properties(where_clause_eval) ne "" \
-		    && [lsearch $list_properties(element_where_clauses) [string trim [uplevel $list_properties(ulevel) $element_properties(where_clause_eval)]]] < 0} {
-		lappend list_properties(element_where_clauses) [uplevel $list_properties(ulevel) $element_properties(where_clause_eval)]
-	    } elseif {$element_properties(where_clause) ne "" \
-			  && [lsearch $list_properties(element_where_clauses) [string trim $element_properties(where_clause)]] < 0} {
-		lappend list_properties(element_where_clauses) $element_properties(where_clause)
-	    }
-	}
+                lappend list_properties(from_clauses) $element_properties(from_clause)
+            }
+            # get the select clause
+            if {$element_properties(select_clause_eval) ne "" \
+                    && [lsearch $list_properties(element_select_clauses) [string trim  [uplevel $list_properties(ulevel) $element_properties(select_clause_eval)]]] < 0} {
+                lappend list_properties(element_select_clauses) [uplevel $list_properties(ulevel) $element_properties(select_clause_eval)]
+            } elseif {$element_properties(select_clause) ne "" \
+                          && [lsearch $list_properties(element_select_clauses) [string trim $element_properties(select_clause)]] < 0} {
+                lappend list_properties(element_select_clauses) $element_properties(select_clause)
+            }
+            # get the where clause
+            if {$element_properties(where_clause_eval) ne "" \
+                    && [lsearch $list_properties(element_where_clauses) [string trim [uplevel $list_properties(ulevel) $element_properties(where_clause_eval)]]] < 0} {
+                lappend list_properties(element_where_clauses) [uplevel $list_properties(ulevel) $element_properties(where_clause_eval)]
+            } elseif {$element_properties(where_clause) ne "" \
+                          && [lsearch $list_properties(element_where_clauses) [string trim $element_properties(where_clause)]] < 0} {
+                lappend list_properties(element_where_clauses) $element_properties(where_clause)
+            }
+        }
     }
- }
+}
 
 
 ad_proc -private template::list::prepare_filters {
@@ -1547,16 +1572,16 @@
     Builds urls, selected_p, etc., for filters
 } {
     set level [template::adp_level]
-    
+
     # Get an upvar'd reference to list_properties
     get_reference -name $name
-    
+
     if {[info exists filter_names]} {
         set filter_refs [list]
         foreach filter_name $filter_names {
             lappend filter_refs ${name}:filter:${filter_name}:properties
         }
-        
+
     } else {
         set filter_refs $list_properties(filter_refs)
     }
@@ -1617,25 +1642,25 @@
                     lappend list_properties(from_clauses) [string trim $filter_properties(from_clause)]
                 }
             }
-	    # get the select clause
-	    if {$filter_properties(select_clause_eval) ne "" \
-		    && [lsearch $list_properties(element_select_clauses) $filter_properties(select_clause_eval)] < 0} {
-		lappend list_properties(filter_select_clauses) [uplevel $list_properties(ulevel) $filter_properties(select_clause_eval)]
-	    } elseif {$filter_properties(select_clause) ne "" \
-			  && [lsearch $list_properties(element_select_clauses) $filter_properties(select_clause)] < 0} {
-		lappend list_properties(filter_select_clauses) $filter_properties(select_clause)
-	    }
-	}
-	
+            # get the select clause
+            if {$filter_properties(select_clause_eval) ne "" \
+                    && [lsearch $list_properties(element_select_clauses) $filter_properties(select_clause_eval)] < 0} {
+                lappend list_properties(filter_select_clauses) [uplevel $list_properties(ulevel) $filter_properties(select_clause_eval)]
+            } elseif {$filter_properties(select_clause) ne "" \
+                          && [lsearch $list_properties(element_select_clauses) $filter_properties(select_clause)] < 0} {
+                lappend list_properties(filter_select_clauses) $filter_properties(select_clause)
+            }
+        }
+
         # If none were found, we may need to provide an 'other' entry below
         set found_selected_p 0
-        
+
         # Now generate selected_p, urls, add_urls
         foreach elm $filter_properties(values) {
 
             # Set label and value from the list element
-            # We do an lrange here, otherwise values would be set wrong 
-            # in case someone accidentally supplies a list with too many elements, 
+            # We do an lrange here, otherwise values would be set wrong
+            # in case someone accidentally supplies a list with too many elements,
             # because then the foreach loop would run more than once
             foreach { label value count } [lrange $elm 0 2] {}
 
@@ -1650,40 +1675,40 @@
                     if { (![info exists current_filter_value] || $current_filter_value eq "") } {
                         set selected_p 0
                     } else {
-			# Since here we have multiple values
-			# we set as selected_p the value that match any
-			# of the values present in the list
-			set selected_p 0
-			foreach val $current_filter_value {
-			    if { [util_sets_equal_p $val $value] } {
-				set selected_p 1
-				break
-			    }
-			}
+                        # Since here we have multiple values
+                        # we set as selected_p the value that match any
+                        # of the values present in the list
+                        set selected_p 0
+                        foreach val $current_filter_value {
+                            if { [util_sets_equal_p $val $value] } {
+                                set selected_p 1
+                                break
+                            }
+                        }
                     }
                 }
                 multivar {
                     # Value is a list of { key value } lists
                     # We only check the value whose key matches the filter name
-		    set selected_p 0
+                    set selected_p 0
                     foreach elm $value {
                         foreach { elm_key elm_value } [lrange $elm 0 1] {}
-                        if {$elm_key eq $filter_properties(name)} { 
+                        if {$elm_key eq $filter_properties(name)} {
                             set selected_p [exists_and_equal current_filter_value $elm_value]
                         }
                     }
                 }
             }
             # DAVEB Make multivar actually DO someting
             # set the other vars according to the settings
-             if {$selected_p && $filter_properties(type) eq "multivar"} {
-                 foreach elm $value {
-                     foreach { elm_key elm_value } [lrange $elm 0 1] {}
-                     if {$elm_key ne $filter_properties(name)} {
-                         set list_properties(filter,$elm_key) $elm_value
-                     }
-                 }
-             }
+            if {$selected_p && $filter_properties(type) eq "multivar"} {
+                foreach elm $value {
+                    foreach { elm_key elm_value } [lrange $elm 0 1] {}
+                    if {$elm_key ne $filter_properties(name)} {
+                        set list_properties(filter,$elm_key) $elm_value
+                    }
+                }
+            }
 
             lappend filter_properties(selected_p) $selected_p
             set found_selected_p [expr {$found_selected_p || $selected_p}]
@@ -1697,8 +1722,8 @@
             switch $filter_properties(type) {
                 singleval - multival {
                     lappend filter_properties(urls) [get_url \
-                                 -name $name \
-                                 -override [list [list $filter_properties(var_spec) $value]]]
+                                                         -name $name \
+                                                         -override [list [list $filter_properties(var_spec) $value]]]
                 }
                 multivar {
                     # We just use the value-list directly
@@ -1714,19 +1739,19 @@
                 set __filter_value $value
                 lappend filter_properties(add_urls) [uplevel $list_properties(ulevel) subst $filter_properties(add_url_eval)]
             }
-	    
 
-	    # Handle 'other_label'
-	    if { ([info exists current_filter_value] && $current_filter_value ne "") && \
-		     !$found_selected_p && \
-		     $filter_properties(other_label) ne "" } {
-		
-		# Add filter entry with the 'other_label'.
-		lappend filter_properties(values) [list $filter_properties(other_label) {}]
-		lappend filter_properties(urls) {}
-		lappend filter_properties(selected_p) 1
-	    }
-	}
+
+            # Handle 'other_label'
+            if { [info exists current_filter_value] && $current_filter_value ne ""
+                 && !$found_selected_p
+                 && $filter_properties(other_label) ne ""
+             } {
+                # Add filter entry with the 'other_label'.
+                lappend filter_properties(values) [list $filter_properties(other_label) {}]
+                lappend filter_properties(urls) {}
+                lappend filter_properties(selected_p) 1
+            }
+        }
     }
 }
 
@@ -1735,7 +1760,7 @@
     {-style ""}
 } {
     set level [template::adp_level]
-    
+
     # Provide a reference to the list properties for use by the list template
     # Get an upvar'd reference to list_properties
     get_reference -name $name
@@ -1758,73 +1783,69 @@
         add_url \
         selected_p \
         type
-    
+
     foreach filter_ref $list_properties(filter_refs) {
 
         upvar #$level $filter_ref filter_properties
-        
+
         if { ![template::util::is_true $filter_properties(hide_p)] } {
 
             # Loop over 'values' and 'url' simultaneously
             foreach elm $filter_properties(values) url $filter_properties(urls) selected_p $filter_properties(selected_p) add_url $filter_properties(add_urls) {
-                
 
+
                 # 'label' is the first element, 'value' the second
-                # We do an lrange here, otherwise values would be set wrong 
-                # in case someone accidentally supplies a list with too many elements, 
+                # We do an lrange here, otherwise values would be set wrong
+                # in case someone accidentally supplies a list with too many elements,
                 # because then the foreach loop would run more than once
                 foreach { label value count } [lrange $elm 0 2] {}
-                
+
                 if { [string trim $label] eq "" } {
                     set label $filter_properties(null_label)
                 }
 
-		if {$filter_properties(type) eq "multival"} {
-		    # We need to ns_urlencode the name to work
-		    set filter_properties_name [ns_urlencode $filter_properties(name)]
-		} else {
-		    set filter_properties_name $filter_properties(name)
-		}
+                if {$filter_properties(type) eq "multival"} {
+                    # We need to ns_urlencode the name to work
+                    set filter_properties_name [ns_urlencode $filter_properties(name)]
+                } else {
+                    set filter_properties_name $filter_properties(name)
+                }
 
-		template::multirow -local append filters \
-		    $filter_properties_name \
-		    $filter_properties(label) \
-		    $filter_properties(clear_url) \
-		    [string_truncate -len 25 -- $label] \
-		    $value \
-		    $url \
-		    $label \
-		    $count \
-		    $add_url \
-		    $selected_p \
-		    $filter_properties(type)
+                template::multirow -local append filters \
+                    $filter_properties_name \
+                    $filter_properties(label) \
+                    $filter_properties(clear_url) \
+                    [string_truncate -len 25 -- $label] \
+                    $value \
+                    $url \
+                    $label \
+                    $count \
+                    $add_url \
+                    $selected_p \
+                    $filter_properties(type)
             }
         }
     }
-    
-    if {$style eq {}} { 
+
+    if {$style eq {}} {
         set style [parameter::get \
                        -package_id [apm_package_id_from_key "acs-templating"] \
                        -parameter DefaultListFilterStyle \
                        -default "filters"]
     }
-    # Added support for storing form templates outside acs-templating
-    if {[regexp {^/(.*)} $style path]} {
-        set file_stub "$::acs::rootdir$path"
-    } else {
-        set file_stub [template::get_resource_path]/lists/$style  
-    }
+    
+    set file_stub [template::resource_path -type lists -style $style]
 
     # ensure that the style template has been compiled and is up-to-date
     template::adp_init adp $file_stub
-    
+
     # get result of template output procedure into __adp_output
     # the only data source on which this template depends is the "elements"
     # multirow data source.  The output of this procedure will be
     # placed in __adp_output in this stack frame.
-   
+
     template::code::adp::$file_stub
-    
+
     return $__adp_output
 }
 
@@ -1838,28 +1859,28 @@
     @param default_summary_p Include a default summary if one does not exist
 
     @return HTML attributes built from the list in array get format
-    
+
     2/28/2007 - Project Zen - Modifying to handle a default value for summary if default_summary_p = 1
 } {
     set output {}
     set summary_exists_p 0
     foreach { key value } $html {
-	if { $key eq "summary" } {
-	    if { $value ne "" } {
-		set summary_exists_p 1
-		append output " summary=\"[ad_quotehtml $value]\""
-	    } 
-	} else {
-	    if { $value ne "" } {
-		append output " [ad_quotehtml $key]=\"[ad_quotehtml $value]\""
-	    } else {
-		append output " [ad_quotehtml $key]"
-	    }
-	}
+        if { $key eq "summary" } {
+            if { $value ne "" } {
+                set summary_exists_p 1
+                append output " summary=\"[ns_quotehtml $value]\""
+            }
+        } else {
+            if { $value ne "" } {
+                append output " [ns_quotehtml $key]=\"[ns_quotehtml $value]\""
+            } else {
+                append output " [ns_quotehtml $key]"
+            }
+        }
     }
 
     if {$default_summary_p && !$summary_exists_p} {
-	append output " summary=\"[_ acs-templating.DefaultSummary [list list_name \@list_properties.name\@]]\""
+        append output " summary=\"[_ acs-templating.DefaultSummary [list list_name \@list_properties.name\@]]\""
     }
 
     return $output
@@ -1881,102 +1902,114 @@
     {-ulevel 1}
 } {
     Adds an element to a list builder list.
-    
+
     

This proc shouldn't be called directly, only through template::list::create. - +

These are the available properties in the spec:

@param list_name Name of list. @param element_name Name of the element. - - @param spec The spec for this filter. This is an array list of property/value pairs, where the right hand side - is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. - + + @param spec The spec for this filter. This is an array list of property/value pairs, where the right hand side + is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. + @param ulevel Where we should uplevel to when doing the subst's. Defaults to '1', meaning the caller's scope. } { # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - - # Get the list properties + + # Get the list properties lappend list_properties(elements) $element_name # We store the full element ref name, so its easy to find later @@ -1995,6 +2028,7 @@ html {} display_col {} display_template {} + display_template_name {} link_url_col {} link_url_eval {} link_html {} @@ -2005,12 +2039,12 @@ orderby_asc {} orderby_desc {} default_direction {} - select_clause {} - select_clause_eval {} - from_clause {} - from_clause_eval {} - where_clause {} - where_clause_eval {} + select_clause {} + select_clause_eval {} + from_clause {} + from_clause_eval {} + where_clause {} + where_clause_eval {} } # These attributes are internal listbuilder attributes @@ -2031,12 +2065,12 @@ # Let the element know its own name set element_properties(name) $element_name - + # Let the element know its owner's name set element_properties(list_name) $list_name - + incr ulevel - + set_properties \ -list_name $list_name \ -element_name $element_name \ @@ -2071,7 +2105,7 @@ lappend orderby_spec $elm $element_properties($elm) } } - + template::list::orderby::create \ -list_name $list_name \ -orderby_name $element_properties(name) \ @@ -2135,7 +2169,7 @@ } { # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - + get_reference \ -list_name $list_name \ -element_name $element_name @@ -2144,14 +2178,14 @@ display_eval - link_url_eval { # This is a chunk of Tcl code, which should be executed later, not now set element_properties($property) $value - + # Remember that we'll have to do dynamic columns set list_properties(dynamic_cols_p) 1 } aggregate { # Remember that we'll have to do aggregation set list_properties(aggregates_p) 1 - + # do an uplevel subst on the value now set element_properties($property) [uplevel $ulevel [list subst $value]] } @@ -2211,14 +2245,21 @@ # We ignore if the element doesn't exist, 'cause then we'll just hope it exists in the multirow and display the value directly get_reference -create -list_name $list_name -element_name $element_name - if { ([info exists element_properties(display_template)] && $element_properties(display_template) ne "") } { - set output $element_properties(display_template) - } elseif { ([info exists element_properties(display_col)] && $element_properties(display_col) ne "") } { - set output "@$multirow.$element_properties(display_col)@" - } else { - set output "@$multirow.$element_name@" + if { [info exists element_properties(display_template_name)] && $element_properties(display_template_name) ne "" } { + set stub [template::resource_path -type display_templates -style $element_properties(display_template_name)] + if {[file readable $stub.adp]} { + set output [template::util::read_file $stub.adp] + } } - + if { ![info exists output] } { + if { [info exists element_properties(display_template)] && $element_properties(display_template) ne "" } { + set output $element_properties(display_template) + } elseif { [info exists element_properties(display_col)] && $element_properties(display_col) ne "" } { + set output "@$multirow.$element_properties(display_col)@" + } else { + set output "@$multirow.$element_name@" + } + } # We have support for making the cell contents a hyperlink right here, because it's so common set link_url {} set link_html {} @@ -2228,17 +2269,18 @@ } elseif { [info exists element_properties(link_url)] && $element_properties(link_url) ne "" } { set link_url $element_properties(link_url) } - + if { [info exists element_properties(link_html_col)] && $element_properties(link_html_col) ne "" } { set link_html "@$multirow.$element_properties(link_html_col)@" } elseif { [info exists element_properties(link_html)] && $element_properties(link_html) ne "" } { set link_html $element_properties(link_html) } - + if { $link_url ne "" } { set old_output $output - set output [subst {$old_output$old_output}] + set output [subst {$old_output$old_output}] } return $output @@ -2261,66 +2303,66 @@ {-ulevel 1} } { Adds a filter to a list builder list. - +

This proc shouldn't be called directly, only through template::list::create. - +

These are the available properties in the spec:

@@ -2331,30 +2373,30 @@ @param list_name Name of list. @param filter_name Name of the filter. - - @param spec The spec for this filter. This is an array list of property/value pairs, where the right hand side - is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. - + + @param spec The spec for this filter. This is an array list of property/value pairs, where the right hand side + is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. + @param ulevel Where we should uplevel to when doing the subst's. Defaults to '1', meaning the caller's scope. } { set level [template::adp_level] # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - + # Remember the filters and their order lappend list_properties(filters) $filter_name # Properties are going to be stored in an array named 'list-name:filter:filter-name:properties' - if {$filter_name eq ""} { - error "Invalid filter name for list '$list_name', spec: $spec" + if {$filter_name eq ""} { + error "Invalid filter name for list '$list_name', spec: $spec" } set filter_ref "$list_name:filter:$filter_name:properties" # We also store the full filter array name, so its easy to find < lappend list_properties(filter_refs) $filter_ref - # Upvar the filter properties array + # Upvar the filter properties array upvar #$level $filter_ref filter_properties # Setup filter defaults @@ -2370,13 +2412,13 @@ where_clause_eval {} null_where_clause {} null_where_clause_eval {} - from_clause {} - from_clause_eval {} - select_clause {} - select_clause_eval {} + from_clause {} + from_clause_eval {} + select_clause {} + select_clause_eval {} other_label {} null_label {} - form_element_properties {} + form_element_properties {} } # Prepopulate some automatically generated values @@ -2386,13 +2428,13 @@ add_urls {} selected_p {} } - + # Let the filter know its own name set filter_properties(name) $filter_name # Let the filter know its owner's name set filter_properties(list_name) $list_name - + set_properties \ -list_name $list_name \ -filter_name $filter_name \ @@ -2408,7 +2450,7 @@ set filter_properties(var_spec) "${filter_name}:multiple" } } - lappend list_properties(filters_export) $filter_properties(var_spec) + lappend list_properties(filters_export) $filter_properties(var_spec) } ad_proc -public template::list::filter::get_refname { @@ -2434,11 +2476,11 @@ Build a reference to the given filter for the given list template. } { set refname [get_refname -list_name $list_name -filter_name $filter_name] - + if { !$create_p && ![uplevel \#[template::adp_level] [list info exists $refname]] } { error "Filter '$filter_name' not found" } - + uplevel upvar #[template::adp_level] $refname $local_name } @@ -2453,7 +2495,7 @@ } { # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - + get_reference \ -list_name $list_name \ -filter_name $filter_name @@ -2531,13 +2573,13 @@ @return True (1) if the filter exists, false (0) if not. } { set refname [get_refname -list_name $list_name -filter_name $filter_name] - + return [uplevel \#[template::adp_level] [list info exists $refname]] } - + ##### # # template::list::format namespace @@ -2552,66 +2594,66 @@ {-ulevel 1} } { Adds a format to a list builder list. - +

This proc shouldn't be called directly, only through template::list::create. - +

These are the available properties in the spec:

@param list_name Name of list. @param format_name Name of the format. - - @param spec The spec for this format. This is an array list of property/value pairs, where the right hand side - is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. - + + @param spec The spec for this format. This is an array list of property/value pairs, where the right hand side + is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. + @param ulevel Where we should uplevel to when doing the subst's. Defaults to '1', meaning the caller's scope. } { set level [template::adp_level] # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - + # Remember the formats and their order lappend list_properties(formats) $format_name @@ -2621,7 +2663,7 @@ # We also store the full format array name, so its easy to find < lappend list_properties(format_refs) $format_ref - # Upvar the format properties array + # Upvar the format properties array upvar #$level $format_ref format_properties # Setup format defaults @@ -2635,13 +2677,13 @@ row {} template {} } - + # Let the format know its own name set format_properties(name) $format_name # Let the format know its owner's name set format_properties(list_name) $list_name - + # Counting the row number within one row of the dataset set subrownum 0 set elementnum 0 @@ -2655,25 +2697,25 @@ # This is the layout specification for table layouts set value [uplevel $ulevel [list subst $value]] incr subrownum - + foreach { element_name spec } $value { incr elementnum - + template::list::element::get_reference \ -list_name $list_name \ -element_name $element_name - + # Set elementnum and subrownum set element_properties(elementnum) $elementnum set element_properties(subrownum) $subrownum - + # Set/override additional element properties from the spec template::list::element::set_properties \ -list_name $list_name \ -element_name $element_name \ -spec $spec \ - -ulevel [expr {$ulevel + 1}] - + -ulevel [expr {$ulevel + 1}] + # Remember the display order lappend list_properties(display_elements) $element_name } @@ -2699,23 +2741,23 @@ } } } - + # For the currently selected format, copy some things over to the list properties if {$format_name eq $selected_format} { if { $format_properties(style) eq "" } { set format_properties(style) $format_properties(layout) } - + # Move style up to the list_properties if { $format_properties(style) ne "" } { set list_properties(style) $format_properties(style) } - + # Move output up to the list_properties if { $format_properties(output) ne "" } { set list_properties(output) $format_properties(output) } - + # Move page_size up to the list_properties if { $format_properties(page_size) ne "" } { set list_properties(page_size) $format_properties(page_size) @@ -2749,74 +2791,74 @@ {-ulevel 1} } { Adds an orderby to a list builder list. - +

This proc shouldn't be called directly, only through template::list::create. - +

These are the available properties in the spec:

It is difficult, but you can sort hierarchical queries. @param list_name Name of list. @param orderby_name Name of the orderby. - - @param spec The spec for this orderby. This is an array list of property/value pairs, where the right hand side - is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. - + + @param spec The spec for this orderby. This is an array list of property/value pairs, where the right hand side + is 'subst'ed in the caller's namespace, except for *_eval properties, which are 'subst'ed inside the multirow. + @param ulevel Where we should uplevel to when doing the subst's. Defaults to '1', meaning the caller's scope. @see template::list::orderby_clause } { # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - - # Get the list properties + + # Get the list properties lappend list_properties(orderbys) $orderby_name # We store the full element ref name, so its easy to find later lappend list_properties(orderby_refs) [get_refname -list_name $list_name -orderby_name $orderby_name] # Create the orderby properties array if {$orderby_name eq ""} { - error "Invalid orderby field or spec for list '$list_name', spec: $spec" + error "Invalid orderby field or spec for list '$list_name', spec: $spec" } get_reference -create -list_name $list_name -orderby_name $orderby_name @@ -2833,15 +2875,15 @@ # These attributes are internal listbuilder attributes array set orderby_properties { } - + # Let the orderby know its own name set orderby_properties(name) $orderby_name - + # Let the orderby know its owner's name set orderby_properties(list_name) $list_name incr ulevel - + set_properties \ -list_name $list_name \ -orderby_name $orderby_name \ @@ -2865,11 +2907,11 @@ -spec [list label [_ acs-templating.Sort_order]] \ -ulevel 2 } - + template::list::filter::get_reference \ -list_name $list_name \ -filter_name $list_properties(orderby_name) - + lappend filter_properties(values) [list $orderby_properties(label) "${orderby_name},$orderby_properties(default_direction)"] # Return an element which can be put into the 'values' property of a filter @@ -2930,7 +2972,7 @@ } { # Get an upvar'd reference to list_properties template::list::get_reference -name $list_name - + get_reference \ -list_name $list_name \ -orderby_name $orderby_name @@ -3005,31 +3047,27 @@ template_tag listtemplate { chunk params } { - set level [template::adp_level] - - set list_name [template::get_attribute listtemplate $params name] + set list_name [template::get_attribute listtemplate $params name] set style [ns_set iget $params style] - - template::adp_append_code "set list_properties(name) [list $list_name]" + template::adp_append_code "set list_properties(name) [list $list_name]" template::adp_append_string \ "\[template::list::render -name \"$list_name\" -style \"$style\"\]" } template_tag listelement { params } { - + set element_name [template::get_attribute listelement $params name] - # list_properties will be available, because + # list_properties will be available, because template::adp_append_string \ "\[template::list::element::render -list_name \${list_properties(name)} -element_name $element_name\]" } template_tag listrow { params } { - set level [template::adp_level] template::adp_append_string \ @@ -3038,10 +3076,10 @@ template_tag listfilters { chunk params } { set level [template::adp_level] - + set list_name [template::get_attribute listfilters $params name] set style [ns_set iget $params style] - + template::adp_append_string \ "\[template::list::render_filters -name \"$list_name\" -style \"$style\"\]" } @@ -3051,7 +3089,7 @@ set list_name [template::get_attribute listfilters $params name] set style [ns_set iget $params style] - + template::adp_append_string \ "\[template::list::render_form_filters -name \"$list_name\" -style \"$style\"\]" } @@ -3060,9 +3098,9 @@ {-name:required} {-style ""} } { - + set level [template::adp_level] - + # Provide a reference to the list properties for use by the list template # Get an upvar'd reference to list_properties get_reference -name $name @@ -3078,49 +3116,49 @@ filter_label \ filter_clear_url \ selected_p \ - clear_one_url \ + clear_one_url \ widget - + foreach filter_ref $list_properties(filter_refs) { upvar #$level $filter_ref filter_properties if { ![template::util::is_true $filter_properties(hide_p)] } { foreach elm $filter_properties(values) url $filter_properties(urls) selected_p $filter_properties(selected_p) add_url $filter_properties(add_urls) { - if {![info exists filter_properties(clear_one_url)]} { - set filter_properties(clear_one_url) "" - } + if {![info exists filter_properties(clear_one_url)]} { + set filter_properties(clear_one_url) "" + } if {[string is true $selected_p]} { - template::multirow -local append filters \ - $filter_properties(name) \ - $filter_properties(label) \ - $filter_properties(clear_url) \ - $selected_p \ - $filter_properties(clear_one_url) \ - [expr {[info exists filter_properties(widget)] ? $filter_properties(widget) : ""}] + template::multirow -local append filters \ + $filter_properties(name) \ + $filter_properties(label) \ + $filter_properties(clear_url) \ + $selected_p \ + $filter_properties(clear_one_url) \ + [expr {[info exists filter_properties(widget)] ? $filter_properties(widget) : ""}] } } } } ############################################################ ############################################################ - if {$style eq {}} { + if {$style eq ""} { set style [parameter::get \ -package_id [apm_package_id_from_key "acs-templating"] \ -parameter DefaultListFilterStyle \ -default "filters"] } - set file_stub "[template::get_resource_path]/lists/$style" + set file_stub [template::resource_path -type lists -style $style] # ensure that the style template has been compiled and is up-to-date template::adp_init adp $file_stub - + # get result of template output procedure into __adp_output # the only data source on which this template depends is the "elements" # multirow data source. The output of this procedure will be # placed in __adp_output in this stack frame. - + template::code::adp::$file_stub - + return $__adp_output } @@ -3147,119 +3185,119 @@ # loop through all the filters in this list foreach filter_ref $list_properties(filter_refs) { upvar #$level $filter_ref filter_properties - if {$filter_properties(label) ne "" && [lsearch $filter_exclude_from_key $filter_properties(name)] < 0} { - # filters with a label will be added to the form for the user - # to choose from - lappend filter_names_options_tmp [list $filter_properties(label) $filter_properties(name)] - } + if {$filter_properties(label) ne "" && [lsearch $filter_exclude_from_key $filter_properties(name)] < 0} { + # filters with a label will be added to the form for the user + # to choose from + lappend filter_names_options_tmp [list $filter_properties(label) $filter_properties(name)] + } - # filters without a label are added as hidden elements - # to the form so that quer params for the list - # and group by/order by are preserved when the filter - # form is used + # filters without a label are added as hidden elements + # to the form so that quer params for the list + # and group by/order by are preserved when the filter + # form is used - # grab the current value of the filter out of the list if - # it exists + # grab the current value of the filter out of the list if + # it exists upvar $list_properties(ulevel) $filter_properties(name) current_filter_value if {[info exists current_filter_value] && $current_filter_value ne ""} { - + if {[lsearch $filter_exclude_from_key $filter_properties(name)] > -1} { lappend filter_hidden_filters $filter_properties(name) } else { lappend filter_key_filters $filter_properties(name) $current_filter_value } - } + } } - upvar #[template::adp_level] __list_filter_form_client_property_key list_filter_form_client_property_key + upvar #[template::adp_level] __list_filter_form_client_property_key list_filter_form_client_property_key # we only get 50 characters # to save our clienty property name, we can encode it into an # ns_sha1 hash to make it fit. we don't extract the data from the # property name so this should work fine -# set list_filter_form_client_property_key [ns_sha1 [list [ad_conn url] $name $filter_key_filters]] + # set list_filter_form_client_property_key [ns_sha1 [list [ad_conn url] $name $filter_key_filters]] set list_filter_form_client_property_key [ns_sha1 [list [ad_conn url] $name]] upvar \#[template::adp_level] __client_property_filters client_property_filters set client_property_filters [ad_get_client_property acs-templating $list_filter_form_client_property_key] # take out filters we already applied... set i 0 foreach option_list $filter_names_options_tmp { - set option_label [lindex $option_list 0] - set option_name [lindex $option_list 1] - if {"${name}:filter:${option_name}:properties" ni $client_property_filters} { - lappend filter_names_options [list $option_label $option_name] - } + set option_label [lindex $option_list 0] + set option_name [lindex $option_list 1] + if {"${name}:filter:${option_name}:properties" ni $client_property_filters} { + lappend filter_names_options [list $option_label $option_name] + } } - # build an ad_form form based on the choosen filters + # build an ad_form form based on the chosen filters set filters_form_name list-filters-$name set add_filter_form_name list-filter-add-$name ad_form -name $add_filter_form_name -form { - {choose_filter:text(select) {label "Add Filter"} {options {$filter_names_options}} } - {name:text(hidden) {value $name}} - {add_filter:text(submit) {label "Add"}} - {clear_all:text(submit) {label "Clear All"}} - {clear_one:text(hidden),optional} + {choose_filter:text(select) {label "Add Filter"} {options {$filter_names_options}} } + {name:text(hidden) {value $name}} + {add_filter:text(submit) {label "Add"}} + {clear_all:text(submit) {label "Clear All"}} + {clear_one:text(hidden),optional} } foreach fhf $filter_hidden_filters { - ad_form -extend -name $add_filter_form_name -form { - {$fhf:text(hidden),optional} - } + ad_form -extend -name $add_filter_form_name -form { + {$fhf:text(hidden),optional} + } } ad_form -extend -name $add_filter_form_name -on_request { - # setup little Xs to click to clear one field - # pass the name of the field in the clear_one variable + # setup little Xs to click to clear one field + # pass the name of the field in the clear_one variable - set __form [ns_getform] - set clear_one [ns_set get $__form clear_one] + set __form [ns_getform] + set clear_one [ns_set get $__form clear_one] - if {([info exists clear_one] && $clear_one ne "")} { - # loop through the saved filters and remove - # the filter from the client property if its - # specified in clear_one - set __old_client_property_filters [ad_get_client_property acs-templating $__list_filter_form_client_property_key] - set __client_property_filters [list] + if {([info exists clear_one] && $clear_one ne "")} { + # loop through the saved filters and remove + # the filter from the client property if its + # specified in clear_one + set __old_client_property_filters [ad_get_client_property acs-templating $__list_filter_form_client_property_key] + set __client_property_filters [list] - foreach {__ref __value} $__old_client_property_filters { - if {[set ${__ref}(name)] ne $clear_one} { - lappend __client_property_filters $__ref $__value - } - } - # if we changed the list of filters, save it in the - # client property, we read it later on to build the - # form of selected filters - set client_property_filters $__client_property_filters - ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters - # now reload the form. excluding var clear_one - set pattern [ns_urlencode "clear_one"]=[ns_urlencode "$clear_one"] - regsub "${pattern}&?" [ad_return_url] {} url - ad_returnredirect $url - } + foreach {__ref __value} $__old_client_property_filters { + if {[set ${__ref}(name)] ne $clear_one} { + lappend __client_property_filters $__ref $__value + } + } + # if we changed the list of filters, save it in the + # client property, we read it later on to build the + # form of selected filters + set client_property_filters $__client_property_filters + ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters + # now reload the form. excluding var clear_one + set pattern [ns_urlencode "clear_one"]=[ns_urlencode "$clear_one"] + regsub "${pattern}&?" [ad_return_url] {} url + ad_returnredirect $url + } } -on_submit { - if {([info exists clear_all] && $clear_all ne "")} { - set __client_property_filters {} - ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters - break - } - template::list::get_reference -name $name - foreach filter_ref $list_properties(filter_refs) { - upvar \#[template::adp_level] $filter_ref filter_properties - if {$filter_properties(name) eq $choose_filter} { - lappend __client_property_filters $filter_ref "" - } - } - ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters + if {([info exists clear_all] && $clear_all ne "")} { + set __client_property_filters {} + ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters + break + } + template::list::get_reference -name $name + foreach filter_ref $list_properties(filter_refs) { + upvar \#[template::adp_level] $filter_ref filter_properties + if {$filter_properties(name) eq $choose_filter} { + lappend __client_property_filters $filter_ref "" + } + } + ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters } # create the form the holds the actual filter values ad_form -name $filters_form_name -has_submit 1 -form { - {name:text(hidden) {value $name}} + {name:text(hidden) {value $name}} } # we need to pass the hidden list filters in this form too - # since we need to preserve the other variables if either + # since we need to preserve the other variables if either # the add filter or the apply filter form is submitted foreach fhf $filter_hidden_filters { - ad_form -extend -name $filters_form_name -form { - {$fhf:text(hidden),optional} - } + ad_form -extend -name $filters_form_name -form { + {$fhf:text(hidden),optional} + } upvar \#[template::adp_level] $name:filter:${fhf}:properties filter_properties set filter_properties(widget) hidden set filter_properties(selected_p) t @@ -3271,37 +3309,37 @@ # sets them, we want to pull them out of the form instead of # setting local variables to prevent collisions foreach fhf $filter_hidden_filters { - lappend filter_hidden_filters_url_vars [list $fhf [template::element::get_value $add_filter_form_name $fhf]] + lappend filter_hidden_filters_url_vars [list $fhf [template::element::get_value $add_filter_form_name $fhf]] } set visible_filters_p 0 # add a select box for filters with a list of valid values # otherwise add a regular text box foreach {f_ref f_value} $client_property_filters { - upvar \#[template::adp_level] $f_ref filter_properties + upvar \#[template::adp_level] $f_ref filter_properties if {$filter_properties(label) ne "" \ && $filter_properties(hide_p) eq 0 \ && [lsearch $filter_exclude_from_key $filter_properties(name)] < 0} { incr visible_filters_p } - if {![template::element::exists $filters_form_name $filter_properties(name)]} { - # extract options - set options [list] + if {![template::element::exists $filters_form_name $filter_properties(name)]} { + # extract options + set options [list] - foreach elm $filter_properties(values) url $filter_properties(urls) selected_p $filter_properties(selected_p) add_url $filter_properties(add_urls) { - # Loop over 'values' and 'url' simultaneously - # 'label' is the first element, 'value' the second - # We do an lrange here, otherwise values would be set wrong - # in case someone accidentally supplies a list with too many elements, - # because then the foreach loop would run more than once - foreach { label value count } [lrange $elm 0 2] {} + foreach elm $filter_properties(values) url $filter_properties(urls) selected_p $filter_properties(selected_p) add_url $filter_properties(add_urls) { + # Loop over 'values' and 'url' simultaneously + # 'label' is the first element, 'value' the second + # We do an lrange here, otherwise values would be set wrong + # in case someone accidentally supplies a list with too many elements, + # because then the foreach loop would run more than once + foreach { label value count } [lrange $elm 0 2] {} - if { [string trim $label] eq "" } { - set label $filter_properties(null_label) - } - lappend options [list $label $value] - } - set clear_url_vars [concat [list [list clear_one $filter_properties(name)]] $filter_hidden_filters_url_vars] - set filter_properties(clear_one_url) [export_vars -base [ad_conn url] $clear_url_vars] + if { [string trim $label] eq "" } { + set label $filter_properties(null_label) + } + lappend options [list $label $value] + } + set clear_url_vars [concat [list [list clear_one $filter_properties(name)]] $filter_hidden_filters_url_vars] + set filter_properties(clear_one_url) [export_vars -base [ad_conn url] $clear_url_vars] set form_element(element_name) $filter_properties(name) set form_element(widget) text @@ -3317,55 +3355,55 @@ } } set ad_form_element [list ${form_element(element_name)}:${form_element(datatype)}(${form_element(widget)}),optional] - if {$filter_properties(type) eq "multival"} { - set ad_form_element [list "[lindex $ad_form_element 0],multiple"] - } + if {$filter_properties(type) eq "multival"} { + set ad_form_element [list "[lindex $ad_form_element 0],multiple"] + } foreach {var value} [array get form_element] { if {[lsearch {name widget datatype} $var] < 0} { lappend ad_form_element [list $var $value] } } ad_form -extend -name $filters_form_name -form [list $ad_form_element] - - set filter_properties(widget) $form_element(widget) + + set filter_properties(widget) $form_element(widget) set filter_properties(selected_p) t - array unset form_element - } - } - + array unset form_element + } + } + ad_form -extend -name $filters_form_name -on_request { - foreach {f_ref f_value} $__client_property_filters { - upvar \#[template::adp_level] $f_ref filter_properties - set $filter_properties(name) $f_value - } + foreach {f_ref f_value} $__client_property_filters { + upvar \#[template::adp_level] $f_ref filter_properties + set $filter_properties(name) $f_value + } } -on_submit { - # set the values of the filters, the creator of the list - # still has to process the values to generate a valid - # where clause - template::list::get_reference -name $name - set templist [list] - foreach {f_ref f_value} $__client_property_filters { - upvar \#[template::adp_level] $f_ref filter_properties - set filter_properties(value) [set $filter_properties(name)] - lappend templist $f_ref $filter_properties(value) - # hack in elements?? - if {[lsearch [template::multirow columns $list_properties(multirow)] $filter_properties(name)] > -1} { - # FIXME Don't do this where, don't allow filters for - # matching elmenet/filter names if element does not exist - # check if its a dynamic element...(has select_clause) - list::element::create -list_name $name -element_name $filter_properties(name) -spec [list label $filter_properties(label)] - } - } - set __client_property_filters $templist - ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters + # set the values of the filters, the creator of the list + # still has to process the values to generate a valid + # where clause + template::list::get_reference -name $name + set templist [list] + foreach {f_ref f_value} $__client_property_filters { + upvar \#[template::adp_level] $f_ref filter_properties + set filter_properties(value) [set $filter_properties(name)] + lappend templist $f_ref $filter_properties(value) + # hack in elements?? + if {[lsearch [template::multirow columns $list_properties(multirow)] $filter_properties(name)] > -1} { + # FIXME Don't do this where, don't allow filters for + # matching elmenet/filter names if element does not exist + # check if its a dynamic element...(has select_clause) + list::element::create -list_name $name -element_name $filter_properties(name) -spec [list label $filter_properties(label)] + } + } + set __client_property_filters $templist + ad_set_client_property acs-templating $__list_filter_form_client_property_key $__client_property_filters } # only show the submit button for the apply filters form if # there are filters selected by the user if {$visible_filters_p} { - ad_form -extend -name $filters_form_name -form { - {submit:text(submit) {label "Apply Filters"}} - } + ad_form -extend -name $filters_form_name -form { + {submit:text(submit) {label "Apply Filters"}} + } } else { # hard to figure out how to conditionally handle this in the # @@ -3383,19 +3421,25 @@ {-value:required} } { Sets a property on multiple list elements - + @param list_name Name of the list @param element_names List of element names @param property Which property to set @param value Value to set, all elements in element_names get this value } { foreach name $element_names { - template::list::element::set_property \ - -list_name $list_name \ - -element_name $name \ - -property $property \ - -value $value + template::list::element::set_property \ + -list_name $list_name \ + -element_name $name \ + -property $property \ + -value $value } } +# +# Local variables: +# mode: tcl +# tcl-indent-level: 4 +# indent-tabs-mode: nil +# End: