Index: /extensions/typetags/admin.php
===================================================================
--- /extensions/typetags/admin.php	(revision 26664)
+++ /extensions/typetags/admin.php	(revision 26665)
@@ -1,51 +1,54 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
-
-load_language('plugin.lang', typetags_PATH);
-
-function get_color_text($color)
-{
-  if (strlen($color) == 7)
-  {
-    $rgb[] = hexdec(substr($color, 1, 2))/255;
-    $rgb[] = hexdec(substr($color, 3, 2))/255;
-    $rgb[] = hexdec(substr($color, 5, 2))/255;
-  }
-  else if (strlen($color) == 4)
-  {
-    $rgb[] = hexdec(substr($color, 1, 1))/15;
-    $rgb[] = hexdec(substr($color, 2, 1))/15;
-    $rgb[] = hexdec(substr($color, 3, 1))/15;
-  }
-  $l = (min($rgb) + max($rgb)) / 2;
-  return $l > 0.45 ? '#000' : '#fff';
-}
+defined('TYPETAGS_PATH') or die('Hacking attempt!');
+
+load_language('plugin.lang', TYPETAGS_PATH);
+
+include_once(TYPETAGS_PATH . 'include/functions.inc.php');
+
 
 // +-----------------------------------------------------------------------+
 // |                                edit typetags                          |
 // +-----------------------------------------------------------------------+
-
-if ( isset($_POST['edittypetag']) and (empty($_POST['typetag_name']) or empty($_POST['typetag_color'])) )
-{
-  $edited_typetag = array(
-    'id' => $_POST['edited_typetag'],
-    'name' => $_POST['typetag_name'],
-    'color' => $_POST['typetag_color'],
-  );
-  
-  array_push($page['errors'],  l10n('typetag_error'));
-}
-else if (isset($_POST['edittypetag']))
-{
-  // we must not rename typetag with an already existing name
-  $query = '
+if (isset($_POST['edittypetag']))
+{
+  if (empty($_POST['typetag_name']) or empty($_POST['typetag_color']))
+  {
+    $page['errors'][] = l10n('You must fill all fields (name and color)');
+  }
+  else
+  {
+    // we must not rename typetag with an already existing name
+    $query = '
 SELECT id
-  FROM '.typetags_TABLE.'
+  FROM ' . TYPETAGS_TABLE . '
   WHERE
-    name = "'.$_POST['typetag_name'].'"
-    AND id != '.$_POST['edited_typetag'].'
-;';
-
-  if ( pwg_db_num_rows(pwg_query($query)) )
+    name = "' . pwg_db_real_escape_string($_POST['typetag_name']) . '"
+    AND id != ' . $_POST['edited_typetag'] . '
+;';
+
+    if (pwg_db_num_rows(pwg_query($query)))
+    {
+      $page['errors'][] = l10n('This name is already used');
+    }
+    else if ( ($color = check_color($_POST['typetag_color'])) === false )
+    {
+      $page['errors'][] = l10n('Invalid color');
+    }
+    else
+    {
+      $query = '
+UPDATE '.TYPETAGS_TABLE.'
+  SET
+    name = "' . pwg_db_real_escape_string($_POST['typetag_name']) . '",
+    color = "' . $color . '"
+  WHERE id = ' . $_POST['edited_typetag'] . '
+;';
+      pwg_query($query);
+
+      $page['infos'][] = l10n('Color saved');
+    }
+  }
+
+  if (count($page['errors']))
   {
     $edited_typetag = array(
@@ -53,149 +56,86 @@
       'name' => $_POST['typetag_name'],
       'color' => $_POST['typetag_color'],
-    );
-    
-    array_push($page['errors'], l10n('typetag_already_exists'));
+      );
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                           delete typetags                             |
+// +-----------------------------------------------------------------------+
+if (isset($_GET['deletetypetag']))
+{
+  $query = '
+UPDATE ' . TAGS_TABLE . '
+  SET id_typetags = NULL
+  WHERE id_typetags = ' . intval($_GET['deletetypetag']) . '
+;';
+  pwg_query($query);
+
+  $query = '
+DELETE FROM ' . TYPETAGS_TABLE . '
+  WHERE id = ' . intval($_GET['deletetypetag']) . '
+;';
+  pwg_query($query);
+
+  if (pwg_db_changes())
+  {
+    $page['infos'][] = l10n('Color deleted');
+  }
+}
+
+// +-----------------------------------------------------------------------+
+// |                               add a typetag                           |
+// +-----------------------------------------------------------------------+
+if (isset($_POST['addtypetag']))
+{
+  if (empty($_POST['typetag_name']) or empty($_POST['typetag_color']))
+  {
+    $page['errors'][] = l10n('You must fill all fields (name and color)');
   }
   else
   {
+    $typetag_name = $_POST['typetag_name'];
+    $typetag_color = $_POST['typetag_color'];
+
+    // does the tag already exists?
     $query = '
-UPDATE '.typetags_TABLE.'
-  SET 
-    name = "'.$_POST['typetag_name'].'",
-    color = "'.$_POST['typetag_color'].'"
-  WHERE id = '.$_POST['edited_typetag'].'
-;';
-    pwg_query($query);
-    
-    array_push($page['infos'], l10n('typetag_saved'));
-  }
-}
-
-// +-----------------------------------------------------------------------+
-// |                           delete typetags                             |
-// +-----------------------------------------------------------------------+
-
-if (isset($_GET['deletetypetag']))
-{
-  $query = '
 SELECT id
-  FROM '.typetags_TABLE.'
-  WHERE id = '.$_GET['deletetypetag'].'
-;';
-  
-  if ( pwg_db_num_rows(pwg_query($query)) )
-  {
-    $query = '
-UPDATE '.TAGS_TABLE.'
-  SET id_typetags = NULL
-  WHERE id_typetags = '.$_GET['deletetypetag'].'
-;';
-    pwg_query($query);
-    
-    $query = '
-DELETE FROM '.typetags_TABLE.'
-  WHERE id = '.$_GET['deletetypetag'].'
-;';
-    pwg_query($query);
-    
-    array_push($page['infos'], l10n('typetag_suppr'));
-  }
-  else
-  {
-    array_push($page['errors'], l10n('typetag_unknown'));
-  }
-}
-
-// +-----------------------------------------------------------------------+
-// |                               add a typetag                           |
-// +-----------------------------------------------------------------------+
-
-if ( isset($_POST['addtypetag']) and (empty($_POST['typetag_name']) or empty($_POST['typetag_color'])) )
-{
-  $template->assign('typetag', array(
-    'NAME' => $_POST['typetag_name'],
-    'COLOR' => $_POST['typetag_color'],
-  ));
-  
-  array_push($page['errors'], l10n('typetag_error'));
-}
-else if (isset($_POST['addtypetag']))
-{
-  $typetag_name = $_POST['typetag_name'];
-  $typetag_color = $_POST['typetag_color'];
-
-  // does the tag already exists?
-  $query = '
-SELECT id
-  FROM '.typetags_TABLE.'
-  WHERE name = "'.$_POST['typetag_name'].'"
+  FROM ' . TYPETAGS_TABLE . '
+  WHERE name = "' . pwg_db_real_escape_string($_POST['typetag_name']) . '"
 ';
 
-  if ( pwg_db_num_rows(pwg_query($query)) )
-  {
-    $template->assign('typetag', array(
-      'NAME' => $_POST['typetag_name'],
-      'COLOR' => $_POST['typetag_color'],
-    ));
-    
-    array_push($page['errors'], l10n('typetag_already_exists'));
-  }
-  else
-  {
-    $query = '
-INSERT INTO '.typetags_TABLE.'(
+    if (pwg_db_num_rows(pwg_query($query)))
+    {
+      $page['errors'][] = l10n('This name is already used');
+    }
+    else if ( ($color = check_color($_POST['typetag_color'])) === false )
+    {
+      $page['errors'][] = l10n('Invalid color');
+    }
+    else
+    {
+      $query = '
+INSERT INTO ' . TYPETAGS_TABLE . '(
     name,
     color
   )
   VALUES(
-    "'.$_POST['typetag_name'].'",
-    "'.$_POST['typetag_color'].'"
+    "' . pwg_db_real_escape_string($_POST['typetag_name']) . '",
+    "' . $color . '"
   )
 ;';
-    pwg_query($query);
-
-    array_push($page['infos'], l10n('typetag_saved'));
-  }
-}
-
-// +-----------------------------------------------------------------------+
-// |                           Associate Tag to Typetage                   |
-// +-----------------------------------------------------------------------+
-
-if (isset($_POST['delete_all_assoc'])) 
-{
-  pwg_query('UPDATE '.TAGS_TABLE.' SET id_typetags = NULL;');
-  array_push($page['infos'], l10n('All associations have been removed'));
-} 
-else if (isset($_POST['associations'])) 
-{
-  // beautify the parameters array
-  $string = preg_replace('#[;]$#', null, $_POST['associations']);
-  $associations = array();
-  $a = explode(';', $string);
-  
-  foreach ($a as $s) 
-  {
-    $v = explode(':', $s);
-    $associations[ltrim($v[0],'t-')] = ltrim($v[1],'tt-');
-  }
-
-  // save associations
-  $updates = array();
-  foreach ($associations as $tag => $typetag) 
-  {
-    array_push($updates, array(
-      'id' => $tag,
-      'id_typetags' => $typetag,
+      pwg_query($query);
+
+      $page['infos'][] = l10n('Color added');
+    }
+  }
+
+  if (count($page['errors']))
+  {
+    $template->assign('typetag', array(
+      'NAME' => $_POST['typetag_name'],
+      'COLOR' => $_POST['typetag_color'],
       ));
   }
-  
-  mass_updates(
-    TAGS_TABLE, 
-    array('primary' => array('id'), 'update' => array('id_typetags')),
-    $updates
-    );
-  
-  array_push($page['infos'], l10n('typetags_associated'));
 }
 
@@ -208,6 +148,7 @@
     'show_all' => $_POST['show_all'] == 'true',
     );
-    
+
   conf_update_param('TypeTags', serialize($conf['TypeTags']));
+  $page['infos'][] = l10n('Information data registered in database');
 }
 
@@ -217,36 +158,18 @@
 // |                             template init                             |
 // +-----------------------------------------------------------------------+
-
-$template->set_filenames(array('plugin_admin_content' => dirname(__FILE__) . '/admin/typetags_admin.tpl'));
-
-// get all tags
-$query = '
-SELECT 
-    id as tagid,
-    name as tagname, 
-    id_typetags as typetagid
-  FROM '.TAGS_TABLE.'
-  ORDER BY name ASC
-;';
-$all_tags = pwg_query($query);
-
-while ($row = pwg_db_fetch_assoc($all_tags))
-{
-  if (!$row['typetagid']) $row['typetagid'] = 'NULL';
-  $row['tagname'] = strip_tags(trigger_event('render_tag_name', $row['tagname']));
-  $template->append('typetags_association', $row);
-}
+$template->assign('TYPETAGS_PATH', TYPETAGS_PATH);
+$template->assign('F_ACTION', TYPETAGS_ADMIN);
 
 // get all typetags
-$query = 'SELECT * FROM '.typetags_TABLE.' ORDER BY name;';
-$all_typetags = pwg_query($query);
-
-while ($row = pwg_db_fetch_assoc($all_typetags))
+$query = 'SELECT * FROM ' . TYPETAGS_TABLE . ' ORDER BY name;';
+$result = pwg_query($query);
+
+while ($row = pwg_db_fetch_assoc($result))
 {
   $row['color_text'] = get_color_text($row['color']);
-  $row['u_edit'] = typetags_ADMIN . '&edittypetag=' . $row['id'];
-  $row['u_delete'] = typetags_ADMIN . '&deletetypetag=' . $row['id'];
-  
-  $template->append('typetags_selection', $row);
+  $row['u_edit'] = TYPETAGS_ADMIN . '&amp;edittypetag=' . $row['id'];
+  $row['u_delete'] = TYPETAGS_ADMIN . '&amp;deletetypetag=' . $row['id'];
+
+  $template->append('typetags', $row);
 }
 
@@ -254,18 +177,15 @@
 if (isset($_GET['edittypetag']))
 {
-  $edited_typetag['id'] = $_GET['edittypetag'];
-}
-
-if (isset($edited_typetag['id']))
+  $edited_typetag['id'] = intval($_GET['edittypetag']);
+}
+
+if (isset($edited_typetag['id']) and $edited_typetag['id']>0)
 {
   $template->assign('edited_typetag', $edited_typetag['id']);
-  
+
 $query = '
-SELECT 
-    id,
-    name,
-    color
-  FROM '.typetags_TABLE.'
-  WHERE id = '.$edited_typetag['id'].'
+SELECT *
+  FROM ' . TYPETAGS_TABLE . '
+  WHERE id = ' . $edited_typetag['id'] . '
 ;';
   $row = pwg_db_fetch_assoc(pwg_query($query));
@@ -278,6 +198,6 @@
     'NAME' => isset($edited_typetag['name']) ? $edited_typetag['name'] : $row['name'],
     'COLOR'=> isset($edited_typetag['color']) ? $edited_typetag['color'] : $row['color'],
-  ));
-  
+    ));
+
   $template->assign('IN_EDIT', true);
 }
@@ -286,7 +206,4 @@
 // |                           sending html code                           |
 // +-----------------------------------------------------------------------+
-
-$template->assign('typetags_ADMIN', typetags_ADMIN);
-$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
-
-?>
+$template->set_filename('typetags', realpath(TYPETAGS_PATH . 'template/admin.tpl'));
+$template->assign_var_from_handle('ADMIN_CONTENT', 'typetags');
Index: /extensions/typetags/include/events_admin.inc.php
===================================================================
--- /extensions/typetags/include/events_admin.inc.php	(revision 26665)
+++ /extensions/typetags/include/events_admin.inc.php	(revision 26665)
@@ -0,0 +1,144 @@
+<?php
+defined('TYPETAGS_PATH') or die('Hacking attempt!');
+
+/**
+ * menu link
+ */
+function typetags_admin_menu($menu)
+{
+  $menu[] = array(
+    'NAME' => 'Coloured Tags',
+    'URL' => TYPETAGS_ADMIN,
+    );
+  return $menu;
+}
+
+/**
+ * tags page
+ */
+function typetags_admin()
+{
+  global $template, $page;
+
+  if ($page['page'] != 'tags')
+  {
+    return;
+  }
+
+  include_once(TYPETAGS_PATH . 'include/functions.inc.php');
+
+  load_language('plugin.lang', TYPETAGS_PATH);
+
+  // save
+  if (isset($_POST['typetags_submit']))
+  {
+    if ($_POST['mode'] == 'global')
+    {
+      $query = '
+UPDATE ' . TAGS_TABLE . '
+  SET id_typetags = ' . ($_POST['tag_color-all']!=-1 ? get_typetag_id($_POST['tag_color-all']) : 'NULL') . '
+  WHERE id IN ('.$_POST['edit_list'].')
+;';
+      pwg_query($query);
+    }
+    else
+    {
+      $updates = $deletes = array();
+
+      foreach (explode(',', $_POST['edit_list']) as $tag_id)
+      {
+        if ($_POST['tag_color-'.$tag_id]!=-1)
+        {
+          $updates[] = array(
+            'id' => $tag_id,
+            'id_typetags' => get_typetag_id($_POST['tag_color-'.$tag_id]),
+            );
+        }
+        else
+        {
+          $deletes[] = $tag_id;
+        }
+      }
+
+      mass_updates(
+        TAGS_TABLE,
+        array('primary' => array('id'), 'update' => array('id_typetags')),
+        $updates
+        );
+
+      if (!empty($deletes))
+      {
+        $query = '
+UPDATE ' . TAGS_TABLE . '
+  SET id_typetags = NULL
+  WHERE id IN('. implode(',', $deletes) .')
+;';
+        pwg_query($query);
+      }
+    }
+  }
+
+  // enter edit
+  if (isset($_POST['typetags']) and isset($_POST['tags']))
+  {
+    $template->assign('TYPETAGS_LIST', implode(',', $_POST['tags']));
+
+    $query = '
+SELECT
+    t.id,
+    t.name,
+    id_typetags,
+    color
+  FROM ' . TAGS_TABLE . ' AS t
+    LEFT JOIN ' . TYPETAGS_TABLE . ' AS tt
+    ON t.id_typetags = tt.id
+  WHERE t.id IN ('.implode(',', $_POST['tags']).')
+;';
+    $result = pwg_query($query);
+    while ($row = pwg_db_fetch_assoc($result))
+    {
+      $row['color_text'] = get_color_text($row['color']);
+      $template->append('tags', $row);
+    }
+
+    $query = 'SELECT * FROM ' . TYPETAGS_TABLE . ' ORDER BY name;';
+    $result = pwg_query($query);
+
+    while ($row = pwg_db_fetch_assoc($result))
+    {
+      $row['color_text'] = get_color_text($row['color']);
+      $template->append('typetags', $row);
+    }
+  }
+
+  $query = '
+SELECT
+    t.id,
+    id_typetags,
+    color
+  FROM ' . TAGS_TABLE . ' AS t
+    LEFT JOIN ' . TYPETAGS_TABLE . ' AS tt
+    ON t.id_typetags = tt.id
+;';
+  $template->assign('tags_color', query2array($query, 'id'));
+
+  $template->assign('TYPETAGS_PATH', TYPETAGS_PATH);
+  $template->set_prefilter('tags', 'typetags_admin_prefilter');
+}
+
+function typetags_admin_prefilter($content)
+{
+  // add button
+  $search[0] = '<input type="submit" name="delete"';
+  $replace[0] = '<input type="submit" name="typetags" value="{\'Set tags color\'|translate}"> ' . $search[0];
+
+  // add form part
+  $search[1] = '<form action="{$F_ACTION}" method="post">';
+  $replace[1] = $search[1] . file_get_contents(realpath(TYPETAGS_PATH . 'template/tags.tpl'));
+
+  // color on main list
+  $search[2] = '<input type="checkbox" name="tags[]" value="{$tag.id}"> {$tag.name}';
+  $replace[2] = '<input type="checkbox" name="tags[]" value="{$tag.id}"> <span style="color:{$tags_color[$tag.id].color};">{$tag.name}</span>';
+
+  return str_replace($search, $replace, $content);
+}
Index: /extensions/typetags/include/events_public.inc.php
===================================================================
--- /extensions/typetags/include/events_public.inc.php	(revision 26665)
+++ /extensions/typetags/include/events_public.inc.php	(revision 26665)
@@ -0,0 +1,187 @@
+<?php
+defined('TYPETAGS_PATH') or die('Hacking attempt!');
+
+/**
+ * triggered by 'render_tag_name'
+ */
+function typetags_render($tag_name, $tag=array())
+{
+  global $pwg_loaded_plugins, $page, $typetags_cache;
+
+  if (defined('IN_ADMIN') and in_array($page['page'], array('photo', 'batch_manager', 'tags')))
+  {
+    return $tag_name;
+  }
+
+  if (isset($typetags_cache['tags'][$tag_name]))
+  {
+    return $typetags_cache['tags'][$tag_name];
+  }
+
+  if (!isset($typetags_cache['colors']))
+  {
+    $query = '
+SELECT id, color
+  FROM ' . TYPETAGS_TABLE . '
+;';
+    $typetags_cache['colors'] = query2array($query, 'id', 'color');
+  }
+
+  if (!empty($tag['id_typetags']))
+  {
+    $color = $typetags_cache['colors'][ $tag['id_typetags'] ];
+  }
+  else
+  {
+    if (isset($tag['id']))
+    {
+      $where = 't.id = ' . $tag['id'];
+    }
+    else
+    {
+      $where = 't.name = "' . pwg_db_real_escape_string($tag_name) . '"';
+    }
+
+    $query = '
+SELECT color
+  FROM ' . TYPETAGS_TABLE . ' AS tt
+    INNER JOIN ' . TAGS_TABLE . ' AS t
+    ON t.id_typetags = tt.id
+  WHERE ' . $where . '
+;';
+    list($color) = pwg_db_fetch_row(pwg_query($query));
+  }
+
+  if ($color === null)
+  {
+    $ret = $tag_name;
+  }
+  elseif (isset($pwg_loaded_plugins['ExtendedDescription']))
+  {
+    $ret = '[lang=all]<span style="color:' . $color . ';">[/lang]' . $tag_name . '[lang=all]</span>[/lang]';
+  }
+  else
+  {
+    $ret = '<span style="color:' . $color . ';">' . $tag_name . '</span>';
+  }
+
+  $typetags_cache['tags'][$tag_name] = $ret;
+  return $ret;
+}
+
+/**
+ * colors tags on picture page
+ */
+/*function typetags_picture()
+{
+  global $template;
+
+  $tags = $template->get_template_vars('related_tags');
+  if (empty($tags)) return;
+
+  $query = '
+SELECT
+    t.id ,
+    tt.color
+  FROM '.TYPETAGS_TABLE.' AS tt
+    INNER JOIN '.TAGS_TABLE.' AS t
+      ON t.id_typetags = tt.id
+  WHERE t.id_typetags IS NOT NULL
+;';
+  $tagsColor = simple_hash_from_query($query, 'id', 'color');
+  if (empty($tagsColor)) return;
+
+  foreach ($tags as $key => $tag)
+  {
+    if (isset($tagsColor[ $tag['id'] ]))
+    {
+      $tags[$key]['URL'].= '" style="color:'.$tagsColor[ $tag['id'] ].';';
+    }
+  }
+
+  $template->clear_assign('related_tags');
+  $template->assign('related_tags', $tags);
+}*/
+
+/**
+ * colors tags on tags page
+ */
+function typetags_tags()
+{
+  global $template, $page, $tags;
+
+  if (empty($tags))
+  {
+    return;
+  }
+
+  $query = '
+SELECT
+    t.id,
+    tt.color
+  FROM ' . TYPETAGS_TABLE . ' AS tt
+    INNER JOIN ' . TAGS_TABLE . ' AS t
+    ON t.id_typetags = tt.id
+  WHERE t.id_typetags IS NOT NULL
+;';
+  $tagsColor = query2array($query, 'id', 'color');
+
+  if (empty($tagsColor))
+  {
+    return;
+  }
+
+  // LETTERS
+  if ($page['display_mode'] == 'letters')
+  {
+    $letters = $template->get_template_vars('letters');
+
+    foreach ($letters as &$letter)
+    {
+      foreach ($letter['tags'] as &$tag)
+      {
+        if (isset($tagsColor[ $tag['id'] ]))
+        {
+          $tag['URL'].= '" style="color:' . $tagsColor[ $tag['id'] ] . ';';
+        }
+      }
+      unset($tag);
+    }
+    unset($letter);
+
+    $template->assign('letters', $letters);
+  }
+  // CLOUD
+  else if ($page['display_mode'] == 'cloud')
+  {
+    $tags = $template->get_template_vars('tags');
+
+    foreach ($tags as &$tag)
+    {
+      if (isset($tagsColor[ $tag['id'] ]))
+      {
+        $tag['URL'].= '" style="color:' . $tagsColor[ $tag['id'] ] . ';';
+      }
+    }
+    unset($tag);
+
+    $template->assign('tags', $tags);
+  }
+  // CUMULUS
+  else if ($page['display_mode'] == 'cumulus')
+  {
+    $tags = $template->get_template_vars('tags');
+
+    foreach ($tags as &$tag)
+    {
+      if (isset($tagsColor[ $tag['id'] ]))
+      {
+        $tagsColor[ $tag['id'] ] = str_replace('#', '0x', $tagsColor[ $tag['id'] ]);
+        $tag['URL'].= '\' color=\'' . $tagsColor[ $tag['id'] ] . '\' hicolor=\'' . $tagsColor[ $tag['id'] ];
+      }
+    }
+    unset($tag);
+
+    $template->assign('tags', $tags);
+  }
+}
Index: /extensions/typetags/include/functions.inc.php
===================================================================
--- /extensions/typetags/include/functions.inc.php	(revision 26665)
+++ /extensions/typetags/include/functions.inc.php	(revision 26665)
@@ -0,0 +1,98 @@
+<?php
+defined('TYPETAGS_PATH') or die('Hacking attempt!');
+
+function get_color_text($color)
+{
+  if (empty($color))
+  {
+    return '';
+  }
+
+  if (strlen($color) == 7)
+  {
+    $rgb[] = hexdec(substr($color, 1, 2))/255;
+    $rgb[] = hexdec(substr($color, 3, 2))/255;
+    $rgb[] = hexdec(substr($color, 5, 2))/255;
+  }
+  else if (strlen($color) == 4)
+  {
+    $rgb[] = hexdec(substr($color, 1, 1))/15;
+    $rgb[] = hexdec(substr($color, 2, 1))/15;
+    $rgb[] = hexdec(substr($color, 3, 1))/15;
+  }
+
+  $l = (min($rgb) + max($rgb)) / 2;
+
+  return $l > 0.45 ? '#000' : '#fff';
+}
+
+function check_color($hex)
+{
+  global $page;
+
+  $hex = ltrim($hex, '#');
+
+  if (strlen($hex) == 3)
+  {
+    $hex = $hex[0].$hex[0].$hex[1].$hex[1].$hex[2].$hex[2];
+  }
+  else if (strlen($hex) != 6)
+  {
+    return false;
+  }
+
+  if (!ctype_xdigit($hex))
+  {
+    return false;
+  }
+
+  return '#'.$hex;
+}
+
+function get_typetag_id($input)
+{
+  if (preg_match('#^~~([0-9]+)~~$#', $input, $matches))
+  {
+    return $matches[1];
+  }
+  else if (strpos($input, '|') !== false)
+  {
+    list($color, $name) = explode('|', $input, 2);
+
+    if ( ($color = check_color($color)) === false)
+    {
+      return false;
+    }
+
+    $query = '
+SELECT id FROM ' . TYPETAGS_TABLE . '
+  WHERE color = "' . $color . '"
+  LIMIT 1
+;';
+    $result = pwg_query($query);
+
+    if (pwg_db_num_rows($result))
+    {
+      list($tt_id) = pwg_db_fetch_row($result);
+      return $tt_id;
+    }
+
+    $query = '
+INSERT INTO ' . TYPETAGS_TABLE . '(
+    name,
+    color
+  )
+  VALUES(
+    "' . pwg_db_real_escape_string($name) . '",
+    "' . $color . '"
+  )
+;';
+    pwg_query($query);
+
+    return pwg_db_insert_id();
+  }
+  else
+  {
+    return false;
+  }
+}
Index: /extensions/typetags/include/index.php
===================================================================
--- /extensions/typetags/include/index.php	(revision 26665)
+++ /extensions/typetags/include/index.php	(revision 26665)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/typetags/language/ca_ES/plugin.lang.php
===================================================================
--- /extensions/typetags/language/ca_ES/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/ca_ES/plugin.lang.php	(revision 26665)
@@ -37,5 +37,5 @@
 $lang['Only on tags page'] = 'Només a la pàgina etiquetes';
 $lang['typetag_already_exists'] = 'Aquest TypeTag ja existeix';
-$lang['typetag_error'] = 'Cal omplir tots els camps (nom i color)';
+$lang['You must fill all fields (name and color)'] = 'Cal omplir tots els camps (nom i color)';
 $lang['typetag_saved'] = 'TypeTag desat';
 $lang['typetag_suppr'] = 'TypeTag eliminat';
Index: /extensions/typetags/language/cs_CZ/plugin.lang.php
===================================================================
--- /extensions/typetags/language/cs_CZ/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/cs_CZ/plugin.lang.php	(revision 26665)
@@ -26,5 +26,5 @@
 $lang['New color'] = 'Nová barva';
 $lang['New name'] = 'Nový název';
-$lang['typetag_error'] = 'Musíte vyplnit všechna pole (název a barva)';
+$lang['You must fill all fields (name and color)'] = 'Musíte vyplnit všechna pole (název a barva)';
 $lang['Color TypeTag'] = 'Barva TypeTagu';
 $lang['Create a Typetag'] = 'Vytvořit TypeTag';
Index: /extensions/typetags/language/da_DK/plugin.lang.php
===================================================================
--- /extensions/typetags/language/da_DK/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/da_DK/plugin.lang.php	(revision 26665)
@@ -38,5 +38,5 @@
 $lang['Only on tags page'] = 'Kun på tagside';
 $lang['typetag_already_exists'] = 'Dette TypeTag findes allerede';
-$lang['typetag_error'] = 'Du skal udfylde alle felter (navn og farve)';
+$lang['You must fill all fields (name and color)'] = 'Du skal udfylde alle felter (navn og farve)';
 $lang['typetag_saved'] = 'TypeTag gemt';
 $lang['typetag_suppr'] = 'TypeTag slettet';
Index: /extensions/typetags/language/de_DE/plugin.lang.php
===================================================================
--- /extensions/typetags/language/de_DE/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/de_DE/plugin.lang.php	(revision 26665)
@@ -21,5 +21,5 @@
 $lang['typetag_suppr'] = 'TypeTag gelöscht';
 $lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'Alle Felder müssen ausgefüllt werden (Name und Farbe)';
+$lang['You must fill all fields (name and color)'] = 'Alle Felder müssen ausgefüllt werden (Name und Farbe)';
 $lang['All associations have been removed'] = 'All associations have been removed';
 $lang['typetags_associated'] = 'TypeTags wurde assoziiert';
Index: /extensions/typetags/language/el_GR/plugin.lang.php
===================================================================
--- /extensions/typetags/language/el_GR/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/el_GR/plugin.lang.php	(revision 26665)
@@ -37,5 +37,5 @@
 $lang['Only on tags page'] = 'Μόνο στη σελίδα ετικετών';
 $lang['typetag_already_exists'] = 'Αυτό το TypeTag υπάρχει ήδη ';
-$lang['typetag_error'] = 'Θα πρέπει να συμπληρώσετε όλα τα πεδία (όνομα και το χρώμα)';
+$lang['You must fill all fields (name and color)'] = 'Θα πρέπει να συμπληρώσετε όλα τα πεδία (όνομα και το χρώμα)';
 $lang['typetag_saved'] = 'TypeTag αποθηκεύτηκε ';
 $lang['typetag_suppr'] = 'TypeTag διεγράφη';
Index: /extensions/typetags/language/en_UK/plugin.lang.php
===================================================================
--- /extensions/typetags/language/en_UK/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/en_UK/plugin.lang.php	(revision 26665)
@@ -1,32 +1,22 @@
 <?php
 
-/* section */
-$lang['Create a Typetag'] = 'Create a TypeTag';
-$lang['Edit typetag'] = 'Edit TypeTag';
-$lang['Edit and associate TypeTags'] = 'Edit and associate TypeTags';
-
-/* fields */
-$lang['Edited TypeTag'] = 'TypeTag edited';
-$lang['New color'] = 'New color';
-$lang['New TypeTag'] = 'TypeTag name';
-$lang['New name'] = 'New name';
-$lang['Color TypeTag'] = 'TypeTag color';
-$lang['Not associated'] = 'Not associated';
+$lang['Add a new color'] = 'Add a new color';
+$lang['Apply the same color to all tags'] = 'Apply the same color to all tags';
+$lang['Color'] = 'Color';
+$lang['Color added'] = 'Color added';
+$lang['Color deleted'] = 'Color deleted';
+$lang['Color saved'] = 'Color saved';
+$lang['Edit color'] = 'Edit color';
+$lang['Go to <a href="%s">Photos/Tags</a> to manage associations.'] = 'Go to <a href="%s">Photos/Tags</a> to manage associations.';
+$lang['Invalid color'] = 'Invalid color';
+$lang['Manage colors'] = 'Manage colors';
+$lang['This name is already used'] = 'This name is already used';
+$lang['Set a different color for each tag'] = 'Set a different color for each tag';
+$lang['Set tags color'] = 'Set tags color';
 $lang['Display colored tags'] = 'Display colored tags';
 $lang['Only on tags page'] = 'Only on tags page';
 $lang['Everywhere'] = 'Everywhere';
-
-/* buttons */
-$lang['Modify'] = 'Modify';
-$lang['Delete all associations'] = 'Delete all associations';
-
-/* messages */
-$lang['typetag_already_exists'] = 'This TypeTag already exists';
-$lang['typetag_saved'] = 'TypeTag saved';
-$lang['typetag_suppr'] = 'TypeTag deleted';
-$lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'You must fill all fields (name and color)';
-$lang['All associations have been removed'] = 'All associations have been removed';
-$lang['typetags_associated'] = 'TypeTags associated';
+$lang['New color'] = 'New color';
+$lang['You must fill all fields (name and color)'] = 'You must fill all fields (name and color)';
 
 ?>
Index: /extensions/typetags/language/es_ES/plugin.lang.php
===================================================================
--- /extensions/typetags/language/es_ES/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/es_ES/plugin.lang.php	(revision 26665)
@@ -21,5 +21,5 @@
 $lang['typetag_suppr'] = 'TypeTag suprimido';
 $lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'Usted debe informar todos los campos (nombre y color)';
+$lang['You must fill all fields (name and color)'] = 'Usted debe informar todos los campos (nombre y color)';
 $lang['All associations have been removed'] = 'All associations have been removed';
 $lang['typetags_associated'] = 'TypeTags asociado';
Index: /extensions/typetags/language/fr_FR/plugin.lang.php
===================================================================
--- /extensions/typetags/language/fr_FR/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/fr_FR/plugin.lang.php	(revision 26665)
@@ -1,32 +1,22 @@
 <?php
 
-/* section */
-$lang['Create a Typetag'] = 'Créer un TypeTag';
-$lang['Edit typetag'] = 'Editer le TypeTag';
-$lang['Edit and associate TypeTags'] = 'Editer et associer les TypeTags';
-
-/* fields */
-$lang['Edited TypeTag'] = 'TypeTag édité';
+$lang['Add a new color'] = 'Ajouter une nouvelle couleur';
+$lang['Apply the same color to all tags'] = 'Appliquer la même couleur à tous les tags';
+$lang['Color'] = 'Couleur';
+$lang['Color added'] = 'Couleur ajoutée';
+$lang['Color deleted'] = 'Couleur supprimée';
+$lang['Color saved'] = 'Couleur sauvegardée';
+$lang['Edit color'] = 'Editer une couleur';
+$lang['Go to <a href="%s">Photos/Tags</a> to manage associations.'] = 'Allez sur <a href="%s">Photos/Tags</a> pour gérer les associations.';
+$lang['Invalid color'] = 'Couleur invalide';
+$lang['Manage colors'] = 'Gérer les couleurs';
+$lang['This name is already used'] = 'The nom est déjà utilisé';
+$lang['Set a different color for each tag'] = 'Appliquer une couleur différente à chaque tag';
+$lang['Set tags color'] = 'Changer la couleur des tags';
+$lang['Display colored tags'] = 'Afficher les tags colorés';
+$lang['Only on tags page'] = 'Uniquement sur la liste des tags';
+$lang['Everywhere'] = 'Partout';
 $lang['New color'] = 'Nouvelle couleur';
-$lang['New TypeTag'] = 'Nom du TypeTag';
-$lang['New name'] = 'Nouveau nom';
-$lang['Color TypeTag'] = 'Couleur du TypeTag';
-$lang['Not associated'] = 'Non associés';
-$lang['Display colored tags'] = 'Afficher les tags colorés';
-$lang['Only on tags page'] = 'Seulement sur la page des tags';
-$lang['Everywhere'] = 'Partout';
-
-/* buttons */
-$lang['Modify'] = 'Modifier';
-$lang['Delete all associations'] = 'Supprimer toutes les associations';
-
-/* messages */
-$lang['typetag_already_exists'] = 'Ce TypeTag existe déjà';
-$lang['typetag_saved'] = 'TypeTag enregistré';
-$lang['typetag_suppr'] = 'TypeTag supprimé';
-$lang['typetag_unknown'] = 'TypeTag inconnu';
-$lang['typetag_error'] = 'Vous devez renseigner tous les champs (nom et couleur)';
-$lang['All associations have been removed'] = 'Tous les associations ont été supprimées';
-$lang['typetags_associated'] = 'TypeTags associés';
+$lang['You must fill all fields (name and color)'] = 'Vous devez remplir tous les champs (nom et couleur)';
 
 ?>
Index: /extensions/typetags/language/gl_ES/plugin.lang.php
===================================================================
--- /extensions/typetags/language/gl_ES/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/gl_ES/plugin.lang.php	(revision 26665)
@@ -32,5 +32,5 @@
 $lang['typetag_unknown'] = 'EtiquetaTipo descoñecida';
 $lang['typetags_associated'] = 'EtiquetasTipo asociadas';
-$lang['typetag_error'] = 'Debes encher tódolos campos (nome e cor)';
+$lang['You must fill all fields (name and color)'] = 'Debes encher tódolos campos (nome e cor)';
 $lang['Delete all associations'] = 'Eliminar todas as asociacións';
 $lang['Display colored tags'] = 'Amosar as etiquetas coloreadas';
Index: /extensions/typetags/language/hu_HU/plugin.lang.php
===================================================================
--- /extensions/typetags/language/hu_HU/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/hu_HU/plugin.lang.php	(revision 26665)
@@ -37,5 +37,5 @@
 $lang['Only on tags page'] = 'Csak a címkék oldalon';
 $lang['typetag_already_exists'] = 'Ilyes címke típus már létezik';
-$lang['typetag_error'] = 'Ki kel tölteni a mezőket (név és szín)';
+$lang['You must fill all fields (name and color)'] = 'Ki kel tölteni a mezőket (név és szín)';
 $lang['typetag_saved'] = 'Címke típus mentve';
 $lang['typetag_suppr'] = 'Címke típus törölve';
Index: /extensions/typetags/language/it_IT/plugin.lang.php
===================================================================
--- /extensions/typetags/language/it_IT/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/it_IT/plugin.lang.php	(revision 26665)
@@ -21,5 +21,5 @@
 $lang['typetag_suppr'] = 'TypeTag cancellato';
 $lang['typetag_unknown'] = 'TypeTag sconosciuto';
-$lang['typetag_error'] = 'Dovete inserire tutti campi (nome e colore)';
+$lang['You must fill all fields (name and color)'] = 'Dovete inserire tutti campi (nome e colore)';
 $lang['All associations have been removed'] = 'Tutte le associazioni sono state rimosse';
 $lang['typetags_associated'] = 'TypeTag associato';
Index: /extensions/typetags/language/lv_LV/plugin.lang.php
===================================================================
--- /extensions/typetags/language/lv_LV/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/lv_LV/plugin.lang.php	(revision 26665)
@@ -21,5 +21,5 @@
 $lang['typetag_suppr'] = 'TypeTag dzēsti';
 $lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'Jums jāinformē visus laukus (nosaukums un krāsa)';
+$lang['You must fill all fields (name and color)'] = 'Jums jāinformē visus laukus (nosaukums un krāsa)';
 $lang['All associations have been removed'] = 'All associations have been removed';
 $lang['typetags_associated'] = 'TypeTags sasaistīts';
Index: /extensions/typetags/language/nb_NO/plugin.lang.php
===================================================================
--- /extensions/typetags/language/nb_NO/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/nb_NO/plugin.lang.php	(revision 26665)
@@ -21,5 +21,5 @@
 $lang['typetag_suppr'] = 'TypeTag slettet';
 $lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'Du må inkludere alle felter (navn og farge)';
+$lang['You must fill all fields (name and color)'] = 'Du må inkludere alle felter (navn og farge)';
 $lang['All associations have been removed'] = 'All associations have been removed';
 $lang['typetags_associated'] = 'TypeTags assossiert';
Index: /extensions/typetags/language/nl_NL/plugin.lang.php
===================================================================
--- /extensions/typetags/language/nl_NL/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/nl_NL/plugin.lang.php	(revision 26665)
@@ -32,5 +32,5 @@
 $lang['New name'] = 'Nieuwe naam';
 $lang['typetag_already_exists'] = 'Deze TypeTag bestaat al';
-$lang['typetag_error'] = 'Je moet alle velden invullen (naam en kleur)';
+$lang['You must fill all fields (name and color)'] = 'Je moet alle velden invullen (naam en kleur)';
 $lang['typetag_saved'] = 'TypeTag opgeslagen';
 $lang['typetag_suppr'] = 'TypeTag verwijderd';
Index: /extensions/typetags/language/pl_PL/plugin.lang.php
===================================================================
--- /extensions/typetags/language/pl_PL/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/pl_PL/plugin.lang.php	(revision 26665)
@@ -33,5 +33,5 @@
 $lang['typetags_associated'] = 'Powiązano TypeTag';
 $lang['typetag_already_exists'] = 'Ten TypeTag już istnieje';
-$lang['typetag_error'] = 'Należy uzupełnić wszystkie pola (nazwę i kolor)';
+$lang['You must fill all fields (name and color)'] = 'Należy uzupełnić wszystkie pola (nazwę i kolor)';
 $lang['typetag_saved'] = 'Zapisano TypeTag';
 $lang['typetag_suppr'] = 'Skasowano TypeTag';
Index: /extensions/typetags/language/pt_BR/plugin.lang.php
===================================================================
--- /extensions/typetags/language/pt_BR/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/pt_BR/plugin.lang.php	(revision 26665)
@@ -38,5 +38,5 @@
 $lang['Only on tags page'] = 'Somente na página etiquetas';
 $lang['typetag_already_exists'] = 'Este TipoEtiqueta já existe';
-$lang['typetag_error'] = 'Você deve preencher todos os campos (nome e cor)';
+$lang['You must fill all fields (name and color)'] = 'Você deve preencher todos os campos (nome e cor)';
 $lang['typetag_saved'] = 'TipoEtiqueta salvo';
 $lang['typetag_suppr'] = 'TipoEtiqueta eliminado';
Index: /extensions/typetags/language/pt_PT/plugin.lang.php
===================================================================
--- /extensions/typetags/language/pt_PT/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/pt_PT/plugin.lang.php	(revision 26665)
@@ -37,5 +37,5 @@
 $lang['Only on tags page'] = 'Apenas na página de etiquetas';
 $lang['typetag_already_exists'] = 'Já existe o tipo de etiqueta';
-$lang['typetag_error'] = 'Deve preencher todos os campos ( nome e cor)';
+$lang['You must fill all fields (name and color)'] = 'Deve preencher todos os campos ( nome e cor)';
 $lang['typetag_saved'] = 'Tipo de etiqueta salvo';
 $lang['typetag_suppr'] = 'Apagado o tipo de etiqueta';
Index: /extensions/typetags/language/ru_RU/plugin.lang.php
===================================================================
--- /extensions/typetags/language/ru_RU/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/ru_RU/plugin.lang.php	(revision 26665)
@@ -32,5 +32,5 @@
 $lang['New name'] = 'Новое название';
 $lang['typetag_already_exists'] = 'Этот тип тегов уже есть';
-$lang['typetag_error'] = 'Нужно заполнить все поля (название и цвет)';
+$lang['You must fill all fields (name and color)'] = 'Нужно заполнить все поля (название и цвет)';
 $lang['typetag_saved'] = 'Тип тегов сохранен';
 $lang['typetag_suppr'] = 'Тип тегов удален';
Index: /extensions/typetags/language/sk_SK/plugin.lang.php
===================================================================
--- /extensions/typetags/language/sk_SK/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/sk_SK/plugin.lang.php	(revision 26665)
@@ -19,5 +19,5 @@
 $lang['typetag_already_exists'] = 'Tento typ kľúčového slova už existuje';
 $lang['typetag_unknown'] = 'Unknown TypeTag';
-$lang['typetag_error'] = 'Môžete meniť všetky údaje (názov a farbu)';
+$lang['You must fill all fields (name and color)'] = 'Môžete meniť všetky údaje (názov a farbu)';
 $lang['All associations have been removed'] = 'All associations have been removed';
 $lang['typetags_associated'] = 'Kľúčové slovo spojené';
Index: /extensions/typetags/language/tr_TR/plugin.lang.php
===================================================================
--- /extensions/typetags/language/tr_TR/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/tr_TR/plugin.lang.php	(revision 26665)
@@ -37,5 +37,5 @@
 $lang['Only on tags page'] = 'Sadece bir etiket sayfası';
 $lang['typetag_already_exists'] = 'Bu TypeTag zaten var';
-$lang['typetag_error'] = 'Tüm alanları doldurmalısınız (isim ve renk)';
+$lang['You must fill all fields (name and color)'] = 'Tüm alanları doldurmalısınız (isim ve renk)';
 $lang['typetag_saved'] = 'TypeTag kaydedildi';
 $lang['typetag_suppr'] = 'TypeTag silindi';
Index: /extensions/typetags/language/uk_UA/plugin.lang.php
===================================================================
--- /extensions/typetags/language/uk_UA/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/uk_UA/plugin.lang.php	(revision 26665)
@@ -33,5 +33,5 @@
 $lang['typetags_associated'] = 'TypeTags, пов\'язані';
 $lang['typetag_already_exists'] = 'Це TypeTag вже існує';
-$lang['typetag_error'] = 'Ви повинні заповнити всі поля (ім\'я та колір)';
+$lang['You must fill all fields (name and color)'] = 'Ви повинні заповнити всі поля (ім\'я та колір)';
 $lang['typetag_saved'] = 'TypeTag збережено';
 $lang['typetag_suppr'] = 'TypeTag видалено';
Index: /extensions/typetags/language/zh_CN/plugin.lang.php
===================================================================
--- /extensions/typetags/language/zh_CN/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/zh_CN/plugin.lang.php	(revision 26665)
@@ -23,5 +23,5 @@
 $lang['Edit and associate TypeTags'] = '编辑和关联TypeTag（标签组）';
 $lang['Not associated'] = '尚未关联到标签组的标签';
-$lang['typetag_error'] = '请完整填写信息（名称与颜色）';
+$lang['You must fill all fields (name and color)'] = '请完整填写信息（名称与颜色）';
 $lang['typetags_associated'] = 'TypeTag（标签组）已关联';
 $lang['All associations have been removed'] = '所有关联已删除';
Index: /extensions/typetags/language/zh_TW/plugin.lang.php
===================================================================
--- /extensions/typetags/language/zh_TW/plugin.lang.php	(revision 26664)
+++ /extensions/typetags/language/zh_TW/plugin.lang.php	(revision 26665)
@@ -28,5 +28,5 @@
 $lang['Only on tags page'] = '僅在標籤頁';
 $lang['typetag_already_exists'] = '此TypeTag（標籤組）已存在';
-$lang['typetag_error'] = '請完整填寫信息（名稱與顏色）';
+$lang['You must fill all fields (name and color)'] = '請完整填寫信息（名稱與顏色）';
 $lang['typetag_saved'] = 'TypeTag（標籤組）已保存';
 $lang['typetag_suppr'] = 'TypeTag（標籤組）已刪除';
Index: /extensions/typetags/main.inc.php
===================================================================
--- /extensions/typetags/main.inc.php	(revision 26664)
+++ /extensions/typetags/main.inc.php	(revision 26665)
@@ -1,22 +1,26 @@
 <?php
 /*
-Plugin Name: TypeT@gs
+Plugin Name: Coloured Tags (TypeT@gs)
 Version: auto
 Description: Allow to manage color of tags, as you want...
-Plugin URI: http://piwigo.org/ext/extension_view.php?eid=166
-Author: Sakkhho & P@t & Mistic
+Plugin URI: auto
+Author: Mistic
 */
 
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
 
 global $prefixeTable, $conf;
 
-define('typetags_PATH' , PHPWG_PLUGINS_PATH . basename(dirname(__FILE__)) . '/');
-define('typetags_TABLE' , $prefixeTable . 'typetags');
-define('typetags_ADMIN', get_root_url().'admin.php?page=plugin-' . basename(dirname(__FILE__)));
+define('TYPETAGS_ID',      basename(dirname(__FILE__)));
+define('TYPETAGS_PATH' ,   PHPWG_PLUGINS_PATH . TYPETAGS_ID . '/');
+define('TYPETAGS_TABLE' ,  $prefixeTable . 'typetags');
+define('TYPETAGS_ADMIN',   get_root_url().'admin.php?page=plugin-' . TYPETAGS_ID);
+define('TYPETAGS_VERSION', 'auto');
 
 
-include_once(typetags_PATH . 'typetags.php');
 $conf['TypeTags'] = unserialize($conf['TypeTags']);
+
+
+include_once(TYPETAGS_PATH . 'include/events_public.inc.php');
 
 // tags on picture page
@@ -27,25 +31,19 @@
 
 // tags everywhere
-if ( $conf['TypeTags']['show_all'] and script_basename() != 'tags' )
+if ($conf['TypeTags']['show_all'] and script_basename() != 'tags')
 {
-  add_event_handler('render_tag_name', 'typetags_render', 0);
-}
-// tags on tags page
-else if (script_basename() == 'tags')
-{
-  add_event_handler('loc_begin_page_header', 'typetags_tags');
+  add_event_handler('render_tag_name', 'typetags_render', 0, 2);
 }
 
+// tags on tags page
+add_event_handler('loc_end_tags', 'typetags_tags');
 
-add_event_handler('get_admin_plugin_menu_links', 'typetags_admin_menu');
 
-function typetags_admin_menu($menu)
+if (defined('IN_ADMIN'))
 {
-  array_push($menu, array(
-    'NAME' => 'TypeT@gs',
-    'URL' => typetags_ADMIN,
-  ));
-  return $menu;
+  add_event_handler('get_admin_plugin_menu_links', 'typetags_admin_menu');
+
+  add_event_handler('loc_begin_admin_page', 'typetags_admin');
+
+  include_once(TYPETAGS_PATH . 'include/events_admin.inc.php');
 }
-
-?>
Index: /extensions/typetags/maintain.inc.php
===================================================================
--- /extensions/typetags/maintain.inc.php	(revision 26664)
+++ /extensions/typetags/maintain.inc.php	(revision 26665)
@@ -1,21 +1,31 @@
 <?php
-if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+defined('PHPWG_ROOT_PATH') or die('Hacking attempt!');
 
-function plugin_install()
+class typetags_maintain extends PluginMaintain
 {
-  global $prefixeTable;
+  private $installed = false;
 
-  $query = 'SHOW FULL COLUMNS FROM ' . TAGS_TABLE . ';';
-  $result = array_from_query($query, 'Field');
-  if (!in_array('id_typetags', $result))
+  private $default_conf = array(
+    'show_all'=>true,
+    );
+
+  function install($plugin_version, &$errors=array())
   {
-    pwg_query('ALTER TABLE '.TAGS_TABLE.' ADD COLUMN `id_typetags` SMALLINT(5);');
-  }
+    global $conf, $prefixeTable;
 
-  $result = pwg_query('SHOW TABLES LIKE "' . $prefixeTable .'typetags"');
-  if (!pwg_db_num_rows($result))
-  {
+    if (empty($conf['TypeTags']))
+    {
+      $conf['TypeTags'] = serialize($this->default_conf);
+      conf_update_param('TypeTags', $conf['TypeTags']);
+    }
+
+    $result = pwg_query('SHOW COLUMNS FROM `' . TAGS_TABLE . '` LIKE "id_typetags";');
+    if (!pwg_db_num_rows($result))
+    {
+      pwg_query('ALTER TABLE `' . TAGS_TABLE . '` ADD `id_typetags` SMALLINT(5) DEFAULT NULL;');
+    }
+
     $query = '
-CREATE TABLE `'. $prefixeTable .'typetags` (
+CREATE TABLE IF NOT EXISTS `' . $prefixeTable . 'typetags` (
   `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,
   `name` varchar(255) NOT NULL,
@@ -25,27 +35,28 @@
 ;';
     pwg_query($query);
+
+    $this->installed = true;
   }
-  
-  conf_update_param('TypeTags', serialize(array('show_all'=>true)));
-}
 
-function plugin_activate()
-{
-  global $conf;
-  
-  if (!isset($conf['TypeTags']))
+  function activate($plugin_version, &$errors=array())
   {
-    conf_update_param('TypeTags', serialize(array('show_all'=>true)));
+    if (!$this->installed)
+    {
+      $this->install($plugin_version, $errors);
+    }
+  }
+
+  function deactivate()
+  {
+  }
+
+  function uninstall()
+  {
+    global $prefixeTable;
+
+    conf_delete_param('TypeTags');
+
+    pwg_query('ALTER TABLE `' . TAGS_TABLE . '` DROP `id_typetags`');
+    pwg_query('DROP TABLE `' . $prefixeTable . 'typetags`;');
   }
 }
-
-function plugin_uninstall()
-{
-  global $prefixeTable;
-
-  pwg_query('ALTER TABLE '.TAGS_TABLE.' DROP COLUMN `id_typetags`');
-  pwg_query('DROP TABLE '. $prefixeTable .'typetags;');
-  pwg_query('DELETE FROM '.CONFIG_TABLE.' WHERE param = "TypeTags" LIMIT 1;');
-}
-
-?>
Index: /extensions/typetags/template/admin.tpl
===================================================================
--- /extensions/typetags/template/admin.tpl	(revision 26665)
+++ /extensions/typetags/template/admin.tpl	(revision 26665)
@@ -0,0 +1,78 @@
+{combine_script id="farbtastic" require="jquery" path=$TYPETAGS_PATH|cat:"template/farbtastic/farbtastic.js"}
+{combine_css path=$TYPETAGS_PATH|cat:"template/farbtastic/farbtastic.css"}
+{combine_css path=$TYPETAGS_PATH|cat:"template/style.css"}
+
+{footer_script}
+// init colorpicker
+jQuery('#colorpicker').farbtastic('#hexval');
+{/footer_script}
+
+<div class="titrePage">
+  <h2>Coloured Tags</h2>
+</div>
+
+<form action="{$F_ACTION}" method="post" name="form">
+  <fieldset>
+  {if isset($IN_EDIT)}
+    <legend>{'Edit color'|translate}</legend>
+    <div class="edit-container">
+      <div id="colorpicker"></div>
+      <p><b>{'Edit color'|translate} : <input type="text" readonly="readonly" size="18" style="background-color:{$typetag.OLD_COLOR};color:{$typetag.COLOR_TEXT};" value="{$typetag.OLD_NAME}"></b></p>
+      <p>&nbsp;</p>
+      <p>{'New name'|translate} : <input type="text" size="18" name="typetag_name" value="{$typetag.NAME}"></p>
+      <p>{'New color'|translate} : <input type="text" id="hexval" name="typetag_color" size="7" maxlength="7" value="{$typetag.COLOR}"></p>
+      <p>&nbsp;</p>
+      <p>
+        <input type="hidden" name="edited_typetag" value="{$edited_typetag}">
+        <input class="submit" type="submit" name="edittypetag" value="{'Save'|translate}">
+        <input class="submit" type="submit" name="cancel" value="{'Reset'|translate}">
+      </p>
+    </div>
+  {else}
+    <legend>{'Add a new color'|translate}</legend>
+    <div class="edit-container">
+      <div id="colorpicker"></div>
+      <p>&nbsp;</p>
+      <p>{'Name'|translate} : <input type="text" size="18" name="typetag_name" value="{if isset($typetag.NAME)}{$typetag.NAME}{/if}"></p>
+      <p>{'Color'|translate} : <input type="text" id="hexval" name="typetag_color" size="7" maxlength="7" value="{if isset($typetag.COLOR)}{$typetag.COLOR}{else}#444444{/if}"></p>
+      <p>&nbsp;</p>
+      <p>
+        <input class="submit" type="submit" name="addtypetag" value="{'Add'|translate}">
+      </p>
+    </div>
+  {/if}
+  </fieldset>
+</form>
+
+{if !empty($typetags)}
+<fieldset>
+  <legend>{'Manage colors'|translate}</legend>
+
+  <ul class="tagSelection typetagSelection">
+  {foreach from=$typetags item=typetag}
+    <li style="background-color:{$typetag.color};color:{$typetag.color_text};">
+      <span class="buttons">
+        <a href="{$typetag.u_edit}" title="{'edit'|translate}"><img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/edit_s.png" class="button" alt="{'edit'|translate}"></a>
+        <a href="{$typetag.u_delete}" title="{'delete'|translate}" onclick="return confirm('{'Are you sure?'|translate}');"><img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/delete.png" class="button" alt="{'delete'|translate}"></a>
+      </span>
+      {$typetag.name}
+    </li>
+  {/foreach}
+  </ul>
+
+  <p style="text-align:left;">{'Go to <a href="%s">Photos/Tags</a> to manage associations.'|translate:($ROOT_URL|cat:'admin.php?page=tags')}</p>
+</fieldset>
+{/if}
+
+
+<form action="{$F_ACTION}" method="post" name="form">
+  <fieldset>
+    <legend>{'Configuration'|translate}</legend>
+
+    <b>{'Display colored tags'|translate}</b>
+    <label><input type="radio" name="show_all" value="false" {if not $SHOW_ALL}checked="checked"{/if}> {'Only on tags page'|translate}</label>
+    <label><input type="radio" name="show_all" value="true" {if $SHOW_ALL}checked="checked"{/if}> {'Everywhere'|translate}</label>
+
+    <p><input class="submit" type="submit" name="save_config" value="{'Submit'|translate}"></p>
+  </fieldset>
+</form>
Index: /extensions/typetags/template/farbtastic/LICENSE.txt
===================================================================
--- /extensions/typetags/template/farbtastic/LICENSE.txt	(revision 26665)
+++ /extensions/typetags/template/farbtastic/LICENSE.txt	(revision 26665)
@@ -0,0 +1,341 @@
+
+        GNU GENERAL PUBLIC LICENSE
+           Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+          Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+        GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+          NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+         END OF TERMS AND CONDITIONS
+
+      How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    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; either version 2 of the License, or
+    (at your option) any later version.
+
+    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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: /extensions/typetags/template/farbtastic/farbtastic.css
===================================================================
--- /extensions/typetags/template/farbtastic/farbtastic.css	(revision 26665)
+++ /extensions/typetags/template/farbtastic/farbtastic.css	(revision 26665)
@@ -0,0 +1,33 @@
+.farbtastic {
+  position: relative;
+}
+.farbtastic * {
+  position: absolute;
+  cursor: crosshair;
+}
+.farbtastic, .farbtastic .wheel {
+  width: 195px;
+  height: 195px;
+}
+.farbtastic .color, .farbtastic .overlay {
+  top: 47px;
+  left: 47px;
+  width: 101px;
+  height: 101px;
+}
+.farbtastic .wheel {
+  background: url(wheel.png) no-repeat;
+  width: 195px;
+  height: 195px;
+}
+.farbtastic .overlay {
+  background: url(mask.png) no-repeat;
+}
+.farbtastic .marker {
+  width: 17px;
+  height: 17px;
+  margin: -8px 0 0 -8px;
+  overflow: hidden; 
+  background: url(marker.png) no-repeat;
+}
+
Index: /extensions/typetags/template/farbtastic/farbtastic.js
===================================================================
--- /extensions/typetags/template/farbtastic/farbtastic.js	(revision 26665)
+++ /extensions/typetags/template/farbtastic/farbtastic.js	(revision 26665)
@@ -0,0 +1,329 @@
+// $Id: farbtastic.js,v 1.2 2007/01/08 22:53:01 unconed Exp $
+// Farbtastic 1.2
+
+jQuery.fn.farbtastic = function (callback) {
+  $.farbtastic(this, callback);
+  return this;
+};
+
+jQuery.farbtastic = function (container, callback) {
+  var container = $(container).get(0);
+  return container.farbtastic || (container.farbtastic = new jQuery._farbtastic(container, callback));
+}
+
+jQuery._farbtastic = function (container, callback) {
+  // Store farbtastic object
+  var fb = this;
+
+  // Insert markup
+  $(container).html('<div class="farbtastic"><div class="color"></div><div class="wheel"></div><div class="overlay"></div><div class="h-marker marker"></div><div class="sl-marker marker"></div></div>');
+  var e = $('.farbtastic', container);
+  fb.wheel = $('.wheel', container).get(0);
+  // Dimensions
+  fb.radius = 84;
+  fb.square = 100;
+  fb.width = 194;
+
+  // Fix background PNGs in IE6
+  if (navigator.appVersion.match(/MSIE [0-6]\./)) {
+    $('*', e).each(function () {
+      if (this.currentStyle.backgroundImage != 'none') {
+        var image = this.currentStyle.backgroundImage;
+        image = this.currentStyle.backgroundImage.substring(5, image.length - 2);
+        $(this).css({
+          'backgroundImage': 'none',
+          'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+        });
+      }
+    });
+  }
+
+  /**
+   * Link to the given element(s) or callback.
+   */
+  fb.linkTo = function (callback) {
+    // Unbind previous nodes
+    if (typeof fb.callback == 'object') {
+      $(fb.callback).unbind('keyup', fb.updateValue);
+    }
+
+    // Reset color
+    fb.color = null;
+
+    // Bind callback or elements
+    if (typeof callback == 'function') {
+      fb.callback = callback;
+    }
+    else if (typeof callback == 'object' || typeof callback == 'string') {
+      fb.callback = $(callback);
+      fb.callback.bind('keyup', fb.updateValue);
+      if (fb.callback.get(0).value) {
+        fb.setColor(fb.callback.get(0).value);
+      }
+    }
+    return this;
+  }
+  fb.updateValue = function (event) {
+    if (this.value && this.value != fb.color) {
+      fb.setColor(this.value);
+    }
+  }
+
+  /**
+   * Change color with HTML syntax #123456
+   */
+  fb.setColor = function (color) {
+    var unpack = fb.unpack(color);
+    if (fb.color != color && unpack) {
+      fb.color = color;
+      fb.rgb = unpack;
+      fb.hsl = fb.RGBToHSL(fb.rgb);
+      fb.updateDisplay();
+    }
+    return this;
+  }
+
+  /**
+   * Change color with HSL triplet [0..1, 0..1, 0..1]
+   */
+  fb.setHSL = function (hsl) {
+    fb.hsl = hsl;
+    fb.rgb = fb.HSLToRGB(hsl);
+    fb.color = fb.pack(fb.rgb);
+    fb.updateDisplay();
+    return this;
+  }
+
+  /////////////////////////////////////////////////////
+
+  /**
+   * Retrieve the coordinates of the given event relative to the center
+   * of the widget.
+   */
+  fb.widgetCoords = function (event) {
+    var x, y;
+    var el = event.target || event.srcElement;
+    var reference = fb.wheel;
+
+    if (typeof event.offsetX != 'undefined') {
+      // Use offset coordinates and find common offsetParent
+      var pos = { x: event.offsetX, y: event.offsetY };
+
+      // Send the coordinates upwards through the offsetParent chain.
+      var e = el;
+      while (e) {
+        e.mouseX = pos.x;
+        e.mouseY = pos.y;
+        pos.x += e.offsetLeft;
+        pos.y += e.offsetTop;
+        e = e.offsetParent;
+      }
+
+      // Look for the coordinates starting from the wheel widget.
+      var e = reference;
+      var offset = { x: 0, y: 0 }
+      while (e) {
+        if (typeof e.mouseX != 'undefined') {
+          x = e.mouseX - offset.x;
+          y = e.mouseY - offset.y;
+          break;
+        }
+        offset.x += e.offsetLeft;
+        offset.y += e.offsetTop;
+        e = e.offsetParent;
+      }
+
+      // Reset stored coordinates
+      e = el;
+      while (e) {
+        e.mouseX = undefined;
+        e.mouseY = undefined;
+        e = e.offsetParent;
+      }
+    }
+    else {
+      // Use absolute coordinates
+      var pos = fb.absolutePosition(reference);
+      x = (event.pageX || 0*(event.clientX + $('html').get(0).scrollLeft)) - pos.x;
+      y = (event.pageY || 0*(event.clientY + $('html').get(0).scrollTop)) - pos.y;
+    }
+    // Subtract distance to middle
+    return { x: x - fb.width / 2, y: y - fb.width / 2 };
+  }
+
+  /**
+   * Mousedown handler
+   */
+  fb.mousedown = function (event) {
+    // Capture mouse
+    if (!document.dragging) {
+      $(document).bind('mousemove', fb.mousemove).bind('mouseup', fb.mouseup);
+      document.dragging = true;
+    }
+
+    // Check which area is being dragged
+    var pos = fb.widgetCoords(event);
+    fb.circleDrag = Math.max(Math.abs(pos.x), Math.abs(pos.y)) * 2 > fb.square;
+
+    // Process
+    fb.mousemove(event);
+    return false;
+  }
+
+  /**
+   * Mousemove handler
+   */
+  fb.mousemove = function (event) {
+    // Get coordinates relative to color picker center
+    var pos = fb.widgetCoords(event);
+
+    // Set new HSL parameters
+    if (fb.circleDrag) {
+      var hue = Math.atan2(pos.x, -pos.y) / 6.28;
+      if (hue < 0) hue += 1;
+      fb.setHSL([hue, fb.hsl[1], fb.hsl[2]]);
+    }
+    else {
+      var sat = Math.max(0, Math.min(1, -(pos.x / fb.square) + .5));
+      var lum = Math.max(0, Math.min(1, -(pos.y / fb.square) + .5));
+      fb.setHSL([fb.hsl[0], sat, lum]);
+    }
+    return false;
+  }
+
+  /**
+   * Mouseup handler
+   */
+  fb.mouseup = function () {
+    // Uncapture mouse
+    $(document).unbind('mousemove', fb.mousemove);
+    $(document).unbind('mouseup', fb.mouseup);
+    document.dragging = false;
+  }
+
+  /**
+   * Update the markers and styles
+   */
+  fb.updateDisplay = function () {
+    // Markers
+    var angle = fb.hsl[0] * 6.28;
+    $('.h-marker', e).css({
+      left: Math.round(Math.sin(angle) * fb.radius + fb.width / 2) + 'px',
+      top: Math.round(-Math.cos(angle) * fb.radius + fb.width / 2) + 'px'
+    });
+
+    $('.sl-marker', e).css({
+      left: Math.round(fb.square * (.5 - fb.hsl[1]) + fb.width / 2) + 'px',
+      top: Math.round(fb.square * (.5 - fb.hsl[2]) + fb.width / 2) + 'px'
+    });
+
+    // Saturation/Luminance gradient
+    $('.color', e).css('backgroundColor', fb.pack(fb.HSLToRGB([fb.hsl[0], 1, 0.5])));
+
+    // Linked elements or callback
+    if (typeof fb.callback == 'object') {
+      // Set background/foreground color
+      $(fb.callback).css({
+        backgroundColor: fb.color,
+        color: fb.hsl[2] > 0.5 ? '#000' : '#fff'
+      });
+
+      // Change linked value
+      $(fb.callback).each(function() {
+        if (this.value && this.value != fb.color) {
+          this.value = fb.color;
+        }
+      });
+    }
+    else if (typeof fb.callback == 'function') {
+      fb.callback.call(fb, fb.color);
+    }
+  }
+
+  /**
+   * Get absolute position of element
+   */
+  fb.absolutePosition = function (el) {
+    var r = { x: el.offsetLeft, y: el.offsetTop };
+    // Resolve relative to offsetParent
+    if (el.offsetParent) {
+      var tmp = fb.absolutePosition(el.offsetParent);
+      r.x += tmp.x;
+      r.y += tmp.y;
+    }
+    return r;
+  };
+
+  /* Various color utility functions */
+  fb.pack = function (rgb) {
+    var r = Math.round(rgb[0] * 255);
+    var g = Math.round(rgb[1] * 255);
+    var b = Math.round(rgb[2] * 255);
+    return '#' + (r < 16 ? '0' : '') + r.toString(16) +
+           (g < 16 ? '0' : '') + g.toString(16) +
+           (b < 16 ? '0' : '') + b.toString(16);
+  }
+
+  fb.unpack = function (color) {
+    if (color.length == 7) {
+      return [parseInt('0x' + color.substring(1, 3)) / 255,
+        parseInt('0x' + color.substring(3, 5)) / 255,
+        parseInt('0x' + color.substring(5, 7)) / 255];
+    }
+    else if (color.length == 4) {
+      return [parseInt('0x' + color.substring(1, 2)) / 15,
+        parseInt('0x' + color.substring(2, 3)) / 15,
+        parseInt('0x' + color.substring(3, 4)) / 15];
+    }
+  }
+
+  fb.HSLToRGB = function (hsl) {
+    var m1, m2, r, g, b;
+    var h = hsl[0], s = hsl[1], l = hsl[2];
+    m2 = (l <= 0.5) ? l * (s + 1) : l + s - l*s;
+    m1 = l * 2 - m2;
+    return [this.hueToRGB(m1, m2, h+0.33333),
+        this.hueToRGB(m1, m2, h),
+        this.hueToRGB(m1, m2, h-0.33333)];
+  }
+
+  fb.hueToRGB = function (m1, m2, h) {
+    h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
+    if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
+    if (h * 2 < 1) return m2;
+    if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
+    return m1;
+  }
+
+  fb.RGBToHSL = function (rgb) {
+    var min, max, delta, h, s, l;
+    var r = rgb[0], g = rgb[1], b = rgb[2];
+    min = Math.min(r, Math.min(g, b));
+    max = Math.max(r, Math.max(g, b));
+    delta = max - min;
+    l = (min + max) / 2;
+    s = 0;
+    if (l > 0 && l < 1) {
+      s = delta / (l < 0.5 ? (2 * l) : (2 - 2 * l));
+    }
+    h = 0;
+    if (delta > 0) {
+      if (max == r && max != g) h += (g - b) / delta;
+      if (max == g && max != b) h += (2 + (b - r) / delta);
+      if (max == b && max != r) h += (4 + (r - g) / delta);
+      h /= 6;
+    }
+    return [h, s, l];
+  }
+
+  // Install mousedown handler (the others are set on the document on-demand)
+  $('*', e).mousedown(fb.mousedown);
+
+    // Init color
+  fb.setColor('#000000');
+
+  // Set linked elements/callback
+  if (callback) {
+    fb.linkTo(callback);
+  }
+}
Index: /extensions/typetags/template/farbtastic/index.php
===================================================================
--- /extensions/typetags/template/farbtastic/index.php	(revision 26665)
+++ /extensions/typetags/template/farbtastic/index.php	(revision 26665)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/typetags/template/index.php
===================================================================
--- /extensions/typetags/template/index.php	(revision 26665)
+++ /extensions/typetags/template/index.php	(revision 26665)
@@ -0,0 +1,7 @@
+<?php
+$url = '../';
+header( 'Request-URI: '.$url );
+header( 'Content-Location: '.$url );
+header( 'Location: '.$url );
+exit();
+?>
Index: /extensions/typetags/template/style.css
===================================================================
--- /extensions/typetags/template/style.css	(revision 26665)
+++ /extensions/typetags/template/style.css	(revision 26665)
@@ -0,0 +1,29 @@
+#colorpicker-container {
+  float:right;
+  width:450px;
+  margin:auto;
+}
+#colorpicker-container .error {
+  color:#e00;
+  font-weight:bold;
+}
+#colorpicker-container .info {
+  color:#090;
+  font-style:italic;
+}
+
+#colorpicker {
+  float:left;
+  margin-right:15px;
+}
+
+.typetagSelection li {
+  padding:2px 3px 0px 3px;
+  border-radius:4px;
+}
+
+.typetagSelection .buttons {
+  float:right;
+  margin-left:-37px;
+  margin-top:2px;
+}
Index: /extensions/typetags/template/tags.tpl
===================================================================
--- /extensions/typetags/template/tags.tpl	(revision 26665)
+++ /extensions/typetags/template/tags.tpl	(revision 26665)
@@ -0,0 +1,142 @@
+{if isset($TYPETAGS_LIST)}
+{combine_script id="farbtastic" require="jquery" path=$TYPETAGS_PATH|cat:"template/farbtastic/farbtastic.js"}
+{combine_css id="farbastic" path=$TYPETAGS_PATH|cat:"template/farbtastic/farbtastic.css"}
+{combine_css path=$TYPETAGS_PATH|cat:"template/style.css"}
+
+{footer_script}
+(function($){
+  var $error = $('#colorpicker-container .error'),
+      $info = $('#colorpicker-container .info'),
+      $all_select = $('select[name^=tag_color]');
+
+  var typetags_names = [{strip}
+    {foreach from=$typetags item=typetag name=loop}
+      {if !$smarty.foreach.loop.first},{/if}
+      '{$typetag.name|escape:javascript}'
+    {/foreach}
+  {/strip}];
+
+  function checkColor(color) {
+    if (color[0] == '#') {
+      color = color.substr(1);
+    }
+
+    if (color.length == 3) {
+      color = color[0]+color[0]+color[1]+color[1]+color[2]+color[2];
+    }
+    else if (color.length != 6 || isNaN(parseInt(color, 16))) {
+      return false;
+    }
+
+    return '#'+color;
+  }
+
+  function duplicateStyle($from, $to) {
+    $to.attr('style', $from.attr('style'));
+  }
+
+
+  // init select and first option with an explicit style attribute
+  $all_select.find('option:first-child').attr('style', 'color:'+ $all_select.css('color') +';background:'+ $all_select.css('background-color') +';');
+
+  // change select color on change
+  $all_select.on('change', function() {
+    duplicateStyle($(this).find(':selected'), $(this));
+    $('input[name=mode]').prop('checked', false).filter('[value='+ $(this).data('mode') +']').prop('checked', true);
+  });
+
+  // init colorpicker
+  $('#colorpicker').farbtastic('#hexval');
+
+  // add color
+  $('input[name=addtypetag]').on('click', function(e) {
+    e.preventDefault();
+
+    $error.hide();
+    $info.hide();
+
+    var name = $('input[name=typetag_name]').val(),
+        color = $('input[name=typetag_color]').val(),
+        color_text = $('input[name=typetag_color]').css('color');
+
+    if (name == '' || color == '') {
+      $error.show().html('{'You must fill all fields (name and color)'|translate|escape:javascript}');
+    }
+    else if (typetags_names.indexOf(name) != -1) {
+      $error.show().html('{'This name is already used'|translate|escape:javascript}');
+    }
+    else if ( (color = checkColor(color)) === false) {
+      $error.show().html('{'Invalid color'|translate|escape:javascript}');
+    }
+    else {
+      typetags_names.push(name);
+
+      $('select[name^=tag_color]').append('<option value="'+ color +'|'+ name +'" style="color:'+ color_text +';background:'+ color +';">'+ name +' ('+ color +')</option>');
+
+      $('input[name=typetag_name]').val(''),
+      $('input[name=typetag_color]').val('#444444').trigger('keyup');
+      $info.show().html('{'Color added'|translate|escape:javascript}');
+    }
+  });
+}(jQuery));
+{/footer_script}
+
+
+<fieldset>
+  <legend>{'Set tags color'|translate}</legend>
+  <input type="hidden" name="edit_list" value="{$TYPETAGS_LIST}">
+
+  <fieldset id="colorpicker-container">
+    <legend>{'Add a new color'|translate}</legend>
+
+    <div id="colorpicker"></div>
+    <p>&nbsp;</p>
+    <p>{'Name'|translate} : <input type="text" size="18" name="typetag_name"></p>
+    <p>{'Color'|translate} : <input type="text" id="hexval" name="typetag_color" size="7" maxlength="7" value="#444444"></p>
+    <p>
+      <span class="error"></span> <span class="info"></span><br>
+      <input class="submit" type="submit" name="addtypetag" value="{'Add'|translate}">
+    </p>
+  </fieldset>
+
+  <p>
+    <label><input type="radio" name="mode" value="global"> {'Apply the same color to all tags'|translate}</label>
+
+    <select name="tag_color-all" style="" data-mode="global">
+      <option value="-1" style="" selected>{'None'|translate}</option>
+    {foreach from=$typetags item=typetag}
+      <option value="~~{$typetag.id}~~" style="color:{$typetag.color_text};background:{$typetag.color};">{$typetag.name} ({$typetag.color})</option>
+    {/foreach}
+    </select>
+  </p>
+
+  <p>
+    <label><input type="radio" name="mode" value="unit" checked> {'Set a different color for each tag'|translate}</label>
+
+    <table class="table2" style="margin:0;">
+      <tr class="throw">
+        <th>{'Tag'|translate}</th>
+        <th>{'New color'|translate}</th>
+      </tr>
+    {foreach from=$tags item=tag}
+      <tr>
+        <td>{$tag.name}</td>
+        <td>
+          <select name="tag_color-{$tag.id}" style="color:{$tag.color_text};background:{$tag.color};" data-mode="unit">
+            <option value="-1" style="">{'None'|translate}</option>
+          {foreach from=$typetags item=typetag}
+            <option value="~~{$typetag.id}~~" style="color:{$typetag.color_text};background:{$typetag.color};" {if $tag.id_typetags==$typetag.id}selected{/if}>{$typetag.name} ({$typetag.color})</option>
+          {/foreach}
+          </select>
+        </td>
+      </tr>
+    {/foreach}
+    </table>
+  </p>
+
+  <p>
+    <input type="submit" name="typetags_submit" value="{'Submit'|translate}">
+    <input type="submit" name="typetags_cancel" value="{'Cancel'|translate}">
+  </p>
+</fieldset>
+{/if}
Index: tensions/typetags/typetags.php
===================================================================
--- /extensions/typetags/typetags.php	(revision 26664)
+++ 	(revision )
@@ -1,146 +1,0 @@
-<?php
-
-/**
- * triggered by 'render_tag_name'
- */
-function typetags_render($tag)
-{
-  global $pwg_loaded_plugins, $page;
-  
-  if ( defined('IN_ADMIN') and in_array($page['page'], array('photo', 'batch_manager')) )
-  {
-    return $tag;
-  }
-  
-  $query = '
-SELECT color
-  FROM '.typetags_TABLE.' AS tt
-    INNER JOIN '.TAGS_TABLE.' AS t
-      ON t.id_typetags = tt.id
-  WHERE t.name = "'.pwg_db_real_escape_string($tag).'"
-;';;
-  list($color) = pwg_db_fetch_row(pwg_query($query));
-  
-  if ($color === null) 
-  {
-    return $tag;
-  }
-  elseif (isset($pwg_loaded_plugins['ExtendedDescription']))
-  {
-    return "[lang=all]<span style='color:".$color.";'>[/lang]".$tag."[lang=all]</span>[/lang]";
-  }
-  else
-  {
-    return "<span style='color:".$color.";'>".$tag."</span>";
-  }
-}
-
-/**
- * colors tags on picture page
- */
-/*function typetags_picture()
-{
-  global $template;
-    
-  $tags = $template->get_template_vars('related_tags');
-  if (empty($tags)) return;
-  
-  $query = '
-SELECT
-    t.id ,
-    tt.color
-  FROM '.typetags_TABLE.' AS tt
-    INNER JOIN '.TAGS_TABLE.' AS t
-      ON t.id_typetags = tt.id
-  WHERE t.id_typetags IS NOT NULL
-;';
-  $tagsColor = simple_hash_from_query($query, 'id', 'color');
-  if (empty($tagsColor)) return;
-
-  foreach ($tags as $key => $tag)
-  {
-    if (isset($tagsColor[ $tag['id'] ]))
-    {
-      $tags[$key]['URL'].= '" style="color:'.$tagsColor[ $tag['id'] ].';';
-    }
-  }
-  
-  $template->clear_assign('related_tags');
-  $template->assign('related_tags', $tags);
-}*/
-
-/**
- * colors tags on tags page
- */
-function typetags_tags()
-{
-  global $template;
-
-  $query = '
-SELECT
-    t.id ,
-    tt.color
-  FROM '.typetags_TABLE.' AS tt
-    INNER JOIN '.TAGS_TABLE.' AS t
-      ON t.id_typetags = tt.id
-  WHERE t.id_typetags IS NOT NULL
-;';
-  $tagsColor = simple_hash_from_query($query, 'id', 'color');
-  if (empty($tagsColor)) return;
-
-  $display = $template->get_template_vars('display_mode');
-  if ($display == 'letters')
-  {
-    $letters = $template->get_template_vars('letters');
-    if (empty($letters)) return;
-
-    foreach ($letters as $k1 => $letter)
-    {
-      foreach ($letter['tags'] as $k2 => $tag)
-      {
-        if (isset($tagsColor[ $tag['id'] ]))
-        {
-          $letters[$k1]['tags'][$k2]['URL'].= '" style="color:'.$tagsColor[ $tag['id'] ].';';
-        }
-      }
-    }
-    
-    $template->clear_assign('letters');
-    $template->assign('letters', $letters);
-  }
-  elseif ($display == 'cloud')
-  {
-    $tags = $template->get_template_vars('tags');
-    if (empty($tags)) return;
-
-    foreach ($tags as $key => $tag)
-    {
-      if (isset($tagsColor[ $tag['id'] ]))
-      {
-        $tags[$key]['URL'].= '" style="color:'.$tagsColor[ $tag['id'] ].';';
-      }
-    }
-    
-    $template->clear_assign('tags');
-    $template->assign('tags', $tags);
-  }
-  elseif ($display == 'cumulus')
-  {
-    $tags = $template->get_template_vars('tags');
-    if (empty($tags)) return;
-
-    foreach ($tags as $key => $tag)
-    {
-      if (isset($tagsColor[ $tag['id'] ]))
-      {
-        $tagsColor[ $tag['id'] ] = str_replace('#', '0x', $tagsColor[ $tag['id'] ]);
-        $tags[$key]['URL'].= '\' color=\''.$tagsColor[ $tag['id'] ].'\' hicolor=\''.$tagsColor[ $tag['id'] ];
-      }
-    }
-    
-    $template->clear_assign('tags');
-    $template->assign('tags', $tags);
-  }
-}
-
-?>
