Allows multiple entries for some medals (Closes #1380).
authorStéphane Jacob <sj@m4x.org>
Tue, 1 Mar 2011 23:20:35 +0000 (00:20 +0100)
committerStéphane Jacob <sj@m4x.org>
Tue, 1 Mar 2011 23:20:35 +0000 (00:20 +0100)
Signed-off-by: Stéphane Jacob <sj@m4x.org>
ChangeLog
htdocs/javascript/profile.js
include/validations/medals.inc.php
modules/profile.php
modules/profile/decos.inc.php
templates/profile/deco.medal.tpl
templates/profile/grades.js.tpl
upgrade/1.1.0/10_deco.sql [new file with mode: 0644]

index ff99938..b262a4d 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,7 @@ Bug/Wish:
 
     * Profile:
         - #1324,1352: Adds jobs to vcards                                  -JAC
+        - #1380: Allows multiple entries for some medals                   -JAC
         - #1389: Do not require validation for private names modifications -JAC
         - #1401: Main addresses are displayed before secondary addresses   -JAC
 
index f0ca309..d4899ec 100644 (file)
@@ -37,11 +37,10 @@ function wizPage_onLoad(id)
         updateGroupSubLink();
         break;
       case 'deco':
-        for (var i in names) {
-            if ($('#medal_' + i).length != 0) {
-                getMedalName(i);
-                buildGrade(i, $('#medal_' + i).find('[name*=medal_' + i + '_grade]').val());
-            }
+        var i = 0;
+        while ($('#medal_' + i).length != 0) {
+            prepareMedal(i);
+            ++i;
         }
         break;
       case 'emploi':
@@ -57,6 +56,7 @@ var educationDegreeAll;
 var educationDegreeName;
 var subgrades;
 var names;
+var multiples;
 
 // Publicity follows the following ordering: private < ax < public.
 var publicity = [];
@@ -437,10 +437,17 @@ function updateGroupSubLink()
 
 // {{{1 Medals
 
+function prepareMedal(i)
+{
+    getMedalName($('#medal_' + i).find('[name="medals[' + i + '][id]"]').val());
+    buildGrade(i);
+}
+
 function updateMedal()
 {
     var val = $('#medals').find('[name*=medal_sel]').val();
-    if (val && ($('#medal_' + val).length == 0)) {
+
+    if ((multiple[val] && subgrades[val]) || $('.medal_name_' + val).length == 0) {
         $('#medal_add').show();
     } else {
         $('#medal_add').hide();
@@ -449,55 +456,80 @@ function updateMedal()
 
 function getMedalName(id)
 {
-    $('#medal_name_' + id).html(names[id]);
+    $('.medal_name_' + id).html(names[id]);
 }
 
-function buildGrade(id, current)
+function buildGrade(i)
 {
-    var grade;
-    var subg = subgrades[id];
-    var obj  = $('#medal_grade_' + id);
+    var id      = $('#medal_' + i).find('[name="medals[' + i + '][id]"]').val();
+    var current = $('#medal_' + i).find('[name="medals_' + i + '_grade"]').val();
+    var subg    = subgrades[id];
+    var obj     = $('#medal_grade_' + i);
     if (!subg) {
-        obj.prepend('<input type="hidden" name="medals[' + id + '][grade]" value="0" />');
+        obj.prepend('<input type="hidden" name="medals[' + i + '][grade]" value="0" />');
     } else {
-        var html = 'Agrafe : <select name="medals[' + id + '][grade]">';
+        var html = 'Agrafe : <select name="medals[' + i + '][grade]">';
         html += '<option value="0">Non précisée</option>';
-        for (grade = 0 ; grade < subg.length ; grade++) {
+        for (var grade = 0; grade < subg.length; ++grade) {
             html += '<option value="' + subg[grade][0] + '"';
             if (subg[grade][0] == current) {
                 html += ' selected="selected"';
             }
             html += '>' + subg[grade][1] + '</option>';
         }
-
         html += '</select>';
         obj.prepend(html);
     }
 }
 
-function makeAddProcess(id)
+function makeAddProcess(i, id)
 {
     return function(data)
     {
         $('#medals').after(data);
         updateMedal();
         getMedalName(id);
-        buildGrade(id, 0);
+        buildGrade(i, 0);
     };
 }
 
 function addMedal()
 {
+    var i = 0;
+    while ($('#medal_' + i).length != 0) {
+        ++i;
+    }
+
     var id = $('#medals').find('[name=medal_sel]').val();
-    $.xget('profile/ajax/medal/' + id, makeAddProcess(id));
+    $.xget('profile/ajax/medal/' + i + '/' + id, makeAddProcess(i, id));
 }
 
 function removeMedal(id)
 {
-    $("#medal_" + id).remove();
+    var total = 0;
+    while ($('#medal_' + total).length != 0) {
+        ++total;
+    }
+    $('#medal_' + id).remove();
+    for (var i = parseInt(id) + 1; i < total; ++i) {
+        renumberMedal(i);
+    }
     updateMedal();
 }
 
+function renumberMedal(i)
+{
+    var new_i = i - 1;
+
+    $('#medal_' + i).attr('id', 'medal_' + new_i);
+    $('#medal_grade_' + i).attr('id', 'medal_grade_' + new_i);
+    $('#medal_grade_' + new_i).find("[name='medals_" + i + "_grade']").attr('name', 'medals_' + new_i + '_grade');
+    $('#medal_grade_' + new_i).find("[name='medals[" + i + "][id]']").attr('name', 'medals[' + new_i + '][id]');
+    $('#medal_grade_' + new_i).find("[name='medals[" + i + "][valid]']").attr('name', 'medals[' + new_i + '][valid]');
+    $('#medal_grade_' + new_i).find("[name='medals[" + i + "][grade]']").attr('name', 'medals[' + new_i + '][grade]');
+    $('#medal_' + new_i).find('a.removeMedal').attr('href', 'javascript:removeMedal(' + new_i + ')');
+}
+
 // Jobs {{{1
 
 function removeJob(id, pref)
index 0d29063..fc77918 100644 (file)
@@ -117,11 +117,11 @@ class MedalReq extends ProfileValidate
     // }}}
     // {{{ function get_request($medal)
 
-    static public function get_request($pid, $type)
+    static public function get_request($pid, $type, $grade)
     {
         $reqs = parent::get_typed_requests($pid, 'medal');
         foreach ($reqs as &$req) {
-            if ($req->mid == $type) {
+            if ($req->mid == $type && $req->gid == $grade) {
                 return $req;
             }
         }
index e93a86f..813028c 100644 (file)
@@ -427,12 +427,12 @@ class ProfileModule extends PLModule
         require_once "education.func.inc.php";
     }
 
-    function handler_ajax_medal($page, $id)
+    function handler_ajax_medal($page, $i, $id)
     {
         pl_content_headers("text/html");
         $page->changeTpl('profile/deco.medal.tpl', NO_SKIN);
-        $page->assign('id', $id);
-        $page->assign('medal', array('valid' => 0, 'grade' => 0));
+        $page->assign('id', $i);
+        $page->assign('medal', array('id' => $id, 'grade' => 0, 'valid' => 0));
     }
 
     function handler_ajax_job($page, $id)
index e96e519..3adbafa 100644 (file)
 
 class ProfileSettingDeco implements ProfileSetting
 {
+    private static function compareMedals(array $a, array $b)
+    {
+        if ($a['id'] == $b['id']) {
+            return $a['grade'] > $b['grade'];
+        }
+        return $a['id'] > $b['id'];
+    }
+
     public function value(ProfilePage $page, $field, $value, &$success)
     {
         $success = true;
         if (is_null($value)) {
             // Fetch already attributed medals
-            $res = XDB::iterRow("SELECT  m.id AS id, s.gid AS grade
-                                   FROM  profile_medals    AS s
-                             INNER JOIN  profile_medal_enum        AS m ON ( s.mid = m.id )
-                                  WHERE  s.pid = {?}",
-                                $page->pid());
-            $value = array();
-            while (list($id, $grade) = $res->next()) {
-                $value[$id] = array('grade' => $grade,
-                                    'valid' => '1');
-            }
+            $value = XDB::fetchAllAssoc('SELECT  mid AS id, gid AS grade, 1 AS valid
+                                           FROM  profile_medals
+                                          WHERE  pid = {?}',
+                                        $page->pid());
 
             // Fetch not yet validated medals
             $medals = ProfileValidate::get_typed_requests($page->pid(), 'medal');
             foreach ($medals as &$medal) {
-                $value[$medal->mid] = array('grade' => $medal->gid,
-                                            'valid' => '0');
+                $value[] = array(
+                    'id'    => $medal->mid,
+                    'grade' => $medal->gid,
+                    'valid' => '0'
+                );
             }
-        } else if (!is_array($value)) {
+        } elseif (!is_array($value)) {
             $value = array();
         }
-        ksort($value);
+        usort($value, 'self::compareMedals');
         return $value;
     }
 
     public function save(ProfilePage $page, $field, $value)
     {
-        $orig =& $page->orig[$field];
+        $original =& $page->orig[$field];
+
+        $i = $j = 0;
+        $total_original = count($original);
+        $total_value = count($value);
 
-        // Remove old ones
-        foreach ($orig as $id=>&$val) {
-            if (!isset($value[$id]) || $val['grade'] != $value[$id]['grade']) {
-                if ($val['valid']) {
-                    XDB::execute("DELETE FROM  profile_medals
-                                        WHERE  pid = {?} AND mid = {?}",
-                                 $page->pid(), $id);
+        while ($i < $total_original || $j < $total_value) {
+            if (isset($value[$j]) && (!isset($original[$i]) || self::compareMedals($original[$i], $value[$j]))) {
+                $req = new MedalReq(S::user(), $page->profile, $value[$j]['id'], $value[$j]['grade']);
+                $req->submit();
+                sleep(1);
+                ++$j;
+            } elseif (isset($original[$i]) && (!isset($value[$j]) || self::compareMedals($value[$j], $original[$i]))) {
+                if ($original[$i]['valid']) {
+                    XDB::execute('DELETE FROM  profile_medals
+                                        WHERE  pid = {?} AND mid = {?} AND gid = {?}',
+                                 $page->pid(), $original[$i]['id'], $original[$i]['grade']);
                 } else {
-                    $req = MedalReq::get_request($page->pid(), $id);
+                    $req = MedalReq::get_request($page->pid(), $original[$i]['id'], $original[$i]['grade']);
                     if ($req) {
                         $req->clean();
                     }
                 }
-            }
-        }
-
-        // Add new ones
-        foreach ($value as $id=>&$val) {
-            if (!isset($orig[$id]) || $orig[$id]['grade'] != $val['grade']) {
-                $req = new MedalReq(S::user(), $page->profile, $id, $val['grade']);
-                $req->submit();
-                sleep(1);
+                ++$i;
+            } else {
+                ++$i;
+                ++$j;
             }
         }
     }
index daa58de..0c99ea0 100644 (file)
 
 <div id="medal_{$id}" style="clear: both; margin-top: 1em; height: 50px; vertical-align: middle">
   <div style="float: left; margin-right: 0.3em">
-    <img src="profile/medal/thumb/{$id}" height="50px" />
+    <img alt="" src="profile/medal/thumb/{$medal.id}" height="50px" />
   </div>
   <div style="float: left; width: 70%">
-    <div><b id="medal_name_{$id}"></b>
-    {if !$medal.valid}(en attente de modération){/if}</div>
-    <div id="medal_grade_{$id}"><input type="hidden" name="medals[{$id}][valid]" value="{$medal.valid}" /></div>
+    <div>
+      <b class="medal_name_{$medal.id}"></b>
+      {if !$medal.valid}(en attente de modération){/if}
+    </div>
+    <div id="medal_grade_{$id}">
+      <input type="hidden" name="medals_{$id}_grade" value="{$medal.grade}" />
+      <input type="hidden" name="medals[{$id}][id]" value="{$medal.id}" />
+      <input type="hidden" name="medals[{$id}][valid]" value="{$medal.valid}" />
+    </div>
   </div>
-  <a href="javascript:removeMedal({$id})" style="vertical-align: middle">
+  <a class="removeMedal" href="javascript:removeMedal({$id})" style="vertical-align: middle">
     {icon name="cross" title="Supprimer cette médaille"}
   </a>
-  <input type="hidden" name="medal_{$id}_grade" value="{$medal.grade}" />
 </div>
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 2d6ef9a..bc4c193 100644 (file)
@@ -22,6 +22,7 @@
 
 subgrades = new Array();
 names     = new Array();
+multiple  = new Array();
 {foreach from=$medal_list key=type item=list}
   {foreach from=$list item=m}
     names[{$m.id}] = "{$m.text|regex_replace:"/\r?\n/":"\\n"}";
@@ -31,6 +32,9 @@ names     = new Array();
         subgrades[{$m.id}][{$g.gid-1}] = [{$g.gid},"{$g.text|regex_replace:"/\r?\n/":"\\n"}"];
       {/foreach}
     {/if}
+    {if $m.type != 'ordre'}
+      multiple[{$m.id}] = true;
+    {/if}
   {/foreach}
 {/foreach}
 
diff --git a/upgrade/1.1.0/10_deco.sql b/upgrade/1.1.0/10_deco.sql
new file mode 100644 (file)
index 0000000..b892031
--- /dev/null
@@ -0,0 +1,17 @@
+DROP TABLE IF EXISTS tmp_profile_medals;
+CREATE TEMPORARY TABLE tmp_profile_medals LIKE profile_medals;
+INSERT INTO tmp_profile_medals SELECT * FROM profile_medals;
+DROP TABLE profile_medals;
+CREATE TABLE profile_medals (
+  pid INT(11) UNSIGNED NOT NULL DEFAULT 0,
+  mid INT(11) NOT NULL DEFAULT 0,
+  gid INT(11) NOT NULL DEFAULT 0,
+  PRIMARY KEY (pid, mid, gid),
+  CONSTRAINT profile_medals_ibfk_1 FOREIGN KEY (pid) REFERENCES profiles (pid) ON DELETE CASCADE ON UPDATE CASCADE
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+INSERT INTO  profile_medals (pid, mid, gid)
+     SELECT  pid, mid, gid
+       FROM  tmp_profile_medals;
+DROP TABLE IF EXISTS tmp_profile_medals;
+
+-- vim:set syntax=mysql: