2016-02-12 23:52:43 +08:00
|
|
|
// turbolinks MUST BE THE LAST inclusion
|
2023-07-05 17:48:22 +08:00
|
|
|
|
2023-08-16 16:52:36 +08:00
|
|
|
//= require moment
|
2016-02-12 23:52:43 +08:00
|
|
|
//= require bootstrap-datetimepicker
|
|
|
|
//= require bootstrap-colorselector
|
2016-07-21 19:11:15 +08:00
|
|
|
//= require bootstrap-tagsinput.min
|
2016-10-04 21:52:48 +08:00
|
|
|
//= require bootstrap-checkbox.min
|
2016-07-21 19:11:15 +08:00
|
|
|
//= require typeahead.bundle.min
|
2016-02-12 23:52:43 +08:00
|
|
|
//= require nested_form_fields
|
2017-12-01 17:48:07 +08:00
|
|
|
//= require jsPlumb-2.0.4-min
|
|
|
|
//= require jsnetworkx
|
2019-10-25 23:38:15 +08:00
|
|
|
//= require_directory ./repository_columns/columns_initializers
|
2017-01-16 22:52:02 +08:00
|
|
|
//= require datatables
|
2023-06-20 18:52:02 +08:00
|
|
|
//= require jquery.dataTables.colResize
|
2023-08-09 20:02:31 +08:00
|
|
|
//= require jquery.ui.touch-punch.min
|
|
|
|
//= require jquery.caret.min
|
|
|
|
//= require jquery.atwho.min
|
2020-02-22 20:03:51 +08:00
|
|
|
//= require clndr.min
|
2018-03-15 22:43:16 +08:00
|
|
|
//= require ajax-bootstrap-select.min
|
2016-02-12 23:52:43 +08:00
|
|
|
//= require underscore
|
|
|
|
//= require i18n.js
|
|
|
|
//= require i18n/translations
|
2019-01-23 22:30:23 +08:00
|
|
|
//= require users/settings/teams/invite_users_modal
|
2019-10-14 21:27:03 +08:00
|
|
|
//= require repository_columns/index
|
2019-04-02 15:56:50 +08:00
|
|
|
//= require perfect-scrollbar.min
|
2019-03-06 16:17:34 +08:00
|
|
|
//= require shared/inline_editing
|
2021-08-30 20:41:31 +08:00
|
|
|
//= require shared/barcode_search
|
2019-07-26 00:00:24 +08:00
|
|
|
//= require activestorage
|
2019-08-26 21:49:33 +08:00
|
|
|
//= require global_activities/side_pane
|
2019-11-20 21:57:53 +08:00
|
|
|
//= require protocols/header
|
2021-12-01 18:16:45 +08:00
|
|
|
//= require protocols/print
|
2019-04-27 02:33:20 +08:00
|
|
|
//= require marvinjslauncher
|
2021-01-06 22:00:21 +08:00
|
|
|
//= require jstree.min
|
2019-12-06 17:39:21 +08:00
|
|
|
//= require_tree ./repositories/renderers
|
2021-05-02 17:22:59 +08:00
|
|
|
//= require_directory ./shared
|
2019-11-18 21:04:53 +08:00
|
|
|
//= require_directory ./repositories/validators
|
2020-02-14 19:07:40 +08:00
|
|
|
//= require_directory ./dashboard
|
2019-11-22 23:12:41 +08:00
|
|
|
//= require_directory ./sitewide
|
2021-04-30 19:26:06 +08:00
|
|
|
//= require_directory ./access_permissions
|
2020-02-28 21:03:08 +08:00
|
|
|
//= require sidebar
|
2019-10-25 20:30:45 +08:00
|
|
|
//= require turbolinks
|
2023-06-08 14:37:11 +08:00
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
// Initialize links for submitting forms. This is useful for submitting
|
|
|
|
// forms with clicking on links outside form in cases when other than
|
|
|
|
// GET method is used.
|
2019-05-31 21:44:27 +08:00
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
function initFormSubmitLinks(el) {
|
|
|
|
|
|
|
|
el = el || $(document.body);
|
|
|
|
$(".form-submit-link", el).click(function () {
|
|
|
|
var val = true;
|
|
|
|
if ($(this).is("[data-confirm-form]")) {
|
|
|
|
val = confirm($(this).data("confirm-form"));
|
|
|
|
}
|
|
|
|
// Only submit form if confirmed
|
|
|
|
if (val) {
|
|
|
|
animateLoading();
|
|
|
|
$("#" + $(this).data("submit-form")).submit();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Enable loading bars */
|
|
|
|
$(document)
|
|
|
|
.bind("ajaxSend", function(){
|
|
|
|
animateLoading();
|
|
|
|
})
|
|
|
|
.bind("ajaxComplete", function(){
|
|
|
|
animateLoading(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show/hide loading indicator on top of page.
|
|
|
|
*/
|
|
|
|
function animateLoading(start){
|
|
|
|
if (start === undefined)
|
|
|
|
start = true;
|
|
|
|
start = start !== false;
|
|
|
|
if (start) {
|
|
|
|
$("#loading-animation").addClass("animate");
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
$("#loading-animation").removeClass("animate");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Show/hide spinner for a given element.
|
|
|
|
* Shows spinner if start is true or not given, hides it if false.
|
|
|
|
* Optional parameter options for spin.js options.
|
|
|
|
*/
|
2020-11-23 21:12:29 +08:00
|
|
|
function animateSpinner(el, start) {
|
2017-06-05 20:09:04 +08:00
|
|
|
// If overlaying the whole page, put the spinner in the middle of the page
|
2020-11-23 21:12:29 +08:00
|
|
|
var overlayPage = _.isUndefined(el) || el === null;
|
2016-07-21 19:11:15 +08:00
|
|
|
|
2020-11-23 21:12:29 +08:00
|
|
|
if (_.isUndefined(start)) start = true;
|
2016-07-21 19:11:15 +08:00
|
|
|
|
2016-02-12 23:52:43 +08:00
|
|
|
if (start) {
|
2016-07-21 19:11:15 +08:00
|
|
|
if (overlayPage) {
|
|
|
|
$(document.body).append('<div class="loading-overlay" />');
|
|
|
|
} else {
|
|
|
|
$(el).append('<div class="loading-overlay" />');
|
|
|
|
}
|
|
|
|
} else {
|
2016-02-12 23:52:43 +08:00
|
|
|
$(".loading-overlay").remove();
|
|
|
|
}
|
2016-08-11 22:05:23 +08:00
|
|
|
}
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2017-06-05 20:09:04 +08:00
|
|
|
/**
|
|
|
|
* Automatic handling of show/hide spinner.
|
|
|
|
* @param {boolean} redirection Whether page is refreshed/redirected on success
|
|
|
|
* @param {boolean} onElement Whether spinner is fixed on the center of fn
|
|
|
|
* element or it's positions on the center of whole page
|
|
|
|
*/
|
|
|
|
$.fn.animateSpinner = function(redirection, onElement) {
|
|
|
|
redirection = _.isUndefined(redirection) ? false : redirection;
|
|
|
|
onElement = _.isUndefined(onElement) ? false : onElement;
|
|
|
|
|
|
|
|
$(this)
|
|
|
|
.on('ajax:beforeSend', function() {
|
|
|
|
onElement ? animateSpinner($(this)) : animateSpinner();
|
|
|
|
})
|
|
|
|
.on('ajax:error', function(e, data) {
|
|
|
|
animateSpinner(null, false);
|
|
|
|
})
|
|
|
|
.on('ajax:success', function(e, data) {
|
|
|
|
if (!redirection) {
|
|
|
|
animateSpinner(null, false);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-08-11 22:05:23 +08:00
|
|
|
/*
|
2016-08-17 15:44:53 +08:00
|
|
|
* Prevents user from accidentally leaving page when server is busy
|
|
|
|
* and notifies him with a message.
|
|
|
|
*
|
|
|
|
* NOTE: Don't prevent event propagation (ev.stopPropagation()), or
|
|
|
|
* else all events occurring when alert is up will be ignored.
|
2016-08-11 22:05:23 +08:00
|
|
|
*/
|
|
|
|
function preventLeavingPage(prevent, msg) {
|
|
|
|
busy = prevent;
|
2016-08-09 20:39:24 +08:00
|
|
|
if (busy && !_.isUndefined(msg)) {
|
|
|
|
busyMsg = msg;
|
|
|
|
}
|
2016-02-12 23:52:43 +08:00
|
|
|
}
|
2016-08-11 22:05:23 +08:00
|
|
|
var busy = false;
|
|
|
|
var busyMsg = I18n.t("general.busy");
|
|
|
|
window.onbeforeunload = function () {
|
|
|
|
if (busy) {
|
|
|
|
var currentMsg = busyMsg;
|
|
|
|
// Reset to default message
|
|
|
|
busyMsg = I18n.t("general.busy");
|
|
|
|
return currentMsg;
|
|
|
|
}
|
|
|
|
}
|
2016-02-12 23:52:43 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable Firefox caching to get rid of issues with pressing
|
|
|
|
* browser back, like opening canvas in edit mode.
|
|
|
|
*/
|
2023-07-05 17:48:22 +08:00
|
|
|
$(window).on("unload", function() {
|
2016-08-11 22:05:23 +08:00
|
|
|
$(window).unbind('unload');
|
|
|
|
});
|
2016-02-12 23:52:43 +08:00
|
|
|
|
2016-12-28 21:52:03 +08:00
|
|
|
var HelperModule = (function(){
|
2016-08-19 16:48:43 +08:00
|
|
|
|
2016-12-28 21:52:03 +08:00
|
|
|
var helpers = {};
|
|
|
|
|
|
|
|
helpers.hideFlashMsg = function() {
|
2016-11-11 19:30:48 +08:00
|
|
|
var flash = $('.alert');
|
|
|
|
if (flash.length > 0) {
|
|
|
|
window.setTimeout(function () {
|
|
|
|
flash.fadeTo(500, 0).slideUp(500, function () {
|
|
|
|
$(this).remove();
|
|
|
|
});
|
2018-04-25 16:43:16 +08:00
|
|
|
}, 3000);
|
2016-11-11 19:30:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-25 13:32:49 +08:00
|
|
|
helpers.dismissAlert = function() {
|
|
|
|
$('#alert-flash').on('click', function() {
|
|
|
|
$('#alert-flash').alert('close');
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2017-03-18 00:56:58 +08:00
|
|
|
helpers.flashAlertMsg = function(message, type) {
|
2018-07-09 19:13:44 +08:00
|
|
|
var alertType, fasSign;
|
2018-05-16 15:31:19 +08:00
|
|
|
|
2017-03-18 00:56:58 +08:00
|
|
|
$('#notifications').html('');
|
|
|
|
if (type === 'success') {
|
|
|
|
alertType = ' alert-success ';
|
2018-07-09 19:13:44 +08:00
|
|
|
fasSign = ' fa-check-circle ';
|
2017-03-18 00:56:58 +08:00
|
|
|
} else if (type === 'danger') {
|
|
|
|
alertType = ' alert-danger ';
|
2020-01-21 22:21:40 +08:00
|
|
|
fasSign = ' fa-exclamation-triangle ';
|
2017-03-28 21:14:05 +08:00
|
|
|
} else if (type === 'info') {
|
|
|
|
alertType = ' alert-info ';
|
2020-01-21 22:21:40 +08:00
|
|
|
fasSign = ' fa-info-circle ';
|
2017-11-22 02:20:15 +08:00
|
|
|
} else if (type === 'warning') {
|
|
|
|
alertType = ' alert-warning ';
|
2020-01-21 22:21:40 +08:00
|
|
|
fasSign = ' fa-exclamation-triangle ';
|
2017-03-18 00:56:58 +08:00
|
|
|
}
|
2018-04-25 13:32:49 +08:00
|
|
|
var htmlSnippet = '<div id="alert-flash" class="alert alert' + alertType +
|
2017-03-18 00:56:58 +08:00
|
|
|
'alert-dismissable alert-floating">' +
|
2020-01-17 17:49:41 +08:00
|
|
|
'<span class="fas' + fasSign + '"></span> ' +
|
|
|
|
'<span class="message">' + message + '</span>' +
|
2018-04-25 16:43:16 +08:00
|
|
|
'<button type="button" class="close" ' +
|
2020-01-17 17:49:41 +08:00
|
|
|
'data-dismiss="alert" aria-label="Close">' +
|
2023-08-17 19:55:17 +08:00
|
|
|
'<i class="sn-icon sn-icon-close"></i></button>' +
|
2020-01-17 17:49:41 +08:00
|
|
|
'</div>';
|
2017-03-18 00:56:58 +08:00
|
|
|
$('#notifications').html(htmlSnippet);
|
|
|
|
helpers.hideFlashMsg();
|
2018-04-25 13:32:49 +08:00
|
|
|
helpers.dismissAlert();
|
2017-03-18 00:56:58 +08:00
|
|
|
}
|
|
|
|
|
2018-07-19 23:56:42 +08:00
|
|
|
$(document).on('turbolinks:load', function() {
|
2016-12-28 21:52:03 +08:00
|
|
|
helpers.hideFlashMsg();
|
2018-04-25 13:32:49 +08:00
|
|
|
helpers.dismissAlert();
|
2016-08-30 19:51:16 +08:00
|
|
|
});
|
2016-12-28 21:52:03 +08:00
|
|
|
|
|
|
|
return helpers;
|
2016-11-11 19:30:48 +08:00
|
|
|
})();
|
2017-01-19 05:40:08 +08:00
|
|
|
|
|
|
|
(function() {
|
2018-07-19 23:56:42 +08:00
|
|
|
$(document).on('turbolinks:load', function() {
|
2018-05-15 00:33:57 +08:00
|
|
|
// fix dropdown-menu style throughout the app
|
|
|
|
$('.dropdown-header').parent('ul').addClass('custom-dropdown-menu');
|
2018-12-18 03:59:22 +08:00
|
|
|
});
|
2018-08-02 17:25:14 +08:00
|
|
|
|
2018-12-18 03:59:22 +08:00
|
|
|
// Close all open modals before caching
|
|
|
|
$(document).on('turbolinks:before-cache', function() {
|
|
|
|
$('.modal').off().modal('hide');
|
2017-01-19 05:40:08 +08:00
|
|
|
});
|
2018-08-24 23:11:59 +08:00
|
|
|
|
|
|
|
$(document).on('turbolinks:load', function() {
|
2019-03-14 23:08:52 +08:00
|
|
|
/* Fix .selectpicker (bootstrap-select) to work with Turbolinks 5.x */
|
2018-08-24 23:11:59 +08:00
|
|
|
$(window).trigger('load.bs.select.data-api');
|
|
|
|
});
|
2020-11-03 05:19:33 +08:00
|
|
|
|
|
|
|
// Show warning if page has unsaved data
|
|
|
|
$(document).on('turbolinks:before-visit', () => {
|
|
|
|
let exit = true;
|
|
|
|
let editing = $(`.${GLOBAL_CONSTANTS.HAS_UNSAVED_DATA_CLASS_NAME}`).length > 0;
|
|
|
|
|
|
|
|
if (editing) {
|
|
|
|
exit = confirm(I18n.t('general.leaving_unsaved_warning'));
|
|
|
|
}
|
|
|
|
|
|
|
|
return exit;
|
|
|
|
});
|
2023-05-31 23:27:07 +08:00
|
|
|
|
2023-07-18 05:50:05 +08:00
|
|
|
const RESIZE_OBSERVER = new ResizeObserver(entries => {
|
|
|
|
entries.forEach(entry => {
|
|
|
|
const { offsetWidth } = entry.target;
|
|
|
|
const breakpoint = parseInt(entry.target.getAttribute('data-width-breakpoint'));
|
|
|
|
|
|
|
|
if (offsetWidth <= breakpoint && offsetWidth !== 0) {
|
2023-05-31 23:27:07 +08:00
|
|
|
entry.target.classList.add('narrow');
|
|
|
|
} else {
|
|
|
|
entry.target.classList.remove('narrow');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
$(document).on('turbolinks:load', function() {
|
|
|
|
$('[data-width-breakpoint]').each(function() {
|
|
|
|
RESIZE_OBSERVER.observe(this);
|
|
|
|
});
|
|
|
|
});
|
2020-11-03 05:19:33 +08:00
|
|
|
}());
|
2020-07-10 17:05:27 +08:00
|
|
|
|
|
|
|
// Check that loaded page, not turbolinks preview
|
|
|
|
function notTurbolinksPreview() {
|
|
|
|
return !document.documentElement.hasAttribute("data-turbolinks-preview");
|
|
|
|
}
|
2020-08-31 15:23:56 +08:00
|
|
|
|
|
|
|
const windowScrollEvents = {};
|
|
|
|
$(window).scroll(function() {
|
|
|
|
$.each(windowScrollEvents, function(key, scroll_function){
|
|
|
|
scroll_function();
|
|
|
|
})
|
|
|
|
})
|
2022-01-20 19:44:57 +08:00
|
|
|
|
|
|
|
// Disable default validation bubbles
|
|
|
|
// NOTE: invalid event doesn't bubble, that's
|
|
|
|
// why need to bind to each element separately
|
|
|
|
$(document).ajaxComplete(function() {
|
|
|
|
setTimeout(function() {
|
|
|
|
$('input,select,textarea').each(function() {
|
|
|
|
$(this).on('invalid', function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}, 10);
|
|
|
|
});
|
|
|
|
|
|
|
|
// enable form validations on form submit
|
|
|
|
$(document).on('ajax:beforeSend', 'form', function() {
|
|
|
|
$(this).removeAttr('novalidate');
|
|
|
|
return this.reportValidity();
|
|
|
|
});
|
2022-06-07 21:14:00 +08:00
|
|
|
|
|
|
|
$(document).keyup(function(e) {
|
|
|
|
if (e.keyCode == 27) {
|
|
|
|
$('.dropdown').removeClass('open');
|
|
|
|
$('.atwho-user-popover').popover("hide");
|
|
|
|
$('.modal').modal("hide");
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2023-05-03 15:46:18 +08:00
|
|
|
window.I18n = I18n;
|
2022-07-04 19:54:22 +08:00
|
|
|
|
|
|
|
// Multiple modal support
|
|
|
|
// https://stackoverflow.com/a/24914782
|
2023-10-18 23:15:17 +08:00
|
|
|
$(document).on('show.bs.modal', '.modal', function() {
|
2023-10-16 16:18:22 +08:00
|
|
|
let zIndex;
|
|
|
|
if ($(this).hasClass('custom-z-index') ) {
|
|
|
|
zIndex = $(this).css('z-index');
|
|
|
|
} else {
|
|
|
|
zIndex = 2040 + 10 * $('.modal:visible').length;
|
|
|
|
$(this).css('z-index', zIndex);
|
|
|
|
}
|
|
|
|
|
2022-07-04 19:54:22 +08:00
|
|
|
setTimeout(() => $('.modal-backdrop').not('.modal-stack').css('z-index', zIndex - 1).addClass('modal-stack'));
|
|
|
|
});
|
2023-05-03 15:46:18 +08:00
|
|
|
|
|
|
|
// User Name popover sitewide support
|
|
|
|
let userNamePopover;
|
|
|
|
const renderUserNamePopover = (url, fullName, email, html) => {
|
|
|
|
return `<div class="user-name-popover-wrapper">
|
2023-06-21 18:53:18 +08:00
|
|
|
<div class='col-xs-3'>
|
2023-05-03 15:46:18 +08:00
|
|
|
<img
|
2023-06-28 18:57:19 +08:00
|
|
|
class='avatar img-responsive'
|
2023-05-03 15:46:18 +08:00
|
|
|
src='${url}'
|
|
|
|
alt='thumb'>
|
|
|
|
</div>
|
2023-06-22 19:36:05 +08:00
|
|
|
<div class='col-xs-9 pl-3'>
|
2023-05-03 15:46:18 +08:00
|
|
|
<div class='row'>
|
2023-06-21 18:53:18 +08:00
|
|
|
<div class='col-xs-12 text-left font-bold'>
|
|
|
|
${fullName}
|
2023-05-03 15:46:18 +08:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<div class='row'>
|
|
|
|
<div class='col-xs-12'>
|
|
|
|
<p class='silver email'>${email}</p>
|
|
|
|
<p>${html}</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>`;
|
|
|
|
};
|
|
|
|
|
|
|
|
$(document).on('focus', '.atwho-user-popover', function() {
|
|
|
|
if (!userNamePopover) {
|
|
|
|
const atwhoUserName = $(this);
|
|
|
|
|
|
|
|
const url = atwhoUserName.data('user-avatar-popover-absolute-url');
|
|
|
|
const fullName = atwhoUserName.data('full-name');
|
|
|
|
const email = atwhoUserName.data('email');
|
|
|
|
const html = atwhoUserName.data('popover-html');
|
|
|
|
|
|
|
|
atwhoUserName.attr('data-content', renderUserNamePopover(url, fullName, email, html));
|
|
|
|
}
|
|
|
|
|
|
|
|
$(this).popover('show');
|
|
|
|
}).on('blur', '.atwho-user-popover', function() {
|
|
|
|
$(this).popover('hide');
|
|
|
|
});
|