This is an automated email from the ASF dual-hosted git repository.

solomax pushed a commit to branch csp
in repository https://gitbox.apache.org/repos/asf/openmeetings.git


The following commit(s) were added to refs/heads/csp by this push:
     new 7ab8f03  [OPENMEETINGS-2165] more work on confirmations and admin
7ab8f03 is described below

commit 7ab8f03c61bd14381b50b5c26e0f42de82a4e3fe
Author: Maxim Solodovnik <[email protected]>
AuthorDate: Sun Feb 9 18:31:24 2020 +0700

    [OPENMEETINGS-2165] more work on confirmations and admin
---
 .../openmeetings/web/admin/backup/BackupPanel.html |  19 +-
 .../openmeetings/web/admin/backup/BackupPanel.java |   6 +-
 .../web/admin/configurations/ConfigForm.java       |  35 +-
 .../web/admin/configurations/ConfigsPanel.html     |  61 +--
 .../web/admin/configurations/admin-config.js       |  32 ++
 .../web/admin/connection/ConnectionsPanel.java     |   2 +-
 .../openmeetings/web/admin/email/EmailForm.java    |   2 +-
 .../web/admin/groups/GroupUsersPanel.java          |   2 +-
 .../web/admin/labels/AddLanguageDialog.html        |   4 +-
 .../web/admin/labels/AddLanguageDialog.java        |  89 ++-
 .../openmeetings/web/admin/labels/LangPanel.html   |  49 +-
 .../openmeetings/web/admin/labels/LangPanel.java   |  39 +-
 .../openmeetings/web/admin/oauth/OAuthForm.java    |   2 +-
 .../openmeetings/web/admin/rooms/RoomForm.java     |   2 +-
 .../openmeetings/web/common/FormActionsPanel.java  |   1 +
 .../web/common/PagedEntityListPanel.html           |   8 +-
 .../web/common/PagedEntityListPanel.java           |  19 +-
 .../web/common/PagingNavigatorPanel.html           |   8 +-
 .../web/common/PagingNavigatorPanel.java           |  18 +-
 .../web/common/UploadableImagePanel.html           |  19 +-
 .../{ => confirmation}/ConfirmableAjaxBorder.html  |   0
 .../{ => confirmation}/ConfirmableAjaxBorder.java  |   2 +-
 .../common/confirmation/ConfirmationBehavior.java  |  84 +++
 .../common/confirmation/ConfirmationConfig.java    | 116 ++++
 .../common/confirmation/bootstrap-confirmation.js  | 597 +++++++++++++++++++++
 .../web/common/tree/FileTreePanel.java             |   4 +-
 .../web/room/sidebar/RoomFilePanel.java            |   2 +-
 .../openmeetings/web/room/sidebar/RoomSidebar.java |   4 +-
 .../openmeetings/web/user/chat/ChatToolbar.java    |   2 +-
 .../web/user/profile/EditProfileForm.html          |  53 +-
 .../web/user/profile/EditProfilePanel.html         |   2 +-
 .../web/user/profile/InvitationDetails.java        |   2 +-
 .../web/user/profile/MessagesContactsPanel.java    |   2 +-
 .../web/util/CallbackFunctionHelper.java           |   5 +-
 openmeetings-web/src/main/webapp/css/raw-admin.css |   3 -
 .../src/main/webapp/css/raw-general.css            |   2 +-
 36 files changed, 1066 insertions(+), 231 deletions(-)

diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.html
index e4b7f44..95cfa17 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.html
@@ -22,14 +22,17 @@
 <html xmlns:wicket="http://wicket.apache.org";>
 <wicket:panel>
        <div wicket:id="feedback"></div>
-       <form wicket:id="backupUpload" class="adminForm adminBackupForm">
+       <form wicket:id="backupUpload" class="adminForm adminBackupForm 
container">
                <fieldset class="ui-widget-content">
                        <legend class="ui-widget-header"><wicket:message 
key="1066" /></legend>
                        <div class="formelement">
                                <div><i class="fas fa-info-circle 
m-1"></i><wicket:message key="1065" /></div>
                        </div>
                        <div class="formelement">
-                               <label 
wicket:for="includeFilesInBackup"><wicket:message key="1537" /></label> <input 
type="checkbox" wicket:id="includeFilesInBackup" />
+                               <div class="custom-control custom-checkbox m-2">
+                                       <label class="custom-control-label" 
wicket:for="includeFilesInBackup"><wicket:message key="1537" /></label>
+                                       <input class="custom-control-input" 
type="checkbox" wicket:id="includeFilesInBackup" />
+                               </div>
                        </div>
                        <div class="formelement">
                                <span wicket:id="progress"></span>
@@ -37,14 +40,14 @@
                        </div>
                        <div class="formelement">
                                <!-- Perform Download -->
-                               <div wicket:id="download" 
class="btn"><wicket:message key="1066"/></div>
+                               <button wicket:id="download"></button>
                                <!-- Perform Upload -->
-                               <div class="fileinput fileinput-new d-inline 
m-0" data-provides="fileinput">
-                                       <span class="btn btn-file ui-button 
ui-widget ui-state-default ui-corner-all ui-button-text-only"><span
-                                               
class="ui-button-text"><wicket:message key="1536"/></span><input 
class="uploadFileField" wicket:id="fileInput" type="file"/></span>
-                               </div>
+                               <button class="fileinput fileinput-new d-inline 
m-0 btn btn-file btn-outline-primary" data-provides="fileinput">
+                                       <wicket:message key="1536"/>
+                                       <input class="uploadFileField" 
wicket:id="fileInput" type="file"/>
+                               </button>
                        </div>
-                       <div class="formelement">
+                       <div class="formelement m-2">
                                <!-- Max upload size -->
                                <wicket:message key="1491" /> <span 
wicket:id="MaxUploadSize" /><span>MB</span>
                        </div>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.java
index 0971cba..63de964 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/backup/BackupPanel.java
@@ -45,6 +45,7 @@ import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.upload.FileUpload;
 import org.apache.wicket.markup.html.form.upload.FileUploadField;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.resource.IResource;
 import org.apache.wicket.resource.FileSystemResource;
 import org.apache.wicket.spring.injection.annot.SpringBean;
@@ -52,9 +53,10 @@ import org.apache.wicket.util.lang.Bytes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.googlecode.wicket.jquery.ui.form.button.AjaxButton;
 import com.googlecode.wicket.jquery.ui.widget.progressbar.ProgressBar;
 
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
 import 
de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
 /**
  * Panel component to manage Backup Import/Export
@@ -131,7 +133,7 @@ public class BackupPanel extends AdminBasePanel {
                        });
                        add(download);
                        // add an download button
-                       add(new AjaxButton("download", this) {
+                       add(new BootstrapAjaxButton("download", new 
ResourceModel("1066"), this, Buttons.Type.Outline_Primary) {
                                private static final long serialVersionUID = 1L;
 
                                @Override
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
index 4f35c30..34eb05c 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigForm.java
@@ -29,6 +29,8 @@ import org.apache.openmeetings.web.app.WebSession;
 import org.apache.openmeetings.web.util.DateLabel;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.markup.html.WebMarkupContainer;
 import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.CheckBox;
@@ -41,6 +43,7 @@ import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.model.CompoundPropertyModel;
 import org.apache.wicket.model.IModel;
 import org.apache.wicket.model.ResourceModel;
+import org.apache.wicket.request.resource.JavaScriptResourceReference;
 import org.apache.wicket.spring.injection.annot.SpringBean;
 import org.apache.wicket.validation.IValidatable;
 import org.apache.wicket.validation.IValidator;
@@ -55,6 +58,10 @@ import org.apache.wicket.validation.ValidationError;
 public class ConfigForm extends AdminBaseForm<Configuration> {
        private static final long serialVersionUID = 1L;
        private final WebMarkupContainer listContainer;
+       private final WebMarkupContainer stringBox = new 
WebMarkupContainer("string-box");
+       private final WebMarkupContainer numberBox = new 
WebMarkupContainer("number-box");
+       private final WebMarkupContainer booleanBox = new 
WebMarkupContainer("boolean-box");
+       private final WebMarkupContainer hotkeyBox = new 
WebMarkupContainer("hotkey-box");
        private final TextArea<String> valueS = new TextArea<>("valueS");
        private final TextField<Long> valueN = new TextField<>("valueN") {
                private static final long serialVersionUID = 1L;
@@ -81,12 +88,15 @@ public class ConfigForm extends 
AdminBaseForm<Configuration> {
 
        private void update(AjaxRequestTarget target) {
                Configuration c = getModelObject();
-               valueS.setVisible(Type.STRING == c.getType());
-               valueN.setVisible(Type.NUMBER == c.getType());
-               valueB.setVisible(Type.BOOL == c.getType());
-               valueH.setVisible(Type.HOTKEY == c.getType());
+               stringBox.setVisible(Type.STRING == c.getType());
+               numberBox.setVisible(Type.NUMBER == c.getType());
+               booleanBox.setVisible(Type.BOOL == c.getType());
+               hotkeyBox.setVisible(Type.HOTKEY == c.getType());
                if (target != null) {
-                       target.add(valueS, valueN, valueB, valueH);
+                       target.add(stringBox, numberBox, booleanBox, hotkeyBox);
+                       if (Type.HOTKEY == c.getType()) {
+                               
target.appendJavaScript("addOmAdminConfigHandlers()");
+                       }
                }
        }
 
@@ -145,10 +155,11 @@ public class ConfigForm extends 
AdminBaseForm<Configuration> {
                                }
                        }
                }));
-               add(valueS.setLabel(new 
ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
-               add(valueN.setLabel(new 
ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
-               add(valueB.setLabel(new 
ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
-               add(valueH.setLabel(new 
ResourceModel("271")).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true));
+               stringBox.add(valueS.setLabel(new 
ResourceModel("271"))).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
+               numberBox.add(valueN.setLabel(new 
ResourceModel("271"))).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
+               booleanBox.add(valueB.setLabel(new 
ResourceModel("271"))).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
+               hotkeyBox.add(valueH.setLabel(new 
ResourceModel("271"))).setOutputMarkupId(true).setOutputMarkupPlaceholderTag(true);
+               add(stringBox, numberBox, booleanBox, hotkeyBox);
        }
 
        @Override
@@ -188,4 +199,10 @@ public class ConfigForm extends 
AdminBaseForm<Configuration> {
                target.add(listContainer);
                refresh(target);
        }
+
+       @Override
+       public void renderHead(IHeaderResponse response) {
+               super.renderHead(response);
+               response.render(JavaScriptHeaderItem.forReference(new 
JavaScriptResourceReference(ConfigForm.class, "admin-config.js")));
+       }
 }
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
index 6833e71..8054a67 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/ConfigsPanel.html
@@ -20,32 +20,6 @@
 -->
 <!DOCTYPE html>
 <html xmlns:wicket="http://wicket.apache.org";>
-<wicket:head>
-       <script>
-               function configHandleKey(evt) {
-                       const inp = $(evt.target);
-                       evt.preventDefault();
-                       let val = '';
-                       if (evt.ctrlKey) {
-                               val += 'Ctrl+';
-                       }
-                       if (evt.altKey) {
-                               val += 'Alt+';
-                       }
-                       if (evt.shiftKey) {
-                               val += 'Shift+';
-                       }
-                       const code = OmUtil.getKeyCode(evt);
-                       if (typeof(code) === 'undefined') {
-                               return;
-                       }
-                       val += code;
-                       if (evt.keyCode !== 16 && evt.keyCode !== 17 && 
evt.keyCode !== 18 && inp.length == 1) {
-                               inp.val(val);
-                       }
-               }
-       </script>
-</wicket:head>
 <wicket:extend>
        <div class="adminPanelColumnTable">
                <div class="adminNav" wicket:id="navigator">[dataview 
navigator]</div>
@@ -73,22 +47,24 @@
                                <fieldset class="ui-widget-content">
                                        <legend 
class="ui-widget-header"><wicket:message key="266" /></legend>
                                        <div class="formelement">
-                                               <label 
wicket:for="type"><wicket:message key="45" /></label><select 
wicket:id="type"></select>
+                                               <label wicket:for="type" 
class="col-3 text-right"><wicket:message key="45" /></label>
+                                               <select class="custom-select 
col-8" wicket:id="type"></select>
                                        </div>
                                        <div class="formelement">
-                                               <label 
wicket:for="key"><wicket:message key="265" /></label><input type="text" 
wicket:id="key"/>
+                                               <label wicket:for="key" 
class="col-3 text-right"><wicket:message key="265" /></label>
+                                               <input class="col-8" 
type="text" wicket:id="key"/>
                                        </div>
                                        <div class="formelement">
-                                               <div wicket:enclosure="valueS">
-                                                       <label 
wicket:for="valueS"><wicket:message key="271" /></label>
-                                                       <textarea 
wicket:id="valueS"/>
+                                               <div wicket:id="string-box">
+                                                       <label 
wicket:for="valueS" class="col-3 text-right"><wicket:message key="271" 
/></label>
+                                                       <textarea class="col-8" 
wicket:id="valueS"/>
                                                </div>
-                                               <div wicket:enclosure="valueN">
-                                                       <label 
wicket:for="valueN"><wicket:message key="271" /></label>
-                                                       <input type="number" 
wicket:id="valueN"/>
+                                               <div wicket:id="number-box">
+                                                       <label 
wicket:for="valueN" class="col-3 text-right"><wicket:message key="271" 
/></label>
+                                                       <input class="col-8" 
type="number" wicket:id="valueN"/>
                                                </div>
-                                               <div wicket:enclosure="valueB">
-                                                       <label 
wicket:for="valueB"><wicket:message key="271" /></label>
+                                               <div wicket:id="boolean-box">
+                                                       <label 
wicket:for="valueB" class="col-3 text-right"><wicket:message key="271" 
/></label>
                                                        <div 
class="onoffswitch">
                                                                <input 
type="checkbox" class="onoffswitch-checkbox" wicket:id="valueB">
                                                                <label 
class="onoffswitch-label" wicket:for="valueB">
@@ -100,19 +76,20 @@
                                                                </label>
                                                        </div>
                                                </div>
-                                               <div wicket:enclosure="value">
-                                                       <label 
wicket:for="value"><wicket:message key="271" /></label>
-                                                       <input type="text" 
onkeydown="configHandleKey(event)" onpaste="return false;" wicket:id="value"/>
+                                               <div wicket:id="hotkey-box">
+                                                       <label 
wicket:for="value" class="col-3 text-right"><wicket:message key="271" /></label>
+                                                       <input type="text" 
class="hotkey-input" wicket:id="value"/>
                                                </div>
                                        </div>
                                        <div class="formelement">
-                                               <label><wicket:message 
key="268" /></label><span wicket:id="updated"/>
+                                               <label class="col-3 
text-right"><wicket:message key="268" /></label><span wicket:id="updated"/>
                                        </div>
                                        <div class="formelement">
-                                               <label><wicket:message 
key="269" /></label><span wicket:id="user.login"/>
+                                               <label class="col-3 
text-right"><wicket:message key="269" /></label><span wicket:id="user.login"/>
                                        </div>
                                        <div class="formelement">
-                                               <label 
wicket:for="comment"><wicket:message key="196" /></label><textarea 
wicket:id="comment"/>
+                                               <label class="col-3 text-right" 
wicket:for="comment"><wicket:message key="196" /></label>
+                                               <textarea class="col-8" 
wicket:id="comment"/>
                                        </div>
                                </fieldset>
                                <div class="bottom-bumper"></div>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/admin-config.js
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/admin-config.js
new file mode 100644
index 0000000..edaf85f
--- /dev/null
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/configurations/admin-config.js
@@ -0,0 +1,32 @@
+/* Licensed under the Apache License, Version 2.0 (the "License") 
http://www.apache.org/licenses/LICENSE-2.0 */
+function addOmAdminConfigHandlers() {
+       $('.hotkey-input')
+               .off()
+               .on('keydown', function(evt) {
+                       const inp = $(evt.target);
+                       evt.preventDefault();
+                       let val = '';
+                       if (evt.ctrlKey) {
+                               val += 'Ctrl+';
+                       }
+                       if (evt.altKey) {
+                               val += 'Alt+';
+                       }
+                       if (evt.shiftKey) {
+                               val += 'Shift+';
+                       }
+                       const code = OmUtil.getKeyCode(evt);
+                       if (typeof(code) === 'undefined') {
+                               return;
+                       }
+                       val += code;
+                       if (evt.keyCode !== 16 && evt.keyCode !== 17 && 
evt.keyCode !== 18 && inp.length == 1) {
+                               inp.val(val);
+                       }
+               })
+               .on('paste', function(e) {
+                       e.preventDefault();
+                       e.stopImmediatePropagation();
+                       return false;
+               });
+}
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
index b939d94..b3576ea 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/connection/ConnectionsPanel.java
@@ -34,6 +34,7 @@ import org.apache.openmeetings.web.admin.AdminBasePanel;
 import org.apache.openmeetings.web.admin.SearchableDataView;
 import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.common.PagedEntityListPanel;
+import org.apache.openmeetings.web.common.confirmation.ConfirmationBehavior;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.ajax.AjaxEventBehavior;
@@ -47,7 +48,6 @@ import org.apache.wicket.spring.injection.annot.SpringBean;
 
 import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxLink;
 import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
-import 
de.agilecoders.wicket.extensions.markup.html.bootstrap.confirmation.ConfirmationBehavior;
 
 public class ConnectionsPanel extends AdminBasePanel {
        private static final long serialVersionUID = 1L;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/email/EmailForm.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/email/EmailForm.java
index ce8c603..694c54d 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/email/EmailForm.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/email/EmailForm.java
@@ -20,7 +20,7 @@ package org.apache.openmeetings.web.admin.email;
 
 import org.apache.openmeetings.db.dao.basic.MailMessageDao;
 import org.apache.openmeetings.db.entity.basic.MailMessage;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.util.DateLabel;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupUsersPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupUsersPanel.java
index 708ad90..ae62611 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupUsersPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/groups/GroupUsersPanel.java
@@ -29,8 +29,8 @@ import org.apache.openmeetings.db.entity.user.GroupUser;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.web.admin.SearchableDataView;
 import org.apache.openmeetings.web.app.WebSession;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.common.PagedEntityListPanel;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.ajax.AjaxRequestTarget;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.html
index 7ae57de..58ba925 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.html
@@ -20,7 +20,7 @@
 -->
 <!DOCTYPE html>
 <html xmlns:wicket="http://wicket.apache.org";>
-<wicket:panel>
+<wicket:extend>
        <form wicket:id="addLangForm">
                <div wicket:id="feedback"></div>
                <table>
@@ -30,5 +30,5 @@
                        </tr>
                </table>
        </form>
-</wicket:panel>
+</wicket:extend>
 </html>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.java
index 2651058..c4d2586 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/AddLanguageDialog.java
@@ -18,9 +18,7 @@
  */
 package org.apache.openmeetings.web.admin.labels;
 
-import java.util.Arrays;
 import java.util.IllformedLocaleException;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
@@ -30,26 +28,55 @@ import 
org.apache.wicket.core.request.handler.IPartialPageRequestHandler;
 import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.RequiredTextField;
 import org.apache.wicket.model.Model;
+import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.validation.IValidatable;
 import org.apache.wicket.validation.IValidator;
 import org.apache.wicket.validation.ValidationError;
 
-import com.googlecode.wicket.jquery.ui.widget.dialog.AbstractFormDialog;
-import com.googlecode.wicket.jquery.ui.widget.dialog.DialogButton;
-
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
 import 
de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
+import de.agilecoders.wicket.core.markup.html.bootstrap.dialog.Modal;
 
-public class AddLanguageDialog extends AbstractFormDialog<String> {
+public class AddLanguageDialog extends Modal<String> {
        private static final long serialVersionUID = 1L;
        private final NotificationPanel feedback = new 
NotificationPanel("feedback");
-       private DialogButton add;
        private final Form<Void> form = new Form<>("addLangForm");
        private final RequiredTextField<String> iso = new 
RequiredTextField<>("iso", Model.of(""));
        private final LangPanel langPanel;
 
        public AddLanguageDialog(String id, final LangPanel langPanel) {
-               super(id, "");
+               super(id);
                this.langPanel = langPanel;
+       }
+
+       @Override
+       protected void onInitialize() {
+               header(new ResourceModel("362"));
+               setCloseOnEscapeKey(true);
+               setBackdrop(Backdrop.STATIC);
+
+               addButton(new BootstrapAjaxButton("button", new 
ResourceModel("366"), form, Buttons.Type.Outline_Primary) {
+                       private static final long serialVersionUID = 1L;
+
+                       @Override
+                       protected void onSubmit(AjaxRequestTarget target) {
+                               try {
+                                       
LabelDao.add(Locale.forLanguageTag(iso.getModelObject()));
+                                       
langPanel.getLangForm().updateLanguages(target);
+                                       AddLanguageDialog.this.close(target);
+                               } catch (Exception e) {
+                                       error("Failed to add, " + 
e.getMessage());
+                                       target.add(feedback);
+                               }
+                       }
+
+                       @Override
+                       protected void onError(AjaxRequestTarget target) {
+                               target.add(feedback);
+                       }
+               });
+
                add(form.add(feedback.setOutputMarkupId(true), 
iso.setOutputMarkupId(true)));
                iso.add(new IValidator<String>() {
                        private static final long serialVersionUID = 1L;
@@ -57,9 +84,9 @@ public class AddLanguageDialog extends 
AbstractFormDialog<String> {
                        @Override
                        public void validate(IValidatable<String> s) {
                                try {
-                                       new 
Locale.Builder().setLanguageTag(s.getValue());
+                                       new 
Locale.Builder().setLanguageTag(s.getValue()).build();
                                } catch (IllformedLocaleException e) {
-                                       s.error(new ValidationError("Invalid 
code, please use "));
+                                       s.error(new ValidationError("Invalid 
code, please specify valid ISO code"));
                                        return;
                                }
                                Locale l = Locale.forLanguageTag(s.getValue());
@@ -71,51 +98,13 @@ public class AddLanguageDialog extends 
AbstractFormDialog<String> {
                                }
                        }
                });
-       }
-
-       @Override
-       protected void onInitialize() {
-               add = new DialogButton("add", getString("366"));
-               getTitle().setObject(getString("362"));
                super.onInitialize();
        }
 
        @Override
-       public Form<?> getForm() {
-               return form;
-       }
-
-       @Override
-       protected List<DialogButton> getButtons() {
-               return Arrays.asList(add);
-       }
-
-       @Override
-       public DialogButton getSubmitButton() {
-               return add;
-       }
-
-       @Override
-       protected void onOpen(IPartialPageRequestHandler handler) {
+       public Modal<String> show(IPartialPageRequestHandler handler) {
                iso.setModelObject("");
                handler.add(iso);
-               super.onOpen(handler);
-       }
-
-       @Override
-       protected void onError(AjaxRequestTarget target, DialogButton btn) {
-               target.add(feedback);
-       }
-
-       @Override
-       protected void onSubmit(AjaxRequestTarget target, DialogButton btn) {
-               try {
-                       
LabelDao.add(Locale.forLanguageTag(iso.getModelObject()));
-                       langPanel.getLangForm().updateLanguages(target);
-                       
target.appendJavaScript("$('#addLanguage').dialog('close');");
-               } catch (Exception e) {
-                       error("Failed to add, " + e.getMessage());
-                       target.add(feedback);
-               }
+               return super.show(handler);
        }
 }
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.html
index 0b4a985..2242030 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.html
@@ -34,32 +34,25 @@
 <wicket:extend>
        <div wicket:id="feedback"></div>
        <div class="adminPanelColumnTable label">
-               <div class="lblNav">
-                       <div class="ui-button ui-widget ui-corner-all 
ui-button-icon-only mt-n2" wicket:id="addLangBtn" wicket:message="title:362">
-                               <span class="ui-button-icon ui-icon 
ui-icon-plusthick"></span>&nbsp;
+               <form wicket:id="langForm" class="addLanguagePanel">
+                       <div class="input-group input-group-sm">
+                               <div class="input-group-prepend">
+                                       <button class="btn btn-outline-success" 
wicket:id="addLangBtn" wicket:message="title:362">
+                                               <i class="fas fa-plus"></i>
+                                       </button>
+                                       <button wicket:id="deleteLangBtn" 
wicket:message="title:363"></button>
+                               </div>
+                               <select wicket:id="language" 
class="form-control"></select>
+                               <div class="input-group-append">
+                                       <button wicket:id="export"></button>
+                                       <button class="fileupload 
fileupload-new m-0 btn btn-file btn-xs btn-primary" data-provides="fileupload">
+                                               <wicket:message key="387"/>
+                                               <input type="file" 
accept="text/xml" wicket:id="fileInput"/>
+                                       </button>
+                                       <span 
wicket:id="progress">[progressbar]</span>
+                               </div>
                        </div>
-                       <div class="ui-button ui-widget ui-corner-all 
ui-button-icon-only ui-state-error mt-n2" wicket:id="deleteLangBtn" 
wicket:message="title:363">
-                               <span class="ui-button-icon ui-icon 
ui-icon-closethick"></span>&nbsp;
-                       </div>
-                       <form wicket:id="langForm" class="addLanguagePanel">
-                               <table>
-                                       <tr>
-                                               <td>
-                                                       <select 
wicket:id="language"></select>
-                                               </td>
-                                               <td>
-                                                       <span 
wicket:id="export" class="btn"><wicket:message key="360"/></span>
-                                               </td>
-                                               <td>
-                                                       <div class="fileupload 
fileupload-new m-0" data-provides="fileupload">
-                                                               <span 
class="btn btn-file ui-button ui-widget ui-state-default ui-corner-all 
ui-button-text-only"><span class="ui-button-text"><wicket:message 
key="387"/></span><input type="file" accept="text/xml" 
wicket:id="fileInput"/></span>
-                                                       </div>
-                                                       <span 
wicket:id="progress">[progressbar]</span>
-                                               </td>
-                                       </tr>
-                               </table>
-                       </form>
-               </div>
+               </form>
                <div class="adminNav" wicket:id="navigator">[dataview 
navigator]</div>
                <table class="list-table table-striped table-hover">
                        <thead>
@@ -83,10 +76,12 @@
                                <fieldset class="ui-widget-content">
                                        <legend 
class="ui-widget-header"><wicket:message key="353" /></legend>
                                        <div class="formelement">
-                                               <label 
wicket:for="key"><wicket:message key="165" /></label><input type="text" 
wicket:id="key"/>
+                                               <label wicket:for="key" 
class="col-3 text-right"><wicket:message key="165" /></label>
+                                               <input type="text" 
wicket:id="key" class="col-8"/>
                                        </div>
                                        <div class="formelement">
-                                               <label 
wicket:for="value"><wicket:message key="271" /></label><textarea 
wicket:id="value"></textarea>
+                                               <label wicket:for="value" 
class="col-3 text-right"><wicket:message key="271" /></label>
+                                               <textarea wicket:id="value" 
class="col-8"></textarea>
                                        </div>
                                </fieldset>
                                <div class="bottom-bumper"></div>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.java
index 1ed3931..1fc8087 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/labels/LangPanel.java
@@ -36,11 +36,11 @@ import org.apache.openmeetings.web.admin.AdminBasePanel;
 import org.apache.openmeetings.web.admin.SearchableDataView;
 import org.apache.openmeetings.web.app.Application;
 import org.apache.openmeetings.web.common.BasePanel;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.common.PagedEntityListPanel;
 import org.apache.openmeetings.web.data.DataViewContainer;
 import org.apache.openmeetings.web.data.OmOrderByBorder;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
+import org.apache.openmeetings.web.util.CallbackFunctionHelper;
 import org.apache.openmeetings.web.util.upload.BootstrapFileUploadBehavior;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.ajax.AjaxEventBehavior;
@@ -55,6 +55,7 @@ import org.apache.wicket.markup.html.basic.Label;
 import org.apache.wicket.markup.html.form.upload.FileUpload;
 import org.apache.wicket.markup.html.form.upload.FileUploadField;
 import org.apache.wicket.markup.repeater.Item;
+import org.apache.wicket.model.ResourceModel;
 import org.apache.wicket.request.resource.ResourceStreamResource;
 import org.apache.wicket.util.resource.AbstractResourceStream;
 import org.apache.wicket.util.resource.IResourceStream;
@@ -62,9 +63,11 @@ import 
org.apache.wicket.util.resource.ResourceStreamNotFoundException;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.googlecode.wicket.jquery.ui.form.button.AjaxButton;
-
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton;
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxLink;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
 import 
de.agilecoders.wicket.core.markup.html.bootstrap.common.NotificationPanel;
+import 
de.agilecoders.wicket.extensions.markup.html.bootstrap.icon.FontAwesome5IconType;
 
 /**
  * Language Editor, add/insert/update Label and add/delete language contains 
several Forms and one list
@@ -157,13 +160,13 @@ public class LangPanel extends AdminBasePanel {
 
                        @Override
                        protected void onSubmit(AjaxRequestTarget target) {
-                               FileUpload download = 
fileUploadField.getFileUpload();
+                               FileUpload upload = 
fileUploadField.getFileUpload();
                                try {
-                                       if (download == null || 
download.getInputStream() == null) {
+                                       if (upload == null || 
upload.getInputStream() == null) {
                                                feedback.error("File is empty");
                                                return;
                                        }
-                                       LabelDao.upload(language.getValue(), 
download.getInputStream());
+                                       LabelDao.upload(language.getValue(), 
upload.getInputStream());
                                } catch (Exception e) {
                                        log.error("Exception on panel language 
editor import ", e);
                                        feedback.error(e);
@@ -213,37 +216,30 @@ public class LangPanel extends AdminBasePanel {
                });
                langForm.add(download);
 
-               langForm.add(new AjaxButton("export"){
+               langForm.add(new BootstrapAjaxLink<String>("export", null, 
Buttons.Type.Outline_Primary, new ResourceModel("360")) {
                        private static final long serialVersionUID = 1L;
 
                        @Override
-                       protected void onSubmit(AjaxRequestTarget target) {
+                       public void onClick(AjaxRequestTarget target) {
                                download.initiate(target);
 
                                // repaint the feedback panel so that it is 
hidden
                                target.add(feedback);
                        }
-
-                       @Override
-                       protected void onError(AjaxRequestTarget target) {
-                               // repaint the feedback panel so errors are 
shown
-                               target.add(feedback);
-                       }
-
                });
 
-               add(langForm);
                final AddLanguageDialog addLang = new 
AddLanguageDialog("addLang", this);
-               add(addLang, new AjaxLink<Void>("addLangBtn") {
+               add(langForm, addLang);
+               langForm.add(new AjaxLink<Void>("addLangBtn") {
                        private static final long serialVersionUID = 1L;
 
                        @Override
                        public void onClick(AjaxRequestTarget target) {
-                               addLang.open(target);
+                               addLang.show(target);
                        }
                });
                add(BootstrapFileUploadBehavior.INSTANCE);
-               add(new ConfirmableAjaxBorder("deleteLangBtn", getString("80"), 
getString("833")) {
+               final BootstrapAjaxButton delLngBtn = new 
BootstrapAjaxButton("deleteLangBtn", Buttons.Type.Outline_Danger) {
                        private static final long serialVersionUID = 1L;
 
                        @Override
@@ -254,13 +250,16 @@ public class LangPanel extends AdminBasePanel {
                                langForm.updateLanguages(target);
                                target.add(listContainer);
                        }
-               });
+               };
+               langForm.add(delLngBtn.setIconType(FontAwesome5IconType.times_s)
+                               
.add(CallbackFunctionHelper.newOkCancelDangerConfirm(this, getString("833"))));
                super.onInitialize();
        }
 
        @Override
        public BasePanel onMenuPanelLoad(IPartialPageRequestHandler handler) {
                reinitJs(handler);
+               super.onMenuPanelLoad(handler);
                return this;
        }
 
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthForm.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthForm.java
index 67e64ac..b4c81fe 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthForm.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/oauth/OAuthForm.java
@@ -32,7 +32,7 @@ import org.apache.openmeetings.db.entity.server.OAuthServer;
 import org.apache.openmeetings.db.entity.server.OAuthServer.RequestInfoMethod;
 import org.apache.openmeetings.db.entity.server.OAuthServer.RequestTokenMethod;
 import org.apache.openmeetings.web.admin.AdminBaseForm;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
index 722b33a..c23fcb0 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/admin/rooms/RoomForm.java
@@ -49,7 +49,7 @@ import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.web.admin.AdminBaseForm;
 import org.apache.openmeetings.web.admin.AdminUserChoiceProvider;
 import org.apache.openmeetings.web.app.ClientManager;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.util.RestrictiveChoiceProvider;
 import org.apache.openmeetings.web.util.RoomTypeDropDown;
 import org.apache.wicket.AttributeModifier;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/FormActionsPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/FormActionsPanel.java
index 2209faa..4706743 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/FormActionsPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/FormActionsPanel.java
@@ -18,6 +18,7 @@
  */
 package org.apache.openmeetings.web.common;
 
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.ajax.markup.html.form.AjaxButton;
 import org.apache.wicket.markup.html.form.Form;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.html
index 8928203..fed18cf 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.html
@@ -23,8 +23,12 @@
 <wicket:panel>
        <div wicket:id="pagedPanel" class="pagedEntityListPanel"></div>
        <form wicket:id="searchForm" class="searchForm">
-               <input type="text" wicket:id="searchText" 
wicket:message="title:714"/>
-               <input type="submit" wicket:id="search" 
wicket:message="value:714"/>
+               <div class="input-group input-group-sm">
+                       <input type="text" wicket:id="searchText" 
wicket:message="title:714" class="form-control"/>
+                       <div class="input-group-append">
+                               <button wicket:id="search"></button>
+                       </div>
+               </div>
        </form>
 </wicket:panel>
 </html>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.java
index bbb1192..fb82c81 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagedEntityListPanel.java
@@ -18,9 +18,6 @@
  */
 package org.apache.openmeetings.web.common;
 
-import java.util.Arrays;
-import java.util.List;
-
 import org.apache.openmeetings.db.entity.IDataProviderEntity;
 import org.apache.openmeetings.web.admin.SearchableDataView;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
@@ -29,17 +26,25 @@ import org.apache.wicket.markup.html.form.Form;
 import org.apache.wicket.markup.html.form.TextField;
 import org.apache.wicket.markup.html.panel.Panel;
 import org.apache.wicket.model.PropertyModel;
+import org.apache.wicket.model.ResourceModel;
 
-import com.googlecode.wicket.jquery.ui.form.button.AjaxButton;
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.button.BootstrapAjaxButton;
+import de.agilecoders.wicket.core.markup.html.bootstrap.button.Buttons;
 
 public abstract class PagedEntityListPanel extends Panel {
        private static final long serialVersionUID = 1L;
-       private List<Integer> numbers = Arrays.asList(10, 25, 50, 75, 100, 200);
+       private final SearchableDataView<? extends IDataProviderEntity> 
dataView;
 
        public PagedEntityListPanel(String id, final SearchableDataView<? 
extends IDataProviderEntity> dataView) {
                super(id);
+               this.dataView = dataView;
+       }
+
+       @Override
+       protected void onInitialize() {
+               super.onInitialize();
 
-               final PagingNavigatorPanel navPanel = new 
PagingNavigatorPanel("pagedPanel", dataView, numbers) {
+               final PagingNavigatorPanel navPanel = new 
PagingNavigatorPanel("pagedPanel", dataView) {
                        private static final long serialVersionUID = 1L;
 
                        @Override
@@ -52,7 +57,7 @@ public abstract class PagedEntityListPanel extends Panel {
                Form<Void> searchForm = new Form<>("searchForm");
                add(searchForm.setOutputMarkupId(true));
                searchForm.add(new TextField<>("searchText", new 
PropertyModel<String>(dp, "search")).setOutputMarkupId(true));
-               AjaxButton b = new AjaxButton("search", searchForm) {
+               BootstrapAjaxButton b = new BootstrapAjaxButton("search", new 
ResourceModel("714"), searchForm, Buttons.Type.Outline_Primary) {
                        private static final long serialVersionUID = 1L;
 
                        @Override
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.html
index d8ce878..6e59ce9 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.html
@@ -22,8 +22,12 @@
 <html xmlns:wicket="http://wicket.apache.org";>
 <wicket:panel>
        <form wicket:id="pagingForm" class="pagedEntityListPanel">
-               <select wicket:id="entitiesPerPage"></select> <span
-                       wicket:id="navigator" class="pagination 
pagination-sm">[dataview navigator]</span>
+               <div class="input-group input-group-sm">
+                       <select wicket:id="entitiesPerPage" 
class="form-control"></select>
+                       <div class="input-group-append">
+                               <span wicket:id="navigator" class="mt-1 
pagination pagination-sm">[dataview navigator]</span>
+                       </div>
+               </div>
        </form>
 </wicket:panel>
 </html>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.java
index b061a72..8a01bf7 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/PagingNavigatorPanel.java
@@ -18,6 +18,7 @@
  */
 package org.apache.openmeetings.web.common;
 
+import java.util.Arrays;
 import java.util.List;
 
 import org.apache.wicket.ajax.AjaxRequestTarget;
@@ -31,15 +32,24 @@ import org.apache.wicket.model.PropertyModel;
 public abstract class PagingNavigatorPanel extends Panel {
        private static final long serialVersionUID = 1L;
        private int entitiesPerPage;
+       private final DataView<?> dataView;
+       private final List<Integer> numbers;
 
-       public PagingNavigatorPanel(String id, final DataView<?> dataView, 
List<Integer> numbers) {
-               this(id, dataView, numbers, 50);
+       public PagingNavigatorPanel(String id, final DataView<?> dataView) {
+               this(id, dataView, Arrays.asList(10, 25, 50, 75, 100, 200), 50);
        }
 
-       public PagingNavigatorPanel(String id, final DataView<?> dataView, 
List<Integer> numbers, int _entitiesPerPage) {
+       public PagingNavigatorPanel(String id, final DataView<?> dataView, 
List<Integer> numbers, int entitiesPerPage) {
                super(id);
                setOutputMarkupId(true);
-               this.entitiesPerPage = _entitiesPerPage;
+               this.entitiesPerPage = entitiesPerPage;
+               this.dataView = dataView;
+               this.numbers = numbers;
+       }
+
+       @Override
+       protected void onInitialize() {
+               super.onInitialize();
                dataView.setItemsPerPage(entitiesPerPage);
                final Form<Void> f = new Form<>("pagingForm");
                f.add(new OmPagingNavigator("navigator", 
dataView).setOutputMarkupId(true))
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/UploadableImagePanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/UploadableImagePanel.html
index 5e9a3bf..5caf8ce 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/UploadableImagePanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/UploadableImagePanel.html
@@ -24,10 +24,19 @@
        <button type="button" class="btn btn-xs btn-secondary remove" 
wicket:id="remove">
                <span aria-hidden="true">×</span>
        </button>
-       <form wicket:id="form" class="img-upload"><div
-               class="fileinput fileinput-new m-0" 
data-provides="fileinput"><div
-               class="fileinput-preview" data-trigger="fileinput"><img 
wicket:id="img"/></div><div><span
-               class="btn btn-file btn btn-xs btn-primary"><wicket:message 
key="379"/><input
-               type="file" accept="image/*" 
wicket:id="image"/></span></div></div><span 
wicket:id="progress">[progressbar]</span></form>
+       <form wicket:id="form" class="img-upload">
+               <div class="fileinput fileinput-new m-0" 
data-provides="fileinput">
+                       <div class="fileinput-preview" data-trigger="fileinput">
+                               <img wicket:id="img"/>
+                       </div>
+                       <div>
+                               <span class="btn btn-file btn-xs btn-primary">
+                                       <wicket:message key="379"/>
+                                       <input type="file" accept="image/*" 
wicket:id="image"/>
+                               </span>
+                       </div>
+               </div>
+               <span wicket:id="progress">[progressbar]</span>
+       </form>
 </wicket:extend>
 </html>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/ConfirmableAjaxBorder.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmableAjaxBorder.html
similarity index 100%
rename from 
openmeetings-web/src/main/java/org/apache/openmeetings/web/common/ConfirmableAjaxBorder.html
rename to 
openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmableAjaxBorder.html
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/ConfirmableAjaxBorder.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmableAjaxBorder.java
similarity index 99%
rename from 
openmeetings-web/src/main/java/org/apache/openmeetings/web/common/ConfirmableAjaxBorder.java
rename to 
openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmableAjaxBorder.java
index 6cb08fc..f48f701 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/ConfirmableAjaxBorder.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmableAjaxBorder.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.openmeetings.web.common;
+package org.apache.openmeetings.web.common.confirmation;
 
 import static org.apache.openmeetings.web.common.BasePanel.EVT_CLICK;
 
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationBehavior.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationBehavior.java
new file mode 100644
index 0000000..bd5bcfd
--- /dev/null
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationBehavior.java
@@ -0,0 +1,84 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.common.confirmation;
+
+import static de.agilecoders.wicket.jquery.JQuery.$;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.JavaScriptHeaderItem;
+import org.apache.wicket.resource.JQueryPluginResourceReference;
+import org.apache.wicket.util.lang.Args;
+
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.behavior.BootstrapJavascriptBehavior;
+import de.agilecoders.wicket.core.util.References;
+
+/**
+ * A behavior that shows a popover with OK/Cancel buttons to confirm an action.
+ * @since 0.9.12
+ */
+public class ConfirmationBehavior extends BootstrapJavascriptBehavior {
+    /** serialVersionUID. */
+    private static final long serialVersionUID = 1L;
+    /** Configuration. */
+    private final ConfirmationConfig config;
+    /** Jquery Selector (if you don't want to use the one of the component for 
singleton for example). */
+    private final String selector;
+
+    /**
+     * Constructor that uses the default configuration
+     */
+    public ConfirmationBehavior() {
+        this(null, new ConfirmationConfig());
+    }
+
+    /**
+     * Constructor that uses a custom configuration
+     * @param config configuration to use
+     */
+    public ConfirmationBehavior(ConfirmationConfig config) {
+        this(null, config);
+    }
+
+    /**
+     * Constructor that uses a custom configuration
+     * @param config configuration to use
+     * @param selector Jquery selector to use instead of the one of the 
component (for singleton's option)
+     */
+    public ConfirmationBehavior(String selector, ConfirmationConfig config) {
+        this.config = Args.notNull(config, "config");
+        this.selector = selector;
+    }
+
+    @Override
+    public void renderHead(Component component, IHeaderResponse response) {
+        super.renderHead(component, response);
+
+        References.renderWithFilter(response, 
JavaScriptHeaderItem.forReference(new 
JQueryPluginResourceReference(ConfirmationBehavior.class, 
"bootstrap-confirmation.js")));
+
+
+        if (selector == null) {
+            config.withRootSelector(component.getMarkupId());
+            response.render($(component).chain("confirmation", 
config).asDomReadyScript());
+        } else {
+            config.withRootSelector(selector);
+            response.render($(selector).chain("confirmation", 
config).asDomReadyScript());
+        }
+    }
+}
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationConfig.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationConfig.java
new file mode 100644
index 0000000..0a6c94f
--- /dev/null
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/ConfirmationConfig.java
@@ -0,0 +1,116 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License") +  you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.openmeetings.web.common.confirmation;
+
+import org.apache.wicket.util.lang.Args;
+
+import 
de.agilecoders.wicket.core.markup.html.bootstrap.components.TooltipConfig;
+import de.agilecoders.wicket.jquery.AbstractConfig;
+import de.agilecoders.wicket.jquery.IKey;
+import de.agilecoders.wicket.jquery.Key;
+
+/**
+ * The configuration of {@link ConfirmationBehavior}.
+ * <br/>
+ * See <a 
href="http://mistic100.github.io/Bootstrap-Confirmation/#usage";>Bootstrap 
Confirmation usage</a>
+ * for all possible options and their meaning.
+ */
+public class ConfirmationConfig extends AbstractConfig {
+    private static final long serialVersionUID = 1L;
+    private static final IKey<String> Title = new Key<>("title", "Are you 
sure?");
+    private static final IKey<Boolean> Singleton = new Key<>("singleton", 
Boolean.FALSE);
+    private static final IKey<Boolean> Popout = new Key<>("popout", 
Boolean.FALSE);
+    private static final IKey<String> BtnOkClass = new Key<>("btnOkClass", 
"btn-xs btn-primary");
+    private static final IKey<String> BtnOkIconClass = new 
Key<>("btnOkIconClass", "glyphicon glyphicon-ok");
+    private static final IKey<String> BtnOkIconContent = new 
Key<>("btnOkIconContent");
+    private static final IKey<String> BtnOkLabel = new Key<>("btnOkLabel", 
"Yes");
+    private static final IKey<String> BtnCancelClass = new 
Key<>("btnCancelClass", "btn-xs btn-default");
+    private static final IKey<String> BtnCancelIconClass = new 
Key<>("btnCancelIconClass", "glyphicon glyphicon-remove");
+    private static final IKey<String> BtnCancelIconContent = new 
Key<>("btnCancelIconContent");
+    private static final IKey<String> BtnCancelLabel = new 
Key<>("btnCancelLabel", "No");
+    private static final IKey<TooltipConfig.Placement> Placement = new 
Key<>("placement", TooltipConfig.Placement.top);
+    private static final IKey<String> RootSelector = new Key<>("rootSelector");
+
+
+
+    public ConfirmationConfig withTitle(String title) {
+        put(Title, title);
+        return this;
+    }
+
+    ConfirmationConfig withRootSelector(String rootSelector) {
+        put(RootSelector, rootSelector);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnOkClass(String btnOkClass) {
+        put(BtnOkClass, btnOkClass);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnOkIconClass(String btnOkIconClass) {
+        put(BtnOkIconClass, btnOkIconClass);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnOkIconContent(String btnOkIconContent) {
+        put(BtnOkIconContent, btnOkIconContent);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnOkLabel(String btnOkLabel) {
+        put(BtnOkLabel, btnOkLabel);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnCancelClass(String btnCancelClass) {
+        put(BtnCancelClass, btnCancelClass);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnCancelIconClass(String 
btnCancelIconClass) {
+        put(BtnCancelIconClass, btnCancelIconClass);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnCancelIconContent(String 
btnCancelIconContent) {
+        put(BtnCancelIconContent, btnCancelIconContent);
+        return this;
+    }
+
+    public ConfirmationConfig withBtnCancelLabel(String btnCancelLabel) {
+        put(BtnCancelLabel, btnCancelLabel);
+        return this;
+    }
+
+    public ConfirmationConfig withSingleton(boolean singleton) {
+        put(Singleton, singleton);
+        return this;
+    }
+
+    public ConfirmationConfig withPopout(boolean popout) {
+        put(Popout, popout);
+        return this;
+    }
+
+    public ConfirmationConfig withPlacement(TooltipConfig.Placement placement) 
{
+        put(Placement, Args.notNull(placement, "placement"));
+        return this;
+    }
+}
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/bootstrap-confirmation.js
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/bootstrap-confirmation.js
new file mode 100644
index 0000000..1f0b16a
--- /dev/null
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/confirmation/bootstrap-confirmation.js
@@ -0,0 +1,597 @@
+/*!
+ * Bootstrap Confirmation (v4.1.0)
+ * @copyright 2013 Nimit Suwannagate <[email protected]>
+ * @copyright 2014-2018 Damien "Mistic" Sorel <[email protected]>
+ * @licence Apache License, Version 2.0
+ */
+/* Licensed under the Apache License, Version 2.0 (the "License") 
http://www.apache.org/licenses/LICENSE-2.0 */
+(function (global, factory) {
+  typeof exports === 'object' && typeof module !== 'undefined' ? 
factory(require('jquery'), require('bootstrap')) :
+  typeof define === 'function' && define.amd ? define(['jquery', 'bootstrap'], 
factory) :
+  (global = global || self, factory(global.jQuery));
+}(this, function ($) { 'use strict';
+
+  $ = $ && $.hasOwnProperty('default') ? $['default'] : $;
+
+  function _defineProperties(target, props) {
+    for (var i = 0; i < props.length; i++) {
+      var descriptor = props[i];
+      descriptor.enumerable = descriptor.enumerable || false;
+      descriptor.configurable = true;
+      if ("value" in descriptor) descriptor.writable = true;
+      Object.defineProperty(target, descriptor.key, descriptor);
+    }
+  }
+
+  function _createClass(Constructor, protoProps, staticProps) {
+    if (protoProps) _defineProperties(Constructor.prototype, protoProps);
+    if (staticProps) _defineProperties(Constructor, staticProps);
+    return Constructor;
+  }
+
+  function _defineProperty(obj, key, value) {
+    if (key in obj) {
+      Object.defineProperty(obj, key, {
+        value: value,
+        enumerable: true,
+        configurable: true,
+        writable: true
+      });
+    } else {
+      obj[key] = value;
+    }
+
+    return obj;
+  }
+
+  function _objectSpread(target) {
+    for (var i = 1; i < arguments.length; i++) {
+      var source = arguments[i] != null ? arguments[i] : {};
+      var ownKeys = Object.keys(source);
+
+      if (typeof Object.getOwnPropertySymbols === 'function') {
+        ownKeys = 
ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) {
+          return Object.getOwnPropertyDescriptor(source, sym).enumerable;
+        }));
+      }
+
+      ownKeys.forEach(function (key) {
+        _defineProperty(target, key, source[key]);
+      });
+    }
+
+    return target;
+  }
+
+  function _inheritsLoose(subClass, superClass) {
+    subClass.prototype = Object.create(superClass.prototype);
+    subClass.prototype.constructor = subClass;
+    subClass.__proto__ = superClass;
+  }
+
+  if (typeof $.fn.popover === 'undefined' || 
$.fn.popover.Constructor.VERSION.split('.').shift() !== '4') {
+    throw new Error('Bootstrap Confirmation 4 requires Bootstrap Popover 4');
+  }
+
+  var Popover = $.fn.popover.Constructor;
+
+  /**
+   * ------------------------------------------------------------------------
+   * Constants
+   * ------------------------------------------------------------------------
+   */
+
+  var NAME = 'confirmation';
+  var VERSION = '4.1.0';
+  var DATA_KEY = "bs." + NAME;
+  var EVENT_KEY = "." + DATA_KEY;
+  var JQUERY_NO_CONFLICT = $.fn[NAME];
+  var BTN_CLASS_BASE = 'h-100 d-flex align-items-center';
+  var BTN_CLASS_DEFAULT = 'btn btn-sm';
+
+  var DefaultType = _objectSpread({}, Popover.DefaultType, {
+    singleton: 'boolean',
+    popout: 'boolean',
+    copyAttributes: '(string|array)',
+    onConfirm: 'function',
+    onCancel: 'function',
+    btnOkClass: 'string',
+    btnOkLabel: 'string',
+    btnOkIconClass: 'string',
+    btnOkIconContent: 'string',
+    btnCancelClass: 'string',
+    btnCancelLabel: 'string',
+    btnCancelIconClass: 'string',
+    btnCancelIconContent: 'string',
+    buttons: 'array'
+  });
+
+  var Default = _objectSpread({}, Popover.Default, {
+    _attributes: {},
+    _selector: null,
+    placement: 'top',
+    title: 'Are you sure?',
+    trigger: 'click',
+    confirmationEvent: undefined,
+    content: '',
+    singleton: false,
+    popout: false,
+    copyAttributes: 'href target',
+    onConfirm: $.noop,
+    onCancel: $.noop,
+    btnOkClass: BTN_CLASS_DEFAULT + " btn-primary",
+    btnOkLabel: 'Yes',
+    btnOkIconClass: '',
+    btnOkIconContent: '',
+    btnCancelClass: BTN_CLASS_DEFAULT + " btn-secondary",
+    btnCancelLabel: 'No',
+    btnCancelIconClass: '',
+    btnCancelIconContent: '',
+    buttons: [],
+    // @formatter:off
+    template: "\n<div class=\"popover confirmation\">\n  <div 
class=\"arrow\"></div>\n  <h3 class=\"popover-header\"></h3>\n  <div 
class=\"popover-body\">\n    <p class=\"confirmation-content\"></p>\n    <div 
class=\"confirmation-buttons text-center\">\n      <div 
class=\"btn-group\"></div>\n    </div>\n  </div>\n</div>" // @formatter:on
+
+  });
+
+  if (Default.whiteList) {
+    Default.whiteList['*'].push('data-apply', 'data-dismiss');
+  }
+
+  var ClassName = {
+    FADE: 'fade',
+    SHOW: 'show'
+  };
+  var Selector = {
+    TITLE: '.popover-header',
+    CONTENT: '.confirmation-content',
+    BUTTONS: '.confirmation-buttons .btn-group'
+  };
+  var Keymap = {
+    13: 'Enter',
+    27: 'Escape',
+    39: 'ArrowRight',
+    40: 'ArrowDown'
+  };
+  var Event = {
+    HIDE: "hide" + EVENT_KEY,
+    HIDDEN: "hidden" + EVENT_KEY,
+    SHOW: "show" + EVENT_KEY,
+    SHOWN: "shown" + EVENT_KEY,
+    INSERTED: "inserted" + EVENT_KEY,
+    CLICK: "click" + EVENT_KEY,
+    FOCUSIN: "focusin" + EVENT_KEY,
+    FOCUSOUT: "focusout" + EVENT_KEY,
+    MOUSEENTER: "mouseenter" + EVENT_KEY,
+    MOUSELEAVE: "mouseleave" + EVENT_KEY,
+    CONFIRMED: "confirmed" + EVENT_KEY,
+    CANCELED: "canceled" + EVENT_KEY,
+    KEYUP: "keyup" + EVENT_KEY
+  };
+  /**
+   * ------------------------------------------------------------------------
+   * Class Definition
+   * ------------------------------------------------------------------------
+   */
+  // keep track of the last openned confirmation for keyboard navigation
+
+  var activeConfirmation;
+
+  var Confirmation =
+  /*#__PURE__*/
+  function (_Popover) {
+    _inheritsLoose(Confirmation, _Popover);
+
+    _createClass(Confirmation, null, [{
+      key: "VERSION",
+      // Getters
+      get: function get() {
+        return VERSION;
+      }
+    }, {
+      key: "Default",
+      get: function get() {
+        return Default;
+      }
+    }, {
+      key: "NAME",
+      get: function get() {
+        return NAME;
+      }
+    }, {
+      key: "DATA_KEY",
+      get: function get() {
+        return DATA_KEY;
+      }
+    }, {
+      key: "Event",
+      get: function get() {
+        return Event;
+      }
+    }, {
+      key: "EVENT_KEY",
+      get: function get() {
+        return EVENT_KEY;
+      }
+    }, {
+      key: "DefaultType",
+      get: function get() {
+        return DefaultType;
+      } // Constructor
+
+    }]);
+
+    function Confirmation(element, config) {
+      var _this;
+
+      _this = _Popover.call(this, element, config) || this;
+      element.setAttribute('title', 
element.getAttribute('data-original-title'));
+      element.setAttribute('data-original-title', '');
+
+      if ((_this.config.popout || _this.config.singleton) && 
!_this.config.rootSelector) {
+        throw new Error('The rootSelector option is required to use popout and 
singleton features since jQuery 3.');
+      } // keep trace of selectors
+
+
+      _this._isDelegate = false;
+
+      if (config.selector) {
+        // container of buttons
+        config._selector = config.rootSelector + " " + config.selector;
+        _this.config._selector = config._selector;
+      } else if (config._selector) {
+        // children of container
+        _this.config._selector = config._selector;
+        _this._isDelegate = true;
+      } else {
+        // standalone
+        _this.config._selector = config.rootSelector;
+      }
+
+      if (_this.config.confirmationEvent === undefined) {
+        _this.config.confirmationEvent = _this.config.trigger;
+      }
+
+      if (!_this.config.selector) {
+        _this._copyAttributes();
+      }
+
+      _this._setConfirmationListeners();
+
+      return _this;
+    } // Overrides
+
+
+    var _proto = Confirmation.prototype;
+
+    _proto.isWithContent = function isWithContent() {
+      return true;
+    };
+
+    _proto.setContent = function setContent() {
+      var $tip = $(this.getTipElement());
+
+      var content = this._getContent();
+
+      if (typeof content === 'function') {
+        content = content.call(this.element);
+      }
+
+      this.setElementContent($tip.find(Selector.TITLE), this.getTitle());
+      $tip.find(Selector.CONTENT).toggle(!!content);
+
+      if (content) {
+        this.setElementContent($tip.find(Selector.CONTENT), content);
+      }
+
+      if (this.config.buttons.length > 0) {
+        this._setButtons($tip, this.config.buttons);
+      } else {
+        this._setStandardButtons($tip);
+      }
+
+      $tip.removeClass(ClassName.FADE + " " + ClassName.SHOW);
+
+      this._setupKeyupEvent();
+    };
+
+    _proto.dispose = function dispose() {
+      $('body').off(Event.CLICK + "." + this.uid);
+      this.eventBody = false;
+
+      this._cleanKeyupEvent();
+
+      _Popover.prototype.dispose.call(this);
+    };
+
+    _proto.hide = function hide(callback) {
+      this._cleanKeyupEvent();
+
+      _Popover.prototype.hide.call(this, callback);
+    } // Private
+
+    /**
+     * Copy the value of `copyAttributes` on the config object
+     * @private
+     */
+    ;
+
+    _proto._copyAttributes = function _copyAttributes() {
+      var _this2 = this;
+
+      this.config._attributes = {};
+
+      if (this.config.copyAttributes) {
+        if (typeof this.config.copyAttributes === 'string') {
+          this.config.copyAttributes = this.config.copyAttributes.split(' ');
+        }
+      } else {
+        this.config.copyAttributes = [];
+      }
+
+      this.config.copyAttributes.forEach(function (attr) {
+        _this2.config._attributes[attr] = $(_this2.element).attr(attr);
+      });
+    }
+    /**
+     * Custom event listeners for popouts and singletons
+     * @private
+     */
+    ;
+
+    _proto._setConfirmationListeners = function _setConfirmationListeners() {
+      var self = this;
+
+      if (!this.config.selector) {
+        // cancel original event
+        $(this.element).on(this.config.trigger, function (e, ack) {
+          if (!ack) {
+            e.preventDefault();
+            e.stopPropagation();
+            e.stopImmediatePropagation();
+          }
+        }); // manage singleton
+
+        $(this.element).on(Event.SHOWN, function () {
+          if (self.config.singleton) {
+            // close all other popover already initialized
+            $(self.config._selector).not($(this)).filter(function () {
+              return $(this).data(DATA_KEY) !== undefined;
+            }).confirmation('hide');
+          }
+        });
+      } else {
+        // cancel original event
+        $(this.element).on(this.config.trigger, this.config.selector, function 
(e, ack) {
+          if (!ack) {
+            e.preventDefault();
+            e.stopPropagation();
+            e.stopImmediatePropagation();
+          }
+        });
+      }
+
+      if (!this._isDelegate) {
+        // manage popout
+        this.eventBody = false;
+        this.uid = this.element.id || Confirmation.getUID(NAME + "_group");
+        $(this.element).on(Event.SHOWN, function () {
+          if (self.config.popout && !self.eventBody) {
+            self.eventBody = $('body').on(Event.CLICK + "." + self.uid, 
function (e) {
+              if ($(self.config._selector).is(e.target) || 
$(self.config._selector).has(e.target).length > 0) {
+                return;
+              } // close all popover already initialized
+
+
+              $(self.config._selector).filter(function () {
+                return $(this).data(DATA_KEY) !== undefined;
+              }).confirmation('hide');
+              $('body').off(Event.CLICK + "." + self.uid);
+              self.eventBody = false;
+            });
+          }
+        });
+      }
+    }
+    /**
+     * Init the standard ok/cancel buttons
+     * @param $tip
+     * @private
+     */
+    ;
+
+    _proto._setStandardButtons = function _setStandardButtons($tip) {
+      var buttons = [{
+        class: this.config.btnOkClass,
+        label: this.config.btnOkLabel,
+        iconClass: this.config.btnOkIconClass,
+        iconContent: this.config.btnOkIconContent,
+        attr: this.config._attributes
+      }, {
+        class: this.config.btnCancelClass,
+        label: this.config.btnCancelLabel,
+        iconClass: this.config.btnCancelIconClass,
+        iconContent: this.config.btnCancelIconContent,
+        cancel: true
+      }];
+
+      this._setButtons($tip, buttons);
+    }
+    /**
+     * Init the buttons
+     * @param $tip
+     * @param buttons
+     * @private
+     */
+    ;
+
+    _proto._setButtons = function _setButtons($tip, buttons) {
+      var self = this;
+      var $group = $tip.find(Selector.BUTTONS).empty();
+      buttons.forEach(function (button) {
+        var btn = $('<a 
href="#"></a>').addClass(BTN_CLASS_BASE).addClass(button.class || 
BTN_CLASS_DEFAULT + " btn-secondary").html(button.label || '').attr(button.attr 
|| {});
+
+        if (button.iconClass || button.iconContent) {
+          btn.prepend($('<i></i>').addClass(button.iconClass || 
'').text(button.iconContent || ''));
+        }
+
+        btn.one('click', function (e) {
+          if ($(this).attr('href') === '#') {
+            e.preventDefault();
+          }
+
+          if (button.onClick) {
+            button.onClick.call($(self.element));
+          }
+
+          if (button.cancel) {
+            self.config.onCancel.call(self.element, button.value);
+            $(self.element).trigger(Event.CANCELED, [button.value]);
+          } else {
+            self.config.onConfirm.call(self.element, button.value);
+            $(self.element).trigger(Event.CONFIRMED, [button.value]);
+            $(self.element).trigger(self.config.confirmationEvent, [true]);
+          }
+
+          self.hide();
+        });
+        $group.append(btn);
+      });
+    }
+    /**
+     * Install the keyboatd event handler
+     * @private
+     */
+    ;
+
+    _proto._setupKeyupEvent = function _setupKeyupEvent() {
+      activeConfirmation = this;
+      $(window).off(Event.KEYUP).on(Event.KEYUP, this._onKeyup.bind(this));
+    }
+    /**
+     * Remove the keyboard event handler
+     * @private
+     */
+    ;
+
+    _proto._cleanKeyupEvent = function _cleanKeyupEvent() {
+      if (activeConfirmation === this) {
+        activeConfirmation = undefined;
+        $(window).off(Event.KEYUP);
+      }
+    }
+    /**
+     * Event handler for keyboard navigation
+     * @param event
+     * @private
+     */
+    ;
+
+    _proto._onKeyup = function _onKeyup(event) {
+      if (!this.tip) {
+        this._cleanKeyupEvent();
+
+        return;
+      }
+
+      var $tip = $(this.getTipElement());
+      var key = event.key || Keymap[event.keyCode || event.which];
+      var $group = $tip.find(Selector.BUTTONS);
+      var $active = $group.find('.active');
+      var $next;
+
+      switch (key) {
+        case 'Escape':
+          this.hide();
+          break;
+
+        case 'ArrowRight':
+          if ($active.length && $active.next().length) {
+            $next = $active.next();
+          } else {
+            $next = $group.children().first();
+          }
+
+          $active.removeClass('active');
+          $next.addClass('active').focus();
+          break;
+
+        case 'ArrowLeft':
+          if ($active.length && $active.prev().length) {
+            $next = $active.prev();
+          } else {
+            $next = $group.children().last();
+          }
+
+          $active.removeClass('active');
+          $next.addClass('active').focus();
+          break;
+
+        default:
+          break;
+      }
+    } // Static
+
+    /**
+     * Generates an uui, copied from Bootrap's utils
+     * @param {string} prefix
+     * @returns {string}
+     */
+    ;
+
+    Confirmation.getUID = function getUID(prefix) {
+      var uid = prefix;
+
+      do {
+        // eslint-disable-next-line no-bitwise
+        uid += ~~(Math.random() * 1000000); // "~~" acts like a faster 
Math.floor() here
+      } while (document.getElementById(uid));
+
+      return uid;
+    };
+
+    Confirmation._jQueryInterface = function _jQueryInterface(config) {
+      return this.each(function () {
+        var data = $(this).data(DATA_KEY);
+
+        var _config = typeof config === 'object' ? config : {};
+
+        _config.rootSelector = $(this).selector || _config.rootSelector; // 
this.selector removed in jQuery > 3
+
+        if (!data && /destroy|hide/.test(config)) {
+          return;
+        }
+
+        if (!data) {
+          data = new Confirmation(this, _config);
+          $(this).data(DATA_KEY, data);
+        }
+
+        if (typeof config === 'string') {
+          if (typeof data[config] === 'undefined') {
+            throw new TypeError("No method named \"" + config + "\"");
+          }
+
+          data[config]();
+        }
+      });
+    };
+
+    return Confirmation;
+  }(Popover);
+  /**
+   * ------------------------------------------------------------------------
+   * jQuery
+   * ------------------------------------------------------------------------
+   */
+
+
+  $.fn[NAME] = Confirmation._jQueryInterface;
+  $.fn[NAME].Constructor = Confirmation;
+
+  $.fn[NAME].noConflict = function () {
+    $.fn[NAME] = JQUERY_NO_CONFLICT;
+    return Confirmation._jQueryInterface;
+  };
+
+}));
+//# sourceMappingURL=bootstrap-confirmation.js.map
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileTreePanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileTreePanel.java
index b3ff049..310469e 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileTreePanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/common/tree/FileTreePanel.java
@@ -42,9 +42,9 @@ import org.apache.openmeetings.db.entity.file.BaseFileItem;
 import org.apache.openmeetings.db.entity.file.BaseFileItem.Type;
 import org.apache.openmeetings.db.entity.file.FileItem;
 import org.apache.openmeetings.db.entity.record.Recording;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
-import 
org.apache.openmeetings.web.common.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.openmeetings.web.common.NameDialog;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
+import 
org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AjaxEventBehavior;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
index 6826db2..63a01ad 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomFilePanel.java
@@ -26,8 +26,8 @@ import org.apache.openmeetings.db.dao.file.FileItemDao;
 import org.apache.openmeetings.db.dao.record.RecordingDao;
 import org.apache.openmeetings.db.dto.record.RecordingContainerData;
 import org.apache.openmeetings.db.entity.file.BaseFileItem;
-import 
org.apache.openmeetings.web.common.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.openmeetings.web.common.NameDialog;
+import 
org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.openmeetings.web.common.tree.FileTreePanel;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.wicket.Component;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
index 8bad4ff..88b6a41 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/room/sidebar/RoomSidebar.java
@@ -37,9 +37,9 @@ import org.apache.openmeetings.db.util.ws.RoomMessage;
 import org.apache.openmeetings.db.util.ws.TextRoomMessage;
 import org.apache.openmeetings.web.app.ClientManager;
 import org.apache.openmeetings.web.app.WebSession;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
-import 
org.apache.openmeetings.web.common.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.openmeetings.web.common.NameDialog;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
+import 
org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder.ConfirmableBorderDialog;
 import org.apache.openmeetings.web.room.RoomPanel;
 import org.apache.openmeetings.web.room.RoomPanel.Action;
 import org.apache.openmeetings.web.room.VideoSettings;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatToolbar.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatToolbar.java
index 761c17f..acfc083 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatToolbar.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/chat/ChatToolbar.java
@@ -37,7 +37,7 @@ import org.apache.openmeetings.db.dao.basic.ChatDao;
 import org.apache.openmeetings.db.entity.basic.ChatMessage;
 import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.web.app.ClientManager;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.pages.BasePage;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfileForm.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfileForm.html
index 48f4112..4781bc5 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfileForm.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfileForm.html
@@ -23,35 +23,30 @@
 <wicket:panel>
        <div class="actions" wicket:id="buttons"></div>
        <div class="profile-edit-form overflow-y-auto">
-               <table class="w-100 h-100">
-                       <tr>
-                               <td rowspan="2">
-                                       <fieldset class="ui-widget-content">
-                                               <legend 
class="ui-widget-header">
-                                                       <wicket:message 
key="143" />
-                                               </legend>
-                                               <button type="button" 
wicket:id="changePwd" id="changePwd"><wicket:message key="327"/></button>
-                                               <div class="formelement" 
wicket:enclosure="passwd">
-                                                       <label 
wicket:for="passwd"><wicket:message key="current.password" /></label><input 
type="password" wicket:id="passwd" />
-                                               </div>
-                                               <form 
wicket:id="general"></form>
-                                       </fieldset>
-                               </td>
-                               <td>
-                                       <div wicket:id="img"></div>
-                               </td>
-                       </tr>
-                       <tr>
-                               <td>
-                                       <fieldset class="ui-widget-content">
-                                               <legend 
class="ui-widget-header">
-                                                       <wicket:message 
key="1159" />
-                                               </legend>
-                                               <form 
wicket:id="comunity"></form>
-                                       </fieldset>
-                               </td>
-                       </tr>
-               </table>
+               <div class="h-100 row m-0">
+                       <div class="col-6">
+                               <fieldset class="">
+                                       <legend class="">
+                                               <wicket:message key="143" />
+                                       </legend>
+                                       <button type="button" 
wicket:id="changePwd" id="changePwd"><wicket:message key="327"/></button>
+                                       <div class="formelement" 
wicket:enclosure="passwd">
+                                               <label class="col-3 text-right" 
wicket:for="passwd"><wicket:message key="current.password" /></label>
+                                               <input type="password" 
wicket:id="passwd" class="col-8"/>
+                                       </div>
+                                       <form wicket:id="general"></form>
+                               </fieldset>
+                       </div>
+                       <div class="col-6">
+                               <div wicket:id="img" class="pb-5"></div>
+                               <fieldset class="mt-5">
+                                       <legend class="">
+                                               <wicket:message key="1159" />
+                                       </legend>
+                                       <form wicket:id="comunity"></form>
+                               </fieldset>
+                       </div>
+               </div>
        </div>
        <div class="pt-2 text-center">
                <a wicket:id="link" target="_blank"><wicket:message 
key="register.privacy.statement"/></a>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfilePanel.html
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfilePanel.html
index b80c4a7..82b066c 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfilePanel.html
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/EditProfilePanel.html
@@ -21,7 +21,7 @@
 <!DOCTYPE html>
 <html xmlns:wicket="http://wicket.apache.org";>
 <wicket:panel>
-       <form wicket:id="form" class="adminForm edit-profile"/>
+       <form wicket:id="form" class="adminForm edit-profile container"/>
        <div wicket:id="changePasswd"></div>
 </wicket:panel>
 </html>
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/InvitationDetails.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/InvitationDetails.java
index 8333bdd..293d312 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/InvitationDetails.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/InvitationDetails.java
@@ -26,7 +26,7 @@ import java.util.Date;
 import org.apache.openmeetings.db.dao.room.InvitationDao;
 import org.apache.openmeetings.db.entity.room.Invitation;
 import org.apache.openmeetings.db.entity.room.Invitation.Valid;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.util.DateLabel;
 import org.apache.wicket.ajax.AjaxRequestTarget;
 import org.apache.wicket.markup.html.WebMarkupContainer;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/MessagesContactsPanel.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/MessagesContactsPanel.java
index 00e739c..17425eb 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/MessagesContactsPanel.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/user/profile/MessagesContactsPanel.java
@@ -45,10 +45,10 @@ import org.apache.openmeetings.db.entity.user.User;
 import org.apache.openmeetings.db.entity.user.UserContact;
 import org.apache.openmeetings.web.admin.SearchableDataView;
 import org.apache.openmeetings.web.app.Application;
-import org.apache.openmeetings.web.common.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.common.NameDialog;
 import org.apache.openmeetings.web.common.PagedEntityListPanel;
 import org.apache.openmeetings.web.common.UserBasePanel;
+import org.apache.openmeetings.web.common.confirmation.ConfirmableAjaxBorder;
 import org.apache.openmeetings.web.data.DataViewContainer;
 import org.apache.openmeetings.web.data.OmOrderByBorder;
 import org.apache.openmeetings.web.data.SearchableDataProvider;
diff --git 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/CallbackFunctionHelper.java
 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/CallbackFunctionHelper.java
index 078fbfd..cca93f8 100644
--- 
a/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/CallbackFunctionHelper.java
+++ 
b/openmeetings-web/src/main/java/org/apache/openmeetings/web/util/CallbackFunctionHelper.java
@@ -20,6 +20,8 @@ import static java.util.UUID.randomUUID;
 
 import java.io.Serializable;
 
+import org.apache.openmeetings.web.common.confirmation.ConfirmationBehavior;
+import org.apache.openmeetings.web.common.confirmation.ConfirmationConfig;
 import org.apache.wicket.AttributeModifier;
 import org.apache.wicket.Component;
 import org.apache.wicket.ajax.AbstractDefaultAjaxBehavior;
@@ -27,9 +29,6 @@ import org.apache.wicket.ajax.attributes.CallbackParameter;
 import org.apache.wicket.markup.head.JavaScriptHeaderItem;
 import org.apache.wicket.util.string.StringValue;
 
-import 
de.agilecoders.wicket.extensions.markup.html.bootstrap.confirmation.ConfirmationBehavior;
-import 
de.agilecoders.wicket.extensions.markup.html.bootstrap.confirmation.ConfirmationConfig;
-
 public class CallbackFunctionHelper {
        private CallbackFunctionHelper() {}
 
diff --git a/openmeetings-web/src/main/webapp/css/raw-admin.css 
b/openmeetings-web/src/main/webapp/css/raw-admin.css
index fb3238a..36132b7 100644
--- a/openmeetings-web/src/main/webapp/css/raw-admin.css
+++ b/openmeetings-web/src/main/webapp/css/raw-admin.css
@@ -139,9 +139,6 @@
        right: 0px;
        background-color: #A1A1A1;
 }
-.addLanguagePanel {
-       display: inline-block;
-}
 .addLanguagePanel select {
        padding: 0px 0px;
        border: solid 1px #aacfe4;
diff --git a/openmeetings-web/src/main/webapp/css/raw-general.css 
b/openmeetings-web/src/main/webapp/css/raw-general.css
index e52807c..cf6221b 100644
--- a/openmeetings-web/src/main/webapp/css/raw-general.css
+++ b/openmeetings-web/src/main/webapp/css/raw-general.css
@@ -96,7 +96,7 @@ html, body {
        max-width: 100%;
        height: calc(100% - 50px);
 }
-.pagedEntityListPanel {
+.pagedEntityListPanel, .addLanguagePanel {
        margin-left: 2px;
        display: inline-block;
 }

Reply via email to