Refactor tagging feature. Put all data in sql
authorclebeaupin
Tue, 20 Apr 2010 19:55:36 +0200
changeset 74 4801799cbf33
parent 73 008defa5256d
child 77 50db792f9151
Refactor tagging feature. Put all data in sql
web/thdProject/apps/frontend/config/routing.yml
web/thdProject/apps/frontend/lib/myUser.class.php
web/thdProject/apps/frontend/modules/editor/actions/addFilmSegmentAction.class.php
web/thdProject/apps/frontend/modules/editor/actions/components.class.php
web/thdProject/apps/frontend/modules/editor/actions/editVideoSegmentAction.class.php
web/thdProject/apps/frontend/modules/editor/actions/suggestVideoSegmentTagListAction.class.php
web/thdProject/apps/frontend/modules/editor/config/view.yml
web/thdProject/apps/frontend/modules/editor/templates/_player.php
web/thdProject/apps/frontend/modules/editor/templates/editVideoSegmentForm.php
web/thdProject/apps/frontend/modules/editor/templates/indexSuccess.php
web/thdProject/apps/frontend/modules/films/config/view.yml
web/thdProject/apps/frontend/modules/films/templates/_filmList.php
web/thdProject/apps/frontend/modules/homepage/templates/_lastTaggedList.php
web/thdProject/apps/frontend/modules/homepage/templates/_mostTaggedList.php
web/thdProject/apps/frontend/modules/partials/actions/components.class.php
web/thdProject/apps/frontend/modules/partials/templates/_filmItem.php
web/thdProject/apps/frontend/modules/reflex/templates/_suggestionFilmList.php
web/thdProject/apps/frontend/modules/test/actions/actions.class.php
web/thdProject/config/ProjectConfiguration.class.php.orig
web/thdProject/config/doctrine/schema.yml
web/thdProject/data/sql/schema.sql
web/thdProject/lib/core/ThdUtil.php
web/thdProject/lib/filter/doctrine/ThdSegmentTagFormFilter.class.php
web/thdProject/lib/filter/doctrine/ThdTagFormFilter.class.php
web/thdProject/lib/filter/doctrine/ThdUserFormFilter.class.php
web/thdProject/lib/filter/doctrine/base/BaseThdSegmentFormFilter.class.php
web/thdProject/lib/filter/doctrine/base/BaseThdSegmentTagFormFilter.class.php
web/thdProject/lib/filter/doctrine/base/BaseThdTagFormFilter.class.php
web/thdProject/lib/filter/doctrine/base/BaseThdUserFormFilter.class.php
web/thdProject/lib/form/doctrine/ThdSegmentTagForm.class.php
web/thdProject/lib/form/doctrine/ThdTagForm.class.php
web/thdProject/lib/form/doctrine/ThdUserForm.class.php
web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php
web/thdProject/lib/form/doctrine/base/BaseThdSegmentTagForm.class.php
web/thdProject/lib/form/doctrine/base/BaseThdTagForm.class.php
web/thdProject/lib/form/doctrine/base/BaseThdUserForm.class.php
web/thdProject/lib/model/doctrine/ThdFilm.class.php
web/thdProject/lib/model/doctrine/ThdSegment.class.php
web/thdProject/lib/model/doctrine/ThdSegmentTag.class.php
web/thdProject/lib/model/doctrine/ThdSegmentTagTable.class.php
web/thdProject/lib/model/doctrine/ThdTag.class.php
web/thdProject/lib/model/doctrine/ThdTagTable.class.php
web/thdProject/lib/model/doctrine/ThdUser.class.php
web/thdProject/lib/model/doctrine/ThdUserTable.class.php
web/thdProject/lib/model/doctrine/ThdVideo.class.php
web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php
web/thdProject/lib/model/doctrine/base/BaseThdSegmentTag.class.php
web/thdProject/lib/model/doctrine/base/BaseThdTag.class.php
web/thdProject/lib/model/doctrine/base/BaseThdUser.class.php
web/thdProject/web/css/jquery.autocomplete.css
web/thdProject/web/js/jquery.autocomplete.min.js
web/thdProject/web/js/segmentation/segments.js
web/thdProject/web/js/uc.editor.js
--- a/web/thdProject/apps/frontend/config/routing.yml	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/config/routing.yml	Tue Apr 20 19:55:36 2010 +0200
@@ -17,24 +17,21 @@
 
 ########  
 #SEGMENT EDITOR
-########  
-editor:
-  url:   /editeur/:ref/:film_slug
-  param: { module: editor, action: index }
-  requirements: {ref: \d+}
-  
-addFilmSegment:
-  url: /segments/:ref/:film_slug/ajout-segment
-  param: { module: editor, action: addFilmSegment}
-  requirements: {ref: \d+}
-  
+########
+
+suggestVideoTagList:
+  url:   /editeur/suggestion-tags
+  param: { module: editor, action: suggestVideoSegmentTagList }  
+
+editVideoSegment:
+  url:   /editeur/:film_slug
+  param: { module: editor, action: editVideoSegment }
+    
 segmentListJson:
-  url: /segments/:ref/:film_slug/list-segment
+  url: /editeur/:film_slug/list-segment
   param: { module: editor, action: segmentListJson}
   requirements: {ref: \d+}
   
-
-
   
 ########
 # SEARCH
--- a/web/thdProject/apps/frontend/lib/myUser.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/lib/myUser.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -11,6 +11,13 @@
     }
   }
 
+  public function getUid() {
+    if (!$this->isAuthenticated()) return false;
+
+    // FIXME
+    return "thd.fake";
+  }
+
   public function logout() {
     $this->clearCredentials();
     $this->setAuthenticated(false);
--- a/web/thdProject/apps/frontend/modules/editor/actions/addFilmSegmentAction.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,35 +0,0 @@
-<?php
-
-class addFilmSegmentAction extends sfAction
-{
-  public function execute($request)
-  {
-  	if ($request->getMethodName() != sfWebRequest::POST) return sfView::ERROR;
-  	
-  	$in=$request->getParameter('frmIn');
-	$out=$request->getParameter('frmOut');
-	$tag=addslashes($request->getParameter('usertag'));
-	$user=addslashes($request->getParameter('username'));
-	$refFilm=$request->getParameter('refFilm');
-	$film=$request->getParameter('film');
-	// Get file Path	
-	$this->path = sfConfig::get('app_storage_uploads');	
-	$this->format = sfConfig::get('app_storage_format');
-	$file = $this->path.$refFilm.$this->format;
-	
-	
-	
-	// Build content to fill
-	$line = array($in,$out,$tag,$user);
-	
-	// Build ldt
-	
-
-	// Create or Update the file
-	$fp = fopen($file, "a");
-	fputcsv($fp,$line);
-	fclose($fp);
-	
-	return sfView::SUCCESS;
-  }
-}
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/editor/actions/components.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/editor/actions/components.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -3,25 +3,14 @@
 class editorComponents extends sfComponents
 {
   public function executeLeftPanel() {
-
   }
-  public function executePlayer() {
-	$ref = $this->getRequestParameter('ref');
-  	$film_slug = $this->getRequestParameter('film_slug');
 
-  	// retrieve infos in database
-  	$query = Doctrine_Query::create()
-      ->from('ThdFilm F')
-      ->leftJoin('F.images I ')
-      ->leftJoin('F.videos V')
-      ->where("F.ref='{$ref}'");
+  public function executePlayer() {
+    // Retrieve film
+    $query = Doctrine_Query::create()
+      ->from('ThdFilm')
+      ->where("id='{$this->video->getFilmId()}'");
     $this->film = $query->execute()->getFirst();
-	  if (!$this->film) return sfView::NONE;
-
-	  // retrieve video infos
-	  $videos = $this->film->getVideos();
-	  $this->filmVideo = ($videos) ? $videos[0] : null;
-
   	return sfView::SUCCESS;
   }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/frontend/modules/editor/actions/editVideoSegmentAction.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,41 @@
+<?php
+
+class editVideoSegmentAction extends sfAction
+{
+  public function execute($request)
+  {
+    // Parse request
+    $film_slug = $request->getParameter('film_slug');
+
+    // Retrieve video
+    $query = Doctrine_Query::create()
+      ->from('ThdVideo vi')
+      ->leftJoin('vi.ThdFilm fi')
+      ->where("fi.slug_url='{$film_slug}'");
+    $this->video = $query->execute()->getFirst();
+    if (!$this->video) return $this->forward404();
+
+    if ($request->getMethodName() == sfWebRequest::POST) {
+      // Parse request
+      $start = (int) $request->getParameter('frmIn');
+      $end = (int) $request->getParameter('frmOut');
+      $dirtyTags = explode(',', $request->getParameter('tags'));
+
+      // Trim tags
+      $tags = Array();
+
+      foreach($dirtyTags as $tag) {
+        $tag = trim($tag);
+        if (!$tag) continue;
+        $tags[] = $tag;
+      }
+
+      // Add video segment
+      $user = sfContext::getInstance()->getUser();
+      $userUid = $user->getUid();
+      $this->video->addSegment($start, $end, $tags, $userUid);
+    }
+
+    return "Form";
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/frontend/modules/editor/actions/suggestVideoSegmentTagListAction.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,27 @@
+<?php
+
+class suggestVideoSegmentTagListAction extends sfAction
+{
+  public function execute($request)
+  {
+    // Parse request
+    $text = $request->getParameter('q');
+    $limit = (int) $request->getParameter('limit', 10);
+
+    // Retrieve video
+    $query = Doctrine_Query::create()
+      ->from('ThdTag')
+      ->where("uniqueid like '{$text}%'")
+      ->limit($limit);
+    $tags = Array();
+
+    foreach ($query->execute() as $item) {
+      $tags[] = $item->getTag();
+    }
+
+    $response = $this->getResponse();
+    $response->clearHttpHeaders();
+    $response->setContent(implode('\n', $tags));
+    return sfView::NONE;
+  }
+}
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/editor/config/view.yml	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/editor/config/view.yml	Tue Apr 20 19:55:36 2010 +0200
@@ -1,8 +1,8 @@
 all:
   
-  stylesheets:    [ /css/editor.css ]
+  stylesheets:    [ editor.css, jquery.autocomplete.css ]
 
-  javascripts:   [ /js/segmentation/segments.js, /js/segmentation/tagtool.js]
+  javascripts:   [ uc.editor.js, jquery.autocomplete.min.js, /js/segmentation/segments.js, /js/segmentation/tagtool.js]
   
   components: 
     sideBar: [ editor, leftPanel ]
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/editor/templates/_player.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/editor/templates/_player.php	Tue Apr 20 19:55:36 2010 +0200
@@ -2,14 +2,13 @@
     // Charge le player
     flowplayer("player", "<?php echo flash_path('flowplayer-3.1.2.swf') ?>",
                {
-                   clip: {url: "<?php echo film_video_path($filmVideo['file']); ?>",
+                   clip: {url: "<?php echo film_video_path($video['file']); ?>",
                           autoPlay: false,
                           autoBuffering: true,
                           onSeek: function() {
                               playerSeek();
                           }
                          },
-
                    plugins: {
 
                        content: {url: "<?php echo flash_path('flowplayer.content-3.1.0.swf') ?>",
@@ -84,7 +83,7 @@
                    tagTool.showTagInPage = false;
 
                }
-    </script>
+</script>
 <div id="editor">
 	<h1><?php
 
@@ -103,18 +102,14 @@
 			<button type="button" id="btMarkIn" class="submit" disabled onClick="segmentMarker.markIn()">Marquer le début</button>
 			<button type="button" id="btMarkOut" class="submit" disabled onClick="segmentMarker.markOut()">Marquer la fin</button>
 			<button type="button" id="btPlaySegment" class="submit" disabled onClick="segmentMarker.playSegment()">Lire la séquence</button>
-		 
-		 <form action="<?php echo url_for("@addFilmSegment?ref={$film->getRef()}&film_slug={$film->getSlugUrl()}");?>" method="post" id="segmentForm" class="ajax" style="display: none;">
+
+		 <form action="<?php echo url_for("@editVideoSegment?film_slug={$film->getSlugUrl()}");?>" method="post" id="segment-add" style="display:none">
 		    <h3>Enregistrer votre segment</h3>
 		    <p>Vous aller créer un segment, entre <span id="mkin">0</span> secondes et <span id="mkout">0</span> secondes.</p>
 		    <span style="text-align: center;">
-		      Votre tag : <input type="text" id="usertag" name="usertag" />&nbsp;
-		      Nom d'utilisateur : <input type="text" id="username" name="username" value="visiteur" />
-		      <input type="hidden" name="xtid" value="<?php echo extract.id;?>" />
+		      <label>Vos tags</label>&nbsp;:&nbsp;<input type="text" name="tags" />
 		      <input type="hidden" name="frmIn" id="frmIn" value="0" />
 		      <input type="hidden" name="frmOut" id="frmOut" value="0" />
-		      <input type="hidden" name="refFilm" id="refFilm" value="<?php echo $film->getRef()."_".$film->getSlugUrl(); ?>" />
-		      <input type="hidden" name="Film" id="Film" value="<?php echo $film->getTitle(); ?>" />
 		      <input type="submit" value="Enregistrer" class="submit" />
 		    </span>
 		 </form>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/apps/frontend/modules/editor/templates/editVideoSegmentForm.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,3 @@
+<div id="content">
+  <?php include_component("editor", "player", Array('video' => $video)) ?>
+</div>
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/editor/templates/indexSuccess.php	Tue Apr 20 18:38:06 2010 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,3 +0,0 @@
-<div id="content">
-	<?php include_component( "editor", "player" ) ?>	
-</div>
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/films/config/view.yml	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/films/config/view.yml	Tue Apr 20 19:55:36 2010 +0200
@@ -1,7 +1,5 @@
 all:
-  stylesheets:    [ /css/flashplayer.css ]
-
-  javascripts:   [ /js/flowplayer/flowplayer-3.1.0.min.js, /js/flowplayer/uc.flowplayer.config.js]
+  javascripts:   [ jquery.autocomplete.min.js ]
   
   components: 
     sideBar: [ homepage, sideBar ]
--- a/web/thdProject/apps/frontend/modules/films/templates/_filmList.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/films/templates/_filmList.php	Tue Apr 20 19:55:36 2010 +0200
@@ -2,12 +2,9 @@
   <?php echo thd_render_pager_navigation($pageIndex, $pageCount, $itemCount, $routeUri); ?>
   <ul class="film-list">
   <?php
-  foreach($films as $item):
-    $tagFilmUri = url_for('@editor?ref='.$item->getRef().'&film_slug='.$item->getSlugUrl());
-  ?>
+  foreach($films as $item): ?>
     <li>
-      <?php include_component('partials', 'filmItem', Array('film' => $item, 'actionUri' => $tagFilmUri)); ?>
-      <div class="tag-action"><a href="<?php echo $tagFilmUri ?>" class="link-button">Tagger le film</a></div>
+      <?php include_component('partials', 'filmItem', Array('film' => $item)); ?>
     </li>
   <?php endforeach; ?>
   </ul>
--- a/web/thdProject/apps/frontend/modules/homepage/templates/_lastTaggedList.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/homepage/templates/_lastTaggedList.php	Tue Apr 20 19:55:36 2010 +0200
@@ -2,12 +2,9 @@
 	<h3 class="head">Les derniers films taggés</h3>
 	<ul>
 	<?php
-	foreach($lastTaggedFilms as $item):
-		$tagFilmUri = url_for('@editor?ref='.$item->getRef().'&film_slug='.$item->getSlugUrl());
-	?>
+	foreach($lastTaggedFilms as $item):	?>
 	<li>
-		<?php include_component('partials', 'filmItem', Array('film' => $item, 'actionUri' => $tagFilmUri)); ?>
-		<div class="tag-action"><a href="<?php echo $tagFilmUri; ?>" class="link-button">Tagger le film</a></div>
+		<?php include_component('partials', 'filmItem', Array('film' => $item)); ?>
 	</li>
 	<?php endforeach; ?>
 	</ul>
--- a/web/thdProject/apps/frontend/modules/homepage/templates/_mostTaggedList.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/homepage/templates/_mostTaggedList.php	Tue Apr 20 19:55:36 2010 +0200
@@ -2,12 +2,9 @@
 	<h3 class="head">Les films les plus taggés</h3>
 	<ul>
 	<?php
-	foreach($mostTaggedFilms as $item):
-		$tagFilmUri = url_for('@editor?ref='.$item->getRef().'&film_slug='.$item->getSlugUrl());
-	?>
+	foreach($mostTaggedFilms as $item):	?>
 	<li>
-		<?php include_component('partials', 'filmItem', Array('film' => $item, 'actionUri' => $tagFilmUri)); ?>
-		<div class="tag-action"><a href="<?php echo $tagFilmUri ?>" class="link-button">Tagger le film</a></div>
+		<?php include_component('partials', 'filmItem', Array('film' => $item)); ?>
 	</li>
 	<?php endforeach; ?>
 	</ul>
--- a/web/thdProject/apps/frontend/modules/partials/actions/components.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/partials/actions/components.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -29,15 +29,11 @@
       $image = $images[0];
       $this->imageFilename = $image->getFile();
     }
-    
-    
-    // Get Tags
-    $tags = $this->film->getTagsArray();
-    $this->tagList = null;
-    if ($tags) {
-    	$this->tagList = $tags;
-    }
-    
+
+
+    // Get Tag cloud
+    // Only display 10 tags
+    $this->tagCloud = ThdUtil::getTagCloud($this->film->getTagCloud(), 10);
 
     // Get video filename
     $videos = $this->film->getVideos();
@@ -47,5 +43,9 @@
       $video = $videos[0];
       $this->videoFilename = $video->getFile();
     }
+
+    // Create tag action
+    $controller = $this->getController();
+    $this->actionUri = $controller->genUrl('@editVideoSegment?film_slug='.$this->film->getSlugUrl());
   }
 }
--- a/web/thdProject/apps/frontend/modules/partials/templates/_filmItem.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/partials/templates/_filmItem.php	Tue Apr 20 19:55:36 2010 +0200
@@ -1,23 +1,21 @@
 <div id="player-<?php echo $film->getRef(); ?>" class="player-item" style="background:transparent url('<?php echo film_image_path($imageFilename); ?>') no-repeat;" href="<?php echo film_video_path($videoFilename);?>">
   <div class="infos">
-      <a href="<?php echo $actionUri; ?>" class="title" target="_top"><?php echo $film->getTitle(); ?></a> <span class="film-infos">De <?php echo thd_render_flat_list($film->getDirectorsArray(), 'name'); ?></span>
-    </div>
-    <img src="<?php echo image_path('buttons/btn_play.png'); ?>"/ id="play"></a>
-     <div class="tags">
+    <a href="<?php echo $actionUri; ?>" class="title" target="_top"><?php echo $film->getTitle(); ?></a> <span class="film-infos">De <?php echo thd_render_flat_list($film->getDirectorsArray(), 'name'); ?></span>
+  </div>
+  <img src="<?php echo image_path('buttons/btn_play.png'); ?>"/ id="play"></a>
+  <?php if ($tagCloud): ?>
+  <div class="tags">
     <ul class="item-list tag-list">
-    <li><span class="head">
-      <i>Tags liés au film :</i>
-    </span></li>
-    <?php 
-	    foreach($film->getTagsArray() as $item) {
-	    	if($item){ 
-	    	$tag = $item;
-	    	echo '<li class="tag-score-'.$tag['score'].'"><a href="">'.$tag.'</a>
-	      </li>';
-	        
-	    }
-    } ?>
-     
+      <li><span class="head">
+        <i>Tags liés au film :</i>
+      </span></li>
+    <?php
+	    foreach($tagCloud as $tag): ?>
+	    <li class="tag-score-<?php echo $tag['count']; ?>"><a href=""><?php echo $tag['tag']; ?></a>
+	    </li>
+    <?php endforeach; ?>
     </ul>
-    </div>
-</div>
\ No newline at end of file
+  </div>
+  <?php endif; ?>
+</div>
+<div class="tag-action"><a href="<?php echo $actionUri ?>" class="link-button">Tagger le film</a></div>
\ No newline at end of file
--- a/web/thdProject/apps/frontend/modules/reflex/templates/_suggestionFilmList.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/reflex/templates/_suggestionFilmList.php	Tue Apr 20 19:55:36 2010 +0200
@@ -2,14 +2,11 @@
 <div id="suggestionFilm-list">
 	<h3 class="head">Les films suivants</h3>
 	<ul>
-	
+
 	<?php
-	foreach($mostTaggedFilms as $item):
-		$tagFilmUri = url_for('@editor?ref='.$item->getRef().'&film_slug='.$item->getSlugUrl());
-	?>
+	foreach($mostTaggedFilms as $item):	?>
 	<li>
 		<?php include_component('partials', 'filmItem', Array('film' => $item, 'actionUri' => $tagFilmUri)); ?>
-		<div class="tag-action"><a href="<?php echo $tagFilmUri ?>" class="link-button">Tagger le film</a></div>
 	</li>
 	<?php endforeach; ?>
 	</ul>
--- a/web/thdProject/apps/frontend/modules/test/actions/actions.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/apps/frontend/modules/test/actions/actions.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -81,4 +81,14 @@
     }
     return sfView::NONE;
   }
+
+  public function executeSegment(sfWebRequest $request) {
+    $query = Doctrine_Query::create()
+      ->from('ThdSegment')
+      ->where("id=1");
+    $segment = $query->execute()->getFirst();
+    var_dump($segment->getThdTags());
+    die();
+    return sfView::NONE;
+  }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/config/ProjectConfiguration.class.php.orig	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,23 @@
+<?php
+// Virtualbox dev
+//require_once '/opt/symfony-1.2.8/lib/autoload/sfCoreAutoload.class.php';
+// Gothbook dev
+putenv("PATH=/opt/local/bin:/usr/bin:/bin:/usr/sbin:/sbin");
+
+
+
+define('SF_ENVIRONMENT', 'dev');
+require_once '/opt/symfony/1.2.9/lib/autoload/sfCoreAutoload.class.php';
+sfCoreAutoload::register();
+
+class ProjectConfiguration extends sfProjectConfiguration
+{
+  public function setup()
+	{
+	  	$this->enableAllPluginsExcept(array('sfPropelPlugin', 'sfCompat10Plugin'));
+	}
+
+  public function configureDoctrineConnection(Doctrine_Connection $conn) {
+    $conn->addRecordListener(new ThdDoctrineListener());
+  }
+}
--- a/web/thdProject/config/doctrine/schema.yml	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/config/doctrine/schema.yml	Tue Apr 20 19:55:36 2010 +0200
@@ -38,7 +38,18 @@
   indexes:
     uniqueidindex:
       fields: [uniqueid]
-      type: unique    
+      type: unique
+ThdUser:
+  tableName: thd_user
+  columns:
+    id:
+      type: integer(4)
+      unsigned: 1
+      primary: true
+      autoincrement: true
+    uniqueid:
+      type: string(255)
+      notnull: true  
 ThdImage:
   tableName: thd_image
   columns:
@@ -64,18 +75,6 @@
       unsigned: 1
       primary: true
       autoincrement: true
-    title:
-      type: string(255)
-      notnull: false
-    tags:
-      type: string(1024)
-      notnull: false
-    description:
-      type: string(2147483647)
-      notnull: false
-    video_ref:
-      type: integer(4)
-      notnull: true
     start:
       type: float(2147483647)
       notnull: true
@@ -84,6 +83,7 @@
       notnull: true
     user_id:
       type: integer(4)
+      unsigned: 1
       notnull: true
     creation_date:
       type: timestamp(25)
@@ -101,6 +101,44 @@
       type: unique
   relations:
     ThdVideo: { onDelete: CASCADE, local: video_id, foreign: id, foreignAlias: segments }
+    ThdUser: { onDelete: CASCADE, local: user_id, foreign: id, foreignAlias: segments }
+ThdSegmentTag:
+  tableName: thd_segment_tag
+  columns:
+    id:
+      type: integer(4)
+      unsigned: 1
+      primary: true
+      autoincrement: true
+    tag_id:
+      type: integer(4)
+      unsigned: 1
+      notnull: true
+    segment_id:
+      type: integer(4)
+      unsigned: 1
+      notnull: true
+  relations:
+    ThdSegment: { onDelete: CASCADE, local: segment_id, foreign: id }
+    ThdTag: { onDelete: CASCADE, local: tag_id, foreign: id }
+ThdTag:
+  tableName: thd_tag
+  columns:
+    id:
+      type: integer(4)
+      unsigned: 1
+      primary: true
+      autoincrement: true
+    tag:
+      type: string(255)
+      notnull: false
+    uniqueid:
+      type: string(255)
+      notnull: true
+  indexes:
+    uniqueidindex:
+      fields: [uniqueid]
+      type: unique
 ThdVideo:
   tableName: thd_video
   columns:
--- a/web/thdProject/data/sql/schema.sql	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/data/sql/schema.sql	Tue Apr 20 19:55:36 2010 +0200
@@ -1,7 +1,13 @@
 CREATE TABLE thd_film (id INT UNSIGNED AUTO_INCREMENT, ref VARCHAR(255) NOT NULL, title VARCHAR(255) NOT NULL, pitch TEXT NOT NULL, duration INT NOT NULL, directors TEXT NOT NULL, actors TEXT NOT NULL, slug_url VARCHAR(255) NOT NULL, original_title VARCHAR(255), production_countries TEXT NOT NULL, production_year BIGINT, uniqueid VARCHAR(36) NOT NULL, UNIQUE INDEX uniqueidindex_idx (uniqueid), PRIMARY KEY(id)) ENGINE = INNODB;
+CREATE TABLE thd_user (id INT UNSIGNED AUTO_INCREMENT, uniqueid VARCHAR(255) NOT NULL, PRIMARY KEY(id)) ENGINE = INNODB;
+CREATE TABLE thd_segment_tag (id INT UNSIGNED AUTO_INCREMENT, tag_id INT UNSIGNED NOT NULL, segment_id INT UNSIGNED NOT NULL, INDEX segment_id_idx (segment_id), INDEX tag_id_idx (tag_id), PRIMARY KEY(id)) ENGINE = INNODB;
 CREATE TABLE thd_image (id INT UNSIGNED AUTO_INCREMENT, file VARCHAR(255) NOT NULL, film_id INT UNSIGNED NOT NULL, INDEX film_id_idx (film_id), PRIMARY KEY(id)) ENGINE = INNODB;
 CREATE TABLE thd_video (id INT UNSIGNED AUTO_INCREMENT, file VARCHAR(255) NOT NULL, title VARCHAR(255), film_id INT UNSIGNED NOT NULL, INDEX film_id_idx (film_id), PRIMARY KEY(id)) ENGINE = INNODB;
-CREATE TABLE thd_segment (id INT UNSIGNED AUTO_INCREMENT, title VARCHAR(255), tags TEXT, description TEXT, video_ref INT NOT NULL, start DOUBLE NOT NULL, end DOUBLE NOT NULL, user_id INT NOT NULL, creation_date DATETIME NOT NULL, uniqueid VARCHAR(36) NOT NULL, video_id INT UNSIGNED NOT NULL, UNIQUE INDEX uniqueidindex_idx (uniqueid), INDEX video_id_idx (video_id), PRIMARY KEY(id)) ENGINE = INNODB;
+CREATE TABLE thd_tag (id INT UNSIGNED AUTO_INCREMENT, tag VARCHAR(255), uniqueid VARCHAR(255) NOT NULL, UNIQUE INDEX uniqueidindex_idx (uniqueid), PRIMARY KEY(id)) ENGINE = INNODB;
+CREATE TABLE thd_segment (id INT UNSIGNED AUTO_INCREMENT, start DOUBLE NOT NULL, end DOUBLE NOT NULL, user_id INT UNSIGNED NOT NULL, creation_date DATETIME NOT NULL, uniqueid VARCHAR(36) NOT NULL, video_id INT UNSIGNED NOT NULL, UNIQUE INDEX uniqueidindex_idx (uniqueid), INDEX video_id_idx (video_id), INDEX user_id_idx (user_id), PRIMARY KEY(id)) ENGINE = INNODB;
+ALTER TABLE thd_segment_tag ADD FOREIGN KEY (tag_id) REFERENCES thd_tag(id) ON DELETE CASCADE;
+ALTER TABLE thd_segment_tag ADD FOREIGN KEY (segment_id) REFERENCES thd_segment(id) ON DELETE CASCADE;
 ALTER TABLE thd_image ADD FOREIGN KEY (film_id) REFERENCES thd_film(id) ON DELETE CASCADE;
 ALTER TABLE thd_video ADD FOREIGN KEY (film_id) REFERENCES thd_film(id) ON DELETE CASCADE;
 ALTER TABLE thd_segment ADD FOREIGN KEY (video_id) REFERENCES thd_video(id) ON DELETE CASCADE;
+ALTER TABLE thd_segment ADD FOREIGN KEY (user_id) REFERENCES thd_user(id) ON DELETE CASCADE;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/core/ThdUtil.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,55 @@
+<?php
+
+/**
+ *
+ * @author cquintin
+ *
+ */
+class ThdUtil extends sfToolKit
+{
+    // Normalized chars
+    private static $normalizedChars = Array(
+      'à' => 'a', 'â' => 'a', 'ä' => 'a',
+      'é' => 'e', 'è' => 'e', 'ë' => 'e', 'ê' => 'e',
+      'ï' => 'i', 'î' => 'i',
+      'ö' => 'o', 'ô' => 'o',
+      'ü' => 'u', 'û' => 'u',
+      'ç' => 'c');
+
+    static public function normalizeText($text)
+    {
+      // replace all non letters width normalized characters
+      $text = mb_strtolower(trim($text), 'UTF-8');
+      $text = strtr($text, self::$normalizedChars);
+      $text = preg_replace('/\W+/', '-', $text);
+      $text = trim($text, '-');
+      return $text;
+    }
+
+    static public function cmpTagCloud($a, $b) {
+      if ($a['count'] == $b['count']) {
+        return 0;
+      }
+
+      return ($a['count'] > $b['count']) ? -1 : 1;
+    }
+
+    static public function getTagCloud($tagCloud, $nbItems, $maxScore=5) {
+      $newTagCloud = $tagCloud;
+      uasort($newTagCloud , 'ThdUtil::cmpTagCloud');
+      $newTagCloud = array_slice($newTagCloud, 0, $nbItems);
+
+      // Apply maxScore ratio
+      if ($newTagCloud) {
+        // Get first tag. Assume it has a score of 5
+        $firstTagCount = $newTagCloud[0]['count'];
+        $scoreRatio = $maxScore/$firstTagCount;
+
+        foreach ($newTagCloud as $index=>$item) {
+          $newTagCloud[$index]['count'] = (int) ceil($item['count']*$scoreRatio);
+        }
+      }
+
+      return $newTagCloud;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/ThdSegmentTagFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdSegmentTag filter form.
+ *
+ * @package    filters
+ * @subpackage ThdSegmentTag *
+ * @version    SVN: $Id: sfDoctrineFormFilterTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class ThdSegmentTagFormFilter extends BaseThdSegmentTagFormFilter
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/ThdTagFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdTag filter form.
+ *
+ * @package    filters
+ * @subpackage ThdTag *
+ * @version    SVN: $Id: sfDoctrineFormFilterTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class ThdTagFormFilter extends BaseThdTagFormFilter
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/ThdUserFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdUser filter form.
+ *
+ * @package    filters
+ * @subpackage ThdUser *
+ * @version    SVN: $Id: sfDoctrineFormFilterTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class ThdUserFormFilter extends BaseThdUserFormFilter
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- a/web/thdProject/lib/filter/doctrine/base/BaseThdSegmentFormFilter.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/filter/doctrine/base/BaseThdSegmentFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -14,26 +14,18 @@
   public function setup()
   {
     $this->setWidgets(array(
-      'title'         => new sfWidgetFormFilterInput(),
-      'tags'          => new sfWidgetFormFilterInput(),
-      'description'   => new sfWidgetFormFilterInput(),
-      'video_ref'     => new sfWidgetFormFilterInput(),
       'start'         => new sfWidgetFormFilterInput(),
       'end'           => new sfWidgetFormFilterInput(),
-      'user_id'       => new sfWidgetFormFilterInput(),
+      'user_id'       => new sfWidgetFormDoctrineChoice(array('model' => 'ThdUser', 'add_empty' => true)),
       'creation_date' => new sfWidgetFormFilterDate(array('from_date' => new sfWidgetFormDate(), 'to_date' => new sfWidgetFormDate(), 'with_empty' => false)),
       'uniqueid'      => new sfWidgetFormFilterInput(),
       'video_id'      => new sfWidgetFormDoctrineChoice(array('model' => 'ThdVideo', 'add_empty' => true)),
     ));
 
     $this->setValidators(array(
-      'title'         => new sfValidatorPass(array('required' => false)),
-      'tags'          => new sfValidatorPass(array('required' => false)),
-      'description'   => new sfValidatorPass(array('required' => false)),
-      'video_ref'     => new sfValidatorSchemaFilter('text', new sfValidatorInteger(array('required' => false))),
       'start'         => new sfValidatorSchemaFilter('text', new sfValidatorNumber(array('required' => false))),
       'end'           => new sfValidatorSchemaFilter('text', new sfValidatorNumber(array('required' => false))),
-      'user_id'       => new sfValidatorSchemaFilter('text', new sfValidatorInteger(array('required' => false))),
+      'user_id'       => new sfValidatorDoctrineChoice(array('required' => false, 'model' => 'ThdUser', 'column' => 'id')),
       'creation_date' => new sfValidatorDateRange(array('required' => false, 'from_date' => new sfValidatorDate(array('required' => false)), 'to_date' => new sfValidatorDate(array('required' => false)))),
       'uniqueid'      => new sfValidatorPass(array('required' => false)),
       'video_id'      => new sfValidatorDoctrineChoice(array('required' => false, 'model' => 'ThdVideo', 'column' => 'id')),
@@ -55,13 +47,9 @@
   {
     return array(
       'id'            => 'Number',
-      'title'         => 'Text',
-      'tags'          => 'Text',
-      'description'   => 'Text',
-      'video_ref'     => 'Number',
       'start'         => 'Number',
       'end'           => 'Number',
-      'user_id'       => 'Number',
+      'user_id'       => 'ForeignKey',
       'creation_date' => 'Date',
       'uniqueid'      => 'Text',
       'video_id'      => 'ForeignKey',
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/base/BaseThdSegmentTagFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,46 @@
+<?php
+
+require_once(sfConfig::get('sf_lib_dir').'/filter/doctrine/BaseFormFilterDoctrine.class.php');
+
+/**
+ * ThdSegmentTag filter form base class.
+ *
+ * @package    filters
+ * @subpackage ThdSegmentTag *
+ * @version    SVN: $Id: sfDoctrineFormFilterGeneratedTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class BaseThdSegmentTagFormFilter extends BaseFormFilterDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'tag_id'     => new sfWidgetFormDoctrineChoice(array('model' => 'ThdTag', 'add_empty' => true)),
+      'segment_id' => new sfWidgetFormDoctrineChoice(array('model' => 'ThdSegment', 'add_empty' => true)),
+    ));
+
+    $this->setValidators(array(
+      'tag_id'     => new sfValidatorDoctrineChoice(array('required' => false, 'model' => 'ThdTag', 'column' => 'id')),
+      'segment_id' => new sfValidatorDoctrineChoice(array('required' => false, 'model' => 'ThdSegment', 'column' => 'id')),
+    ));
+
+    $this->widgetSchema->setNameFormat('thd_segment_tag_filters[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdSegmentTag';
+  }
+
+  public function getFields()
+  {
+    return array(
+      'id'         => 'Number',
+      'tag_id'     => 'ForeignKey',
+      'segment_id' => 'ForeignKey',
+    );
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/base/BaseThdTagFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,46 @@
+<?php
+
+require_once(sfConfig::get('sf_lib_dir').'/filter/doctrine/BaseFormFilterDoctrine.class.php');
+
+/**
+ * ThdTag filter form base class.
+ *
+ * @package    filters
+ * @subpackage ThdTag *
+ * @version    SVN: $Id: sfDoctrineFormFilterGeneratedTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class BaseThdTagFormFilter extends BaseFormFilterDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'tag'      => new sfWidgetFormFilterInput(),
+      'uniqueid' => new sfWidgetFormFilterInput(),
+    ));
+
+    $this->setValidators(array(
+      'tag'      => new sfValidatorPass(array('required' => false)),
+      'uniqueid' => new sfValidatorPass(array('required' => false)),
+    ));
+
+    $this->widgetSchema->setNameFormat('thd_tag_filters[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdTag';
+  }
+
+  public function getFields()
+  {
+    return array(
+      'id'       => 'Number',
+      'tag'      => 'Text',
+      'uniqueid' => 'Text',
+    );
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/filter/doctrine/base/BaseThdUserFormFilter.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,43 @@
+<?php
+
+require_once(sfConfig::get('sf_lib_dir').'/filter/doctrine/BaseFormFilterDoctrine.class.php');
+
+/**
+ * ThdUser filter form base class.
+ *
+ * @package    filters
+ * @subpackage ThdUser *
+ * @version    SVN: $Id: sfDoctrineFormFilterGeneratedTemplate.php 11675 2008-09-19 15:21:38Z fabien $
+ */
+class BaseThdUserFormFilter extends BaseFormFilterDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'uniqueid' => new sfWidgetFormFilterInput(),
+    ));
+
+    $this->setValidators(array(
+      'uniqueid' => new sfValidatorPass(array('required' => false)),
+    ));
+
+    $this->widgetSchema->setNameFormat('thd_user_filters[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdUser';
+  }
+
+  public function getFields()
+  {
+    return array(
+      'id'       => 'Number',
+      'uniqueid' => 'Text',
+    );
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/ThdSegmentTagForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdSegmentTag form.
+ *
+ * @package    form
+ * @subpackage ThdSegmentTag
+ * @version    SVN: $Id: sfDoctrineFormTemplate.php 6174 2007-11-27 06:22:40Z fabien $
+ */
+class ThdSegmentTagForm extends BaseThdSegmentTagForm
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/ThdTagForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdTag form.
+ *
+ * @package    form
+ * @subpackage ThdTag
+ * @version    SVN: $Id: sfDoctrineFormTemplate.php 6174 2007-11-27 06:22:40Z fabien $
+ */
+class ThdTagForm extends BaseThdTagForm
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/ThdUserForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,15 @@
+<?php
+
+/**
+ * ThdUser form.
+ *
+ * @package    form
+ * @subpackage ThdUser
+ * @version    SVN: $Id: sfDoctrineFormTemplate.php 6174 2007-11-27 06:22:40Z fabien $
+ */
+class ThdUserForm extends BaseThdUserForm
+{
+  public function configure()
+  {
+  }
+}
\ No newline at end of file
--- a/web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/form/doctrine/base/BaseThdSegmentForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -13,13 +13,9 @@
   {
     $this->setWidgets(array(
       'id'            => new sfWidgetFormInputHidden(),
-      'title'         => new sfWidgetFormInput(),
-      'tags'          => new sfWidgetFormTextarea(),
-      'description'   => new sfWidgetFormTextarea(),
-      'video_ref'     => new sfWidgetFormInput(),
       'start'         => new sfWidgetFormInput(),
       'end'           => new sfWidgetFormInput(),
-      'user_id'       => new sfWidgetFormInput(),
+      'user_id'       => new sfWidgetFormDoctrineChoice(array('model' => 'ThdUser', 'add_empty' => false)),
       'creation_date' => new sfWidgetFormDateTime(),
       'uniqueid'      => new sfWidgetFormInput(),
       'video_id'      => new sfWidgetFormDoctrineChoice(array('model' => 'ThdVideo', 'add_empty' => false)),
@@ -27,13 +23,9 @@
 
     $this->setValidators(array(
       'id'            => new sfValidatorDoctrineChoice(array('model' => 'ThdSegment', 'column' => 'id', 'required' => false)),
-      'title'         => new sfValidatorString(array('max_length' => 255, 'required' => false)),
-      'tags'          => new sfValidatorString(array('max_length' => 1024, 'required' => false)),
-      'description'   => new sfValidatorString(array('max_length' => 2147483647, 'required' => false)),
-      'video_ref'     => new sfValidatorInteger(),
       'start'         => new sfValidatorNumber(),
       'end'           => new sfValidatorNumber(),
-      'user_id'       => new sfValidatorInteger(),
+      'user_id'       => new sfValidatorDoctrineChoice(array('model' => 'ThdUser')),
       'creation_date' => new sfValidatorDateTime(),
       'uniqueid'      => new sfValidatorString(array('max_length' => 36)),
       'video_id'      => new sfValidatorDoctrineChoice(array('model' => 'ThdVideo')),
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/base/BaseThdSegmentTagForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,38 @@
+<?php
+
+/**
+ * ThdSegmentTag form base class.
+ *
+ * @package    form
+ * @subpackage thd_segment_tag
+ * @version    SVN: $Id: sfDoctrineFormGeneratedTemplate.php 8508 2008-04-17 17:39:15Z fabien $
+ */
+class BaseThdSegmentTagForm extends BaseFormDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'id'         => new sfWidgetFormInputHidden(),
+      'tag_id'     => new sfWidgetFormDoctrineChoice(array('model' => 'ThdTag', 'add_empty' => false)),
+      'segment_id' => new sfWidgetFormDoctrineChoice(array('model' => 'ThdSegment', 'add_empty' => false)),
+    ));
+
+    $this->setValidators(array(
+      'id'         => new sfValidatorDoctrineChoice(array('model' => 'ThdSegmentTag', 'column' => 'id', 'required' => false)),
+      'tag_id'     => new sfValidatorDoctrineChoice(array('model' => 'ThdTag')),
+      'segment_id' => new sfValidatorDoctrineChoice(array('model' => 'ThdSegment')),
+    ));
+
+    $this->widgetSchema->setNameFormat('thd_segment_tag[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdSegmentTag';
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/base/BaseThdTagForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,42 @@
+<?php
+
+/**
+ * ThdTag form base class.
+ *
+ * @package    form
+ * @subpackage thd_tag
+ * @version    SVN: $Id: sfDoctrineFormGeneratedTemplate.php 8508 2008-04-17 17:39:15Z fabien $
+ */
+class BaseThdTagForm extends BaseFormDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'id'       => new sfWidgetFormInputHidden(),
+      'tag'      => new sfWidgetFormInput(),
+      'uniqueid' => new sfWidgetFormInput(),
+    ));
+
+    $this->setValidators(array(
+      'id'       => new sfValidatorDoctrineChoice(array('model' => 'ThdTag', 'column' => 'id', 'required' => false)),
+      'tag'      => new sfValidatorString(array('max_length' => 255, 'required' => false)),
+      'uniqueid' => new sfValidatorString(array('max_length' => 255)),
+    ));
+
+    $this->validatorSchema->setPostValidator(
+      new sfValidatorDoctrineUnique(array('model' => 'ThdTag', 'column' => array('uniqueid')))
+    );
+
+    $this->widgetSchema->setNameFormat('thd_tag[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdTag';
+  }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/form/doctrine/base/BaseThdUserForm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,36 @@
+<?php
+
+/**
+ * ThdUser form base class.
+ *
+ * @package    form
+ * @subpackage thd_user
+ * @version    SVN: $Id: sfDoctrineFormGeneratedTemplate.php 8508 2008-04-17 17:39:15Z fabien $
+ */
+class BaseThdUserForm extends BaseFormDoctrine
+{
+  public function setup()
+  {
+    $this->setWidgets(array(
+      'id'       => new sfWidgetFormInputHidden(),
+      'uniqueid' => new sfWidgetFormInput(),
+    ));
+
+    $this->setValidators(array(
+      'id'       => new sfValidatorDoctrineChoice(array('model' => 'ThdUser', 'column' => 'id', 'required' => false)),
+      'uniqueid' => new sfValidatorString(array('max_length' => 255)),
+    ));
+
+    $this->widgetSchema->setNameFormat('thd_user[%s]');
+
+    $this->errorSchema = new sfValidatorErrorSchema($this->validatorSchema);
+
+    parent::setup();
+  }
+
+  public function getModelName()
+  {
+    return 'ThdUser';
+  }
+
+}
--- a/web/thdProject/lib/model/doctrine/ThdFilm.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/model/doctrine/ThdFilm.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -8,27 +8,27 @@
     public function getSonyengineFields()
     {
     	$fields = array('id' => $this->getUniqueid());
-    	
+
     	return $fields;
     }
-    
+
     private function getSolrTextValue($original_value) {
         return $original_value==null?"":strval($original_value);
     }
-    
+
     public function getSolrDocumentFields()
     {
         // keys of this array are fields' name of solr's schema.xml
         $type = "ThdFilm";
-        
+
         $title = $this->getSolrTextValue($this->getTitle());
         $desc = $this->getSolrTextValue($this->getPitch());
         $directors = $this->getSolrTextValue($this->getDirectors());
         $actors = $this->getSolrTextValue($this->getActors());
         $original_title = $this->getSolrTextValue($this->getOriginal_title());
-        $tags = $this->getSolrTextValue($this->getTags());
+        $tags = $this->getSolrTextValue($this->getTagsToText());
         //$all = implode(" ",array($title,$desc,$directors,$actors,$original_title,$tags));
-        
+
         $fields = array('type'           => $this->getSolrTextValue($type),
                         'id'             => $this->getSolrTextValue($this->getUniqueid()),
                         'title'          => array('value' => $title, 'boost' => 1.0),
@@ -66,36 +66,65 @@
     public function getProductionCountriesArray() {
       return $this->decodeJsonData('production_countries');
     }
-    
-    public function getTags() {
-    	$tags = "";
-    	$q = Doctrine_Query::create()
-    	   ->select('s.*')
-    	   ->from('ThdSegment s')
-    	   ->leftJoin('s.ThdVideo v')
-    	   ->leftJoin('v.ThdFilm f')
-    	   ->where('f.id = ?', $this->id);
-        
-    	$segments = $q->fetchArray();
-    	
-    	foreach($segments as $segment) {
-    		$tags .= $segment['tags'].",";
-    	}
-    	
-    	return rtrim($tags,',');
+
+  public function getThdVideos() {
+    $query = Doctrine_Query::create()
+      ->from('ThdVideo')
+      ->where("film_id='{$this->getId()}'");
+    return $query->execute()->getData();
+  }
+
+  public function getTagsToText() {
+    return implode(',', $this->getTags());
+  }
+
+  public function getTagsArray() {
+    return $this->getTags();
+  }
+
+  /*
+   * 'tag' => tag, 'count' => weight
+   */
+  public function getTagCloud() {
+    $tags = Array();
+
+    foreach ($this->getTags() as $tag) {
+      $score = (isset($tags[$tag])) ? $tags[$tag]+1 : 1;
+      $tags[$tag] = $score;
     }
-    
-    public function getTagsArray() {
-    	
-    	$tags = $this->getTags();
-    	$res = array();
-    	
-    	foreach (explode(',',$tags) as $tag_name) {
-    		$res[] = trim($tag_name);
-    	}
-    	
-    	return $res;
+
+    // Convert to final structure
+    $newTags = Array();
+
+    foreach ($tags as $tag=>$count) {
+      $newTags[] = Array('tag' => $tag, 'count' => $count);
+    }
+
+    return $newTags;
+  }
+
+  public function getTags() {
+    $tags = Array();
+
+    foreach ($this->getThdVideos() as $item) {
+      $tags = array_merge($tags, $item->getTags());
     }
-    
+
+    return $tags;
+  }
+
+  public function getDistinctTags() {
+    $tags = Array();
+
+    foreach ($this->getThdVideos() as $item) {
+      foreach ($item->getDistinctTags() as $tag) {
+        if (in_array($tag, $tags)) continue;
+        $tags[] = $tag;
+      }
+    }
+
+    return $tags;
+  }
+
 
 }
--- a/web/thdProject/lib/model/doctrine/ThdSegment.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/model/doctrine/ThdSegment.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -6,8 +6,50 @@
 class ThdSegment extends BaseThdSegment
 {
 
-    /*public function getSolrDocumentFields()
-    {           // keys of this array are fields' name of solr's schema.xml 
+
+  public function preInsert($event) {
+    $this->uniqueid = UUID::generate(UUID::UUID_TIME, UUID::FMT_STRING,     "mosatags");
+    $this->creation_date = strftime('%Y-%m-%d %H:%M:%S');
+  }
+
+
+  public function getThdTags() {
+    $objs = Array();
+    $query = Doctrine_Query::create()
+      ->from('ThdSegmentTag')
+      ->where("segment_id='{$this->getId()}'");
+
+    foreach ($query->execute() as $item) {
+      $objs[] = $item->getThdTag();
+    }
+
+    return $objs;
+  }
+
+  public function getTags() {
+    $tags = Array();
+
+    foreach ($this->getThdTags() as $item) {
+      $tags[] = $item->getTag();
+    }
+
+    return $tags;
+  }
+
+  public function getDistinctTags() {
+    $tags = Array();
+
+    foreach ($this->getThdTags() as $item) {
+      $tag = $item->getTag();
+      if (in_array($tag, $tags)) continue;
+      $tags[] = $tag;
+    }
+
+    return $tags;
+  }
+
+      /*public function getSolrDocumentFields()
+    {           // keys of this array are fields' name of solr's schema.xml
         $type = "ThdFilm";
         $fields = array('type'           => $type,
                         'id'             => $this->getId(),
@@ -15,30 +57,27 @@
                         'tags'           => array('value' => $this->getTags(), 'boost' => 1.0),
                         'desc'           => array('value' => $this->getDesc(), 'boost' => 1.0),
                         'uniqueid'       => array('value' => $this->getUniqueid(), 'boost' => 1.0),
-        );  
+        );
 
         return $fields;
     }*/
 
 
-    public function preInsert($event)
-    {
-        $this->uniqueid = UUID::generate(UUID::UUID_TIME, UUID::FMT_STRING,     "mosatags");
-    }
-    
+
+/*
     public function getTagsArray() {
-    	
+
         $tags = $this->getTags();
         $res = array();
-        
+
         foreach (explode(',',$tags) as $tag_name) {
             $res[] = trim($tag_name);
         }
-        
+
         return $res;
     }
-    
-    
+
+
     public function postInsert($event) {
 
         $q = Doctrine_Query::create()
@@ -46,24 +85,24 @@
            ->innerJoin('s.ThdVideo v')
            ->innerJoin('v.ThdFilm f')
            ->where('s.id = ?', $this->id);
-                   
+
         $segment = $q->fetchOne();
-                
+
         $tags_array = array();
-        
+
         $tags = $this->getTagsArray();
         foreach ($tags as $tag_name) {
             $tags_array[] = array('segment_id'=>$segment->ThdVideo->ThdFilm->uniqueid,'name'=>$tag_name);
         }
-        
+
         sfContext::getInstance()->getLogger()->info("insert segment " . print_r($tags_array,true));
-        
+
     	$dispatcher = sfContext::getInstance()->getEventDispatcher();
     	$dispatcher->notify(new sfEvent($this, 'iri_sonyengine.tag_add', array('object'=>$tags_array, 'retrain'=>true)));
 
-    	$dispatcher->notify(new sfEvent($this, 'uvmc_solr.update_document', array('object' => $segment->ThdVideo->ThdFilm, 'commit' => true)));    	
-    	
-    	
-    }
+    	$dispatcher->notify(new sfEvent($this, 'uvmc_solr.update_document', array('object' => $segment->ThdVideo->ThdFilm, 'commit' => true)));
+
+
+    }*/
 
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdSegmentTag.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdSegmentTag extends BaseThdSegmentTag
+{
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdSegmentTagTable.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,8 @@
+<?php
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdSegmentTagTable extends Doctrine_Table
+{
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdTag.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,29 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdTag extends BaseThdTag
+{
+  /*
+   * Add new tag and returns the new tag object
+   * If already exists returns tag object
+   */
+  public static function addTag($tag) {
+    $tagUid = ThdUtil::normalizeText($tag);
+
+    // Search tag
+    $query = Doctrine_Query::create()
+      ->from('ThdTag')
+      ->where("uniqueid = '{$tagUid}'");
+    $obj = $query->execute()->getFirst();
+    if ($obj) return $obj;
+
+    // Tag does not exist so create it
+    $obj = new ThdTag();
+    $obj->setTag($tag);
+    $obj->setUniqueid($tagUid);
+    $obj->save();
+    return $obj;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdTagTable.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,8 @@
+<?php
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdTagTable extends Doctrine_Table
+{
+
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdUser.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,26 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdUser extends BaseThdUser
+{
+/*
+   * Add new user and returns the new user object
+   * If already exists returns user object
+   */
+  public static function addUser($userUid) {
+    // Search tag
+    $query = Doctrine_Query::create()
+      ->from('ThdUser')
+      ->where("uniqueid = '{$userUid}'");
+    $obj = $query->execute()->getFirst();
+    if ($obj) return $obj;
+
+    // User does not exist so create it
+    $obj = new ThdUser();
+    $obj->setUniqueid($userUid);
+    $obj->save();
+    return $obj;
+  }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/ThdUserTable.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,8 @@
+<?php
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+class ThdUserTable extends Doctrine_Table
+{
+
+}
\ No newline at end of file
--- a/web/thdProject/lib/model/doctrine/ThdVideo.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/model/doctrine/ThdVideo.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -5,5 +5,54 @@
  */
 class ThdVideo extends BaseThdVideo
 {
+  public function addSegment($start, $end, $tags, $userUid) {
+    $userObj = ThdUser::addUser($userUid);
+    $segmentObj = new ThdSegment();
+    $segmentObj->setStart($start);
+    $segmentObj->setEnd($end);
+    $segmentObj->setUserId($userObj->getId());
+    $segmentObj->setVideoId($this->getId());
+    $segmentObj->save();
 
+    // Add tags to segment
+    foreach ($tags as $tag) {
+      $tagObj = ThdTag::addTag($tag);
+      $segmentTagObj = new ThdSegmentTag();
+      $segmentTagObj->setSegmentId($segmentObj->getId());
+      $segmentTagObj->setTagId($tagObj->getId());
+      $segmentTagObj->save();
+    }
+
+    return $segmentObj;
+  }
+
+  public function getThdSegments() {
+    $query = Doctrine_Query::create()
+      ->from('ThdSegment')
+      ->where("video_id='{$this->getId()}'");
+    return $query->execute()->getData();
+  }
+
+  public function getTags() {
+    $tags = Array();
+
+    foreach ($this->getThdSegments() as $item) {
+      $tags = array_merge($tags, $item->getTags());
+    }
+
+    return $tags;
+  }
+
+  public function getDistinctTags() {
+    $tags = Array();
+
+    foreach ($this->getThdSegments() as $item) {
+      foreach ($item->getDistinctTags() as $tag) {
+        if (in_array($tag, $tags)) continue;
+        $tags[] = $tag;
+      }
+    }
+
+    return $tags;
+  }
 }
\ No newline at end of file
--- a/web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/lib/model/doctrine/base/BaseThdSegment.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -15,23 +15,6 @@
              'autoincrement' => true,
              'length' => '4',
              ));
-        $this->hasColumn('title', 'string', 255, array(
-             'type' => 'string',
-             'length' => '255',
-             ));
-        $this->hasColumn('tags', 'string', 1024, array(
-             'type' => 'string',
-             'length' => '1024',
-             ));
-        $this->hasColumn('description', 'string', 2147483647, array(
-             'type' => 'string',
-             'length' => '2147483647',
-             ));
-        $this->hasColumn('video_ref', 'integer', 4, array(
-             'type' => 'integer',
-             'notnull' => true,
-             'length' => '4',
-             ));
         $this->hasColumn('start', 'float', 2147483647, array(
              'type' => 'float',
              'notnull' => true,
@@ -44,6 +27,7 @@
              ));
         $this->hasColumn('user_id', 'integer', 4, array(
              'type' => 'integer',
+             'unsigned' => '1',
              'notnull' => true,
              'length' => '4',
              ));
@@ -80,5 +64,14 @@
              'local' => 'video_id',
              'foreign' => 'id',
              'onDelete' => 'CASCADE'));
+
+        $this->hasOne('ThdUser', array(
+             'local' => 'user_id',
+             'foreign' => 'id',
+             'onDelete' => 'CASCADE'));
+
+        $this->hasMany('ThdSegmentTag', array(
+             'local' => 'id',
+             'foreign' => 'segment_id'));
     }
 }
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/base/BaseThdSegmentTag.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+abstract class BaseThdSegmentTag extends sfDoctrineRecord
+{
+    public function setTableDefinition()
+    {
+        $this->setTableName('thd_segment_tag');
+        $this->hasColumn('id', 'integer', 4, array(
+             'type' => 'integer',
+             'unsigned' => '1',
+             'primary' => true,
+             'autoincrement' => true,
+             'length' => '4',
+             ));
+        $this->hasColumn('tag_id', 'integer', 4, array(
+             'type' => 'integer',
+             'unsigned' => '1',
+             'notnull' => true,
+             'length' => '4',
+             ));
+        $this->hasColumn('segment_id', 'integer', 4, array(
+             'type' => 'integer',
+             'unsigned' => '1',
+             'notnull' => true,
+             'length' => '4',
+             ));
+    }
+
+    public function setUp()
+    {
+        $this->hasOne('ThdSegment', array(
+             'local' => 'segment_id',
+             'foreign' => 'id',
+             'onDelete' => 'CASCADE'));
+
+        $this->hasOne('ThdTag', array(
+             'local' => 'tag_id',
+             'foreign' => 'id',
+             'onDelete' => 'CASCADE'));
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/base/BaseThdTag.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,44 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+abstract class BaseThdTag extends sfDoctrineRecord
+{
+    public function setTableDefinition()
+    {
+        $this->setTableName('thd_tag');
+        $this->hasColumn('id', 'integer', 4, array(
+             'type' => 'integer',
+             'unsigned' => '1',
+             'primary' => true,
+             'autoincrement' => true,
+             'length' => '4',
+             ));
+        $this->hasColumn('tag', 'string', 255, array(
+             'type' => 'string',
+             'length' => '255',
+             ));
+        $this->hasColumn('uniqueid', 'string', 255, array(
+             'type' => 'string',
+             'notnull' => true,
+             'length' => '255',
+             ));
+
+
+        $this->index('uniqueidindex', array(
+             'fields' => 
+             array(
+              0 => 'uniqueid',
+             ),
+             'type' => 'unique',
+             ));
+    }
+
+    public function setUp()
+    {
+        $this->hasMany('ThdSegmentTag', array(
+             'local' => 'id',
+             'foreign' => 'tag_id'));
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/lib/model/doctrine/base/BaseThdUser.class.php	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,31 @@
+<?php
+
+/**
+ * This class has been auto-generated by the Doctrine ORM Framework
+ */
+abstract class BaseThdUser extends sfDoctrineRecord
+{
+    public function setTableDefinition()
+    {
+        $this->setTableName('thd_user');
+        $this->hasColumn('id', 'integer', 4, array(
+             'type' => 'integer',
+             'unsigned' => '1',
+             'primary' => true,
+             'autoincrement' => true,
+             'length' => '4',
+             ));
+        $this->hasColumn('uniqueid', 'string', 255, array(
+             'type' => 'string',
+             'notnull' => true,
+             'length' => '255',
+             ));
+    }
+
+    public function setUp()
+    {
+        $this->hasMany('ThdSegment as segments', array(
+             'local' => 'id',
+             'foreign' => 'user_id'));
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/web/css/jquery.autocomplete.css	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,48 @@
+.ac_results {
+	padding: 0px;
+	border: 1px solid black;
+	background-color: white;
+	overflow: hidden;
+	z-index: 99999;
+}
+
+.ac_results ul {
+	width: 100%;
+	list-style-position: outside;
+	list-style: none;
+	padding: 0;
+	margin: 0;
+}
+
+.ac_results li {
+	margin: 0px;
+	padding: 2px 5px;
+	cursor: default;
+	display: block;
+	/* 
+	if width will be 100% horizontal scrollbar will apear 
+	when scroll mode will be used
+	*/
+	/*width: 100%;*/
+	font: menu;
+	font-size: 12px;
+	/* 
+	it is very important, if line-height not setted or setted 
+	in relative units scroll will be broken in firefox
+	*/
+	line-height: 16px;
+	overflow: hidden;
+}
+
+.ac_loading {
+	background: white url('indicator.gif') right center no-repeat;
+}
+
+.ac_odd {
+	background-color: #eee;
+}
+
+.ac_over {
+	background-color: #0A246A;
+	color: white;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/web/js/jquery.autocomplete.min.js	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,13 @@
+/*
+ * jQuery Autocomplete plugin 1.1
+ *
+ * Copyright (c) 2009 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ *   http://www.opensource.org/licenses/mit-license.php
+ *   http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $
+ */;(function($){$.fn.extend({autocomplete:function(urlOrData,options){var isUrl=typeof urlOrData=="string";options=$.extend({},$.Autocompleter.defaults,{url:isUrl?urlOrData:null,data:isUrl?null:urlOrData,delay:isUrl?$.Autocompleter.defaults.delay:10,max:options&&!options.scroll?10:150},options);options.highlight=options.highlight||function(value){return value;};options.formatMatch=options.formatMatch||options.formatItem;return this.each(function(){new $.Autocompleter(this,options);});},result:function(handler){return this.bind("result",handler);},search:function(handler){return this.trigger("search",[handler]);},flushCache:function(){return this.trigger("flushCache");},setOptions:function(options){return this.trigger("setOptions",[options]);},unautocomplete:function(){return this.trigger("unautocomplete");}});$.Autocompleter=function(input,options){var KEY={UP:38,DOWN:40,DEL:46,TAB:9,RETURN:13,ESC:27,COMMA:188,PAGEUP:33,PAGEDOWN:34,BACKSPACE:8};var $input=$(input).attr("autocomplete","off").addClass(options.inputClass);var timeout;var previousValue="";var cache=$.Autocompleter.Cache(options);var hasFocus=0;var lastKeyPressCode;var config={mouseDownOnSelect:false};var select=$.Autocompleter.Select(options,input,selectCurrent,config);var blockSubmit;$.browser.opera&&$(input.form).bind("submit.autocomplete",function(){if(blockSubmit){blockSubmit=false;return false;}});$input.bind(($.browser.opera?"keypress":"keydown")+".autocomplete",function(event){hasFocus=1;lastKeyPressCode=event.keyCode;switch(event.keyCode){case KEY.UP:event.preventDefault();if(select.visible()){select.prev();}else{onChange(0,true);}break;case KEY.DOWN:event.preventDefault();if(select.visible()){select.next();}else{onChange(0,true);}break;case KEY.PAGEUP:event.preventDefault();if(select.visible()){select.pageUp();}else{onChange(0,true);}break;case KEY.PAGEDOWN:event.preventDefault();if(select.visible()){select.pageDown();}else{onChange(0,true);}break;case options.multiple&&$.trim(options.multipleSeparator)==","&&KEY.COMMA:case KEY.TAB:case KEY.RETURN:if(selectCurrent()){event.preventDefault();blockSubmit=true;return false;}break;case KEY.ESC:select.hide();break;default:clearTimeout(timeout);timeout=setTimeout(onChange,options.delay);break;}}).focus(function(){hasFocus++;}).blur(function(){hasFocus=0;if(!config.mouseDownOnSelect){hideResults();}}).click(function(){if(hasFocus++>1&&!select.visible()){onChange(0,true);}}).bind("search",function(){var fn=(arguments.length>1)?arguments[1]:null;function findValueCallback(q,data){var result;if(data&&data.length){for(var i=0;i<data.length;i++){if(data[i].result.toLowerCase()==q.toLowerCase()){result=data[i];break;}}}if(typeof fn=="function")fn(result);else $input.trigger("result",result&&[result.data,result.value]);}$.each(trimWords($input.val()),function(i,value){request(value,findValueCallback,findValueCallback);});}).bind("flushCache",function(){cache.flush();}).bind("setOptions",function(){$.extend(options,arguments[1]);if("data"in arguments[1])cache.populate();}).bind("unautocomplete",function(){select.unbind();$input.unbind();$(input.form).unbind(".autocomplete");});function selectCurrent(){var selected=select.selected();if(!selected)return false;var v=selected.result;previousValue=v;if(options.multiple){var words=trimWords($input.val());if(words.length>1){var seperator=options.multipleSeparator.length;var cursorAt=$(input).selection().start;var wordAt,progress=0;$.each(words,function(i,word){progress+=word.length;if(cursorAt<=progress){wordAt=i;return false;}progress+=seperator;});words[wordAt]=v;v=words.join(options.multipleSeparator);}v+=options.multipleSeparator;}$input.val(v);hideResultsNow();$input.trigger("result",[selected.data,selected.value]);return true;}function onChange(crap,skipPrevCheck){if(lastKeyPressCode==KEY.DEL){select.hide();return;}var currentValue=$input.val();if(!skipPrevCheck&&currentValue==previousValue)return;previousValue=currentValue;currentValue=lastWord(currentValue);if(currentValue.length>=options.minChars){$input.addClass(options.loadingClass);if(!options.matchCase)currentValue=currentValue.toLowerCase();request(currentValue,receiveData,hideResultsNow);}else{stopLoading();select.hide();}};function trimWords(value){if(!value)return[""];if(!options.multiple)return[$.trim(value)];return $.map(value.split(options.multipleSeparator),function(word){return $.trim(value).length?$.trim(word):null;});}function lastWord(value){if(!options.multiple)return value;var words=trimWords(value);if(words.length==1)return words[0];var cursorAt=$(input).selection().start;if(cursorAt==value.length){words=trimWords(value)}else{words=trimWords(value.replace(value.substring(cursorAt),""));}return words[words.length-1];}function autoFill(q,sValue){if(options.autoFill&&(lastWord($input.val()).toLowerCase()==q.toLowerCase())&&lastKeyPressCode!=KEY.BACKSPACE){$input.val($input.val()+sValue.substring(lastWord(previousValue).length));$(input).selection(previousValue.length,previousValue.length+sValue.length);}};function hideResults(){clearTimeout(timeout);timeout=setTimeout(hideResultsNow,200);};function hideResultsNow(){var wasVisible=select.visible();select.hide();clearTimeout(timeout);stopLoading();if(options.mustMatch){$input.search(function(result){if(!result){if(options.multiple){var words=trimWords($input.val()).slice(0,-1);$input.val(words.join(options.multipleSeparator)+(words.length?options.multipleSeparator:""));}else{$input.val("");$input.trigger("result",null);}}});}};function receiveData(q,data){if(data&&data.length&&hasFocus){stopLoading();select.display(data,q);autoFill(q,data[0].value);select.show();}else{hideResultsNow();}};function request(term,success,failure){if(!options.matchCase)term=term.toLowerCase();var data=cache.load(term);if(data&&data.length){success(term,data);}else if((typeof options.url=="string")&&(options.url.length>0)){var extraParams={timestamp:+new Date()};$.each(options.extraParams,function(key,param){extraParams[key]=typeof param=="function"?param():param;});$.ajax({mode:"abort",port:"autocomplete"+input.name,dataType:options.dataType,url:options.url,data:$.extend({q:lastWord(term),limit:options.max},extraParams),success:function(data){var parsed=options.parse&&options.parse(data)||parse(data);cache.add(term,parsed);success(term,parsed);}});}else{select.emptyList();failure(term);}};function parse(data){var parsed=[];var rows=data.split("\n");for(var i=0;i<rows.length;i++){var row=$.trim(rows[i]);if(row){row=row.split("|");parsed[parsed.length]={data:row,value:row[0],result:options.formatResult&&options.formatResult(row,row[0])||row[0]};}}return parsed;};function stopLoading(){$input.removeClass(options.loadingClass);};};$.Autocompleter.defaults={inputClass:"ac_input",resultsClass:"ac_results",loadingClass:"ac_loading",minChars:1,delay:400,matchCase:false,matchSubset:true,matchContains:false,cacheLength:10,max:100,mustMatch:false,extraParams:{},selectFirst:true,formatItem:function(row){return row[0];},formatMatch:null,autoFill:false,width:0,multiple:false,multipleSeparator:", ",highlight:function(value,term){return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)("+term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi,"\\$1")+")(?![^<>]*>)(?![^&;]+;)","gi"),"<strong>$1</strong>");},scroll:true,scrollHeight:180};$.Autocompleter.Cache=function(options){var data={};var length=0;function matchSubset(s,sub){if(!options.matchCase)s=s.toLowerCase();var i=s.indexOf(sub);if(options.matchContains=="word"){i=s.toLowerCase().search("\\b"+sub.toLowerCase());}if(i==-1)return false;return i==0||options.matchContains;};function add(q,value){if(length>options.cacheLength){flush();}if(!data[q]){length++;}data[q]=value;}function populate(){if(!options.data)return false;var stMatchSets={},nullData=0;if(!options.url)options.cacheLength=1;stMatchSets[""]=[];for(var i=0,ol=options.data.length;i<ol;i++){var rawValue=options.data[i];rawValue=(typeof rawValue=="string")?[rawValue]:rawValue;var value=options.formatMatch(rawValue,i+1,options.data.length);if(value===false)continue;var firstChar=value.charAt(0).toLowerCase();if(!stMatchSets[firstChar])stMatchSets[firstChar]=[];var row={value:value,data:rawValue,result:options.formatResult&&options.formatResult(rawValue)||value};stMatchSets[firstChar].push(row);if(nullData++<options.max){stMatchSets[""].push(row);}};$.each(stMatchSets,function(i,value){options.cacheLength++;add(i,value);});}setTimeout(populate,25);function flush(){data={};length=0;}return{flush:flush,add:add,populate:populate,load:function(q){if(!options.cacheLength||!length)return null;if(!options.url&&options.matchContains){var csub=[];for(var k in data){if(k.length>0){var c=data[k];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub.push(x);}});}}return csub;}else
+if(data[q]){return data[q];}else
+if(options.matchSubset){for(var i=q.length-1;i>=options.minChars;i--){var c=data[q.substr(0,i)];if(c){var csub=[];$.each(c,function(i,x){if(matchSubset(x.value,q)){csub[csub.length]=x;}});return csub;}}}return null;}};};$.Autocompleter.Select=function(options,input,select,config){var CLASSES={ACTIVE:"ac_over"};var listItems,active=-1,data,term="",needsInit=true,element,list;function init(){if(!needsInit)return;element=$("<div/>").hide().addClass(options.resultsClass).css("position","absolute").appendTo(document.body);list=$("<ul/>").appendTo(element).mouseover(function(event){if(target(event).nodeName&&target(event).nodeName.toUpperCase()=='LI'){active=$("li",list).removeClass(CLASSES.ACTIVE).index(target(event));$(target(event)).addClass(CLASSES.ACTIVE);}}).click(function(event){$(target(event)).addClass(CLASSES.ACTIVE);select();input.focus();return false;}).mousedown(function(){config.mouseDownOnSelect=true;}).mouseup(function(){config.mouseDownOnSelect=false;});if(options.width>0)element.css("width",options.width);needsInit=false;}function target(event){var element=event.target;while(element&&element.tagName!="LI")element=element.parentNode;if(!element)return[];return element;}function moveSelect(step){listItems.slice(active,active+1).removeClass(CLASSES.ACTIVE);movePosition(step);var activeItem=listItems.slice(active,active+1).addClass(CLASSES.ACTIVE);if(options.scroll){var offset=0;listItems.slice(0,active).each(function(){offset+=this.offsetHeight;});if((offset+activeItem[0].offsetHeight-list.scrollTop())>list[0].clientHeight){list.scrollTop(offset+activeItem[0].offsetHeight-list.innerHeight());}else if(offset<list.scrollTop()){list.scrollTop(offset);}}};function movePosition(step){active+=step;if(active<0){active=listItems.size()-1;}else if(active>=listItems.size()){active=0;}}function limitNumberOfItems(available){return options.max&&options.max<available?options.max:available;}function fillList(){list.empty();var max=limitNumberOfItems(data.length);for(var i=0;i<max;i++){if(!data[i])continue;var formatted=options.formatItem(data[i].data,i+1,max,data[i].value,term);if(formatted===false)continue;var li=$("<li/>").html(options.highlight(formatted,term)).addClass(i%2==0?"ac_even":"ac_odd").appendTo(list)[0];$.data(li,"ac_data",data[i]);}listItems=list.find("li");if(options.selectFirst){listItems.slice(0,1).addClass(CLASSES.ACTIVE);active=0;}if($.fn.bgiframe)list.bgiframe();}return{display:function(d,q){init();data=d;term=q;fillList();},next:function(){moveSelect(1);},prev:function(){moveSelect(-1);},pageUp:function(){if(active!=0&&active-8<0){moveSelect(-active);}else{moveSelect(-8);}},pageDown:function(){if(active!=listItems.size()-1&&active+8>listItems.size()){moveSelect(listItems.size()-1-active);}else{moveSelect(8);}},hide:function(){element&&element.hide();listItems&&listItems.removeClass(CLASSES.ACTIVE);active=-1;},visible:function(){return element&&element.is(":visible");},current:function(){return this.visible()&&(listItems.filter("."+CLASSES.ACTIVE)[0]||options.selectFirst&&listItems[0]);},show:function(){var offset=$(input).offset();element.css({width:typeof options.width=="string"||options.width>0?options.width:$(input).width(),top:offset.top+input.offsetHeight,left:offset.left}).show();if(options.scroll){list.scrollTop(0);list.css({maxHeight:options.scrollHeight,overflow:'auto'});if($.browser.msie&&typeof document.body.style.maxHeight==="undefined"){var listHeight=0;listItems.each(function(){listHeight+=this.offsetHeight;});var scrollbarsVisible=listHeight>options.scrollHeight;list.css('height',scrollbarsVisible?options.scrollHeight:listHeight);if(!scrollbarsVisible){listItems.width(list.width()-parseInt(listItems.css("padding-left"))-parseInt(listItems.css("padding-right")));}}}},selected:function(){var selected=listItems&&listItems.filter("."+CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE);return selected&&selected.length&&$.data(selected[0],"ac_data");},emptyList:function(){list&&list.empty();},unbind:function(){element&&element.remove();}};};$.fn.selection=function(start,end){if(start!==undefined){return this.each(function(){if(this.createTextRange){var selRange=this.createTextRange();if(end===undefined||start==end){selRange.move("character",start);selRange.select();}else{selRange.collapse(true);selRange.moveStart("character",start);selRange.moveEnd("character",end);selRange.select();}}else if(this.setSelectionRange){this.setSelectionRange(start,end);}else if(this.selectionStart){this.selectionStart=start;this.selectionEnd=end;}});}var field=this[0];if(field.createTextRange){var range=document.selection.createRange(),orig=field.value,teststring="<->",textLength=range.text.length;range.text=teststring;var caretAt=field.value.indexOf(teststring);field.value=orig;this.selection(caretAt,caretAt+textLength);return{start:caretAt,end:caretAt+textLength}}else if(field.selectionStart!==undefined){return{start:field.selectionStart,end:field.selectionEnd}}};})(jQuery);
\ No newline at end of file
--- a/web/thdProject/web/js/segmentation/segments.js	Tue Apr 20 18:38:06 2010 +0200
+++ b/web/thdProject/web/js/segmentation/segments.js	Tue Apr 20 19:55:36 2010 +0200
@@ -6,7 +6,7 @@
     mkout: 0,
 
     markIn: function() {
-        // Besoin d'arrondir à cause de la precision limitee
+        // Besoin d'arrondir � cause de la precision limitee
         // des cuepoints.
         this.mkin = Math.round($f().getTime() * 10) / 10;
         $("#btMarkOut").removeAttr("disabled");
@@ -21,7 +21,7 @@
         $("#frmOut").val(this.mkout * 1000);
         $("#mkin").text(this.mkin);
         $("#mkout").text(this.mkout);
-        $("#segmentForm").show();
+        $("#segment-add").show();
         // Arrete la lecture sur la marque de sortie de segment
         player.onCuepoint([this.mkout * 1000],
                           function(clip, cue) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/web/thdProject/web/js/uc.editor.js	Tue Apr 20 19:55:36 2010 +0200
@@ -0,0 +1,12 @@
+
+
+jQuery(document).ready(function() {
+	jQuery("#segment-add input[name=tags]").autocomplete("../editeur/suggestion-tags", {
+		width: 300,
+		multiple: true,
+		matchContains: true,
+		formatItem: function(item) {
+		    return item[0];
+		}
+	});
+});
\ No newline at end of file