Palette という呼び名のコンポーネント

Wicket extension には昔から Palette なるものが存在してました。
意外にも使いやすかったのですが、あまり使うことがなく忘れてました。

前のWicketで使われてなかったjQuery で再現してみたところ、jQueryコーディング の良いトレーニングになります。

f:id:posturan:20160313174418j:plain


まず、このHTMLは、以下のとおりです。
   (optionタグは長いのでここでは省略)
======================
<div class="palette">
   <table>
      <thead><tr><th>非選択</th><th></th><th>選 択</th><th></th></tr></thead>
      <tbody>
         <tr>
            <td>
               <select id="unactiveSelections" size="20" multiple="multiple" >
                  :
               </select>

            </td>
            <td>
               <button id="shiftRight" type="button"><img src="right_arrow.png" width="28px" height="28px"></button>
               <br/><br/><br/><br/>
               <button id="shiftLeft" type="button"><img src="left_arrow.png" width="28px" height="28px"></button>
            </td>
            <td>
               <select id="activeSelections" size="20" multiple="multiple" >
                  :
               </select>

            </td>
            <td>
               <button id="upBtn" type="button"><img src="up_arrow.png" width="28px" height="28px"></button>
               <br/><br/><br/><br/>
               <button id="downBtn" type="button"><img src="down_arrow.png" width="28px" height="28px"></button>
            </td>
         </tr>
      </tbody>
   </table>
   <input type="hidden" name="unactiveList" value="1,2,3,4,5">
   <input type="hidden" name="activeList" value="11,12,13,14,15,16">

</div>

======================

次に、jQuery は、わずかこれでだけで済みます。
======================
$(function(){
   var setHiddenList = function(options, hidden){
      var a = new Array();
      $(options).each(function(){
         a.push($(this).val());
      });
      $(hidden).val(a.join(","));
   };
   $('#shiftRight').click(function(){
      $($('#unactiveSelections option:selected').get().reverse()).each(function(){
         $('#activeSelections').prepend($(this));
         $('#activeSelections').scrollTop(0);
      });
      /* hidden に結果をセット */
      setHiddenList('#unactiveSelections option', 'input[name="unactiveList"]');
      setHiddenList('#activeSelections option', 'input[name="activeList"]');

   });
   $('#shiftLeft').click(function(){
      $($('#activeSelections option:selected').get().reverse()).each(function(){
         $('#unactiveSelections').prepend($(this));
         $('#unactiveSelections').scrollTop(0);
      });
      /* hidden に結果をセット */
      setHiddenList('#unactiveSelections option', 'input[name="unactiveList"]');
      setHiddenList('#activeSelections option', 'input[name="activeList"]');

   });
   $('#upBtn').click(function(){
      $('#activeSelections option:selected').each(function(){
         if ($(this).prev() != undefined){
            $(this).after($(this).prev());
         }
      });
      /* hidden に結果をセット */
      setHiddenList('#unactiveSelections option', 'input[name="unactiveList"]');
      setHiddenList('#activeSelections option', 'input[name="activeList"]');

   });
   $('#downBtn').click(function(){
      $($('#activeSelections option:selected').get().reverse()).each(function(){
         if ($(this).prev() != undefined){
            $(this).before($(this).next());
         }
      });
      /* hidden に結果をセット */
      setHiddenList('#unactiveSelections option', 'input[name="unactiveList"]');
      setHiddenList('#activeSelections option', 'input[name="activeList"]');

   });
});

======================
選択済み、:selected フィルタで取得したリストを reverse で参照するのが重要です。
そうしないと、移動した時に並びが逆になってしまいます。

CSSは、以下のとおり。

div.palette{ margin-left: 40px; }

.palette table{
   box-sizing: border-box;
   border-spacing; 0;
   border-collapse: collapse;
   white-space: nowrap;
   width: 540px;
}
.palette th:nth-child(odd){
   background-color: #f0f8ff;
   border-top: 2px solid #0000c0;
   border-bottom: 3px double #0000c0;
}
.palette td{
   padding: 0;
}
.palette td:nth-child(1){ width: 180px; }
.palette td:nth-child(2){ width: 90px;   text-align: center; }
.palette td:nth-child(3){ width: 180px; }
.palette td:nth-child(4){ width: 90px;   text-align: center; }
.palette select{
   width: 100%;
   height: 180px;
}
.palette button{ cursor: pointer; }