Browse Source

Evolution #79: TagsPrompt: Plus d'userFriendlyté

bastien 12 years ago
parent
commit
02fb53bed8

+ 35 - 21
src/Muzich/CoreBundle/Controller/SearchController.php View File

@@ -63,39 +63,53 @@ class SearchController extends Controller
63 63
   {
64 64
     if ($this->getRequest()->isXmlHttpRequest())
65 65
     {
66
-      $words = explode(' ', $string_search);
67
-      $where = '';
68
-      $params = array();
69
-      foreach ($words as $i => $word)
66
+      if (strlen($string_search) > 1)
70 67
       {
71
-        if ($where == '')
68
+        $words = explode(' ', $string_search);
69
+        $where = '';
70
+        $params = array();
71
+        foreach ($words as $i => $word)
72 72
         {
73
-          $where .= 'WHERE UPPER(t.name) LIKE :str'.$i;
73
+          if ($where == '')
74
+          {
75
+            $where .= 'WHERE UPPER(t.name) LIKE :str'.$i;
76
+          }
77
+          else
78
+          {
79
+            $where .= ' OR UPPER(t.name) LIKE :str'.$i;
80
+          }
81
+
82
+          $params['str'.$i] = '%'.strtoupper($word).'%';
74 83
         }
75
-        else
84
+
85
+        $tags = $this->getDoctrine()->getEntityManager()->createQuery("
86
+          SELECT t.name FROM MuzichCoreBundle:Tag t
87
+          $where
88
+          ORDER BY t.name ASC"
89
+        )->setParameters($params)
90
+        ->getScalarResult()
91
+        ;
92
+
93
+        $tags_response = array();
94
+        foreach ($tags as $tag)
76 95
         {
77
-          $where .= ' OR UPPER(t.name) LIKE :str'.$i;
96
+          $tags_response[] = $tag['name'];
78 97
         }
79 98
         
80
-        $params['str'.$i] = '%'.strtoupper($word).'%';
99
+        $status = 'success';
100
+        $error  = '';
81 101
       }
82
-      
83
-      $tags = $this->getDoctrine()->getEntityManager()->createQuery("
84
-        SELECT t.name FROM MuzichCoreBundle:Tag t
85
-        $where
86
-        ORDER BY t.name ASC"
87
-      )->setParameters($params)
88
-      ->getScalarResult()
89
-      ;
90
-      
91
-      $tags_response = array();
92
-      foreach ($tags as $tag)
102
+      else
93 103
       {
94
-        $tags_response[] = $tag['name'];
104
+        $status = 'error';
105
+        $tags_response = array();
106
+        $error = 'Vous devez saisir au moins deux caractères';
95 107
       }
96 108
       
97 109
       $return_array = array(
110
+        'status'    => $status,
98 111
         'timestamp' => $timestamp,
112
+        'error'     => $error,
99 113
         'data'      => $tags_response
100 114
       );
101 115
       

+ 198 - 25
src/Muzich/CoreBundle/Resources/views/Tag/tagsPrompt.html.twig View File

@@ -13,8 +13,13 @@
13 13
     {% endif %}
14 14
   {% endif %}
15 15
   
16
-   <img id="tag_loader_{{ form_name }}" class="tag_loader" style="display: none;" src="{{ asset('/bundles/muzichcore/img/ajax-loader.gif') }}" alt="loading"/>
17 16
    <input class="tags_prompt_list" id="tags_prompt_list_{{ form_name }}" name="tags" value=""> 
17
+   <div id="search_tag_{{ form_name }}" class="search_tag_list" style="display: none;">
18
+     <img id="tag_loader_{{ form_name }}" class="tag_loader" style="display: none;" src="{{ asset('/bundles/muzichcore/img/ajax-loader.gif') }}" alt="loading"/>
19
+     <span class="info"></span>
20
+     <ul class="search_tag_list"></ul>
21
+     <a class="more" href="#" style="display: none;">Afficher les autres tags correspondant a la recherche</a>
22
+   </div>
18 23
 </div>
19 24
 
20 25
 <script language="javascript" type="text/javascript">
@@ -50,34 +55,202 @@
50 55
           .appendTo( ul );
51 56
   };
52 57
   
53
-  // The autocomplete for the last tagbox
54
-  $("#tags_prompt_{{ form_name }} ul.tagbox li.input input").autocomplete({
55
-      source: function(req, responseFn) {
56
-        
57
-        // ici il faut faire une ajax q pour obtenir la liste
58
-        // ou a est un tableau de strings
59
-        $('#tag_loader_{{ form_name }}').css('display', 'block');
60
-        ajax_query_timestamp = new Date().getTime();
61
-        $.getJSON('/app_dev.php/fr/search/tag/'+req.term+'/'+ajax_query_timestamp, function(data) {
62
-          
63
-          // Ce contrôle permet de ne pas continuer si une requete
64
-          // ajax a été faite depuis.
65
-          if (data.timestamp == ajax_query_timestamp)
58
+  ////////////////////////
59
+    
60
+  // Les deux clicks ci-dessous permettent de faire disparaitre
61
+  // la div de tags lorsque l'on clique ailleurs
62
+  $('html').click(function() {
63
+    if ($("#search_tag_{{ form_name }}").is(':visible'))
64
+    {
65
+      $("#search_tag_{{ form_name }}").hide();
66
+    }
67
+  });
68
+  
69
+  $("#search_tag_{{ form_name }}").click(function(event){
70
+    event.stopPropagation();
71
+  });
72
+  
73
+  function autocomplete_tag(input, form_name)
74
+  {
75
+    // Il doit y avoir au moin un caractère
76
+    if (input.val().length > 0) 
77
+    {
78
+
79
+      // on met en variable l'input
80
+      inputTag = input;
81
+
82
+      // On récupére la div de tags
83
+      divtags = $("#search_tag_"+form_name);
84
+
85
+      // Si la fenêtre de tags est caché
86
+      if (!divtags.is(':visible'))
87
+      {
88
+        // On la replace
89
+        position = input.position();
90
+        divtags.css('left', Math.round(position.left) + 5);
91
+        divtags.css('top', Math.round(position.top) + 28);
92
+        // Et on l'affiche
93
+        divtags.show();
94
+      }
95
+      // On affiche le loader
96
+      $('#tag_loader_'+form_name).show();
97
+      // On cache la liste de tags
98
+      search_tag_list = divtags.find('ul.search_tag_list');
99
+      search_tag_list.hide();
100
+      // Et on affiche une info
101
+      span_info = divtags.find('span.info');
102
+      span_info.show();
103
+      span_info.text("Recherche des tags correspondants à \""+input.val()+"\" ...");
104
+
105
+      // C'est en fonction du nb de resultats qu'il sera affiché
106
+      divtags.find('a.more').hide();
107
+
108
+      // On récupère le timestamp pour reconnaitre la dernière requête effectué
109
+      ajax_query_timestamp = new Date().getTime();
110
+
111
+      // Récupération des tags correspondants
112
+      $.getJSON('/app_dev.php/fr/search/tag/'+input.val()+'/'+ajax_query_timestamp, function(data) {
113
+        // Ce contrôle permet de ne pas continuer si une requete
114
+        // ajax a été faite depuis.
115
+        if (data.timestamp == ajax_query_timestamp)
116
+        {
117
+          status = data.status;
118
+          tags   = data.data;
119
+
120
+          // Si on spécifie une erreur
121
+          if (status == 'error')
66 122
           {
67
-            responseFn( data.data );
68
-            $('#tag_loader_{{ form_name }}').css('display', 'none');
123
+            // On l'affiche a l'utilisateur
124
+            span_info.text(data.error);
69 125
           }
70
-        });
71
-      },
72
-      minLength: 2,
73
-      select: function(e, ui) {
74
-          e.preventDefault();
75
-          if(e.keyCode != 13) {
76
-              $(this).val(ui.item.value);
77
-              $(this).trigger("selectTag");
126
+          // Si c'est un succés
127
+          else if (status == 'success')
128
+          {
129
+            if (tags.length > 1)
130
+            {
131
+              more = false;
132
+              // Pour chaque tags retournés
133
+              for (i in tags)
134
+              {
135
+                // On construit un li
136
+                li_tag = 
137
+                  $('<li>').append(
138
+                    $('<a>').attr('href','#'+tags[i])
139
+                    // qui réagit quand on clique dessus
140
+                    .click(function(e){
141
+                      // On récupère le nom du tag
142
+                      inputTag.val($(this).attr('href').substr(1,$(this).attr('href').length));
143
+                      // Et on execute l'évènement selectTag de l'input
144
+                      inputTag.trigger("selectTag");
145
+                      // On cache la liste puisque le choix vient d'être fait
146
+                      divtags.hide();
147
+                      return false;
148
+                    })
149
+                    .append(tags[i])
150
+                );
151
+
152
+                // Si on depasse les 30 tags
153
+                if (i > 30)
154
+                {
155
+                  more = true;
156
+                  // On le cache
157
+                  li_tag.hide();
158
+                }
159
+
160
+                // On ajout ce li a la liste
161
+                search_tag_list.append(li_tag);
162
+              } 
163
+
164
+              if (more)
165
+              {
166
+                divtags.find('a.more').show();
167
+              }
168
+
169
+              // On cache l'info
170
+              span_info.hide();
171
+              // Et on affiche la liste
172
+              search_tag_list.show();
173
+            }
174
+            else
175
+            {
176
+              span_info.text("Aucun tag de trouvé pour \""+inputTag.val()+"\"");
177
+            }
178
+            
78 179
           }
180
+
181
+          // On cache le loader
182
+          $('#tag_loader_'+form_name).hide();
183
+        }
184
+      });
185
+      
186
+    }
187
+  }
188
+  
189
+  
190
+
191
+  last_keypress = 0;
192
+  
193
+  function check_timelaps_and_search(input, form_name, time_id, timed, info)
194
+  {
195
+    if (!timed)
196
+    {
197
+      // C'est une nouvelle touche (pas redirigé) on lui donne un id
198
+      // et on met a jour l'id de la dernière pressé
199
+      last_keypress = new Date().getTime(); 
200
+      var this_time_id = last_keypress;
201
+    }
202
+    else
203
+    {
204
+      // Si elle a été redirigé, on met son id dans cette variable
205
+      var this_time_id = time_id;
206
+    }
207
+    
208
+    // C'est une touche redirigé dans le temps qui a été suivit d'une autre touche
209
+    if (time_id != last_keypress && timed)
210
+    {
211
+      // elle disparait
212
+    }
213
+    else
214
+    {
215
+      //
216
+      if ((new Date().getTime() - last_keypress) < 600 || timed == false)
217
+      {
218
+        // Si elle vient d'être tapé (timed == false) elle doit attendre (au cas ou une autre touche soit tapé)
219
+        // Si c'est une redirigé qui n'a pas été remplacé par une nouvelle lettre
220
+        // elle doit attendre au cas ou soit pressé.
221
+        setTimeout(function(){check_timelaps_and_search(input, form_name, this_time_id, true, info)}, 700);
222
+      }
223
+      else
224
+      {
225
+        // il n'y a plus a attendre, on envoie la demande de tag.
226
+        autocomplete_tag(input, '{{ form_name }}');
79 227
       }
80
-  });  
228
+    }
229
+  }
230
+
231
+  // Autocompletion de tags
232
+  $("#tags_prompt_{{ form_name }} ul.tagbox li.input input").keypress(function(e){
233
+    
234
+    var code = (e.keyCode ? e.keyCode : e.which);
235
+
236
+    if ((e.which !== 0 && e.charCode !== 0) || (code == 8 || code == 46))
237
+    {
238
+      check_timelaps_and_search($(this), '{{ form_name }}', new Date().getTime(), false, $(this).val());
239
+    }
240
+     
241
+  });
242
+  
243
+  // Un click sur ce lien affiche tout les tags cachés de la liste
244
+  $('div.search_tag_list a.more').click(function(){
245
+    jQuery.each( $(this).parent('div').find('ul.search_tag_list li') , function(){
246
+      $(this).show();
247
+    });
248
+    return false;
249
+  });
250
+  
251
+  /////////////////////////////////
252
+  
253
+
81 254
   
82 255
   $('#tags_prompt_{{ form_name }} input[type="text"]').val(tag_text_help);
83 256
   $('#tags_prompt_{{ form_name }} input[type="text"]').formDefaults();

+ 8 - 0
web/bundles/muzichcore/css/main.css View File

@@ -519,4 +519,12 @@ div.no_elements
519 519
 {
520 520
   text-align: center;
521 521
   background-color: #d9f7ff;
522
+}
523
+
524
+/*  Recherche de tags dynamique  */
525
+
526
+div.search_tag_list
527
+{
528
+  position: absolute;  
529
+  background-color: red;
522 530
 }

+ 1 - 1
web/js/tags/jquery.tagBox.js View File

@@ -61,7 +61,7 @@
61 61
           }
62 62
           
63 63
           input = $(this);
64
-
64
+          
65 65
           // Ici il faut faire un ajax q pour connaitre l'id, on a que le string
66 66
           // ajax loader gif
67 67
           $('#tag_loader_'+options.form_name).css('display', 'block');