Index: /extensions/SmartAlbums/admin.php
===================================================================
--- /extensions/SmartAlbums/admin.php	(revision 26441)
+++ /extensions/SmartAlbums/admin.php	(revision 26442)
@@ -1,4 +1,4 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('SMART_PATH') or die('Hacking attempt!');
 
 global $conf, $template, $page;
@@ -25,4 +25,2 @@
 
 $template->assign_var_from_handle('ADMIN_CONTENT', 'SmartAlbums_content');
-
-?>
Index: /extensions/SmartAlbums/admin/album.php
===================================================================
--- /extensions/SmartAlbums/admin/album.php	(revision 26441)
+++ /extensions/SmartAlbums/admin/album.php	(revision 26442)
@@ -1,26 +1,4 @@
 <?php
-// +-----------------------------------------------------------------------+
-// | Piwigo - a PHP based photo gallery                                    |
-// +-----------------------------------------------------------------------+
-// | Copyright(C) 2008-2012 Piwigo Team                  http://piwigo.org |
-// | Copyright(C) 2003-2008 PhpWebGallery Team    http://phpwebgallery.net |
-// | Copyright(C) 2002-2003 Pierrick LE GALL   http://le-gall.net/pierrick |
-// +-----------------------------------------------------------------------+
-// | This program is free software; you can redistribute it and/or modify  |
-// | it under the terms of the GNU General Public License as published by  |
-// | the Free Software Foundation                                          |
-// |                                                                       |
-// | This program is distributed in the hope that it will be useful, but   |
-// | WITHOUT ANY WARRANTY; without even the implied warranty of            |
-// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      |
-// | General Public License for more details.                              |
-// |                                                                       |
-// | You should have received a copy of the GNU General Public License     |
-// | along with this program; if not, write to the Free Software           |
-// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
-// | USA.                                                                  |
-// +-----------------------------------------------------------------------+
-
-if(!defined("PHPWG_ROOT_PATH")) die ("Hacking attempt!");
+defined('SMART_PATH') or die('Hacking attempt!');
 
 // +-----------------------------------------------------------------------+
@@ -33,12 +11,13 @@
 
 check_input_parameter('cat_id', $_GET, false, PATTERN_ID);
-
-$admin_album_base_url = get_root_url().'admin.php?page=album-'.$_GET['cat_id'];
-$self_url = SMART_ADMIN.'-album&amp;cat_id='.$_GET['cat_id'];
+$cat_id = $_GET['cat_id'];
+
+$admin_album_base_url = get_root_url().'admin.php?page=album-'.$cat_id;
+$self_url = SMART_ADMIN.'-album&amp;cat_id='.$cat_id;
 
 $query = '
 SELECT *
   FROM '.CATEGORIES_TABLE.'
-  WHERE id = '.$_GET['cat_id'].'
+  WHERE id = '.$cat_id.'
 ;';
 $category = pwg_db_fetch_assoc(pwg_query($query));
@@ -48,4 +27,11 @@
   die("unknown album");
 }
+
+// category must be virtual
+if ($category['dir'] != NULL)
+{
+  die("physical album");
+}
+
 
 // +-----------------------------------------------------------------------+
@@ -60,12 +46,4 @@
 
 
-$cat_id = $_GET['cat_id'];
-
-// category must be virtual
-if ($category['dir'] != NULL)
-{
-  die("physical album");
-}
-
 // +-----------------------------------------------------------------------+
 // | Save Filters                                                          |
@@ -78,31 +56,34 @@
     var_dump($_POST['filters']);
   }
-  
+
   // test if it was a Smart Album
   $query = '
-SELECT DISTINCT category_id 
-  FROM '.CATEGORY_FILTERS_TABLE.' 
+SELECT DISTINCT category_id
+  FROM '.CATEGORY_FILTERS_TABLE.'
   WHERE category_id = '.$cat_id.'
 ;';
   $was_smart = pwg_db_num_rows(pwg_query($query));
-  
+
   /* this album is no longer a SmartAlbum */
-  if ( $was_smart AND !isset($_POST['is_smart']) )
+  if ($was_smart and !isset($_POST['is_smart']))
   {
     pwg_query('DELETE FROM '.IMAGE_CATEGORY_TABLE.' WHERE category_id = '.$cat_id.' AND smart = true;');
     pwg_query('DELETE FROM '.CATEGORY_FILTERS_TABLE.' WHERE category_id = '.$cat_id.';');
+
     set_random_representant(array($cat_id));
+
+    define('SMART_NOT_UPDATE', 1);
     invalidate_user_cache();
   }
   /* no filter selected */
-  else if ( isset($_POST['is_smart']) AND empty($_POST['filters']) )
-  {
-    array_push($page['errors'], l10n('No filter selected'));
+  else if (isset($_POST['is_smart']) and empty($_POST['filters']))
+  {
+    $page['errors'][] = l10n('No filter selected');
   }
   /* everything is fine */
-  else if ( isset($_POST['is_smart']) )
+  else if (isset($_POST['is_smart']))
   {
     pwg_query('DELETE FROM '.CATEGORY_FILTERS_TABLE.' WHERE category_id = '.$cat_id.';');
-    
+
     $inserts = array();
     foreach ($_POST['filters'] as $filter)
@@ -114,17 +95,17 @@
       }
     }
-    
+
     mass_inserts(
-      CATEGORY_FILTERS_TABLE, 
-      array('category_id', 'type', 'cond', 'value'), 
+      CATEGORY_FILTERS_TABLE,
+      array('category_id', 'type', 'cond', 'value'),
       $inserts,
       array('ignore'=>true)
       );
-    
+
     $associated_images = smart_make_associations($cat_id);
     $template->assign('IMAGE_COUNT', l10n_dec('%d photo', '%d photos', count($associated_images)));
-    
-    array_push($page['infos'], sprintf(l10n('%d photos associated to album %s'), count($associated_images), ''));
-    
+
+    $page['infos'][] = l10n('%d photos associated to album %s', count($associated_images), '');
+
     define('SMART_NOT_UPDATE', 1);
     invalidate_user_cache();
@@ -225,9 +206,9 @@
 /* get filters for this album */
 $query = '
-SELECT * 
-  FROM '.CATEGORY_FILTERS_TABLE.' 
+SELECT *
+  FROM '.CATEGORY_FILTERS_TABLE.'
   WHERE category_id = '.$cat_id.'
-  ORDER BY 
-    type ASC, 
+  ORDER BY
+    type ASC,
     cond ASC
 ;';
@@ -250,7 +231,7 @@
   WHERE id IN('.$filter['value'].')
 ;';
-    $filter['value'] = get_taglist($query); 
-  }
-  
+    $filter['value'] = get_taglist($query);
+  }
+
   $template->append('filters', $filter);
 }
@@ -260,5 +241,5 @@
 $template->assign('format_options', array(
   'portrait' => l10n('Portrait'),
-  'square'   => l10n('Square'),
+  'square'   => l10n('square'),
   'lanscape' => l10n('Landscape'),
   'panorama' => l10n('Panorama'),
@@ -274,8 +255,8 @@
 /* all albums */
 $query = '
-SELECT 
-    id, 
-    name, 
-    uppercats, 
+SELECT
+    id,
+    name,
+    uppercats,
     global_rank
   FROM '.CATEGORIES_TABLE.'
@@ -303,7 +284,10 @@
 while ($row = pwg_db_fetch_assoc($result))
 {
-  $widths[] = $row['width'];
-  $heights[] = $row['height'];
-  $ratios[] = floor($row['width'] * 100 / $row['height']) / 100;
+  if ($row['width']>0 && $row['height']>0)
+  {
+    $widths[] = $row['width'];
+    $heights[] = $row['height'];
+    $ratios[] = floor($row['width'] / $row['height'] * 100) / 100;
+  }
 }
 
@@ -354,11 +338,11 @@
 }
 
-foreach (array_keys($ratio_categories) as $ratio_category)
-{
-  if (count($ratio_categories[$ratio_category]) > 0)
-  {
-    $dimensions['ratio_'.$ratio_category] = array(
-      'min' => $ratio_categories[$ratio_category][0],
-      'max' => $ratio_categories[$ratio_category][count($ratio_categories[$ratio_category]) - 1]
+foreach ($ratio_categories as $ratio_name => $ratio_values)
+{
+  if (count($ratio_values) > 0)
+  {
+    $dimensions['ratio_'.$ratio_name] = array(
+      'min' => $ratio_values[0],
+      'max' => array_pop($ratio_values),
       );
   }
@@ -371,8 +355,8 @@
 {
   $query = '
-SELECT count(1) 
-  FROM '.IMAGE_CATEGORY_TABLE.' 
-  WHERE 
-    category_id = '.$cat_id.' 
+SELECT count(1)
+  FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE
+    category_id = '.$cat_id.'
     AND smart = true
 ';
@@ -396,5 +380,3 @@
 ));
 
-$template->set_filename('SmartAlbums_content', dirname(__FILE__).'/template/album.tpl');
-
-?>
+$template->set_filename('SmartAlbums_content', realpath(SMART_PATH . 'admin/template/album.tpl'));
Index: /extensions/SmartAlbums/admin/cat_list.php
===================================================================
--- /extensions/SmartAlbums/admin/cat_list.php	(revision 26441)
+++ /extensions/SmartAlbums/admin/cat_list.php	(revision 26442)
@@ -1,4 +1,4 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('SMART_PATH') or die('Hacking attempt!');
 
 if (isset($_GET['hide_messages']))
@@ -16,5 +16,5 @@
 $categories = array();
 $query = '
-SELECT 
+SELECT
     id,
     name,
@@ -51,5 +51,5 @@
   if (isset($output_create['error']))
   {
-    array_push($page['errors'], $output_create['error']);
+    $page['errors'][] = $output_create['error'];
   }
   else
@@ -69,9 +69,9 @@
     {
       $associated_images = smart_make_associations($category['id']);
-      array_push($page['infos'], 
-        sprintf(l10n('%d photos associated to album %s'), 
-          count($associated_images), 
-          '&laquo;'.trigger_event('render_category_name', $category['name'], 'admin_cat_list').'&raquo;'
-          )
+
+      $page['infos'][] = l10n(
+        '%d photos associated to album %s',
+        count($associated_images),
+        '&laquo;'.trigger_event('render_category_name', $category['name'], 'admin_cat_list').'&raquo;'
         );
     }
@@ -80,13 +80,13 @@
   else
   {
-    $associated_images = smart_make_associations($_GET['smart_generate']);    
-    array_push($page['infos'], 
-      sprintf(l10n('%d photos associated to album %s'), 
-        count($associated_images), 
-        '&laquo;'.trigger_event('render_category_name', $categories[ $_GET['smart_generate'] ]['name'], 'admin_cat_list').'&raquo;'
-        )
+    $associated_images = smart_make_associations($_GET['smart_generate']);
+
+    $page['infos'][] = l10n(
+      '%d photos associated to album %s',
+      count($associated_images),
+      '&laquo;'.trigger_event('render_category_name', $categories[ $_GET['smart_generate'] ]['name'], 'admin_cat_list').'&raquo;'
       );
   }
-  
+
   define('SMART_NOT_UPDATE', 1);
   invalidate_user_cache();
@@ -100,5 +100,5 @@
   'PWG_TOKEN' => get_pwg_token(),
  ));
- 
+
 // retrieve all existing categories for album creation
 $query = '
@@ -108,14 +108,13 @@
 
 display_select_cat_wrapper(
-  $query,
-  null,
+  $query, null,
   'category_options'
   );
-  
+
 if ($conf['SmartAlbums']['show_list_messages'])
 {
-  array_push($page['warnings'], l10n('Only SmartAlbums are displayed on this page'));
-  array_push($page['warnings'], sprintf(l10n('To order albums please go the main albums <a href="%s">management page</a>'), $base_url.'cat_list'));
-  array_push($page['warnings'], '<a href="'.$self_url.'&hide_messages">['.l10n('Don\'t show this message again').']</a>');
+  $page['warnings'][] = l10n('Only SmartAlbums are displayed on this page');
+  $page['warnings'][] = sprintf(l10n('To order albums please go the main albums <a href="%s">management page</a>'), $base_url.'cat_list');
+  $page['warnings'][] = '<a href="'.$self_url.'&hide_messages">['.l10n('Don\'t show this message again').']</a>';
 }
 
@@ -125,9 +124,9 @@
 
 $categories_count_images = array();
-if ( count($categories) )
+if (count($categories))
 {
   $query = '
-SELECT 
-    category_id, 
+SELECT
+    category_id,
     COUNT(image_id) AS total_images
   FROM '.IMAGE_CATEGORY_TABLE.'
@@ -154,9 +153,7 @@
       'U_SMART'     => $self_url.'&amp;smart_generate='.$category['id'],
     );
-  
+
   $template->append('categories', $tpl_cat);
 }
 
-$template->set_filename('SmartAlbums_content', dirname(__FILE__).'/template/cat_list.tpl');
-
-?>
+$template->set_filename('SmartAlbums_content', realpath(SMART_PATH . 'admin/template/cat_list.tpl'));
Index: /extensions/SmartAlbums/admin/config.php
===================================================================
--- /extensions/SmartAlbums/admin/config.php	(revision 26441)
+++ /extensions/SmartAlbums/admin/config.php	(revision 26442)
@@ -1,14 +1,13 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('SMART_PATH') or die('Hacking attempt!');
 
-// Enregistrement de la configuration
 if (isset($_POST['submit']))
 {
-  if ( $_POST['update_timeout'] == 0 or !preg_match('#^[0-9.]+$#', $_POST['update_timeout']) )
+  if ($_POST['update_timeout'] == 0 or !preg_match('#^[0-9.]+$#', $_POST['update_timeout']))
   {
-    array_push($page['errors'], l10n('Invalid number of days'));
+    $page['errors'][] = l10n('Invalid number of days');
     $_POST['update_timeout'] = $conf['SmartAlbums']['update_timeout'];
   }
-    
+
   $conf['SmartAlbums'] = array(
     'show_list_messages' => $conf['SmartAlbums']['show_list_messages'],
@@ -19,12 +18,10 @@
     'smart_is_forbidden' => isset($_POST['smart_is_forbidden']),
     );
-  
+
   conf_update_param('SmartAlbums', serialize($conf['SmartAlbums']));
-  array_push($page['infos'], l10n('Information data registered in database'));
+  $page['infos'][] = l10n('Information data registered in database');
 }
 
 $template->assign($conf['SmartAlbums']);
 
-$template->set_filename('SmartAlbums_content', dirname(__FILE__).'/template/config.tpl');
-
-?>
+$template->set_filename('SmartAlbums_content', realpath(SMART_PATH . 'admin/template/config.tpl'));
Index: /extensions/SmartAlbums/admin/template/album.tpl
===================================================================
--- /extensions/SmartAlbums/admin/template/album.tpl	(revision 26441)
+++ /extensions/SmartAlbums/admin/template/album.tpl	(revision 26442)
@@ -1,264 +1,278 @@
-{combine_css path=$SMART_PATH|@cat:"admin/template/style.css"}
-{combine_script id='sprintf' load='footer' path=$SMART_PATH|@cat:"admin/template/sprintf.js"}
+{combine_css path=$SMART_PATH|cat:'admin/template/style.css'}
 {include file='include/datepicker.inc.tpl'}
+{combine_script id='common' load='footer' path='admin/themes/default/js/common.js'}
+
+{combine_css path='themes/default/js/plugins/jquery.tokeninput.css'}
 {combine_script id='jquery.tokeninput' load='footer' require='jquery' path='themes/default/js/plugins/jquery.tokeninput.js'}
-{combine_css path="themes/default/js/plugins/chosen.css"}
+
+{combine_css path='themes/default/js/plugins/chosen.css'}
 {combine_script id='jquery.chosen' load='footer' path='themes/default/js/plugins/chosen.jquery.min.js'}
-{combine_css path="themes/default/js/ui/theme/jquery.ui.slider.css"}
+
+{combine_css path='themes/default/js/ui/theme/jquery.ui.slider.css'}
 {combine_script id='jquery.ui.slider' require='jquery.ui' load='footer' path='themes/default/js/ui/minified/jquery.ui.slider.min.js'}
 
-{footer_script}{literal}
-var count=0;
-var limit_count=0;
-var level_count=0;
-
-// MAIN EVENT HANDLERS
-$('#addFilter').change(function() {
-  add_filter($(this).attr('value'));
-  $(this).attr('value', '-1');
-});
-  
-$('#removeFilters').click(function() {
-  $('#filtersList li').each(function() {
-    $(this).remove();
+{*combine_script id='smartalbums.filters' require='common,datepicker.js,jquery.tokeninput,jquery.chosen,jquery.ui.slider'
+  path=$SMART_PATH|cat:'admin/template/filters.js' load='footer' template=true*}
+
+{footer_script require='jquery'}
+var addFilter = (function($){
+  var count=0,
+      limit_count=0,
+      level_count=0;
+
+  // MAIN EVENT HANDLERS
+  $('#addFilter').change(function() {
+    if ($(this).val() != -1) {
+      add_filter($(this).val());
+      $(this).val(-1);
+    }
   });
-  
-  limit_level=0;
-  level_count=0;
-  return false;
-});
-
-$('input[name="is_smart"]').change(function() {
-  $('#SmartAlbum_options').toggle();
-  $('input[name="countImages"]').toggle();
-  $('.count_images_wrapper').toggle();
-});
-
-$('input[name="countImages"]').click(function() {
-  countImages($("#smart"));
-  return false;
-});
-
-
-// ADD FILTER FUNCTIONS
-function add_filter(type, cond, value) {
-  count++;
-  
-  content = $("#filtersRepo #filter_"+type).html().replace(/iiii/g, count);
-  $block = $(content);
-  $("#filtersList").append($block);
-  
-  if (cond) {
-    select_cond($block, type, cond);
-  }
-  
-  if (value) {
-    if (type == "tags") {
-      $block.find(".filter-value .tagSelect").html(value);
-    }
-    else if (type == "album") {
-      select_options($block, value);
-    }
-    else if (type == "level") {
-      select_options($block, value);
-    }
-    else if (type != "dimensions") {
-      $block.find(".filter-value input").val(value);
-    }
-  }
-  
-  init_jquery_handlers($block);
-  
-  if (type == "dimensions") {
-    select_dimensions($block, cond, value);
-  }
-  
-  if (type == 'limit') {
-    limit_count=1;
-    $("#addFilter option[value='limit']").attr('disabled','disabled');
-  }
-  else if (type == 'level') {
-    level_count=1;
-    $("#addFilter option[value='level']").attr('disabled','disabled');
-  }
-}
-
-function select_cond($block, type, cond) {
-  $block.find(".filter-cond option").removeAttr('selected');
-  $block.find(".filter-cond option[value='"+cond+"']").attr('selected', 'selected');
-}
-
-function select_dimensions($block, cond, value) {
-  if (!cond) cond = 'width';
-  
-  $block.find(".filter-value span:not(.filter_dimension_info)").hide();
-  $block.find(".filter-value .dimension_"+cond).show();
-  
-  if (value) {
-    values = value.split(',');
-  }
-  else {
-    values = $block.find(".filter_dimension_"+cond+"_slider").slider("values");
-  }
-  $block.find(".filter_dimension_"+cond+"_slider").slider("values", values);
-}
-
-function select_options($block, value) {  
-  values = value.split(',');
-  for (j in values) {
-    $block.find(".filter-value option[value='"+ values[j] +"']").attr('selected', 'selected');
-  }
-}
-
-
-// DECLARE JQUERY PLUGINS AND VERSATILE HANDLERS
-function init_jquery_handlers($block) {
-  // remove filter
-  $block.find(".removeFilter").click(function() {
-    type = $(this).next("input").val();
+
+  $('#removeFilters').click(function() {
+    $('#filtersList li').each(function() {
+      $(this).remove();
+    });
+
+    limit_level=0;
+    level_count=0;
+    return false;
+  });
+
+  $('input[name="is_smart"]').change(function() {
+    $('#SmartAlbum_options').toggle();
+    $('input[name="countImages"]').toggle();
+    $('.count_images_wrapper').toggle();
+  });
+
+  $('input[name="countImages"]').click(function() {
+    countImages($("#smart"));
+    return false;
+  });
+
+
+  // ADD FILTER FUNCTIONS
+  function add_filter(type, cond, value) {
+    count++;
+
+    var content = $("#filtersRepo #filter_"+type).html().replace(/iiii/g, count);
+    $block = $($.parseHTML(content)).appendTo("#filtersList");
+
+    if (cond) {
+      select_cond($block, type, cond);
+    }
+
+    if (value) {
+      if (type == "tags") {
+        $block.find(".filter-value .tagSelect").html(value);
+      }
+      else if (type == "album") {
+        select_options($block, value);
+      }
+      else if (type == "level") {
+        select_options($block, value);
+      }
+      else if (type != "dimensions") {
+        $block.find(".filter-value input").val(value);
+      }
+    }
+
+    init_jquery_handlers($block);
+
+    if (type == "dimensions") {
+      select_dimensions($block, cond, value);
+    }
+
     if (type == 'limit') {
       limit_count=1;
-      $("#addFilter option[value='limit']").removeAttr('disabled');
+      $("#addFilter option[value='limit']").attr('disabled','disabled');
     }
     else if (type == 'level') {
       level_count=1;
-      $("#addFilter option[value='level']").removeAttr('disabled');
-    }
-    
-    $(this).parents('li').remove();
-    return false;
-  });
-
-  // date filter
-  if ($block.hasClass('filter_date')) {
-    $block.find("input[type='text']").each(function() {
-      $(this).datepicker({dateFormat:'yy-mm-dd', firstDay:1});
+      $("#addFilter option[value='level']").attr('disabled','disabled');
+    }
+  }
+
+  function select_cond($block, type, cond) {
+    $block.find(".filter-cond option").removeAttr('selected');
+    $block.find(".filter-cond option[value='"+cond+"']").attr('selected', 'selected');
+  }
+
+  function select_dimensions($block, cond, value) {
+    console.log($block, cond, value);
+    cond = cond || 'width';
+
+    $block.find(">.filter-value>span").hide();
+    $block.find(".dimension_"+cond).show();
+
+    if (value) {
+      values = value.split(',');
+    }
+    else {
+      values = $block.find(".filter_dimension_"+cond+"_slider").slider("values");
+    }
+    $block.find(".filter_dimension_"+cond+"_slider").slider("values", values);
+  }
+
+  function select_options($block, value) {
+    values = value.split(',');
+    for (j in values) {
+      $block.find(".filter-value option[value='"+ values[j] +"']").attr('selected', 'selected');
+    }
+  }
+
+
+  // DECLARE JQUERY PLUGINS AND VERSATILE HANDLERS
+  function init_jquery_handlers($block) {
+    // remove filter
+    $block.find(".removeFilter").click(function() {
+      type = $(this).next("input").val();
+      if (type == 'limit') {
+        limit_count=1;
+        $("#addFilter option[value='limit']").removeAttr('disabled');
+      }
+      else if (type == 'level') {
+        level_count=1;
+        $("#addFilter option[value='level']").removeAttr('disabled');
+      }
+
+      $(this).parents('li').remove();
+      return false;
     });
-  }
-
-  // tags filter
-  if ($block.hasClass('filter_tags')) {
-    $block.find(".tagSelect").tokenInput(
-    {/literal}
-      [{foreach from=$all_tags item=tag name=tags}{ldelim}"name":"{$tag.name|@escape:'javascript'}","id":"{$tag.id}"{rdelim}{if !$smarty.foreach.tags.last},{/if}{/foreach}],
-      {ldelim}
-        hintText: '{'Type in a search term'|@translate}',
-        noResultsText: '{'No results'|@translate}',
-        searchingText: '{'Searching...'|@translate}',
-        animateDropdown: false,
-        preventDuplicates: true,
-        allowCreation: false
-    {literal}
-    });
-  }
-  
-  // album filter
-  if ($block.hasClass('filter_album')) {
-    $block.find(".albumSelect").chosen();
-  }
-  
-  // dimension filter
-  if ($block.hasClass('filter_dimensions')) {
-    $block.find(".filter-cond select").change(function() {
-      select_dimensions($block, $(this).attr("value"));
-    });
-    {/literal}
-    
-    $block.find(".filter_dimension_width_slider").slider({ldelim}
-      range: true,
-      min: {$dimensions.bounds.min_width},
-      max: {$dimensions.bounds.max_width},
-      values: [{$dimensions.bounds.min_width}, {$dimensions.bounds.max_width}],
-      slide: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %d and %d pixels'|@translate}");
-      },
-      change: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %d and %d pixels'|@translate}");
-      }
-    });
-    
-    $block.find(".filter_dimension_height_slider").slider({ldelim}
-      range: true,
-      min: {$dimensions.bounds.min_height},
-      max: {$dimensions.bounds.max_height},
-      values: [{$dimensions.bounds.min_height}, {$dimensions.bounds.max_height}],
-      slide: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %d and %d pixels'|@translate}");
-      },
-      change: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %d and %d pixels'|@translate}");
-      }
-    });
-    
-    $block.find(".filter_dimension_ratio_slider").slider({ldelim}
-      range: true,
-      step: 0.01,
-      min: {$dimensions.bounds.min_ratio},
-      max: {$dimensions.bounds.max_ratio},
-      values: [{$dimensions.bounds.min_ratio}, {$dimensions.bounds.max_ratio}],
-      slide: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %.2f and %.2f'|@translate}");
-      },
-      change: function(event, ui) {ldelim}
-        change_dimension_info($block, ui.values, "{'between %.2f and %.2f'|@translate}");
-      }
-    });
-    {literal}
-    
-    $block.find("a.dimensions-choice").click(function() {
-      $block.find(".filter_dimension_"+ $(this).data("type") +"_slider").slider("values", 
-        [$(this).data("min"), $(this).data("max")]
+
+    // date filter
+    if ($block.hasClass('filter_date')) {
+      $block.find("input[type='text']").each(function() {
+        $(this).datepicker({
+          dateFormat:'yy-mm-dd',
+          firstDay:1
+        });
+      });
+    }
+
+    // tags filter
+    if ($block.hasClass('filter_tags')) {
+      $block.find(".tagSelect").tokenInput(
+        [{foreach from=$all_tags item=tag name=tags}{ name:"{$tag.name|escape:javascript}", id:"{$tag.id}" }{if !$smarty.foreach.tags.last},{/if}{/foreach}],
+        {
+          hintText: '{'Type in a search term'|translate}',
+          noResultsText: '{'No results'|translate}',
+          searchingText: '{'Searching...'|translate}',
+          animateDropdown: false,
+          preventDuplicates: true,
+          allowFreeTagging: false
+        }
       );
-    });
-  }
-}
-
-
-// GENERAL FUNCTIONS
-function change_dimension_info($block, values, text) {
-  $block.find("input[name$='[value][min]']").val(values[0]);
-  $block.find("input[name$='[value][max]']").val(values[1]);
-  $block.find(".filter_dimension_info").html(sprintf(text, values[0], values[1]));
-}
-
-function countImages(form) {
-{/literal}
-  jQuery.post("{$COUNT_SCRIPT_URL}", 'cat_id={$CAT_ID}&'+form.serialize(),
-{literal}
-    function success(data) {
-      jQuery('.count_images_wrapper').html(data);
-    }
-  );
-}
-
-function doBlink(obj,start,finish) { 
-  jQuery(obj).fadeOut(400).fadeIn(400); 
-  if(start!=finish) { 
-    doBlink(obj,start+1,finish);
-  } else {
-    jQuery(obj).fadeOut(400);
-  }
-}
-{/literal}
-
-{if isset($new_smart)}doBlink('.new_smart', 0, 3);{/if}
+    }
+
+    // album filter
+    if ($block.hasClass('filter_album')) {
+      $block.find(".albumSelect").chosen();
+    }
+
+    // dimension filter
+    if ($block.hasClass('filter_dimensions')) {
+      $block.find(".filter-cond select").change(function() {
+        select_dimensions($block, $(this).val());
+      });
+
+      $block.find(".filter_dimension_width_slider").slider({
+        range: true,
+        min: {$dimensions.bounds.min_width},
+        max: {$dimensions.bounds.max_width},
+        values: [{$dimensions.bounds.min_width}, {$dimensions.bounds.max_width}],
+        slide: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %d and %d pixels'|translate}");
+        },
+        change: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %d and %d pixels'|translate}");
+        }
+      });
+
+      $block.find(".filter_dimension_height_slider").slider({
+        range: true,
+        min: {$dimensions.bounds.min_height},
+        max: {$dimensions.bounds.max_height},
+        values: [{$dimensions.bounds.min_height}, {$dimensions.bounds.max_height}],
+        slide: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %d and %d pixels'|translate}");
+        },
+        change: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %d and %d pixels'|translate}");
+        }
+      });
+
+      $block.find(".filter_dimension_ratio_slider").slider({
+        range: true,
+        step: 0.01,
+        min: {$dimensions.bounds.min_ratio},
+        max: {$dimensions.bounds.max_ratio},
+        values: [{$dimensions.bounds.min_ratio}, {$dimensions.bounds.max_ratio}],
+        slide: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %.2f and %.2f'|translate}");
+        },
+        change: function(event, ui) {
+          change_dimension_info($block, ui.values, "{'between %.2f and %.2f'|translate}");
+        }
+      });
+
+      $block.find("a.dimensions-choice").click(function() {
+        $block.find(".filter_dimension_"+ $(this).data("type") +"_slider").slider("values",
+          [$(this).data("min"), $(this).data("max")]
+        );
+      });
+    }
+  }
+
+
+  // GENERAL FUNCTIONS
+  function change_dimension_info($block, values, text) {
+    $block.find("input[name$='[value][min]']").val(values[0]);
+    $block.find("input[name$='[value][max]']").val(values[1]);
+    $block.find(".filter_dimension_info").html(sprintf(text, values[0], values[1]));
+  }
+
+  function countImages(form) {
+    jQuery.post("{$COUNT_SCRIPT_URL}", 'cat_id={$CAT_ID}&'+form.serialize(),
+      function success(data) {
+        jQuery('.count_images_wrapper').html(data);
+      }
+    );
+  }
+
+
+  {if isset($new_smart)}
+  function doBlink(obj,start,finish) {
+    jQuery(obj).fadeOut(400).fadeIn(400);
+    if(start!=finish) {
+      doBlink(obj,start+1,finish);
+    }
+    else {
+      jQuery(obj).fadeOut(400);
+    }
+  }
+
+  doBlink('.new_smart', 0, 3);
+  {/if}
+
+  return add_filter; // expose add_filter method
+}(jQuery));
 {/footer_script}
 
 
 <div class="titrePage">
-  <h2><span style="letter-spacing:0">{$CATEGORIES_NAV}</span> &#8250; {'Edit album'|@translate} [SmartAlbum]</h2>
+  <h2><span style="letter-spacing:0">{$CATEGORIES_NAV}</span> &#8250; {'Edit album'|translate} [SmartAlbum]</h2>
 </div>
 
 <noscript>
-<div class="errors"><ul><li>JavaScript required!</li></ul></div>
+  <div class="errors"><ul><li>JavaScript required!</li></ul></div>
 </noscript>
 
 <div id="batchManagerGlobal">
 <form action="{$F_ACTION}" method="POST" id="smart">
-  <p style="text-align:left;"><label><input type="checkbox" name="is_smart" {if isset($filters) OR isset($new_smart)}checked="checked"{/if}/> {'This album is a SmartAlbum'|@translate}</label></p>
+  <p style="text-align:left;"><label><input type="checkbox" name="is_smart" {if isset($filters) OR isset($new_smart)}checked="checked"{/if}/> {'This album is a SmartAlbum'|translate}</label></p>
 
   <fieldset id="SmartAlbum_options" style="margin-top:1em;{if !isset($filters) AND !isset($new_smart)}display:none;{/if}">
-    <legend>{'Filters'|@translate}</legend>
-      
+    <legend>{'Filters'|translate}</legend>
+
     <ul id="filtersList">
     {foreach from=$filters item=filter}{strip}
@@ -268,5 +282,5 @@
         {assign var='value' value=$filter.value}
       {/if}
-      
+
       {if $filter.type == 'limit'}
         {footer_script}
@@ -280,11 +294,11 @@
         {/footer_script}
       {/if}
-      
-      {footer_script}add_filter('{$filter.type}', '{$filter.cond}', '{$value|escape:javascript}');{/footer_script}
+
+      {footer_script}addFilter('{$filter.type}', '{$filter.cond}', '{$value|escape:javascript}');{/footer_script}
     {/strip}{/foreach}
     </ul>
-    
+
     <div>
-      <b>{'Mode'|@translate} :</b>
+      <b>{'Mode'|translate} :</b>
       <label><input type="radio" name="filters[0][value]" value="and" {if $filter_mode=='and'}checked="checked"{/if}> AND</label>
       <label><input type="radio" name="filters[0][value]" value="or" {if $filter_mode=='or'}checked="checked"{/if}> OR</label>
@@ -292,28 +306,28 @@
       <input type="hidden" name="filters[0][cond]" value="mode">
     </div>
-    
+
     <p class="actionButtons">
       <select id="addFilter">
-        <option value="-1">{'Add a filter'|@translate}</option>
+        <option value="-1">{'Add a filter'|translate}</option>
         <option disabled="disabled">------------------</option>
-        <option value="tags">{'Tags'|@translate}</option>
-        <option value="date">{'Date'|@translate}</option>
-        <option value="name">{'Photo name'|@translate}</option>
-        <option value="album">{'Album'|@translate}</option>
-        <option value="dimensions">{'Dimensions'|@translate}</option>
-        <option value="author">{'Author'|@translate}</option>
-        <option value="hit">{'Hits'|@translate}</option>
-        <option value="rating_score">{'Rating score'|@translate}</option>
-        <option value="level">{'Privacy level'|@translate}</option>
-        <option value="limit">{'Max. number of photos'|@translate}</option>
-      </select>
-      <a id="removeFilters">{'Remove all filters'|@translate}</a>
-      {if isset($new_smart)}<span class="new_smart">{'Add filters here'|@translate}</span>{/if}
+        <option value="tags">{'Tags'|translate}</option>
+        <option value="date">{'Date'|translate}</option>
+        <option value="name">{'Photo name'|translate}</option>
+        <option value="album">{'Album'|translate}</option>
+        <option value="dimensions">{'Dimensions'|translate}</option>
+        <option value="author">{'Author'|translate}</option>
+        <option value="hit">{'Hits'|translate}</option>
+        <option value="rating_score">{'Rating score'|translate}</option>
+        <option value="level">{'Privacy level'|translate}</option>
+        <option value="limit">{'Max. number of photos'|translate}</option>
+      </select>
+      <a id="removeFilters">{'Remove all filters'|translate}</a>
+      {if isset($new_smart)}<span class="new_smart">{'Add filters here'|translate}</span>{/if}
     </p>
   </fieldset>
-  
+
   <p class="actionButtons" id="applyFilterBlock">
-    <input class="submit" type="submit" value="{'Submit'|@translate}" name="submitFilters"/>
-    <input class="submit" type="submit" value="{'Count'|@translate}" name="countImages" {if !isset($filters) AND !isset($new_smart)}style="display:none;"{/if}/>
+    <input class="submit" type="submit" value="{'Submit'|translate}" name="submitFilters"/>
+    <input class="submit" type="submit" value="{'Count'|translate}" name="countImages" {if !isset($filters) AND !isset($new_smart)}style="display:none;"{/if}/>
     <span class="count_images_wrapper" {if !isset($filters) AND !isset($new_smart)}style="display:none;"{/if}><span class="count_image">{$IMAGE_COUNT}</span></span>
   </p>
@@ -327,9 +341,9 @@
   <li id="filter_iiii" class="filter_tags">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="tags"/>
       {$options.tags.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -337,5 +351,5 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <select name="filters[iiii][value]" class="tagSelect">
@@ -344,14 +358,14 @@
   </li>
   </div>
-  
+
   <!-- date -->
   <div id="filter_date">
   <li id="filter_iiii" class="filter_date">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="date"/>
       {$options.date.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -359,5 +373,5 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="30"/>
@@ -365,14 +379,14 @@
   </li>
   </div>
-  
+
   <!-- name -->
   <div id="filter_name">
   <li id="filter_iiii" class="filter_name">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="name"/>
       {$options.name.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -380,5 +394,5 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="30"/>
@@ -386,14 +400,14 @@
   </li>
   </div>
-  
+
   <!-- album -->
   <div id="filter_album">
   <li id="filter_iiii" class="filter_album">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="album"/>
       {$options.album.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -401,7 +415,7 @@
       </select>
     </span>
-    
-    <span class="filter-value">
-      <select name="filters[iiii][value][]" class="albumSelect" multiple="multiple" data-placeholder="{'Select albums...'|@translate}">
+
+    <span class="filter-value">
+      <select name="filters[iiii][value][]" class="albumSelect" multiple="multiple" data-placeholder="{'Select albums...'|translate}">
         {html_options options=$all_albums}
       </select>
@@ -409,10 +423,10 @@
   </li>
   </div>
-  
+
   <!-- dimensions -->
   <div id="filter_dimensions">
   <li id="filter_iiii" class="filter_dimensions">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="dimensions"/>
       {$options.dimensions.name}
@@ -427,31 +441,31 @@
     <span class="filter-value">
       <span class="dimension_width">
-      <span class="filter_dimension_info"></span>
-        | <a class="dimensions-choice" data-type="width" data-min="{$dimensions.bounds.min_width}" data-max="{$dimensions.bounds.max_width}">{'Reset'|@translate}</a>
-        <div class="filter_dimension_width_slider"></div>
+        <span class="filter_dimension_info"></span>
+          | <a class="dimensions-choice" data-type="width" data-min="{$dimensions.bounds.min_width}" data-max="{$dimensions.bounds.max_width}">{'Reset'|translate}</a>
+          <div class="filter_dimension_width_slider"></div>
       </span>
 
-      <span class="filter-value dimension_height">
-      <span class="filter_dimension_info"></span>
-        | <a class="dimensions-choice" data-type="height" data-min="{$dimensions.bounds.min_height}" data-max="{$dimensions.bounds.max_height}">{'Reset'|@translate}</a>
-        <div class="filter_dimension_height_slider"></div>
+      <span class="dimension_height">
+        <span class="filter_dimension_info"></span>
+          | <a class="dimensions-choice" data-type="height" data-min="{$dimensions.bounds.min_height}" data-max="{$dimensions.bounds.max_height}">{'Reset'|translate}</a>
+          <div class="filter_dimension_height_slider"></div>
       </span>
 
-      <span class="filter-value dimension_ratio">
-      <span class="filter_dimension_info"></span>
-{if isset($dimensions.ratio_portrait)}
-        | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_portrait.min}" data-max="{$dimensions.ratio_portrait.max}">{'Portrait'|@translate}</a>
-{/if}
-{if isset($dimensions.ratio_square)}
-        | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_square.min}" data-max="{$dimensions.ratio_square.max}">{'square'|@translate}</a>
-{/if}
-{if isset($dimensions.ratio_landscape)}
-        | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_landscape.min}" data-max="{$dimensions.ratio_landscape.max}">{'Landscape'|@translate}</a>
-{/if}
-{if isset($dimensions.ratio_panorama)}
-        | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_panorama.min}" data-max="{$dimensions.ratio_panorama.max}">{'Panorama'|@translate}</a>
-{/if}
-        | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.bounds.min_ratio}" data-max="{$dimensions.bounds.max_ratio}">{'Reset'|@translate}</a>
-        <div class="filter_dimension_ratio_slider"></div>
+      <span class="dimension_ratio">
+        <span class="filter_dimension_info"></span>
+        {if isset($dimensions.ratio_portrait)}
+          | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_portrait.min}" data-max="{$dimensions.ratio_portrait.max}">{'Portrait'|translate}</a>
+        {/if}
+        {if isset($dimensions.ratio_square)}
+          | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_square.min}" data-max="{$dimensions.ratio_square.max}">{'square'|translate}</a>
+        {/if}
+        {if isset($dimensions.ratio_landscape)}
+          | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_landscape.min}" data-max="{$dimensions.ratio_landscape.max}">{'Landscape'|translate}</a>
+        {/if}
+        {if isset($dimensions.ratio_panorama)}
+          | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.ratio_panorama.min}" data-max="{$dimensions.ratio_panorama.max}">{'Panorama'|translate}</a>
+        {/if}
+          | <a class="dimensions-choice" data-type="ratio" data-min="{$dimensions.bounds.min_ratio}" data-max="{$dimensions.bounds.max_ratio}">{'Reset'|translate}</a>
+          <div class="filter_dimension_ratio_slider"></div>
       </span>
     </span>
@@ -461,14 +475,14 @@
   </li>
   </div>
-  
+
   <!-- author -->
   <div id="filter_author">
   <li id="filter_iiii" class="filter_author">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="author"/>
       {$options.author.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -476,21 +490,21 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="30"/>
-      <i>{'For "Is (not) in", separate each author by a comma'|@translate}</i>
-    </span>
-  </li>
-  </div>
-  
+      <i>{'For "Is (not) in", separate each author by a comma'|translate}</i>
+    </span>
+  </li>
+  </div>
+
   <!-- hit -->
   <div id="filter_hit">
   <li id="filter_iiii" class="filter_hit">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="hit"/>
       {$options.hit.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -498,5 +512,5 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="5"/>
@@ -504,14 +518,14 @@
   </li>
   </div>
-  
+
   <!-- rating_score -->
   <div id="filter_rating_score">
   <li id="filter_iiii" class="filter_rating_score">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="rating_score"/>
       {$options.rating_score.name}
     </span>
-    
+
     <span class="filter-cond">
       <select name="filters[iiii][cond]">
@@ -519,5 +533,5 @@
       </select>
     </span>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="5"/>
@@ -525,16 +539,16 @@
   </li>
   </div>
-  
+
   <!-- level -->
   <div id="filter_level">
   <li id="filter_iiii" class="filter_level">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="level"/>
       {$options.level.name}
     </span>
-    
+
     <input type="hidden" name="filters[iiii][cond]" value="level"/>
-    
+
     <span class="filter-value">
       <select name="filters[iiii][value]">
@@ -544,16 +558,16 @@
   </li>
   </div>
-  
+
   <!-- limit -->
   <div id="filter_limit">
   <li id="filter_iiii" class="filter_limit">
     <span class="filter-title">
-      <a href="#" class="removeFilter" title="{'remove this filter'|@translate}"><span>[x]</span></a>
+      <a href="#" class="removeFilter" title="{'remove this filter'|translate}"><span>[x]</span></a>
       <input type="hidden" name="filters[iiii][type]" value="limit"/>
       {$options.limit.name}
     </span>
-    
+
     <input type="hidden" name="filters[iiii][cond]" value="limit"/>
-    
+
     <span class="filter-value">
       <input type="text" name="filters[iiii][value]" size="5"/>
Index: /extensions/SmartAlbums/admin/template/cat_list.tpl
===================================================================
--- /extensions/SmartAlbums/admin/template/cat_list.tpl	(revision 26441)
+++ /extensions/SmartAlbums/admin/template/cat_list.tpl	(revision 26442)
@@ -1,17 +1,14 @@
-{footer_script require='jquery.ui.sortable'}{literal}
-jQuery(document).ready(function(){
-  jQuery("#addAlbumOpen").click(function(){
-    jQuery("#createAlbum").toggle();
-    jQuery("input[name=virtual_name]").focus();
-    jQuery("#autoOrder").hide();
-  });
+{footer_script require='jquery'}
+jQuery("#addAlbumOpen").click(function(){
+  jQuery("#createAlbum").toggle();
+  jQuery("input[name=virtual_name]").focus();
+  jQuery("#autoOrder").hide();
+});
 
-  jQuery("#addAlbumClose").click(function(){
-    jQuery("#createAlbum").hide();
-  });
+jQuery("#addAlbumClose").click(function(){
+  jQuery("#createAlbum").hide();
 });
-{/literal}{/footer_script}
+{/footer_script}
 
-{* è *}
 
 <div class="titrePage">
@@ -24,19 +21,19 @@
 <p class="showCreateAlbum">
   <span id="notManualOrder">
-    <a href="#" id="addAlbumOpen">{'create a new SmartAlbum'|@translate}</a>
-    | <a href="{$F_ACTION}&amp;smart_generate=all">{'Regenerate photos list of all SmartAlbums'|@translate}</a>
+    <a href="#" id="addAlbumOpen">{'create a new SmartAlbum'|translate}</a>
+    | <a href="{$F_ACTION}&amp;smart_generate=all">{'Regenerate photos list of all SmartAlbums'|translate}</a>
   </span>
 </p>
 
 <fieldset id="createAlbum" style="display:none;">
-  <legend>{'create a new SmartAlbum'|@translate}</legend>
+  <legend>{'create a new SmartAlbum'|translate}</legend>
   <input type="hidden" name="pwg_token" value="{$PWG_TOKEN}">
 
   <p>
-    <strong>{'Album name'|@translate}</strong> :
+    <strong>{'Album name'|translate}</strong> :
     <input type="text" name="virtual_name">
   </p>
   <p>
-    <strong>{'Parent album'|@translate}</strong>  :
+    <strong>{'Parent album'|translate}</strong>  :
     <select class="categoryDropDown" name="parent_id">
       <option value="0">------------</option>
@@ -45,6 +42,6 @@
   </p>
   <p class="actionButtons">
-    <input class="submit" type="submit" value="{'Create'|@translate}" name="submitAdd">
-    <a href="#" id="addAlbumClose">{'Cancel'|@translate}</a>
+    <input class="submit" type="submit" value="{'Create'|translate}" name="submitAdd">
+    <a href="#" id="addAlbumClose">{'Cancel'|translate}</a>
   </p>
 </fieldset>
@@ -58,17 +55,17 @@
       <!-- category {$category.ID} -->
       <p class="albumTitle">
-        <strong><a href="{$category.U_CHILDREN}" title="{'manage sub-albums'|@translate}">{$category.NAME}</a></strong>
+        <strong><a href="{$category.U_CHILDREN}" title="{'manage sub-albums'|translate}">{$category.NAME}</a></strong>
         <img src="{$SMART_PATH}admin/template/lightning.png">
-        {'%d photos'|@translate|sprintf:$category.IMG_COUNT}
+        {'%d photos'|translate:$category.IMG_COUNT}
       </p>
 
       <p class="albumActions">
-        <a href="{$category.U_EDIT}">{'Edit'|@translate}</a>
-        | <a href="{$category.U_SMART}" title="{$category.LAST_UPDATE}">{'Regenerate photos list of this SmartAlbum'|@translate}</a>
+        <a href="{$category.U_EDIT}">{'Edit'|translate}</a>
+        | <a href="{$category.U_SMART}" title="{$category.LAST_UPDATE}">{'Regenerate photos list of this SmartAlbum'|translate}</a>
         {if isset($category.U_DELETE) }
-        | <a href="{$category.U_DELETE}" onclick="return confirm('{'Are you sure?'|@translate|@escape:javascript}');">{'delete album'|@translate}</a>
+        | <a href="{$category.U_DELETE}" onclick="return confirm('{'Are you sure?'|translate|escape:javascript}');">{'delete album'|translate}</a>
         {/if}
         {if cat_admin_access($category.ID)}
-        | <a href="{$category.U_JUMPTO}">{'jump to album'|@translate} ?</a>
+        | <a href="{$category.U_JUMPTO}">{'jump to album'|translate} ?</a>
         {/if}
       </p>
Index: /extensions/SmartAlbums/admin/template/config.tpl
===================================================================
--- /extensions/SmartAlbums/admin/template/config.tpl	(revision 26441)
+++ /extensions/SmartAlbums/admin/template/config.tpl	(revision 26442)
@@ -1,24 +1,12 @@
-{html_head}{literal}
-<style type="text/css">
-.showInfo {
-  position:static;
-  display:inline-block;
-  padding:1px 6px !important;
-  width:auto;
-  font-size:0.8em;
-  line-height:1.2em;
-}
-</style>
-{/literal}{/html_head}
+{footer_script require="jquery"}
+jQuery(".showInfo").tipTip({
+  delay: 0,
+  fadeIn: 200,
+  fadeOut: 200,
+  maxWidth: '300px',
+  defaultPosition:"right"
+});
+{/footer_script}
 
-{footer_script require="jquery"}
-jQuery(".showInfo").tipTip({ldelim}
-    delay: 0,
-    fadeIn: 200,
-    fadeOut: 200,
-    maxWidth: '300px',
-    defaultPosition:"right"
-  });
-{/footer_script}
 
 <div class="titrePage">
@@ -26,19 +14,19 @@
 </div>
 
-<form method="post" action="" class="properties"> 
+<form method="post" action="" class="properties">
   <fieldset id="commentsConf">
     <ul>
       <li>
         <label>
-          <input type="checkbox" name="update_on_upload" value="true" {if $update_on_upload}checked="checked"{/if}/>
-          <b>{'Update albums on file upload'|@translate}</b>
-          <a class="showInfo" title="{'can cause slowdowns'|@translate}">i</a>
-        </label>
+          <input type="checkbox" name="update_on_date" value="true" {if $update_on_date}checked="checked"{/if}/>
+          {assign var=input value='</label><input type="text" name="update_timeout" size="2" value="'|cat:$update_timeout|cat:'"/>'}
+          <b>{'Update albums every %s days'|translate:$input}</b>
+        <!-- label -->
       </li>
       <li>
         <label>
-          <input type="checkbox" name="update_on_date" value="true" {if $update_on_date}checked="checked"{/if}/>
-          {assign var=input value='<input type="text" name="update_timeout" size="2" value="'|cat:$update_timeout|cat:'"/>'}
-          <b>{'Update albums every %s days'|@translate|sprintf:$input}</b>
+          <input type="checkbox" name="update_on_upload" value="true" {if $update_on_upload}checked="checked"{/if}/>
+          <b>{'Update albums on file upload'|translate}</b>
+          <a class="icon-info-circled-1 showInfo" title="{'can cause slowdowns'|translate}"></a>
         </label>
       </li>
@@ -46,11 +34,11 @@
         <label>
           <input type="checkbox" name="smart_is_forbidden" value="true" {if $smart_is_forbidden}checked="checked"{/if}/>
-          <b>{'Exclude SmartAlbums from permissions management'|@translate}</b>
-          <a class="showInfo" title="{'SmartAlbums are considered private for everyone, and a user can see it\'s content only if available in another album he has access to.'|@translate}">i</a>
+          <b>{'Exclude SmartAlbums from permissions management'|translate}</b>
+          <a class="icon-info-circled-1 showInfo" title="{'SmartAlbums are considered private for everyone, and a user can see it\'s content only if available in another album he has access to.'|translate}"></a>
         </label>
       </li>
     </ul>
   </fieldset>
-    
-  <p class="formButtons"><input class="submit" type="submit" value="{'Submit'|@translate}" name="submit" /></p>
+
+  <p class="formButtons"><input class="submit" type="submit" value="{'Submit'|translate}" name="submit" /></p>
 </form>
Index: tensions/SmartAlbums/admin/template/sprintf.js
===================================================================
--- /extensions/SmartAlbums/admin/template/sprintf.js	(revision 26441)
+++ 	(revision )
@@ -1,46 +1,0 @@
-function str_repeat(i, m) {
-        for (var o = []; m > 0; o[--m] = i);
-        return o.join('');
-}
-
-function sprintf() {
-        var i = 0, a, f = arguments[i++], o = [], m, p, c, x, s = '';
-        while (f) {
-                if (m = /^[^\x25]+/.exec(f)) {
-                        o.push(m[0]);
-                }
-                else if (m = /^\x25{2}/.exec(f)) {
-                        o.push('%');
-                }
-                else if (m = /^\x25(?:(\d+)\$)?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(f)) {
-                        if (((a = arguments[m[1] || i++]) == null) || (a == undefined)) {
-                                throw('Too few arguments.');
-                        }
-                        if (/[^s]/.test(m[7]) && (typeof(a) != 'number')) {
-                                throw('Expecting number but found ' + typeof(a));
-                        }
-                        switch (m[7]) {
-                                case 'b': a = a.toString(2); break;
-                                case 'c': a = String.fromCharCode(a); break;
-                                case 'd': a = parseInt(a); break;
-                                case 'e': a = m[6] ? a.toExponential(m[6]) : a.toExponential(); break;
-                                case 'f': a = m[6] ? parseFloat(a).toFixed(m[6]) : parseFloat(a); break;
-                                case 'o': a = a.toString(8); break;
-                                case 's': a = ((a = String(a)) && m[6] ? a.substring(0, m[6]) : a); break;
-                                case 'u': a = Math.abs(a); break;
-                                case 'x': a = a.toString(16); break;
-                                case 'X': a = a.toString(16).toUpperCase(); break;
-                        }
-                        a = (/[def]/.test(m[7]) && m[2] && a >= 0 ? '+'+ a : a);
-                        c = m[3] ? m[3] == '0' ? '0' : m[3].charAt(1) : ' ';
-                        x = m[5] - String(a).length - s.length;
-                        p = m[5] ? str_repeat(c, x) : '';
-                        o.push(s + (m[4] ? a + p : p + a));
-                }
-                else {
-                        throw('Huh ?!');
-                }
-                f = f.substring(m[0].length);
-        }
-        return o.join('');
-}
Index: /extensions/SmartAlbums/admin/template/style.css
===================================================================
--- /extensions/SmartAlbums/admin/template/style.css	(revision 26441)
+++ /extensions/SmartAlbums/admin/template/style.css	(revision 26442)
@@ -8,10 +8,10 @@
 }
 #batchManagerGlobal #filtersList li.token-input-input-token {
-  margin-bottom:-3px !important; 
+  margin-bottom:-3px !important;
 }
 
 #batchManagerGlobal .filter_dimensions .ui-slider-horizontal {
-    margin: 5px 0 3px 0;
-    width: 500px;
+  margin:5px 0 3px 0;
+  width:400px;
 }
 
Index: tensions/SmartAlbums/include/cat_list.php
===================================================================
--- /extensions/SmartAlbums/include/cat_list.php	(revision 26441)
+++ 	(revision )
@@ -1,111 +1,0 @@
-<?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-/**
- * Add a link into categories list to regenerate associations
- */
-$smart_count = 0;
-
-function smart_cat_list()
-{
-  global $template, $page, $smart_count;
-
-  $self_url = get_root_url().'admin.php?page=cat_list'.(isset($_GET['parent_id']) ? '&amp;parent_id='.$_GET['parent_id'] : null);
-  
-  /* get categories with smart filters */
-  $query = '
-SELECT DISTINCT id, name 
-  FROM '.CATEGORIES_TABLE.' AS c
-    INNER JOIN '.CATEGORY_FILTERS_TABLE.' AS cf
-      ON c.id = cf.category_id';
-  if (!isset($_GET['parent_id']))
-  {
-    // $query.= '
-    // WHERE id_uppercat IS NULL';
-  }
-  else
-  {
-    $query .= '
-  WHERE uppercats LIKE \'%'.$_GET['parent_id'].'%\'';
-  }
-  $query .= '
-;';
-  
-  $smart_cats = hash_from_query($query, 'id'); 
-  $smart_count = count($smart_cats);
-  
-  if (isset($_GET['smart_generate']))
-  {
-    /* regenerate photo list | all (sub) categories */
-    if ($_GET['smart_generate'] == 'all')
-    {
-      foreach ($smart_cats as $category)
-      {
-        $associated_images = smart_make_associations($category['id']);
-        array_push($page['infos'], 
-          sprintf(l10n('%d photos associated to album %s'), 
-            count($associated_images), 
-            '&laquo;'.trigger_event('render_category_name', $category['name'], 'admin_cat_list').'&raquo;'
-            )
-          );
-      }
-    }
-    /* regenerate photo list | one category */
-    else
-    {
-      $associated_images = smart_make_associations($_GET['smart_generate']);    
-      array_push($page['infos'], 
-        sprintf(l10n('%d photos associated to album %s'), 
-          count($associated_images), 
-          '&laquo;'.trigger_event('render_category_name', $smart_cats[ $_GET['smart_generate'] ]['name'], 'admin_cat_list').'&raquo;'
-          )
-        );
-    }
-    
-    define('SMART_NOT_UPDATE', 1);
-    invalidate_user_cache();
-  }
-  
-  // create regenerate link
-  $tpl_cat = array();
-  foreach ($smart_cats as $cat => $name)
-  {
-    $tpl_cat[$cat] = $self_url.'&amp;smart_generate='.$cat;
-  }
-  $tpl_cat['all'] = $self_url.'&amp;smart_generate=all';
-  
-  $template->assign(array(
-    'SMART_URL' => $tpl_cat,
-    'SMART_PATH' => SMART_PATH,
-  ));
-  
-  $template->set_prefilter('categories', 'smart_cat_list_prefilter');
-}
-
-
-function smart_cat_list_prefilter($content, &$smarty)
-{
-  global $smart_count;
-  
-  $search[0] = '{if isset($category.U_MANAGE_ELEMENTS) }';
-  $replacement[0] = $search[0].'
-{if isset($SMART_URL[$category.ID])}
-| <a href="{$SMART_URL[$category.ID]}">{\'Regenerate photos list of this SmartAlbum\'|@translate}</a>
-{/if}';
-
-  if ($smart_count > 0)
-  {
-    $search[1] = '<a href="#" id="autoOrderOpen">{\'apply automatic sort order\'|@translate}</a>';
-    $replacement[1] = $search[1].'
-| <a href="{$SMART_URL.all}">{\'Regenerate photos list of all SmartAlbums\'|@translate}</a>';
-  }
-  
-  $search[2] = '{$category.NAME}</a></strong>';
-  $replacement[2] = $search[2].'
-{if isset($SMART_URL[$category.ID])}
-<img src="'.SMART_PATH.'admin/template/lightning.png">
-{/if}';
-
-  return str_replace($search, $replacement, $content);
-}
-
-?>
Index: /extensions/SmartAlbums/include/count_images.php
===================================================================
--- /extensions/SmartAlbums/include/count_images.php	(revision 26441)
+++ /extensions/SmartAlbums/include/count_images.php	(revision 26442)
@@ -10,5 +10,5 @@
 include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
 
-if (!is_admin()) die('Hacking attempt!');
+is_admin() or die('Hacking attempt!');
 
 
@@ -18,14 +18,14 @@
   $page['errors'] = array();
   $limit_is_set = false;
-  
+
   foreach ($_POST['filters'] as $filter)
   {
     if (($filter = smart_check_filter($filter)) != false)
     {
-      array_push($filters, $filter);
+      $filters[] = $filter;
     }
     else
     {
-      echo '<span class="filter_error">'.$page['errors'][ count($page['errors'])-1 ].'</span>';
+      echo '<span class="filter_error">'. array_pop($page['errors']) .'</span>';
       exit;
     }
Index: /extensions/SmartAlbums/include/events.inc.php
===================================================================
--- /extensions/SmartAlbums/include/events.inc.php	(revision 26442)
+++ /extensions/SmartAlbums/include/events.inc.php	(revision 26442)
@@ -0,0 +1,129 @@
+<?php
+defined('SMART_PATH') or die('Hacking attempt!');
+
+/**
+ * clean table when categories are deleted
+ */
+function smart_delete_categories($ids)
+{
+  $query = '
+DELETE FROM '.CATEGORY_FILTERS_TABLE.'
+  WHERE category_id IN('.implode(',', $ids).')
+;';
+  pwg_query($query);
+}
+
+/**
+ * update images list periodically
+ */
+function smart_periodic_update()
+{
+  global $conf;
+
+  // we only search for old albums every hour, nevermind which user is connected
+  if ($conf['SmartAlbums']['last_update'] > time() - 3600) return;
+
+  $conf['SmartAlbums']['last_update'] = time();
+  conf_update_param('SmartAlbums', serialize($conf['SmartAlbums']));
+
+  // get categories with smart filters
+  $query = '
+SELECT DISTINCT category_id
+  FROM '.CATEGORY_FILTERS_TABLE.'
+  WHERE updated < DATE_SUB(NOW(), INTERVAL '.$conf['SmartAlbums']['update_timeout'].' DAY)
+;';
+
+  // regenerate photo list
+  $smart_cats = query2array($query, null, 'category_id');
+  array_map('smart_make_associations', $smart_cats);
+}
+
+/**
+ * Remove picture that must not be displayed from $page['items']
+ *
+ * here we get all pictures that current user could see
+ * if SmartAlbums doesn't exist, and make intersect with pictures
+ * actually displayed
+ */
+function smart_init_page_items()
+{
+  global $user, $page, $conf;
+
+  if (
+    ('categories' == $page['section']) and
+    (!isset($page['chronology_field'])) and
+    (
+      (isset($page['category'])) or
+      (isset($page['flat']))
+    )
+  ) {
+
+    $query = '
+SELECT DISTINCT category_id
+  FROM '.CATEGORY_FILTERS_TABLE.'
+;';
+    $smart_albums = query2array($query, null, 'category_id');
+
+    if (count($smart_albums) > 0 and !is_admin())
+    {
+      // add SmartAlbums to forbidden categories
+      $user['forbidden_categories_old'] = $user['forbidden_categories'];
+      $user['forbidden_categories'] = explode(',', $user['forbidden_categories']);
+      $user['forbidden_categories'] = array_unique(array_merge($user['forbidden_categories'], $smart_albums));
+      $user['forbidden_categories'] = implode(',', $user['forbidden_categories']);
+
+      if (isset($page['category']))
+      {
+        $query = '
+SELECT id
+  FROM '.CATEGORIES_TABLE.'
+  WHERE
+    '.get_sql_condition_FandF(
+      array(
+        'forbidden_categories' => 'id',
+        'visible_categories' => 'id',
+        )
+      );
+        $subcat_ids = query2array($query, null, 'id');
+        $subcat_ids[] = 0;
+        $where_sql = 'category_id IN ('.implode(',',$subcat_ids).')';
+        // remove categories from forbidden because just checked above
+        $forbidden = get_sql_condition_FandF(
+          array(
+            'visible_images' => 'id'
+            ),
+          'AND'
+          );
+      }
+      else
+      {
+        $where_sql = '1=1';
+        $forbidden = get_sql_condition_FandF(
+          array(
+            'forbidden_categories' => 'category_id',
+            'visible_categories' => 'category_id',
+            'visible_images' => 'id'
+            ),
+          'AND'
+          );
+      }
+
+      // Main query
+      $query = '
+SELECT DISTINCT(image_id)
+  FROM '.IMAGE_CATEGORY_TABLE.'
+    INNER JOIN '.IMAGES_TABLE.' ON id = image_id
+  WHERE
+    '.$where_sql.'
+'.$forbidden.'
+  '.$conf['order_by'].'
+;';
+
+      $page['items_wo_sa'] = query2array($query, null, 'image_id');
+      $page['items'] = array_intersect($page['items'], $page['items_wo_sa']);
+
+      // restore forbidden categories
+      $user['forbidden_categories'] = $user['forbidden_categories_old'];
+    }
+  }
+}
Index: /extensions/SmartAlbums/include/events_admin.inc.php
===================================================================
--- /extensions/SmartAlbums/include/events_admin.inc.php	(revision 26442)
+++ /extensions/SmartAlbums/include/events_admin.inc.php	(revision 26442)
@@ -0,0 +1,143 @@
+<?php
+defined('SMART_PATH') or die('Hacking attempt!');
+
+/**
+ * new tab on album properties page
+ */
+function smart_tab($sheets, $id)
+{
+  if ($id == 'album')
+  {
+    global $category;
+
+    if ($category['dir'] == null)
+    {
+      $sheets['smartalbum'] = array(
+        'caption' => 'SmartAlbum',
+        'url' => SMART_ADMIN.'-album&amp;cat_id='.$_GET['cat_id'],
+        );
+    }
+  }
+
+  return $sheets;
+}
+
+/**
+ * admin plugins menu link
+ */
+function smart_admin_menu($menu)
+{
+  $menu[] = array(
+    'NAME' => 'SmartAlbums',
+    'URL' => SMART_ADMIN,
+    );
+  return $menu;
+}
+
+/**
+ * Add a link into categories list to regenerate associations
+ */
+function smart_cat_list()
+{
+  global $template, $page;
+
+  if (!isset($smart_count))
+  {
+    $smart_count = 0;
+  }
+
+  $self_url = get_root_url().'admin.php?page=cat_list'.(isset($_GET['parent_id']) ? '&amp;parent_id='.$_GET['parent_id'] : null);
+
+  /* get categories with smart filters */
+  $query = '
+SELECT DISTINCT id, name
+  FROM '.CATEGORIES_TABLE.' AS c
+    INNER JOIN '.CATEGORY_FILTERS_TABLE.' AS cf
+    ON c.id = cf.category_id';
+  if (!isset($_GET['parent_id']))
+  {
+    // $query.= '
+    // WHERE id_uppercat IS NULL';
+  }
+  else
+  {
+    $query .= '
+  WHERE uppercats LIKE \'%'.$_GET['parent_id'].'%\'';
+  }
+  $query .= '
+;';
+
+  $smart_cats = query2array($query, 'id');
+
+  if (isset($_GET['smart_generate']))
+  {
+    /* regenerate photo list | all (sub) categories */
+    if ($_GET['smart_generate'] == 'all')
+    {
+      foreach ($smart_cats as $category)
+      {
+        $associated_images = smart_make_associations($category['id']);
+
+        $page['infos'][] = l10n(
+          '%d photos associated to album %s',
+          count($associated_images),
+          '&laquo;'.trigger_event('render_category_name', $category['name'], 'admin_cat_list').'&raquo;'
+          );
+      }
+    }
+    /* regenerate photo list | one category */
+    else
+    {
+      $associated_images = smart_make_associations($_GET['smart_generate']);
+
+      $page['infos'][] = l10n(
+        '%d photos associated to album %s',
+        count($associated_images),
+        '&laquo;'.trigger_event('render_category_name', $smart_cats[ $_GET['smart_generate'] ]['name'], 'admin_cat_list').'&raquo;'
+        );
+    }
+
+    define('SMART_NOT_UPDATE', 1);
+    invalidate_user_cache();
+  }
+
+  // create regenerate link
+  $tpl_cat = array();
+  foreach ($smart_cats as $cat => $name)
+  {
+    $tpl_cat[$cat] = $self_url.'&amp;smart_generate='.$cat;
+  }
+  if (count($smart_cats))
+  {
+    $tpl_cat['all'] = $self_url.'&amp;smart_generate=all';
+  }
+
+  $template->assign(array(
+    'SMART_URL' => $tpl_cat,
+    'SMART_PATH' => SMART_PATH,
+  ));
+
+  $template->set_prefilter('categories', 'smart_cat_list_prefilter');
+}
+
+
+function smart_cat_list_prefilter($content)
+{
+  $search[0] = '{if isset($category.U_MANAGE_ELEMENTS) }';
+  $replacement[0] = $search[0].'
+{if isset($SMART_URL[$category.ID])}
+| <a href="{$SMART_URL[$category.ID]}">{\'Regenerate photos list of this SmartAlbum\'|@translate}</a>
+{/if}';
+
+  $search[1] = '<a href="#" id="autoOrderOpen">{\'apply automatic sort order\'|@translate}</a>';
+  $replacement[1] = $search[1].'
+{if isset($SMART_URL.all)}| <a href="{$SMART_URL.all}">{\'Regenerate photos list of all SmartAlbums\'|@translate}</a>{/if}';
+
+  $search[2] = '{$category.NAME}</a></strong>';
+  $replacement[2] = $search[2].'
+{if isset($SMART_URL[$category.ID])}
+<img src="'.SMART_PATH.'admin/template/lightning.png">
+{/if}';
+
+  return str_replace($search, $replacement, $content);
+}
Index: /extensions/SmartAlbums/include/functions.inc.php
===================================================================
--- /extensions/SmartAlbums/include/functions.inc.php	(revision 26441)
+++ /extensions/SmartAlbums/include/functions.inc.php	(revision 26442)
@@ -1,4 +1,4 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('SMART_PATH') or die('Hacking attempt!');
 
 /*
@@ -10,13 +10,13 @@
 {
   $query = '
-DELETE FROM '.IMAGE_CATEGORY_TABLE.' 
-  WHERE 
-    category_id = '.$cat_id.' 
+DELETE FROM '.IMAGE_CATEGORY_TABLE.'
+  WHERE
+    category_id = '.$cat_id.'
     AND smart = true
 ;';
   pwg_query($query);
-  
+
   $images = smart_get_pictures($cat_id);
-  
+
   if (count($images) != 0)
   {
@@ -30,11 +30,11 @@
     }
     mass_inserts(
-      IMAGE_CATEGORY_TABLE, 
-      array_keys($datas[0]), 
+      IMAGE_CATEGORY_TABLE,
+      array_keys($datas[0]),
       $datas,
       array('ignore'=>true)
       );
   }
-  
+
   // representant, try to not overwrite if still in images list
   $query = '
@@ -44,11 +44,11 @@
 ;';
   list($rep_id) = pwg_db_fetch_row(pwg_query($query));
-  
-  if ( !in_array($rep_id, $images) )
+
+  if (!in_array($rep_id, $images))
   {
     include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
     set_random_representant(array($cat_id));
   }
-  
+
   $query = '
 UPDATE '.CATEGORY_FILTERS_TABLE.'
@@ -57,5 +57,5 @@
 ;';
   pwg_query($query);
-  
+
   return $images;
 }
@@ -69,17 +69,18 @@
 {
   global $conf;
-  
-  if ( defined('SMART_NOT_UPDATE') OR !$conf['SmartAlbums']['update_on_upload'] ) return;
-  
+
+  if (defined('SMART_NOT_UPDATE'))
+  {
+    return;
+  }
+
   // get categories with smart filters
   $query = '
-SELECT DISTINCT id
-  FROM '.CATEGORIES_TABLE.' AS c
-    INNER JOIN '.CATEGORY_FILTERS_TABLE.' AS cf
-    ON c.id = cf.category_id
+SELECT DISTINCT category_id
+  FROM '.CATEGORY_FILTERS_TABLE.'
 ;';
-  
+
   // regenerate photo list
-  $smart_cats = array_from_query($query, 'id');
+  $smart_cats = query2array($query, null, 'category_id');
   array_map('smart_make_associations', $smart_cats);
 }
@@ -97,16 +98,19 @@
 
   /* get filters */
-  if ($filters === null)
+  if (!isset($filters))
   {
     $query = '
-SELECT * 
-  FROM '.CATEGORY_FILTERS_TABLE.' 
-  WHERE category_id = '.$cat_id.' 
+SELECT *
+  FROM '.CATEGORY_FILTERS_TABLE.'
+  WHERE category_id = '.$cat_id.'
   ORDER BY type ASC, cond ASC
 ;';
     $result = pwg_query($query);
-    
-    if (!pwg_db_num_rows($result)) return array();
-    
+
+    if (!pwg_db_num_rows($result))
+    {
+      return array();
+    }
+
     $filters = array();
     while ($row = pwg_db_fetch_assoc($result))
@@ -123,11 +127,14 @@
     return array();
   }
-  
+
   $mode = 'and';
-  
+
   /* build constrains */
   ## generate 'join', 'where' arrays and 'limit' string to create the SQL query
   ## inspired by PicsEngine 3 by Michael Villar
   $i_tags = 1;
+  $join = array();
+  $where = array();
+
   foreach ($filters as $filter)
   {
@@ -142,4 +149,55 @@
           case 'all':
           {
+            $tags_arr = explode(',', $filter['value']);
+            foreach ($tags_arr as $value)
+            {
+              $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
+              $where[] = 'it'.$i_tags.'.tag_id = '.$value;
+              $i_tags++;
+            }
+
+            break;
+          }
+          // search images which tags are in the list
+          case 'one':
+          {
+            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
+            $where[] = 'it'.$i_tags.'.tag_id IN ('.$filter['value'].')';
+            $i_tags++;
+
+            break;
+          }
+          // exclude images which tags are in the list
+          case 'none':
+          {
+            $sub_query = '
+      SELECT it'.$i_tags.'.image_id
+        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
+        WHERE
+          it'.$i_tags.'.image_id = i.id AND
+          it'.$i_tags.'.tag_id IN ('.$filter['value'].')
+        GROUP BY it'.$i_tags.'.image_id
+      ';
+            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
+            $where[] = 'NOT EXISTS ('.$sub_query.')';
+            $i_tags++;
+
+            break;
+          }
+          // exclude images which tags are not in the list and search images which have all tags
+          case 'only':
+          {
+            $sub_query = '
+      SELECT it'.$i_tags.'.image_id
+        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
+        WHERE
+          it'.$i_tags.'.image_id = i.id AND
+          it'.$i_tags.'.tag_id NOT IN ('.$filter['value'].')
+        GROUP BY it'.$i_tags.'.image_id
+      ';
+            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
+            $where[] = 'NOT EXISTS ('.$sub_query.')';
+            $i_tags++;
+
             $tags_arr = explode(',', $filter['value']);
             foreach($tags_arr as $value)
@@ -149,63 +207,12 @@
               $i_tags++;
             }
-            
-            break;
-          }
-          // search images which tags are in the list
-          case 'one':
-          {
-            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
-            $where[] = 'it'.$i_tags.'.tag_id IN ('.$filter['value'].')';
-            $i_tags++;
-            
-            break;
-          }
-          // exclude images which tags are in the list
-          case 'none':
-          {
-            $sub_query = '
-      SELECT it'.$i_tags.'.image_id
-        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
-        WHERE 
-          it'.$i_tags.'.image_id = i.id AND
-          it'.$i_tags.'.tag_id IN ('.$filter['value'].')
-        GROUP BY it'.$i_tags.'.image_id
-      ';
-            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
-            $where[] = 'NOT EXISTS ('.$sub_query.')';
-            $i_tags++;
-            
-            break;
-          }
-          // exclude images which tags are not in the list and search images which have all tags
-          case 'only':
-          {
-            $sub_query = '
-      SELECT it'.$i_tags.'.image_id
-        FROM '.IMAGE_TAG_TABLE.' AS it'.$i_tags.'
-        WHERE 
-          it'.$i_tags.'.image_id = i.id AND
-          it'.$i_tags.'.tag_id NOT IN ('.$filter['value'].')
-        GROUP BY it'.$i_tags.'.image_id
-      ';
-            $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
-            $where[] = 'NOT EXISTS ('.$sub_query.')';
-            $i_tags++;
-            
-            $tags_arr = explode(',', $filter['value']);
-            foreach($tags_arr as $value)
-            {
-              $join[] = IMAGE_TAG_TABLE.' AS it'.$i_tags.' ON i.id = it'.$i_tags.'.image_id';
-              $where[] = 'it'.$i_tags.'.tag_id = '.$value;
-              $i_tags++;
-            }
-            
-            break;
-          }
-        }
-        
-        break;
-      }
-    
+
+            break;
+          }
+        }
+
+        break;
+      }
+
       // date
       case 'date':
@@ -232,8 +239,8 @@
             break;
         }
-        
-        break;
-      }
-      
+
+        break;
+      }
+
       // name
       case 'name':
@@ -263,8 +270,8 @@
             break;
         }
-        
-        break;
-      }
-      
+
+        break;
+      }
+
       // album
       case 'album':
@@ -279,5 +286,5 @@
             {
               $sub_query = '
-      SELECT image_id 
+      SELECT image_id
         FROM '.IMAGE_CATEGORY_TABLE.'
         WHERE category_id = '.$value.'
@@ -285,5 +292,5 @@
               $where[] = 'i.id IN ('.$sub_query.')';
             }
-            
+
             break;
           }
@@ -297,5 +304,5 @@
       ';
             $where[] = 'i.id IN ('.$sub_query.')';
-            
+
             break;
           }
@@ -309,5 +316,5 @@
       ';
             $where[] = 'i.id NOT IN ('.$sub_query.')';
-            
+
             break;
           }
@@ -321,10 +328,10 @@
       ';
             $where[] = 'i.id NOT IN ('.$sub_query.')';
-            
+
             $albums_arr = explode(',', $filter['value']);
             foreach($albums_arr as $value)
             {
               $sub_query = '
-      SELECT image_id 
+      SELECT image_id
         FROM '.IMAGE_CATEGORY_TABLE.'
         WHERE category_id = '.$value.'
@@ -332,17 +339,17 @@
               $where[] = 'i.id IN ('.$sub_query.')';
             }
-            
-            break;
-          }
-        }
-        
-        break;
-      }
-      
+
+            break;
+          }
+        }
+
+        break;
+      }
+
       // dimensions
       case 'dimensions':
       {
         $filter['value'] = explode(',', $filter['value']);
-        
+
         switch ($filter['cond'])
         {
@@ -358,5 +365,5 @@
         }
       }
-      
+
       // author
       case 'author':
@@ -384,8 +391,8 @@
             break;
         }
-        
-        break;
-      }
-      
+
+        break;
+      }
+
       // hit
       case 'hit':
@@ -400,8 +407,8 @@
             break;
         }
-        
-        break;
-      }
-      
+
+        break;
+      }
+
       // rating_score
       case 'rating_score':
@@ -416,8 +423,8 @@
             break;
         }
-        
-        break;
-      }
-      
+
+        break;
+      }
+
       // level
       case 'level':
@@ -426,5 +433,5 @@
         break;
       }
-      
+
       // limit
       case 'limit':
@@ -433,5 +440,5 @@
         break;
       }
-      
+
       // mode
       case 'mode':
@@ -442,16 +449,16 @@
     }
   }
-  
+
   /* bluid query */
   $MainQuery = '
 SELECT i.id
   FROM '.IMAGES_TABLE.' AS i';
-    
-    if (isset($join))
+
+    if (count($join))
     {
       $MainQuery.= '
     LEFT JOIN '.implode("\n    LEFT JOIN ", $join);
     }
-    if (isset($where))
+    if (count($where))
     {
       $MainQuery.= '
@@ -471,6 +478,6 @@
     file_put_contents(SMART_PATH.'dump_query.sql', $MainQuery);
   }
-  
-  return array_from_query($MainQuery, 'id');
+
+  return query2array($MainQuery, null, 'id');
 }
 
@@ -484,9 +491,9 @@
 {
   global $page, $limit_is_set, $level_is_set;
+
   $error = false;
-  
   if (!isset($limit_is_set)) $limit_is_set = false;
   if (!isset($level_is_set)) $level_is_set = false;
-  
+
   switch ($filter['type'])
   {
@@ -496,6 +503,5 @@
       if ($filter['value'] == null)
       {
-        $error = true;
-        array_push($page['errors'], l10n('No tag selected'));
+        $page['errors'][] = l10n('No tag selected');
       }
       else
@@ -511,6 +517,5 @@
       if (!preg_match('#([0-9]{4})-([0-9]{2})-([0-9]{2})#', $filter['value']))
       {
-        $error = true;
-        array_push($page['errors'], l10n('Date string is malformed'));
+        $page['errors'][] = l10n('Date string is malformed');
       }
       break;
@@ -521,11 +526,9 @@
       if (empty($filter['value']))
       {
-        $error = true;
-        array_push($page['errors'], l10n('Name is empty'));
-      }
-      else if ( $filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false )
-      {
-        $error = true;
-        array_push($page['errors'], l10n('Regex is malformed'));
+        $page['errors'][] = l10n('Name is empty');
+      }
+      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
+      {
+        $page['errors'][] = l10n('Regex is malformed');
       }
       break;
@@ -536,6 +539,5 @@
       if (@$filter['value'] == null)
       {
-        $error = true;
-        array_push($page['errors'], l10n('No album selected'));
+        $page['errors'][] = l10n('No album selected');
       }
       else
@@ -548,5 +550,5 @@
     case 'dimensions':
     {
-      if ( empty($filter['value']['min']) or empty($filter['value']['max']) )
+      if (empty($filter['value']['min']) or empty($filter['value']['max']))
       {
         $error = true;
@@ -563,11 +565,9 @@
       if (empty($filter['value']))
       {
-        $error = true;
-        array_push($page['errors'], l10n('Author is empty'));
-      }
-      else if ( $filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false )
-      {
-        $error = true;
-        array_push($page['errors'], l10n('Regex is malformed'));
+        $page['errors'][] = l10n('Author is empty');
+      }
+      else if ($filter['cond']=='regex' and @preg_match('/'.$filter['value'].'/', null)===false)
+      {
+        $page['errors'][] = l10n('Regex is malformed');
       }
       else
@@ -580,8 +580,7 @@
     case 'hit':
     {
-      if (!preg_match('#([0-9]{1,})#', $filter['value']))
-      {
-        $error = true;
-        array_push($page['errors'], l10n('Hits must be an integer'));
+      if (!preg_match('#([0-9]+)#', $filter['value']))
+      {
+        $page['errors'][] = l10n('Hits must be an integer');
       }
       break;
@@ -590,8 +589,7 @@
     case 'rating_score':
     {
-      if (!preg_match('#([0-9]{1,})#', $filter['value']))
-      {
-        $error = true;
-        array_push($page['errors'], l10n('Rating score must be an integer'));
+      if (!preg_match('#([0-9]+)#', $filter['value']))
+      {
+        $page['errors'][] = l10n('Rating score must be an integer');
       }
       break;
@@ -602,6 +600,5 @@
       if ($level_is_set == true) // only one level is allowed, first is saved
       {
-        $error = true;
-        array_push($page['errors'], l10n('You can\'t use more than one level filter'));
+        $page['errors'][] = l10n('You can\'t use more than one level filter');
       }
       else
@@ -617,15 +614,13 @@
       if ($limit_is_set == true) // only one limit is allowed, first is saved
       {
-        $error = true;
-        array_push($page['errors'], l10n('You can\'t use more than one limit filter'));
-      }
-      else if (!preg_match('#([0-9]{1,})#', $filter['value']))
-      {
-        $error = true;
-        array_push($page['errors'], l10n('Limit must be an integer'));
-      }
-      else 
-      {
-        $filter['cond'] = 'level';
+        $page['errors'][] = l10n('You can\'t use more than one limit filter');
+      }
+      else if (!preg_match('#([0-9]+)#', $filter['value']))
+      {
+        $page['errors'][] = l10n('Limit must be an integer');
+      }
+      else
+      {
+        $filter['cond'] = 'limit';
         $limit_is_set = true;
       }
@@ -638,5 +633,5 @@
       break;
     }
-    
+
     default:
     {
@@ -645,7 +640,7 @@
     }
   }
-  
-  
-  if ($error == false)
+
+
+  if (!$error && empty($page['errors']))
   {
     return $filter;
@@ -656,44 +651,2 @@
   }
 }
-
-
-/**
- * clean table when categories are deleted
- */
-function smart_delete_categories($ids)
-{
-  $query = '
-DELETE FROM '.CATEGORY_FILTERS_TABLE.'
-  WHERE category_id IN('.implode(',', $ids).')
-;';
-  pwg_query($query);
-}
-
-/**
- * update images list periodically
- */
-function smart_periodic_update()
-{
-  global $conf;
-  
-  // we only search for old albums every hour, nevermind which user is connected
-  if ($conf['SmartAlbums']['last_update'] > time() - 3600) return;
-  
-  $conf['SmartAlbums']['last_update'] = time();
-  conf_update_param('SmartAlbums', serialize($conf['SmartAlbums']));
-  
-  // get categories with smart filters
-  $query = '
-SELECT DISTINCT id
-  FROM '.CATEGORIES_TABLE.' AS c
-    INNER JOIN '.CATEGORY_FILTERS_TABLE.' AS cf
-    ON c.id = cf.category_id
-  WHERE updated < DATE_SUB(NOW(), INTERVAL '.$conf['SmartAlbums']['update_timeout'].' DAY)
-;';
-  
-  // regenerate photo list
-  $smart_cats = array_from_query($query, 'id');
-  array_map('smart_make_associations', $smart_cats);
-}
-
-?>
Index: tensions/SmartAlbums/include/install.inc.php
===================================================================
--- /extensions/SmartAlbums/include/install.inc.php	(revision 26441)
+++ 	(revision )
@@ -1,101 +1,0 @@
-<?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-function smart_albums_install() 
-{
-  global $conf, $prefixeTable;
-  
-  // configuration
-  if (!isset($conf['SmartAlbums']))
-  {
-    $smart_default_config = serialize(array(
-      'update_on_upload' => false,
-      'update_on_date' => true,
-      'update_timeout' => 3,
-      'show_list_messages' => true,
-      'smart_is_forbidden' => false,
-      'last_update' => 0,
-      ));
-    
-    conf_update_param('SmartAlbums', $smart_default_config);
-    $conf['SmartAlbums'] = $smart_default_config;
-  }
-  else
-  {
-    $new_conf = unserialize($conf['SmartAlbums']);
-    // new param in 2.0.2
-    if (!isset($new_conf['smart_is_forbidden']))
-    {
-      $new_conf['smart_is_forbidden'] = true;
-    }
-    // new params in 2.1.0
-    if (!isset($new_conf['update_on_date']))
-    {
-      $new_conf['update_on_date'] = true;
-      $new_conf['update_timeout'] = 3;
-      $new_conf['last_update'] = 0;
-    }
-    conf_update_param('SmartAlbums', serialize($new_conf));
-    $conf['SmartAlbums'] = serialize($new_conf);
-  }
-  
-  // new table
-	pwg_query(
-'CREATE TABLE IF NOT EXISTS `' . $prefixeTable . 'category_filters` (
-  `category_id` smallint(5) unsigned NOT NULL,
-  `type` varchar(16) NOT NULL,
-  `cond` varchar(16) NULL,
-  `value` text NULL,
-  `updated` DATETIME NOT NULL DEFAULT "1970-01-01 00:00:00"
-) ENGINE=MyISAM DEFAULT CHARSET=utf8
-;');
-  
-  // new column on image category table
-  $result = pwg_query('SHOW COLUMNS FROM `' . IMAGE_CATEGORY_TABLE . '` LIKE "smart";');
-  if (!pwg_db_num_rows($result))
-  {      
-    pwg_query('ALTER TABLE `' . IMAGE_CATEGORY_TABLE . '` ADD `smart` ENUM(\'true\', \'false\') NOT NULL DEFAULT \'false\';');
-  }
-  
-  // new column on category filters table
-  $result = pwg_query('SHOW COLUMNS FROM `' . $prefixeTable . 'category_filters` LIKE "updated";');
-  if (!pwg_db_num_rows($result))
-  {      
-    pwg_query('ALTER TABLE `' . $prefixeTable . 'category_filters` ADD `updated` DATETIME NOT NULL DEFAULT "1970-01-01 00:00:00"');
-  }
-  
-  // remove column on category table, moved to category filters table
-  $result = pwg_query('SHOW COLUMNS FROM `' . CATEGORIES_TABLE . '` LIKE "smart_update";');
-  if (pwg_db_num_rows($result))
-  {
-    pwg_query('UPDATE `' . $prefixeTable . 'category_filters` AS f SET updated = ( SELECT smart_update FROM `' . CATEGORIES_TABLE . '` AS c WHERE c.id = f.category_id );');
-    pwg_query('ALTER TABLE `' . CATEGORIES_TABLE . '` DROP `smart_update`;');
-  }
-  
-  // date filters renamed in 2.0
-  $query = '
-SELECT category_id
-  FROM `' . $prefixeTable . 'category_filters`
-  WHERE 
-    type = "date" AND
-    cond IN ("the","before","after","the_crea","before_crea","after_crea")
-;';
-
-  if (pwg_db_num_rows(pwg_query($query)))
-  {
-    $name_changes = array(
-      'the' => 'the_post',
-      'before' => 'before_post',
-      'after' => 'after_post',
-      'the_crea' => 'the_taken',
-      'before_crea' => 'before_taken',
-      'after_crea' => 'after_taken',
-      );
-    foreach ($name_changes as $old => $new)
-    {
-      pwg_query('UPDATE `' . $prefixeTable . 'category_filters` SET cond = "'.$new.'" WHERE type = "date" AND cond = "'.$old.'";');
-    }
-  }
-}
-
-?>
Index: tensions/SmartAlbums/include/page_items.php
===================================================================
--- /extensions/SmartAlbums/include/page_items.php	(revision 26441)
+++ 	(revision )
@@ -1,97 +1,0 @@
-<?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-/**
- * Remove picture that musn't be displayed from $page['items']
- *
- * here we get all pictures that current user could see 
- * if SmartAlbums doesn't exist, and make intersect with pictures
- * actually displayed
- */
-function smart_init_page_items()
-{
-  global $user, $page, $conf;
-
-  if (
-    ('categories' == $page['section']) and
-    (!isset($page['chronology_field'])) and
-    (
-      (isset($page['category'])) or
-      (isset($page['flat']))
-    )
-  ) {
-  
-    $query = '
-SELECT DISTINCT(cat.id) AS id
-  FROM '.CATEGORIES_TABLE.' AS cat
-    INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS img
-    ON img.category_id = cat.id
-  WHERE img.smart = "true"
-;';
-    $smart_albums = array_from_query($query, 'id');
-      
-    if (count($smart_albums) > 0 and !is_admin())
-    {
-      // add SmartAlbums to forbidden categories
-      $user['forbidden_categories_old'] = $user['forbidden_categories'];
-      $user['forbidden_categories'] = explode(',', $user['forbidden_categories']);
-      $user['forbidden_categories'] = array_unique(array_merge($user['forbidden_categories'], $smart_albums));
-      $user['forbidden_categories'] = implode(',', $user['forbidden_categories']);
-    
-      if ( isset($page['category']) )
-      {
-        $query = '
-SELECT id
-  FROM '.CATEGORIES_TABLE.'
-  WHERE
-    '.get_sql_condition_FandF(
-      array(
-        'forbidden_categories' => 'id',
-        'visible_categories' => 'id',
-        )
-      );
-        $subcat_ids = array_from_query($query, 'id');
-        $subcat_ids[] = 0;
-        $where_sql = 'category_id IN ('.implode(',',$subcat_ids).')';
-        // remove categories from forbidden because just checked above
-        $forbidden = get_sql_condition_FandF(
-          array( 
-            'visible_images' => 'id'
-            ),
-          'AND'
-          );
-      }
-      else
-      {
-        $where_sql = '1=1';
-        $forbidden = get_sql_condition_FandF(
-          array(
-            'forbidden_categories' => 'category_id',
-            'visible_categories' => 'category_id',
-            'visible_images' => 'id'
-            ),
-          'AND'
-          );
-      }
-
-      // Main query
-      $query = '
-SELECT DISTINCT(image_id)
-  FROM '.IMAGE_CATEGORY_TABLE.'
-    INNER JOIN '.IMAGES_TABLE.' ON id = image_id
-  WHERE
-    '.$where_sql.'
-'.$forbidden.'
-  '.$conf['order_by'].'
-;';
-
-      $page['items_wo_sa'] = array_from_query($query, 'image_id');
-      $page['items'] = array_intersect($page['items'], $page['items_wo_sa']);
-      
-      // restore forbidden categories
-      $user['forbidden_categories'] = $user['forbidden_categories_old'];
-    }
-  }
-}
-
-?>
Index: /extensions/SmartAlbums/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/SmartAlbums/language/en_UK/plugin.lang.php	(revision 26441)
+++ /extensions/SmartAlbums/language/en_UK/plugin.lang.php	(revision 26442)
@@ -2,6 +2,4 @@
 
 $lang['No filter selected'] = 'No filter selected';
-$lang['%d photo'] = '%d photo';
-$lang['%d photos'] = '%d photos';
 $lang['All these tags'] = 'All these tags';
 $lang['One of these tags'] = 'One of these tags';
@@ -63,4 +61,7 @@
 $lang['SmartAlbums are considered private for everyone, and a user can see it\'s content only if available in another album he has access to.'] = 'SmartAlbums are considered private for everyone, and a user can see it\'s content only if available in another album he has access to.';
 $lang['Update albums every %s days'] = 'Update albums every %s days';
+$lang['Invalid number of days'] = 'Invalid number of days';
+$lang['Mode'] = 'Mode';
+$lang['Select albums...'] = 'Select albums...';
 
 ?>
Index: /extensions/SmartAlbums/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/SmartAlbums/language/fr_FR/plugin.lang.php	(revision 26441)
+++ /extensions/SmartAlbums/language/fr_FR/plugin.lang.php	(revision 26442)
@@ -2,6 +2,4 @@
 
 $lang['No filter selected'] = 'Aucun filtre sélectionné';
-$lang['%d photo'] = '%d photo';
-$lang['%d photos'] = '%d photos';
 $lang['All these tags'] = 'Tous les tags';
 $lang['One of these tags'] = 'Un des tags';
@@ -63,4 +61,7 @@
 $lang['SmartAlbums are considered private for everyone, and a user can see it\'s content only if available in another album he has access to.'] = 'Les SmartAlbums sont considérés comme privés pour tout le monde, et un utilisateur ne peut voir leur contenu que si disponible dans un autre album auquel il a accès.';
 $lang['Update albums every %s days'] = 'Mettre à jour les albums tous les %s jours';
+$lang['Invalid number of days'] = 'Nombre de jour invalide';
+$lang['Mode'] = 'Mode';
+$lang['Select albums...'] = 'Albums...';
 
 ?>
Index: /extensions/SmartAlbums/main.inc.php
===================================================================
--- /extensions/SmartAlbums/main.inc.php	(revision 26441)
+++ /extensions/SmartAlbums/main.inc.php	(revision 26442)
@@ -4,32 +4,34 @@
 Version: auto
 Description: Easily create dynamic albums with tags, date and other criteria
-Plugin URI: http://piwigo.org/ext/extension_view.php?eid=544
+Plugin URI: auto
 Author: Mistic
 Author URI: http://www.strangeplanet.fr
 */
 
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
+
 global $prefixeTable;
 
-define('SMART_PATH',     PHPWG_PLUGINS_PATH . 'SmartAlbums/');
+define('SMART_ID',      'SmartAlbums');
+define('SMART_PATH',    PHPWG_PLUGINS_PATH . SMART_ID . '/');
 define('CATEGORY_FILTERS_TABLE', $prefixeTable . 'category_filters');
-define('SMART_ADMIN',    get_root_url() . 'admin.php?page=plugin-SmartAlbums');
-define('SMART_VERSION',  'auto');
-//define('SMART_DEBUG',    true);
+define('SMART_ADMIN',   get_root_url() . 'admin.php?page=plugin-' . SMART_ID);
+define('SMART_VERSION', 'auto');
+// define('SMART_DEBUG',   true);
 
 
 add_event_handler('init', 'smart_init');
 add_event_handler('init', 'smart_periodic_update');
-add_event_handler('invalidate_user_cache', 'smart_make_all_associations');
+add_event_handler('delete_categories', 'smart_delete_categories');
 
 if (defined('IN_ADMIN'))
 {
-  include_once(SMART_PATH.'include/cat_list.php');
+  include_once(SMART_PATH.'include/events_admin.inc.php');
   add_event_handler('loc_begin_cat_list', 'smart_cat_list');
-  add_event_handler('tabsheet_before_select','smart_tab', EVENT_HANDLER_PRIORITY_NEUTRAL, 2); 
+  add_event_handler('tabsheet_before_select','smart_tab', EVENT_HANDLER_PRIORITY_NEUTRAL, 2);
   add_event_handler('get_admin_plugin_menu_links', 'smart_admin_menu');
-  add_event_handler('delete_categories', 'smart_delete_categories');
 }
 
+include_once(SMART_PATH.'include/events.inc.php');
 include_once(SMART_PATH.'include/functions.inc.php');
 
@@ -40,32 +42,10 @@
 function smart_init()
 {
-  global $conf, $pwg_loaded_plugins;
-  
-  if (
-    SMART_VERSION == 'auto' or
-    $pwg_loaded_plugins['SmartAlbums']['version'] == 'auto' or
-    version_compare($pwg_loaded_plugins['SmartAlbums']['version'], SMART_VERSION, '<')
-  )
-  {
-    include_once(SMART_PATH . 'include/install.inc.php');
-    smart_albums_install();
-    
-    if ( $pwg_loaded_plugins['SmartAlbums']['version'] != 'auto' and SMART_VERSION != 'auto' )
-    {
-      $query = '
-UPDATE '. PLUGINS_TABLE .'
-SET version = "'. SMART_VERSION .'"
-WHERE id = "SmartAlbums"';
-      pwg_query($query);
-      
-      $pwg_loaded_plugins['SmartAlbums']['version'] = SMART_VERSION;
-      
-      if (defined('IN_ADMIN'))
-      {
-        $_SESSION['page_infos'][] = 'Smart Albums updated to version '. SMART_VERSION;
-      }
-    }
-  }
-  
+  global $conf;
+
+  include_once(SMART_PATH . 'maintain.inc.php');
+  $maintain = new SmartAlbums_maintain(SMART_ID);
+  $maintain->autoUpdate(SMART_VERSION, 'install');
+
   if (defined('IN_ADMIN'))
   {
@@ -73,44 +53,13 @@
   }
   $conf['SmartAlbums'] = unserialize($conf['SmartAlbums']);
-  
-  if ( script_basename() == 'index' and $conf['SmartAlbums']['smart_is_forbidden'] )
+
+  if (script_basename() == 'index' and $conf['SmartAlbums']['smart_is_forbidden'])
   {
     add_event_handler('loc_end_section_init', 'smart_init_page_items');
-    include_once(SMART_PATH.'include/page_items.php');
+  }
+
+  if ($conf['SmartAlbums']['update_on_upload'])
+  {
+    add_event_handler('invalidate_user_cache', 'smart_make_all_associations');
   }
 }
-
-/**
- * new tab on album properties page
- */
-function smart_tab($sheets, $id)
-{
-  if ($id != 'album') return $sheets;
-  
-  global $category;
-  
-  if ($category['dir'] == null)
-  {
-    $sheets['smartalbum'] = array(
-      'caption' => 'SmartAlbum',
-      'url' => SMART_ADMIN.'-album&amp;cat_id='.$_GET['cat_id'],
-      );
-  }
-  
-  return $sheets;
-}
-
-
-/**
- * admin plugins menu link
- */
-function smart_admin_menu($menu) 
-{
-  array_push($menu, array(
-      'NAME' => 'SmartAlbums',
-      'URL' => SMART_ADMIN,
-    ));
-  return $menu;
-}
-
-?>
Index: /extensions/SmartAlbums/maintain.inc.php
===================================================================
--- /extensions/SmartAlbums/maintain.inc.php	(revision 26441)
+++ /extensions/SmartAlbums/maintain.inc.php	(revision 26442)
@@ -1,29 +1,140 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
 
-include_once(PHPWG_PLUGINS_PATH . 'SmartAlbums/include/install.inc.php');
+class SmartAlbums_maintain extends PluginMaintain
+{
+  private $installed = false;
 
-function plugin_install() 
-{
-  smart_albums_install();
-  define('smart_albums_installed', true);
-}
+  private $default_conf = array(
+    'update_on_upload' => false,
+    'update_on_date' => true,
+    'update_timeout' => 3,
+    'show_list_messages' => true,
+    'smart_is_forbidden' => false,
+    'last_update' => 0,
+    );
 
-function plugin_activate()
-{ 
-  if (!defined('smart_albums_installed'))
+  private $table;
+
+  function __construct($plugin_id)
   {
-    smart_albums_install();
+    global $prefixeTable;
+
+    parent::__construct($plugin_id);
+
+    $this->table = $prefixeTable . 'category_filters';
+  }
+
+  function install($plugin_version, &$errors=array())
+  {
+    global $conf, $prefixeTable;
+
+    if (empty($conf['SmartAlbums']))
+    {
+      $conf['SmartAlbums'] = serialize($this->default_conf);
+      conf_update_param('SmartAlbums', $conf['SmartAlbums']);
+    }
+    else
+    {
+      $new_conf = is_string($conf['SmartAlbums']) ? unserialize($conf['SmartAlbums']) : $conf['SmartAlbums'];
+
+      // new param in 2.0.2
+      if (!isset($new_conf['smart_is_forbidden']))
+      {
+        $new_conf['smart_is_forbidden'] = true;
+      }
+
+      // new params in 2.1.0
+      if (!isset($new_conf['update_on_date']))
+      {
+        $new_conf['update_on_date'] = true;
+        $new_conf['update_timeout'] = 3;
+        $new_conf['last_update'] = 0;
+      }
+
+      $conf['SmartAlbums'] = serialize($new_conf);
+      conf_update_param('SmartAlbums', $conf['SmartAlbums']);
+    }
+
+    // new table
+    pwg_query(
+'CREATE TABLE IF NOT EXISTS `' . $this->table . '` (
+  `category_id` smallint(5) unsigned NOT NULL,
+  `type` varchar(16) NOT NULL,
+  `cond` varchar(16) NULL,
+  `value` text NULL,
+  `updated` DATETIME NOT NULL DEFAULT "1970-01-01 00:00:00"
+) ENGINE=MyISAM DEFAULT CHARSET=utf8
+;');
+
+    // new column on image category table
+    $result = pwg_query('SHOW COLUMNS FROM `' . IMAGE_CATEGORY_TABLE . '` LIKE "smart";');
+    if (!pwg_db_num_rows($result))
+    {
+      pwg_query('ALTER TABLE `' . IMAGE_CATEGORY_TABLE . '` ADD `smart` ENUM(\'true\', \'false\') NOT NULL DEFAULT \'false\';');
+    }
+
+    // new column on category filters table (2.1.1)
+    $result = pwg_query('SHOW COLUMNS FROM `' . $this->table . '` LIKE "updated";');
+    if (!pwg_db_num_rows($result))
+    {
+      pwg_query('ALTER TABLE `' . $this->table . '` ADD `updated` DATETIME NOT NULL DEFAULT "1970-01-01 00:00:00"');
+    }
+
+    // remove column on category table, moved to category filters table (2.1.1)
+    $result = pwg_query('SHOW COLUMNS FROM `' . CATEGORIES_TABLE . '` LIKE "smart_update";');
+    if (pwg_db_num_rows($result))
+    {
+      pwg_query('UPDATE `' . $this->table . '` AS f SET updated = ( SELECT smart_update FROM `' . CATEGORIES_TABLE . '` AS c WHERE c.id = f.category_id );');
+      pwg_query('ALTER TABLE `' . CATEGORIES_TABLE . '` DROP `smart_update`;');
+    }
+
+    // date filters renamed in 2.0
+    $query = '
+SELECT category_id
+  FROM `' . $this->table . '`
+  WHERE
+    type = "date" AND
+    cond IN ("the","before","after","the_crea","before_crea","after_crea")
+;';
+
+    if (pwg_db_num_rows(pwg_query($query)))
+    {
+      $name_changes = array(
+        'the' => 'the_post',
+        'before' => 'before_post',
+        'after' => 'after_post',
+        'the_crea' => 'the_taken',
+        'before_crea' => 'before_taken',
+        'after_crea' => 'after_taken',
+        );
+      foreach ($name_changes as $old => $new)
+      {
+        pwg_query('UPDATE `' . $this->table . '` SET cond = "' . $new . '" WHERE type = "date" AND cond = "' . $old . '";');
+      }
+    }
+
+    $this->installed = true;
+  }
+
+  function activate($plugin_version, &$errors=array())
+  {
+    if (!$this->installed)
+    {
+      $this->install($plugin_version, $errors);
+    }
+  }
+
+  function deactivate()
+  {
+  }
+
+  function uninstall()
+  {
+    conf_delete_param('SmartAlbums');
+
+    pwg_query('DROP TABLE `' . $this->table . '`;');
+
+    pwg_query('ALTER TABLE `' . IMAGE_CATEGORY_TABLE . '` DROP `smart`;');
   }
 }
-
-function plugin_uninstall() 
-{
-  global $prefixeTable;
-  
-  pwg_query('DROP TABLE `' . $prefixeTable . 'category_filters`;');
-  pwg_query('ALTER TABLE `' . IMAGE_CATEGORY_TABLE . '` DROP `smart`;');
-  pwg_query('DELETE FROM `' . CONFIG_TABLE . '` WHERE param = \'SmartAlbums\' LIMIT 1;');
-}
-
-?>
