diff --git a/addons/default/visiosoft/base-theme/resources/js/theme/modal.js b/addons/default/visiosoft/base-theme/resources/js/theme/modal.js
new file mode 100644
index 000000000..2a478e37e
--- /dev/null
+++ b/addons/default/visiosoft/base-theme/resources/js/theme/modal.js
@@ -0,0 +1,85 @@
+let initModal = function () {
+
+ let modal = $('.modal.remote:not([data-initialized])');
+
+ let loading = '
';
+
+ // Loading state
+ modal.on('loading', function() {
+ $(this).find('.modal-content').append(loading);
+ });
+
+ // Clear remote modals when closed.
+ modal.on('hidden.bs.modal', function () {
+
+ $(this).removeData('bs.modal');
+
+ $(this).find('.modal-content').html(loading);
+ });
+
+ // Show loader for remote modals.
+ modal.on('show.bs.modal', function () {
+ $(this).find('.modal-content').html(loading);
+ });
+
+ // Handle ajax links in modals.
+ modal.on('click', 'a.ajax, .pagination a', function (e) {
+
+ e.preventDefault();
+
+ let wrapper = $(this).closest('.modal-content');
+
+ wrapper.append(loading);
+
+ $.get($(this).attr('href'), function (html) {
+ wrapper.html(html);
+ });
+ });
+
+ // Handle ajax forms in modals.
+ modal.on('submit', 'form.ajax', function (e) {
+
+ e.preventDefault();
+
+ let wrapper = $(this).closest('.modal-content');
+
+ wrapper.append(loading);
+
+ if ($(this).attr('method') == 'GET') {
+ $.get($(this).attr('action'), $(this).serializeArray(), function (html) {
+ wrapper.html(html);
+ });
+ } else {
+ $.post($(this).attr('action'), $(this).serializeArray(), function (html) {
+ wrapper.html(html);
+ });
+ }
+ });
+
+ // Handle load indicators in modals.
+ modal.on('click', '[data-toggle="loader"]', function () {
+
+ let wrapper = $(this).closest('.modal-content');
+
+ wrapper.append(loading);
+ });
+
+ // Mark as initialized.
+ modal.attr('data-initialized', '');
+};
+
+$(document).ready(function () {
+ initModal();
+});
+
+$(document).ajaxComplete(function () {
+ initModal();
+});
+
+$(document).on('show.bs.modal', '.modal', function () {
+ let zIndex = 1040 + (10 * $('.modal:visible').length);
+ $(this).css('z-index', zIndex);
+ setTimeout(function() {
+ $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack');
+ }, 0);
+});
diff --git a/addons/default/visiosoft/base-theme/resources/js/theme/search.js b/addons/default/visiosoft/base-theme/resources/js/theme/search.js
new file mode 100644
index 000000000..d73818e9e
--- /dev/null
+++ b/addons/default/visiosoft/base-theme/resources/js/theme/search.js
@@ -0,0 +1,191 @@
+$(function () {
+
+ var form = $('#search');
+ var input = form.find('input');
+ var list = form.find('.results');
+ var items = list.find('a');
+ var selected = null;
+
+ // Don't submit on return.
+ form.on('submit', function () {
+ return false;
+ });
+
+ // Open search
+ input.on('focus', function () {
+ form.addClass('open');
+ });
+
+ // Close search.
+ $(window).click(function () {
+ form.removeClass('open');
+ });
+
+ form.click(function (e) {
+ e.stopPropagation();
+ });
+
+ // Handle simple searching
+ input.on('keydown', function (e) {
+
+ /**
+ * Capture the down arrow.
+ */
+ if (e.which == 40) {
+
+ if (selected) {
+
+ /**
+ * If we have a selection then
+ * push to the next visible option.
+ */
+ if (selected.nextAll('a:visible').length) {
+ items.removeClass('active');
+ selected = selected.nextAll('a:visible').first();
+ selected.addClass('active');
+ }
+ } else {
+
+ /**
+ * Otherwise select the first
+ * visible option in the list.
+ */
+ selected = items.filter('a:visible').first();
+ selected.addClass('active');
+ }
+ }
+
+ /**
+ * Capture the up arrow.
+ */
+ if (e.which == 38) {
+
+ if (selected) {
+
+ /**
+ * If we have a selection then push
+ * to the previous visible option.
+ */
+ if (selected.prevAll('a:visible').length) {
+ items.removeClass('active');
+ selected = selected.prevAll('a:visible').first();
+ selected.addClass('active');
+ }
+ } else {
+
+ /**
+ * Otherwise select the last
+ * visible option in the list.
+ */
+ selected = items.filter('a:visible').last();
+ selected.addClass('active');
+ }
+ }
+
+ /**
+ * Capture the enter key.
+ */
+ if (e.which == 13) {
+
+ if (selected) {
+
+ /**
+ * If the key press was the return
+ * key and we have a selection
+ * then follow the link.
+ */
+ if (selected.hasClass('has-click-event') || selected.hasClass('ajax')) {
+ selected.trigger('click');
+ } else {
+
+ /**
+ * If nothing is selected
+ * there's nothing to do.
+ */
+ if (!selected.length) {
+ return false;
+ }
+
+ /**
+ * If control or the meta key is
+ * being held open a new window.
+ */
+ if (e.ctrlKey || e.metaKey) {
+ window.open(selected.attr('href'), "_blank");
+ } else {
+ window.location = selected.attr('href');
+ }
+
+ input.val('');
+ input.blur();
+ form.removeClass('open');
+
+ modal.find('.modal-content').append('');
+ }
+ }
+ }
+
+ /**
+ * Capture up and down arrows.
+ */
+ if (e.which == 38 || e.which == 40) {
+
+ // store current positions in variables
+ var start = input[0].selectionStart,
+ end = input[0].selectionEnd;
+
+ // restore from variables...
+ input[0].setSelectionRange(start, end);
+
+ e.preventDefault();
+ }
+
+ /**
+ * Capture the escape key.
+ */
+ if (e.which == 27) {
+
+ form.removeClass('open');
+
+ items
+ .show()
+ .removeClass('active');
+
+ input.val('').blur();
+ }
+ });
+
+ input.on('keyup', function (e) {
+
+ /**
+ * If the keyup was a an arrow
+ * up or down then skip this step.
+ */
+ if (e.which == 38 || e.which == 40) {
+ return;
+ }
+
+ var value = $(this).val();
+
+ /**
+ * Filter the list by the items to
+ * show only those containing value.
+ */
+ items.each(function () {
+ if ($(this).text().toLowerCase().indexOf(value.toLowerCase()) >= 0) {
+ $(this).show();
+ } else {
+ $(this).hide();
+ }
+ });
+
+ /**
+ * If we don't have a selected item
+ * then choose the first visible option.
+ */
+ if (!selected || !selected.is(':visible')) {
+ selected = items.filter(':visible').first();
+ selected.addClass('active');
+ }
+ });
+});
diff --git a/addons/default/visiosoft/base-theme/resources/views/partials/assets.twig b/addons/default/visiosoft/base-theme/resources/views/partials/assets.twig
index 48582c6d5..efae4833f 100644
--- a/addons/default/visiosoft/base-theme/resources/views/partials/assets.twig
+++ b/addons/default/visiosoft/base-theme/resources/views/partials/assets.twig
@@ -17,8 +17,9 @@
{{ asset_add("theme.js", "visiosoft.theme.base::js/script.js") }}
{# Theme Scripts #}
-{#{{ asset_add("theme.js", "visiosoft.theme.base::js/plugins/*") }}#}
{{ asset_add("theme.js", "visiosoft.theme.base::js/theme/initialize.js") }}
+{{ asset_add("theme.js", "visiosoft.theme.base::js/theme/search.js") }}
+{{ asset_add("theme.js", "visiosoft.theme.base::js/theme/modal.js") }}
{{ asset_script("theme.js") }}
diff --git a/addons/default/visiosoft/singlefile-field_type/resources/js/upload.js b/addons/default/visiosoft/singlefile-field_type/resources/js/upload.js
index 5aaa7684f..f4e39538c 100644
--- a/addons/default/visiosoft/singlefile-field_type/resources/js/upload.js
+++ b/addons/default/visiosoft/singlefile-field_type/resources/js/upload.js
@@ -64,9 +64,6 @@ $(function () {
var response = JSON.parse(file.xhr.response);
uploaded.push(response.id);
- $('[data-provides="visiosoft.field_type.singlefile"]').val(response.id)
- $('#file-modal').modal('hide');
- $('#profile-detail').submit();
file.previewElement.querySelector('[data-dz-uploadprogress]').setAttribute('class', 'progress progress-success');
@@ -83,4 +80,12 @@ $(function () {
alert(message.error ? message.error : message);
});
+
+ // When all files are processed.
+ dropzone.on('queuecomplete', function () {
+
+ uploader.find('.uploaded .modal-body').html(element.data('loading') + '...');
+
+ uploader.find('.uploaded').load(REQUEST_ROOT_PATH + '/streams/singlefile-field_type/recent?uploaded=' + uploaded.join(','));
+ });
});