LazyModalPanel

先日、Wicket で、処理中をModalWindow で表現するを書いたのですが、、
oboe2uran.hatenablog.com

処理が終わった後に、正常終了か異常終了かのメッセージを表示したい
というのを対応しようと書き直しました。
f:id:posturan:20181206220011j:plain
というのを処理完了時に出すようにします。

Wicket-Panel のHTML を以下のように修正します。
処理開始トリガになる見えないボタン wicket:id="lazy_mocal_start" id="lazy_mocal_start" と
処理終了時に見せるボタン wicket:id="lazy_mocal_close" として、ボタンラベルも span で書きます。
必要な JavaScript もここに書きます(前回は、JSファイルに分けていた)

<!DOCTYPE html>
<html xmlns:wicket="http://wicket.apache.org">
<body>
<wicket:panel>
   <form wicket:id="lazy_mocal_form" id="lazy_mocal_form" >
      <section class="lazy-modal-panel">
         <div>
            <ul>
               <li id="lazy_modal_progress_container"><div id="lazy_modal_progress"></div></li>
               <li><span wicket:id="message"></span></li>
               <li id="lazy_modal_close_container" style="display:none">
                  <button wicket:id="lazy_mocal_close" type="button"><span wicket:id="closeLabel"></span></button>
               </li>
               <li style="display:none">
                  <button wicket:id="lazy_mocal_start" id="lazy_mocal_start" type="button"></button>
               </li>
            </ul>
         </div>
      </section>
   </form>
<script type="text/javascript">
var sizefitMessageModal = function(){
   $('.w_content_container').css("height", $('.lazy-modal-panel ul').outerHeight(true) + "px" );
   $('.wicket-modal').css("width", $('.lazy-modal-panel ul').outerWidth(true) + 22 + "px" );
};
var convergementLazy = function(){
   $('#lazy_modal_progress_container').remove();
   $('#lazy_modal_close_container').removeAttr('style');
   $('.lazy-modal-panel li span').addClass('reduce');
   $('.w_content_container').css("height", $('.lazy-modal-panel ul').outerHeight(true) + "px" );
   $('.wicket-modal').css("width", $('.lazy-modal-panel ul li span').outerWidth(true) + 40 + "px" );
};
$(function(){
   new Spinner().spin(document.getElementById('lazy_modal_progress'));
   setTimeout("$('#lazy_mocal_form').parent().parent().parent().parent().parent().prev().children('a').css('display','none');",100);
});
</script>
</wicket:panel>
</body>
</html>

スタイルシート CSS は、処理終了時、spin.js によるSPINアニメーションを表示しない分、調整します
.lazy-modal-panel li span.reduce

@CHARSET "UTF-8";
/* lazymodal.css */
.lazy-modal-panel ul{
   margin: 10px 0;
   padding: 10px;
}
.lazy-modal-panel li{
	list-style-type: none;
   white-space: nowrap;
   display: flex;
   align-items: center;
   justify-content: space-around;
}
.lazy-modal-panel li span{
   margin: 40px 0 5px 0;
}
.lazy-modal-panel li span.reduce{
	margin: 5px 20px !important;
}
#lazy_modal_progress{
	position: absolute;
	margin-top: 10px;
}

Panel の Javaソース
終了時メッセージ表示しない自動で閉じる場合も、コンストラクタとして残します。
メッセージ表示するコンストラクタは、ボタンラベル文字列やボタンのスタイル class属性を
付与できるものを用意します。省略もできます。

import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.wicket.ajax.AjaxEventBehavior;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.core.util.string.JavaScriptUtils;
import org.apache.wicket.extensions.ajax.markup.html.modal.ModalWindow;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.head.CssHeaderItem;
import org.apache.wicket.markup.head.IHeaderResponse;
import org.apache.wicket.markup.head.JavaScriptHeaderItem;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Button;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.resource.CssResourceReference;
import org.apache.wicket.request.resource.JavaScriptResourceReference;
import org.danekja.java.util.function.serializable.SerializableConsumer;
import org.danekja.java.util.function.serializable.SerializableFunction;
import org.yipuran.wicketcustom.function.SerialThrowableConsumer;
/**
 * LazyModalPanel
 */
public class LazyModalPanel extends Panel{
   /**
    * コンストラクタ(自動で閉じる)
    * @param id Wicket-ID
    * @param model 処理中メッセージ
    * @param consumer 目的の処理実行する Throwableな Consumer
    *                  例外発生すると oncatch指定のConsumerが実行される
    * @param oncatch 目的の処理をするconsumerで例外を捕捉した時に実行するConsumer
    */
   public LazyModalPanel(String id, IModel<String> model
         , SerializableConsumer<AjaxRequestTarget> consumer
         , SerializableConsumer<Exception> oncatch){
      super(id, model);
      queue(new Form<Void>("lazy_mocal_form"));
      queue(new Label("message", Optional.ofNullable(model.getObject()).orElse("")));
      queue(new Label("closeLabel", ""));
      queue(new Button("lazy_mocal_start").add(AjaxEventBehavior.onEvent("click", SerialThrowableConsumer.of(t->{
         consumer.accept(t);
         ModalWindow.closeCurrent(t);
      },(t, x)->{
         oncatch.accept(x);
         ModalWindow.closeCurrent(t);
      }))));
      queue(new Button("lazy_mocal_close"));
   }
   public LazyModalPanel(String id, IModel<String> model, String closeLabel
         , SerializableFunction<AjaxRequestTarget, String> function
         , SerializableFunction<Exception, String> oncatch){
      this(id, model, closeLabel, null, function, oncatch);
   }
   public LazyModalPanel(String id, IModel<String> model
         , SerializableFunction<AjaxRequestTarget, String> function
         , SerializableFunction<Exception, String> oncatch){
      this(id, model, "OK", null, function, oncatch);
   }
   /**
    * コンストラクタ(終了後結果表示する場合)
    * @param id Wicket-ID
    * @param model 処理中メッセージ
    * @param closeLabel CLOSEボタンのラベル
    * @param stylelist CLOSEボタンに付けるclass属性、
    * @param function 目的の処理を実行して正常終了のメッセージを返す Throwable な Function
    *                  例外発生すると oncatch指定の Function が実行される
    * @param oncatch 目的の処理で例外を捕捉した時に実行する Function
    *                 表示する異常終了のメッセージを返す Function
    */
   public LazyModalPanel(String id, IModel<String> model
         , String closeLabel
         , List<String> stylelist
         , SerializableFunction<AjaxRequestTarget, String> function
         , SerializableFunction<Exception, String> oncatch){
      super(id, model);
      queue(new Form<Void>("lazy_mocal_form"));
      final Label mesageLabel = new Label("message", Optional.ofNullable(model.getObject()).orElse(""));
      mesageLabel.setEscapeModelStrings(false);
      mesageLabel.setOutputMarkupId(true);
      queue(mesageLabel);
      queue(new Label("closeLabel", closeLabel));
      queue(new Button("lazy_mocal_start")
      .add(AjaxEventBehavior.onEvent("click", SerialThrowableConsumer.of(t->{
         String s = function.apply(t);
         mesageLabel.setDefaultModelObject(Optional.ofNullable(s).orElse(null));
         t.appendJavaScript("convergementLazy();");
         t.add(mesageLabel);
      },(t, x)->{
         String s = oncatch.apply(x);
         mesageLabel.setDefaultModelObject(Optional.ofNullable(s).orElse(null));
         t.appendJavaScript("convergementLazy();");
         t.add(mesageLabel);
      }))));
      queue(new Button("lazy_mocal_close"){
         @Override
         protected void onComponentTag(ComponentTag tag){
            super.onComponentTag(tag);
            Optional.ofNullable(stylelist).filter(li->li.size() > 0).ifPresent(li->{
               tag.put("class", li.stream().collect(Collectors.joining(" ")));
            });
         }
      }.add(AjaxEventBehavior.onEvent("click", t->ModalWindow.closeCurrent(t))));
   }

   @Override
   protected void onAfterRender(){
      super.onAfterRender();
      JavaScriptUtils.writeJavaScript(getResponse()
      , "setTimeout('sizefitMessageModal();$(\"#lazy_mocal_start\").trigger(\"click\");', 100);");
   }
   @Override
   public void renderHead(IHeaderResponse response){
      super.renderHead(response);
      response.render(CssHeaderItem.forReference(
            new CssResourceReference(LazyModalPanel.class, "lazymodal.css")));
      response.render(JavaScriptHeaderItem.forReference(
            new JavaScriptResourceReference(LazyModalPanel.class, "spin.min.js")));
   }
}

処理終了でメッセージ表示する例の呼び出しコード
Arrays.asList を使えば、ボタンデザインのスタイルも簡単に記述できます
以下は、Bootstrap使用 のボタンの場合です。

final ModalWindow window = new ModalWindow("lazy_window").setResizable(true).setAutoSize(true);
queue(window);

queue(new Button("link").add(AjaxEventBehavior.onEvent("click", t->{
   window.setContent(new LazyModalPanel(window.getContentId(), Model.of("処理中...")
   , "OK", Arrays.asList("btn", "btn-primary")
   , u->{

      // 時間がかかる処理

      return "正常終了<br/>メッセージ";
   }, x->{

      // 例外捕捉

      return "異常終了";
   }));
   window.show(t);
})));

上は、Page クラスのHTMLで、wicket:head タグを以下のように書いてます。

<wicket:head>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
</wicket:head>