Index: /extensions/GThumb/admin.php
===================================================================
--- /extensions/GThumb/admin.php	(revision 13651)
+++ /extensions/GThumb/admin.php	(revision 13652)
@@ -3,44 +3,93 @@
 if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
 
+function delete_gthumb_cache($height)
+{
+  $pattern = '#.*-cu_s9999x'.$height.'\.[a-zA-Z0-9]{3,4}$#';
+  if ($contents = @opendir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR))
+  {
+    while (($node = readdir($contents)) !== false)
+    {
+      if ($node != '.'
+          and $node != '..'
+          and is_dir(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node))
+      {
+        clear_derivative_cache_rec(PHPWG_ROOT_PATH.PWG_DERIVATIVE_DIR.$node, $pattern);
+      }
+    }
+    closedir($contents);
+  }
+}
+
+if (isset($_GET['getMissingDerivative']))
+{
+  list($max_id, $image_count) = pwg_db_fetch_row( pwg_query('SELECT MAX(id)+1, COUNT(*) FROM '.IMAGES_TABLE) );
+  $start_id = intval($_POST['prev_page']);
+  $max_urls = intval($_POST['max_urls']);
+  if ($start_id<=0)
+  {
+    $start_id = $max_id;
+  }
+
+  $uid = '&b='.time();
+  global $conf;
+  $conf['question_mark_in_urls'] = $conf['php_extension_in_urls'] = true;
+  $conf['derivative_url_style']=2; //script
+
+  $qlimit = min(5000, ceil(max($image_count/500, $max_urls)));
+
+  $query_model = 'SELECT id, path, representative_ext, width, height
+  FROM '.IMAGES_TABLE.'
+  WHERE id < start_id
+  ORDER BY id DESC
+  LIMIT '.$qlimit;
+
+  $urls=array();
+  do
+  {
+    $result = pwg_query( str_replace('start_id', $start_id, $query_model));
+    $is_last = pwg_db_num_rows($result) < $qlimit;
+    while ($row=pwg_db_fetch_assoc($result))
+    {
+      $start_id = $row['id'];
+      $src_image = new SrcImage($row);
+      if ($src_image->is_mimetype())
+        continue;
+      $derivative = new DerivativeImage(ImageStdParams::get_custom(9999, $conf['GThumb']['height']), $src_image);
+      if (@filemtime($derivative->get_path())===false)
+      {
+        $urls[] = $derivative->get_url().$uid;
+      }
+      if (count($urls)>=$max_urls && !$is_last)
+        break;
+    }
+    if ($is_last)
+    {
+      $start_id = 0;
+    }
+  }while (count($urls)<$max_urls && $start_id);
+
+  $ret = array();
+  if ($start_id)
+  {
+    $ret['next_page']=$start_id;
+  }
+  $ret['urls']=$urls;
+  echo json_encode($ret);
+  exit();
+}
+
 global $template, $conf, $page;
 
 load_language('plugin.lang', GTHUMB_PATH);
-include_once(GTHUMB_PATH.'functions.inc.php');
 include(dirname(__FILE__).'/config_default.inc.php');
 $params = $conf['GThumb'];
 
 // Delete cache
-if (isset($_GET['deletecache']))
+if (isset($_POST['cachedelete']))
 {
-  check_pwg_token();                             
-  gtdeltree(GTHUMB_CACHE_DIR);
+  check_pwg_token();
+  delete_gthumb_cache($conf['GThumb']['height']);
+  delete_gthumb_cache($conf['GThumb']['height'] * 2 + $conf['GThumb']['margin']);
   redirect('admin.php?page=plugin-GThumb');
-}
-
-// Generate cache
-if (isset($_GET['generatecache']))
-{
-  if ($_GET['generatecache'] == 'complete')
-  {
-    array_push($page['infos'], l10n('Cache have been generated'));
-  }
-  else
-  {
-    $query = 'SELECT id, path, md5sum, tn_ext FROM '.IMAGES_TABLE.';';
-    $result = pwg_query($query);
-    $cache_dir = GTHUMB_CACHE_DIR.'/'.$conf['GThumb']['height'].'/';
-    $missing = array();
-
-    while ($row = pwg_db_fetch_assoc($result))
-    {
-      if (!is_file($cache_dir.md5($row['path'].(!empty($row['md5sum']) ? $row['md5sum'] : '')).'.'.$row['tn_ext'])
-        and in_array(get_extension($row['path']), $conf['picture_ext']))
-      {
-        array_push($missing, $row['id']);
-      }
-    }
-    echo json_encode($missing);
-    exit();
-  }
 }
 
@@ -72,9 +121,9 @@
   if ($params['height'] != $conf['GThumb']['height'])
   {
-    gtdeltree(GTHUMB_CACHE_DIR);
+    delete_gthumb_cache($conf['GThumb']['height']);
   }
   elseif ($params['margin'] != $conf['GThumb']['margin'])
   {
-    gtdeltree(GTHUMB_CACHE_DIR.'/'.($conf['GThumb']['height'] * 2 + $conf['GThumb']['margin']));
+    delete_gthumb_cache($conf['GThumb']['height'] * 2 + $conf['GThumb']['margin']);
   }
 
@@ -101,15 +150,5 @@
     'CACHE_BIG_THUMB' => $params['cache_big_thumb'],
     'METHOD'          => $params['method'],
-  )
-);
-
-// Informations
-$data = gtdirsize(GTHUMB_CACHE_DIR);
-
-$template->assign(
-  array(
-    'NB_FILES' => $data['nb_files'],
-    'CACHE_SIZE' => $data['size'],
-    'PWG_TOKEN' => get_pwg_token(),
+    'PWG_TOKEN'       => get_pwg_token(),
   )
 );
Index: tensions/GThumb/functions.inc.php
===================================================================
--- /extensions/GThumb/functions.inc.php	(revision 13651)
+++ 	(revision )
@@ -1,173 +1,0 @@
-<?php
-
-function ws_images_getGThumbPlusThumbnail($params, &$service)
-{
-  global $conf;
-
-  if (empty($params['image_id']))
-  {
-    return new PwgError(403, "image_id is required");
-  }
-
-  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
-
-  $forbidden = get_sql_condition_FandF(
-    array(
-      'forbidden_categories' => 'ic.category_id',
-      'visible_categories' => 'ic.category_id',
-      'visible_images' => 'i.id'
-    ),
-    'AND'
-  );
-
-  $query = 'SELECT i.*
-FROM '.IMAGES_TABLE.' AS i
-  INNER JOIN '.IMAGE_CATEGORY_TABLE.' AS ic ON i.id = ic.image_id
-  INNER JOIN '.CATEGORIES_TABLE.' AS c ON ic.category_id = c.id
-WHERE i.id = '.$params['image_id'].'
-'.$forbidden.'
-;';
-
-  $picture = pwg_db_fetch_assoc(pwg_query($query));
-
-  if (empty($picture))
-  {
-    return new PwgError(404, "image not found");
-  }
-
-  $data = get_gthumb_data($picture, $params['size']);
-  $result = array();
- 
-  if (empty($data['src']))
-  {
-    $result = make_gthumb_image($picture, $data);
-    $file = $result['destination'];
-  }
-  else
-  {
-    $file = $data['src'];
-    $result['width'] = $data['width'];
-    $result['height'] = $data['height'];
-  }
-
-  if ($params['return'])
-  {
-    switch (get_extension($file))
-    {
-      case 'jpg':
-      case 'jpeg':
-        header('Content-type: image/jpeg'); break;
-      case 'gif':
-        header('Content-type: image/gif'); break;
-      case 'png':
-        header('Content-type: image/png'); break;
-      default:
-        header('Content-type: unknow'); break;
-    }  
-    
-    header('Last-Modified: '.date('r', filemtime($file)));
-    readfile($file);
-    if (!$conf['GThumb']['cache_big_thumb'])
-    {
-      @unlink($file);
-    }
-    exit();
-  }
-
-  return array(
-    'id' => $picture['id'],
-    'src' => $file,
-    'width' => $result['width'],
-    'height' => $result['height'],
-    'filesize' => filesize($file),
-  );
-}
-
-function make_gthumb_image($picture, $data)
-{
-  global $conf;
-
-  $cache_dir = GTHUMB_CACHE_DIR.'/';
-  if ($data['size'] == 'small' or $conf['GThumb']['cache_big_thumb'])
-  {
-    $cache_dir = $data['cache_path'];
-  }
-  $file = $cache_dir.md5($picture['path'].(!empty($picture['md5sum']) ? $picture['md5sum'] : '')).'.'.$picture['tn_ext'];
-
-  if (!is_dir($cache_dir))
-  {
-    mkgetdir($cache_dir, MKGETDIR_DEFAULT&~MKGETDIR_DIE_ON_ERROR);
-    if (!is_writable($cache_dir))
-    {
-      die("Give write access (chmod 777) to $cache_dir directory at the root of your Piwigo installation");
-    }
-  }
-
-  $filepath = $picture['path'];
-  if ($data['use_high'])
-  {
-    include_once(PHPWG_ROOT_PATH.'admin/include/functions_upload.inc.php');
-    $filepath = file_path_for_type($filepath, 'high');
-  }
-  $img = new pwg_image($filepath);
-  $result = $img->pwg_resize($file, $data['width'], $data['height'], $conf['upload_form_thumb_quality'], false, true, ($data['size'] == 'big'), false);
-  $img->destroy();
-
-  return $result;
-}
-
-function gtdeltree($path)
-{
-  if (is_dir($path))
-  {
-    $fh = opendir($path);
-    while ($file = readdir($fh))
-    {
-      if ($file != '.' and $file != '..')
-      {
-        $pathfile = $path . '/' . $file;
-        if (is_dir($pathfile))
-        {
-          gtdeltree($pathfile);
-        }
-        else
-        {
-          @unlink($pathfile);
-        }
-      }
-    }
-    closedir($fh);
-    return @rmdir($path);
-  }
-}
-
-function gtdirsize($path, &$size=0, &$nb_files=0)
-{
-  if (is_dir($path))
-  {
-    $fh = opendir($path);
-    while ($file = readdir($fh))
-    {
-      if ($file != '.' and $file != '..' and $file != 'index.htm')
-      {
-        $pathfile = $path . '/' . $file;
-        if (is_dir($pathfile))
-        {
-          $data = gtdirsize($pathfile, $size, $nb_files);
-        }
-        else
-        {
-          $size += filesize($pathfile);
-          $nb_files++;
-        }
-      }
-    }
-    closedir($fh);
-  }
-  return array(
-    'size' => $size,
-    'nb_files' => $nb_files,
-  );
-}
-
-?>
Index: /extensions/GThumb/js/gthumb.js
===================================================================
--- /extensions/GThumb/js/gthumb.js	(revision 13651)
+++ /extensions/GThumb/js/gthumb.js	(revision 13652)
@@ -1,5 +1,4 @@
 var GThumb = {
 
-  root: './',
   max_height: 200,
   margin: 10,
@@ -10,19 +9,11 @@
   t: new Array,
 
-  queue: jQuery.manageAjax.create('queued', {
-    queue: true,  
-    cacheResponse: false,
-    maxRequests: 3,
-    preventDoubleRequests: false
-  }),
-
   build: function () {
 
     GThumb.t = new Array;
-    jQuery('#thumbnails img.thumbnail').each(function() {
-      id = parseInt(this.id.substring(2));
+    jQuery('#thumbnails img.thumbnail').each(function(index) {
       width = parseInt(jQuery(this).attr('width'));
       height = parseInt(jQuery(this).attr('height'));
-      th = {id:id,width:width,height:height,real_width:width,real_height:height};
+      th = {index:index,width:width,height:height,real_width:width,real_height:height};
       if (height < GThumb.max_height) {
         th.width = Math.round(GThumb.max_height * width / height);
@@ -30,37 +21,12 @@
       }
       GThumb.t.push(th);
+    });
 
-      if (jQuery(this).attr('src') == '') {
-        GThumb.addToQueue(id, 1);
-      }
-    });
+    first = GThumb.t[0];
+    GThumb.small_thumb = {index:first.index,width:first.real_width,height:first.real_height,src:jQuery('#thumbnails img:first').attr('src')}
 
     jQuery.resize.throttleWindow = false;
     jQuery.resize.delay = 50;
     GThumb.process();
-  },
-
-  addToQueue: function (id, loop) {
-
-    GThumb.queue.add({
-      type: 'GET', 
-      url: GThumb.root+'ws.php', 
-      data: {
-        method: 'pwg.images.getGThumbPlusThumbnail',
-        image_id: id,
-        format: 'json'
-      },
-      dataType: 'json',
-      success: function(data) {
-        if (data.stat == 'ok') {
-          jQuery('#gt'+data.result.id).prop('src', GThumb.root+data.result.src).show();
-        } else if (loop < 4) {
-          GThumb.addToQueue(id, ++loop);
-        }
-      },
-      error: function() {
-        if (loop < 4) GThumb.addToQueue(id, ++loop);
-      }
-    });
   },
 
@@ -98,5 +64,5 @@
             if (line > 2) {
               if (height >= best_size.height && width/height >= min_ratio && height<=GThumb.big_thumb.height) {
-                best_size = {width:width,height:height}
+                best_size = {width:width,height:height};
               }
               break;
@@ -153,5 +119,5 @@
       if (width_count > available_width) {
 
-        last_thumb = GThumb.t[i].id;
+        last_thumb = GThumb.t[i].index;
         ratio = width_count / available_width;
         new_height = Math.round(max_height / ratio);
@@ -161,5 +127,5 @@
         for (j=0;j<thumb_process.length;j++) {
 
-          if (thumb_process[j].id == last_thumb) {
+          if (thumb_process[j].index == last_thumb) {
             new_width = available_width - width_count - GThumb.margin;
           } else {
@@ -168,5 +134,5 @@
             new_width = Math.round(new_width);
           }
-          GThumb.resize(jQuery('#gt'+thumb_process[j].id), thumb_process[j].real_width, thumb_process[j].real_height, new_width, new_height, false);
+          GThumb.resize(jQuery('#thumbnails img.thumbnail').eq(thumb_process[j].index), thumb_process[j].real_width, thumb_process[j].real_height, new_width, new_height, false);
 
           width_count += new_width + GThumb.margin;
@@ -181,5 +147,5 @@
     // Last line does not need to be cropped
     for (j=0;j<thumb_process.length;j++) {
-      GThumb.resize(jQuery('#gt'+thumb_process[j].id), thumb_process[j].real_width, thumb_process[j].real_height, thumb_process[j].width, max_height, false);
+      GThumb.resize(jQuery('#thumbnails img.thumbnail').eq(thumb_process[j].index), thumb_process[j].real_width, thumb_process[j].real_height, thumb_process[j].width, max_height, false);
     }
 
Index: /extensions/GThumb/main.inc.php
===================================================================
--- /extensions/GThumb/main.inc.php	(revision 13651)
+++ /extensions/GThumb/main.inc.php	(revision 13652)
@@ -14,5 +14,4 @@
 
 define('GTHUMB_PATH' , PHPWG_PLUGINS_PATH . basename(dirname(__FILE__)) . '/');
-define('GTHUMB_CACHE_DIR', PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb');
 
 $conf['GThumb'] = unserialize($conf['GThumb']);
@@ -26,5 +25,4 @@
 
 add_event_handler('loc_begin_index', 'GThumb_init', 60);
-add_event_handler('ws_add_methods', 'add_gthumb_thumbnails_method');
 add_event_handler('get_admin_plugin_menu_links', 'GThumb_admin_menu');
 
@@ -48,166 +46,13 @@
   $template->assign('GThumb', $conf['GThumb']);
 
-  include_once(PHPWG_ROOT_PATH.'admin/include/image.class.php');
+  $template->assign('GThumb_derivative_params', ImageStdParams::get_custom(9999, $conf['GThumb']['height']));
 
-  foreach ($tpl_vars as $key => &$tpl_var)
+  if ($conf['GThumb']['big_thumb'] and !empty($tpl_vars[0]))
   {
-    $data = get_gthumb_data($pictures[$key]);
-
-    $tpl_var['TN_SRC'] = $data['src'];
-    $tpl_var['TN_WIDTH'] = $data['width'];
-    $tpl_var['TN_HEIGHT'] = $data['height'];
+    $derivative_params = ImageStdParams::get_custom(9999, 2 * $conf['GThumb']['height'] + $conf['GThumb']['margin']);
+    $template->assign('GThumb_big', new DerivativeImage($derivative_params, $tpl_vars[0]['src_image']));
   }
 
-  if ($conf['GThumb']['big_thumb'])
-  {
-    $ft = &$tpl_vars[0];
-
-    // Small thumb data
-    $small_thumb = array(
-      'id' => $ft['ID'],
-      'src' => $ft['TN_SRC'],
-      'width' => $ft['TN_WIDTH'],
-      'height' => $ft['TN_HEIGHT'],
-    );
-
-    if (empty($small_thumb['src']))
-    {
-      include_once(GTHUMB_PATH.'functions.inc.php');
-      $data = get_gthumb_data($pictures[0]);
-      $result = make_gthumb_image($pictures[0], $data);
-      $small_thumb['src'] = $result['destination'];
-    }
-
-    // Big thumb data
-    $data = get_gthumb_data($pictures[0], 'big');
-
-    $big_thumb = array(
-      'id' => $ft['ID'],
-      'src' => $data['src'],
-      'width' => $data['width'],
-      'height' => $data['height'],
-    );
-    if (empty($big_thumb['src']))
-    {
-      if ($conf['GThumb']['cache_big_thumb'])
-      {
-        include_once(GTHUMB_PATH.'functions.inc.php');
-        $result = make_gthumb_image($pictures[0], $data);
-        $big_thumb['src'] = embellish_url(get_root_url().$result['destination']);
-      }
-      else
-      {
-        $big_thumb['src'] = get_root_url().'ws.php?method=pwg.images.getGThumbPlusThumbnail&image_id='.$ft['ID'].'&size=big&return=true';
-      }
-    }
-
-    $template->assign(
-      array(
-        'small_thumb' => $small_thumb,
-        'big_thumb' => $big_thumb,
-      )
-    );
-    $ft['TN_SRC'] = $big_thumb['src'];
-    $ft['TN_WIDTH'] = $big_thumb['width'];
-    $ft['TN_HEIGHT'] = $big_thumb['height'];
-  }
-  
   return $tpl_vars;
-}
-
-function add_gthumb_thumbnails_method($arr)
-{
-  include_once(GTHUMB_PATH.'functions.inc.php');
-
-  $service = &$arr[0];
-  $service->addMethod(
-    'pwg.images.getGThumbPlusThumbnail',
-    'ws_images_getGThumbPlusThumbnail',
-    array(
-      'image_id' => array(),
-      'size' => array('default'=>'small'),
-      'return' => array('default'=>false),
-    ),
-    'Get thumbnail for GThumb+ plugin. Size parameter can be "small" or "big".'
-  );
-}
-
-function get_gthumb_data($picture, $size='small')
-{
-  global $conf;
-
-  $picture_ext = array('jpg', 'jpeg', 'png', 'gif');
-
-  if (!in_array(strtolower(get_extension($picture['path'])), $picture_ext))
-  {
-    list($width, $height) = getimagesize(get_thumbnail_path($picture));
-
-    return array(
-      'src' => get_thumbnail_url($picture),
-      'width' => $width,
-      'height' => $height,
-    );
-  }
-
-  $new_height = $size == 'small' ? $conf['GThumb']['height'] : $conf['GThumb']['height'] * 2 + $conf['GThumb']['margin'];
-  $file = GTHUMB_CACHE_DIR.'/'.$new_height.'/'.md5($picture['path'].(!empty($picture['md5sum']) ? $picture['md5sum'] : '')).'.'.$picture['tn_ext'];
-
-  if (file_exists($file))
-  {
-    list($width, $height) = getimagesize($file);
-
-    return array(
-      'src' => embellish_url(get_root_url().$file),
-      'width' => $width,
-      'height' => $height,
-    );
-  }
-
-  if ( !empty($picture['tn_ext']) )
-  {
-    $file = substr_replace(get_filename_wo_extension($picture['path']), '/thumbnail/GT-',strrpos($picture['path'],'/'),1).'.'.$picture['tn_ext'];
-    if (file_exists($file))
-    {
-      list($width, $height) = getimagesize($file);
-
-      return array(
-        'src' => embellish_url(get_root_url().$file),
-        'width' => $width,
-        'height' => $height,
-      );
-    }
-  }
-
-  $width = $picture['width'];
-  $height = $picture['height'];
-  $use_high = false;
-
-  if ($height < $new_height and $picture['has_high'] == 'true')
-  {
-    $width = $picture['high_width'];
-    $height = $picture['high_height'];
-    $use_high = true;
-  }
-
-  if ($size == 'big')
-  {
-    $width = min($width, round(max($height, $new_height) * 1.15));
-  }
-
-  $result = pwg_image::get_resize_dimensions($width, $height, 5000, $new_height);
-  $result['src'] = '';
-
-  // Test thumbnail size
-  list($width, $height) = getimagesize(get_thumbnail_path($picture));
-  if ($result['width'] == $width and $result['height'] == $height)
-  {
-    $result['src'] = get_thumbnail_url($picture);
-  }
-
-  $result['use_high'] = $use_high;
-  $result['cache_path'] = GTHUMB_CACHE_DIR.'/'.$new_height.'/';
-  $result['size'] = $size;
-
-  return $result;
 }
 
Index: /extensions/GThumb/maintain.inc.php
===================================================================
--- /extensions/GThumb/maintain.inc.php	(revision 13651)
+++ /extensions/GThumb/maintain.inc.php	(revision 13652)
@@ -15,6 +15,8 @@
 function plugin_uninstall()
 {
-  include_once(dirname(__FILE__).'/functions.inc.php');
-  gtdeltree(PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb');
+  if (is_dir(PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb'))
+  {
+    gtdeltree(PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb');
+  }
   
   $query = 'DELETE FROM ' . CONFIG_TABLE . ' WHERE param="GThumb" LIMIT 1;';
@@ -24,10 +26,34 @@
 function plugin_activate($plugin_id, $version)
 {
-  if (in_array($version, array('2.3.a', '2.3.b')))
+  if (is_dir(PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb'))
   {
-    include_once(PHPWG_PLUGINS_PATH.basename(dirname(__FILE__)).'/functions.inc.php');
     gtdeltree(PHPWG_ROOT_PATH.PWG_LOCAL_DIR.'GThumb');
   }
 }
 
+function gtdeltree($path)
+{
+  if (is_dir($path))
+  {
+    $fh = opendir($path);
+    while ($file = readdir($fh))
+    {
+      if ($file != '.' and $file != '..')
+      {
+        $pathfile = $path . '/' . $file;
+        if (is_dir($pathfile))
+        {
+          gtdeltree($pathfile);
+        }
+        else
+        {
+          @unlink($pathfile);
+        }
+      }
+    }
+    closedir($fh);
+    return @rmdir($path);
+  }
+}
+
 ?>
Index: /extensions/GThumb/template/admin.tpl
===================================================================
--- /extensions/GThumb/template/admin.tpl	(revision 13651)
+++ /extensions/GThumb/template/admin.tpl	(revision 13652)
@@ -47,18 +47,40 @@
 </fieldset>
 
-<p><input type="submit" name="submit" value="{'Submit'|@translate}"></p>
+<p>
+  <input type="hidden" name="pwg_token" value="{$PWG_TOKEN}">
+  <input type="submit" name="submit" value="{'Submit'|@translate}">
+  <input type="submit" name="cachedelete" value="{'Purge thumbnails cache'|@translate}" title="{'Delete images in GThumb+ cache.'|@translate}" onclick="return confirm('{'Are you sure?'|@translate}');">
+  <input type="button" name="cachebuild" value="{'Pre-cache thumbnails'|@translate}" title="{'Finds images that have not been cached and creates the cached version.'|@translate}" onclick="start()">
+</p>
 </form>
 
-<fieldset id="cacheinfo">
-<legend>{'Cache Informations'|@translate}</legend>
-<p id="cache_data">&nbsp;</p>
-<p id="GThumbAction">
-  <button onclick="GThumb.deletecache();" title="{'Delete images in GThumb+ cache.'|@translate}">{'Purge thumbnails cache'|@translate}</button>
-  <button onclick="GThumb.generatecache();" title="{'Finds images that have not been cached and creates the cached version.'|@translate}">{'Pre-cache thumbnails'|@translate}</button>
+<fieldset id="generate_cache">
+<legend>{'Pre-cache thumbnails'|@translate}</legend>
+<p>
+<table>
+	<tr>
+		<td>Errors</td>
+		<td id="errors">0</td>
+	</tr>
+	<tr>
+		<td>Loaded</td>
+		<td id="loaded">0</td>
+	</tr>
+	<tr>
+		<td>Remaining</td>
+		<td id="remaining">0</td>
+	</tr>
+</table>
 </p>
-<div id="GThumbProgressbar" style="display:none;">
-  {'Generating cache, please wait...'|@translate}<br>
-  <div id="progressbar"></div>
-  <p><button onclick="GThumb.abort();">{'Cancel'|@translate}</button></p>
+<p>
+	<input id="startLink" value="{'Start'|@translate}" onclick="start()" type="button">
+	<input id="pauseLink" value="{'Pause'|@translate}" onclick="pause()" type="button" disabled="disbled">
+	<input id="stopLink" value="{'Stop'|@translate}" onclick="stop()" type="button" disabled="disbled">
+</p>
+<div id="feedbackWrap" style="height:320px; min-height:320px;">
+<img id="feedbackImg">
+</div>
+
+<div id="errorList">
 </div>
 </fieldset>
@@ -69,115 +91,111 @@
 #cacheinfo p, #GThumbProgressbar { text-align:left; line-height:20px; margin:20px }
 .ui-progressbar-value { background-image: url(plugins/GThumb/template/pbar-ani.gif); }
+#generate_cache { display: none; }
 </style>
 {/literal}{/html_head}
 
-{combine_script id='jquery.ui.progressbar' load='footer'}
-{combine_script id='jquery.ajaxmanager' load='footer' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
-
-{footer_script}
-var pwg_token = '{$PWG_TOKEN}';
-var confirm_message = '{'Are you sure?'|@translate}';
-var nb_files_str  = '{'%d file'|@translate}';
-var nb_files_str_plur = '{'%d files'|@translate}';
-var lang_info_zero_plural = {if $lang_info.zero_plural}true{else}false{/if};
-var cache_size = {$CACHE_SIZE};
-var nb_files = {$NB_FILES};
-
-{literal}
-var GThumb = {
-
-  total: 0,
-  done: 0,
-
-  queue: jQuery.manageAjax.create('queued', { 
-    queue: true,  
-    cacheResponse: false,
-    maxRequests: 3
-  }),
-
-  deletecache: function() {
-    if (confirm(confirm_message)) {
-      window.location = 'admin.php?page=plugin-GThumb&deletecache=true&pwg_token='+pwg_token;
-    }
-  },
-
-  generatecache: function() {
-    GThumb.total = nb_files;
-    GThumb.done = nb_files;
-    jQuery("#progressbar").progressbar({value: 1});
-    jQuery.ajax({
-      url: 'admin.php?page=plugin-GThumb&generatecache=request',
-      dataType: 'json',
-      success: function(data) {
-        if (data.length > 0) {
-          jQuery("#GThumbProgressbar, #GThumbAction").toggle();
-          GThumb.total = data.length + GThumb.done;
-          jQuery("#progressbar").progressbar({value: Math.ceil(GThumb.done * 100 / GThumb.total)});
-          for (i=0;i<data.length;i++) {
-            GThumb.queue.add({
-              type: 'GET', 
-              url: 'ws.php', 
-              data: {
-                method: 'pwg.images.getGThumbPlusThumbnail',
-                image_id: data[i],
-                format: 'json'
-              },
-              dataType: 'json',
-              success: function(data) {
-                nb_files++;
-                cache_size += data.result.filesize;
-                updateCacheSizeAndFiles();
-                GThumb.progressbar();
-              },
-              error: GThumb.progressbar
-            });
-          }
-        } else {
-          window.location = 'admin.php?page=plugin-GThumb&generatecache=complete';
-        }
-      },
-      error: function() {
-        alert('An error occured');
-      }
-    });
-    return false;
-  },
-
-  progressbar: function() {
-    jQuery( "#progressbar" ).progressbar({
-      value: Math.ceil(++GThumb.done * 100 / GThumb.total)
-    });
-    if (GThumb.done == GThumb.total) {
-      window.location = 'admin.php?page=plugin-GThumb&generatecache=complete';
-    }
-  },
-
-  abort: function() {
-    GThumb.queue.clear();
-    GThumb.queue.abort();
-    jQuery("#GThumbProgressbar, #GThumbAction").toggle();
+{combine_script id='iloader' load='footer' path='themes/default/js/image.loader.js'}
+
+{footer_script require='jquery.effects.slide'}{literal}
+jQuery('input[name^="cache"]').tipTip({'delay' : 0, 'fadeIn' : 200, 'fadeOut' : 200});
+
+var loader = new ImageLoader( {onChanged: loaderChanged, maxRequests:1 } )
+	, pending_next_page = null
+	, last_image_show_time = 0
+	, allDoneDfd, urlDfd;
+
+function start() {
+	allDoneDfd = jQuery.Deferred();
+	urlDfd = jQuery.Deferred();
+
+	allDoneDfd.always( function() {
+			jQuery("#startLink").attr('disabled', false).css("opacity", 1);
+			jQuery("#pauseLink,#stopLink").attr('disabled', true).css("opacity", 0.5);
+		} );
+
+	urlDfd.always( function() {
+		if (loader.remaining()==0)
+			allDoneDfd.resolve();
+		} );
+
+  jQuery('#generate_cache').show();
+	jQuery("#startLink").attr('disabled', true).css("opacity", 0.5);
+	jQuery("#pauseLink,#stopLink").attr('disabled', false).css("opacity", 1);
+
+	loader.pause(false);
+	updateStats();
+	getUrls('0');
+}
+
+function pause() {
+	loader.pause( !loader.pause() );
+}
+
+function stop() {
+	loader.clear();
+	urlDfd.resolve();
+}
+
+function getUrls(page_token) {
+	data = {prev_page: page_token, max_urls: 195, types: []};
+	jQuery.post( '{/literal}{$ROOT_URL}{literal}admin.php?page=plugin-GThumb&getMissingDerivative=',
+		data, wsData, "json").fail( wsError );
+}
+
+function wsData(data) {
+  if (data.urls.length == 0) {
+    jQuery('#generate_cache, input[name="cachebuild"]').hide();
   }
-};
-
-function updateCacheSizeAndFiles() {
-  
-  if ( nb_files > 1 || (nb_files == 0 && lang_info_zero_plural)) {
-    nbstr = nb_files_str_plur;
-  } else {
-    nbstr = nb_files_str;
-  }
-
-  ret = nbstr.replace('%d', nb_files) + ', ';
-
-  if (cache_size > 1024 * 1024)
-    ret += Math.round((cache_size / (1024 * 1024))*100)/100 + ' MB';
-  else
-    ret += Math.round((cache_size / 1024)*100)/100 + ' KB';
-
-  jQuery("#cache_data").html(ret);
-}
-
-updateCacheSizeAndFiles();
-
-jQuery('#GThumbAction button').tipTip({'delay' : 0, 'fadeIn' : 200, 'fadeOut' : 200});
+	loader.add( data.urls );
+	if (data.next_page) {
+		if (loader.pause() || loader.remaining() > 100) {
+			pending_next_page = data.next_page;
+		}
+		else {
+			getUrls(data.next_page);
+		}
+	}
+}
+
+function wsError() {
+	urlDfd.reject();
+}
+
+function updateStats() {
+	jQuery("#loaded").text( loader.loaded );
+	jQuery("#errors").text( loader.errors );
+	jQuery("#remaining").text( loader.remaining() );
+}
+
+function loaderChanged(type, img) {
+	updateStats();
+	if (img) {
+		if (type==="load") {
+			var now = jQuery.now();
+			if (now - last_image_show_time > 3000) {
+				last_image_show_time = now;
+				var h=img.height, url=img.src;
+				jQuery("#feedbackWrap").hide("slide", {direction:'down'}, function() {
+					last_image_show_time = jQuery.now();
+					if (h > 300 )
+						jQuery("#feedbackImg").attr("height", 300);
+					else
+						jQuery("#feedbackImg").removeAttr("height");
+					jQuery("#feedbackImg").attr("src", url);
+					jQuery("#feedbackWrap").show("slide", {direction:'up'} );
+					} );
+			}
+		}
+		else {
+			jQuery("#errorList").prepend( '<a href="'+img.src+'">'+img.src+'</a>' + "<br>");
+		}
+	}
+	if (pending_next_page && 100 > loader.remaining() )	{
+		getUrls(pending_next_page);
+		pending_next_page = null;
+	}
+	else if (loader.remaining() == 0 && (urlDfd.isResolved() || urlDfd.isRejected()))	{
+		allDoneDfd.resolve();
+	}
+}
 {/literal}{/footer_script}
Index: /extensions/GThumb/template/gthumb.tpl
===================================================================
--- /extensions/GThumb/template/gthumb.tpl	(revision 13651)
+++ /extensions/GThumb/template/gthumb.tpl	(revision 13652)
@@ -1,26 +1,26 @@
 {if !empty($thumbnails)}
-{strip}{foreach from=$thumbnails item=thumbnail}
+{foreach from=$thumbnails item=thumbnail}
+{assign var=derivative value=$pwg->derivative($GThumb_derivative_params, $thumbnail.src_image)}
 <li class="gthumb">
   <a href="{$thumbnail.URL}">
-    <img id="gt{$thumbnail.ID}" class="thumbnail" src="{$thumbnail.TN_SRC}" alt="{$thumbnail.TN_ALT}" title="{$thumbnail.TN_TITLE}"
-         width="{$thumbnail.TN_WIDTH}" height="{$thumbnail.TN_HEIGHT}" {if empty($thumbnail.TN_SRC)}style="display:none;"{/if}>
+    <img class="thumbnail" {if !$derivative->is_cached()}data-{/if}src="{$derivative->get_url()}" alt="{$thumbnail.TN_ALT}" title="{$thumbnail.TN_TITLE}" {$derivative->get_size_htm()}>
   </a>
 </li>
-{/foreach}{/strip}
+{/foreach}
 
 {combine_css path="plugins/GThumb/template/gthumb.css"}
-{combine_script id='jquery.ajaxmanager' path='themes/default/js/plugins/jquery.ajaxmanager.js' load="footer"}
+{combine_script id='jquery.ajaxmanager' path='themes/default/js/plugins/jquery.ajaxmanager.js' load='footer'}
+{combine_script id='thumbnails.loader' path='themes/default/js/thumbnails.loader.js' require='jquery.ajaxmanager' load='footer'}
 {combine_script id='jquery.ba-resize' path='plugins/GThumb/js/jquery.ba-resize.min.js' load="footer"}
-{combine_script id='gthumb' require='jquery,jquery.ajaxmanager,jquery.ba-resize' path='plugins/GThumb/js/gthumb.js' load="footer"}
+{combine_script id='gthumb' require='jquery,jquery.ba-resize' path='plugins/GThumb/js/gthumb.js' load="footer"}
 
 {footer_script require="gthumb"}
-GThumb.root = '{$ROOT_URL}';
 GThumb.max_height = {$GThumb.height};
 GThumb.margin = {$GThumb.margin};
 GThumb.method = '{$GThumb.method}';
 
-{if isset($big_thumb)}
-GThumb.small_thumb = {ldelim}id:{$small_thumb.id},src:'{$small_thumb.src}',width:{$small_thumb.width},height:{$small_thumb.height}{rdelim};
-GThumb.big_thumb = {ldelim}id:{$big_thumb.id},src:'{$big_thumb.src}',width:{$big_thumb.width},height:{$big_thumb.height}{rdelim};
+{if isset($GThumb_big)}
+{assign var=gt_size value=$GThumb_big->get_size()}
+GThumb.big_thumb = {ldelim}id:{$GThumb_big->src_image->id},src:'{$GThumb_big->get_url()}',width:{$gt_size[0]},height:{$gt_size[1]}{rdelim};
 {/if}
 
