--- a/src/ztfy/myams/resources/js/myams.js Tue Jun 03 23:40:12 2014 +0200
+++ b/src/ztfy/myams/resources/js/myams.js Tue Jun 03 23:45:55 2014 +0200
@@ -2,7 +2,7 @@
* MyAMS
* « My Application Management Skin »
*
- * $Tag$
+ * $Tag: 0.1.2 $
* A bootstrap based application/administration skin
*
* Custom administration and application skin tools
@@ -102,6 +102,9 @@
*/
$.fn.extend({
+ /*
+ * Check if current object is empty or not
+ */
exists: function() {
return $(this).length > 0;
},
@@ -136,6 +139,9 @@
}
},
+ /*
+ * Remove CSS classes starting with a given prefix
+ */
removeClassPrefix: function (prefix) {
this.each(function (i, it) {
var classes = it.className.split(" ").map(function(item) {
@@ -146,6 +152,9 @@
return this;
},
+ /*
+ * Main menus manager
+ */
myams_menu: function(options) {
// Extend our default options with those provided
var defaults = {
@@ -321,6 +330,7 @@
enable_widgets: true,
enable_mobile: false,
enable_fastclick: false,
+ warn_on_form_change: false,
ismobile: (/iphone|ipad|ipod|android|blackberry|mini|windows\sce|palm/i.test(navigator.userAgent.toLowerCase()))
};
}
@@ -613,6 +623,21 @@
},
/**
+ * Handle AJAX upload and download progress
+ *
+ * @param event: the source event
+ * @param request: the request
+ * @param options: AJAX options
+ */
+ progress: function(event) {
+ if (!event.lengthComputable)
+ return;
+ if (event.loaded >= event.total)
+ return;
+ console.log(parseInt((event.loaded / event.total * 100), 10) + "%");
+ },
+
+ /**
* Post data to given URL
*/
post: function(url, data, options, callback) {
@@ -764,7 +789,7 @@
}
if (result.content) {
var content = result.content;
- var container = $(content.target || form || '#content');
+ var container = $(content.target || target || form || '#content');
container.html(content.html);
ams.initContent(container);
}
@@ -774,7 +799,7 @@
ams.skin.alert($(form || '#content'),
status, '', message);
else
- ams.skin.alert($(message.target || form || '#content'),
+ ams.skin.alert($(message.target || target || form || '#content'),
message.status || 'success',
message.header,
message.body,
@@ -886,7 +911,7 @@
* - @options: additional JSON-RPC procedure parameters
* - @callback: name of a callback which will be called on server response
*/
- post: function(method, options, callback) {
+ post: function(method, data, options, callback) {
ams.ajax.check($.jsonRpc,
ams.baseURL + 'ext/jquery-jsonrpc' + (ams.devmode ? '.js' : '.min.js'),
function() {
@@ -903,18 +928,19 @@
callback = ams.getFunctionByName(callback);
delete options.callback;
- var settings = {
+ var defaults = {
url: ams.jsonrpc.getAddr(options.url),
type: 'post',
cache: false,
method: method,
- params: options,
+ params: data,
async: typeof(callback) == 'function',
- success: callback || function(data, status) {
+ success: callback || function(data /*, status*/) {
result = data.result;
},
error: ams.error.show
};
+ var settings = $.extend({}, defaults, options);
$.jsonRpc(settings);
return result;
});
@@ -928,6 +954,72 @@
MyAMS.form = {
/**
+ * Init forms to activate form change listeners
+ *
+ * @param element: the parent element
+ */
+ init: function(element) {
+ // Activate form changes if required
+ if (ams.warn_on_form_change)
+ var forms = $('FORM[data-ams-warn-on-change!="false"]', element);
+ else
+ forms = $('FORM[data-ams-warn-on-change="true"]', element);
+ forms.each(function() {
+ var form = $(this);
+ $('INPUT[type="text"], ' +
+ 'INPUT[type="checkbox"], ' +
+ 'INPUT[type="radio"], ' +
+ 'SELECT, ' +
+ 'TEXTAREA, ' +
+ '[data-ams-changed-event]', form).each(function() {
+ var source = $(this);
+ if (source.data('ams-ignore-change') !== true) {
+ var event = source.data('ams-changed-event') || 'change';
+ source.on(event, function () {
+ $(this).parents('FORM').attr('data-ams-form-changed', true);
+ });
+ }
+ });
+ form.on('reset', function() {
+ $(this).removeAttr('data-ams-form-changed');
+ });
+ });
+ },
+
+ /**
+ * Check for modified forms before exiting
+ */
+ checkBeforeUnload: function() {
+ var forms = $('FORM[data-ams-form-changed="true"]');
+ if (forms.exists()) {
+ return ams.i18n.FORM_CHANGED_WARNING;
+ }
+ },
+
+ /**
+ * Check for modified forms before loading new inner content
+ */
+ confirmChangedForm: function(element, callback) {
+ if (typeof(element) == 'function') {
+ callback = element;
+ element = undefined;
+ }
+ var forms = $('FORM[data-ams-form-changed="true"]', element);
+ if (forms.exists()) {
+ ams.skin.bigBox({
+ title: ams.i18n.WARNING,
+ content: '<i class="text-danger fa fa-2x fa-bell shake animated"></i> ' + ams.i18n.FORM_CHANGED_WARNING,
+ buttons: ams.i18n.BTN_OK_CANCEL
+ }, function(button) {
+ if (button == ams.i18n.BTN_OK)
+ callback.call(element);
+ });
+ } else {
+ callback.call(element);
+ }
+ },
+
+ /**
* Submit given form
*/
submit: function(form, handler, submit_options) {
@@ -1049,6 +1141,7 @@
button.button('reset');
form.data('submitted', false);
form.removeData('ams-submit-button');
+ form.removeAttr('data-ams-form-changed');
},
iframe: hasUpload
}
@@ -1329,8 +1422,13 @@
}
if (typeof(source) == 'string')
var url = source;
- else
+ else {
url = source.attr('href') || source.data('ams-url');
+ var url_getter = ams.getFunctionByName(url);
+ if (typeof(url_getter) == 'function') {
+ url = url_getter.call(source);
+ }
+ }
if (!url)
return;
$('body').modalmanager('loading');
@@ -1734,38 +1832,47 @@
var input = $('<input type="checkbox">').attr('name', fieldname)
.attr('id', fieldname.replace(/\./, '_'))
.data('ams-checker-init', true)
- .val(data.amsCheckerState == 'on')
- .on('change', function(e) {
- e.preventDefault();
- var veto = {};
- legend.trigger('ams.checker.before-switch', [legend, veto]);
- if (veto.veto)
- return;
- if ($(this).is(':checked')) {
- if (data.amsCheckerMode == 'disable')
- fieldset.removeAttr('disabled')
- else
- fieldset.removeClass('switched');
- legend.trigger('ams.checker.opened', [legend]);
- } else {
- if (data.amsCheckerMode == 'disable')
- fieldset.attr('disabled', 'disabled');
- else
- fieldset.addClass('switched');
- legend.trigger('ams.checker.closed', [legend]);
- }
- })
- .appendTo(checker);
+ .val(data.amsCheckerState == 'on');
+ if (data.amsCheckerReadonly) {
+ input.attr('disabled', 'disabled');
+ } else {
+ input.on('change', function(e) {
+ e.preventDefault();
+ var veto = {};
+ legend.trigger('ams.checker.before-switch', [legend, veto]);
+ if (veto.veto)
+ return;
+ if ($(this).is(':checked')) {
+ if (data.amsCheckerMode == 'disable')
+ fieldset.removeAttr('disabled')
+ else
+ fieldset.removeClass('switched');
+ $('[data-required]', fieldset).attr('required', 'required');
+ legend.trigger('ams.checker.opened', [legend]);
+ } else {
+ if (data.amsCheckerMode == 'disable')
+ fieldset.attr('disabled', 'disabled');
+ else
+ fieldset.addClass('switched');
+ $('[data-required]', fieldset).removeAttr('required');
+ legend.trigger('ams.checker.closed', [legend]);
+ }
+ });
+ }
+ input.appendTo(checker);
$('.legend', legend).attr('for', input.attr('id'));
checker.append('<i></i>')
.prependTo(legend);
- if (data.amsCheckerState == 'on')
+ var required = $('[required]', fieldset);
+ required.attr('data-required', true);
+ if (data.amsCheckerState == 'on') {
input.attr('checked', true);
- else {
+ } else {
if (data.amsCheckerMode == 'disable')
fieldset.attr('disabled', 'disabled');
else
fieldset.addClass('switched');
+ required.removeAttr('required');
}
legend.data('ams-checker', 'on');
}
@@ -2737,7 +2844,7 @@
updateActiveMenus(menu);
ams.skin.loadURL(url, container);
document.title = $('[data-ams-page-title]:first', container).data('ams-page-title') ||
- $('nav A[href="' + hash + '"]').attr('title') ||
+ menu.attr('title') ||
document.title;
} else {
var active_url = $('[data-ams-active-menu]').data('ams-active-menu');
@@ -2822,6 +2929,31 @@
$.ajax(settings);
},
+ /**
+ * Change user language
+ */
+ setLanguage: function(options) {
+ var lang = options.lang;
+ var handler_type = options.handler_type || 'json';
+ switch (handler_type) {
+ case 'json':
+ var method = options.method || 'setUserLanguage';
+ ams.jsonrpc.post(method, {lang: lang}, function() {
+ window.location.reload(true);
+ });
+ break;
+ case 'ajax':
+ var href = options.href || 'setUserLanguage';
+ ams.ajax.post(href, {lang: lang}, function() {
+ window.location.reload(true);
+ });
+ break;
+ }
+ },
+
+ /**
+ * Go to logout page
+ */
logout: function() {
window.location = ams.loginURL;
}
@@ -2840,6 +2972,21 @@
ams.shortcuts = $('#shortcut');
// Init main AJAX events
+ var jquery_xhr = $.ajaxSettings.xhr;
+ $.ajaxSetup({
+ progress: ams.ajax.progress,
+ progressUpload: ams.ajax.progress,
+ xhr: function() {
+ var request = jquery_xhr();
+ if (request && (typeof(request.addEventListener) == "function")) {
+ var that = this;
+ request.addEventListener("progress", function(evt) {
+ that.progress(evt);
+ }, false);
+ }
+ return request;
+ }
+ });
$(document).ajaxError(ams.error.ajax);
// Check mobile/desktop
@@ -3004,22 +3151,30 @@
if (!href || href.startsWith('javascript:') || link.attr('target'))
return;
e.preventDefault();
+ var href_getter = ams.getFunctionByName(href);
+ if (typeof(href_getter) == 'function') {
+ href = href_getter.call(link);
+ }
var target = link.data('ams-target');
if (target) {
- ams.skin.loadURL(href, target, link.data('ams-link-options'), link.data('ams-link-callback'));
+ ams.form.confirmChangedForm(target, function() {
+ ams.skin.loadURL(href, target, link.data('ams-link-options'), link.data('ams-link-callback'));
+ });
} else {
- if (href.startsWith('#')) {
- if (href != location.hash) {
- if (ams.root.hasClass('mobile-view-activated')) {
- ams.root.removeClass('hidden-menu');
- window.setTimeout(function() {
+ ams.form.confirmChangedForm(function() {
+ if (href.startsWith('#')) {
+ if (href != location.hash) {
+ if (ams.root.hasClass('mobile-view-activated')) {
+ ams.root.removeClass('hidden-menu');
+ window.setTimeout(function () {
+ window.location.hash = href;
+ }, 150);
+ } else
window.location.hash = href;
- }, 150);
- } else
- window.location.hash = href;
- }
- } else
- window.location = href;
+ }
+ } else
+ window.location = href;
+ });
}
});
$(document).on('click', 'a[target="_blank"]', function(e) {
@@ -3028,7 +3183,9 @@
});
$(document).on('click', 'a[target="_top"]', function(e) {
e.preventDefault();
- window.location = $(e.currentTarget).attr('href');
+ ams.form.confirmChangedForm(function() {
+ window.location = $(e.currentTarget).attr('href');
+ });
});
// Check URL when hash changed
@@ -3057,6 +3214,8 @@
var source = $(this);
var data = source.data();
if (data.amsClickHandler) {
+ if (data.amsClickStopPropagation === true)
+ e.stopPropagation();
if (data.amsClickKeepDefault !== true)
e.preventDefault();
var callback = ams.getFunctionByName(data.amsClickHandler);
@@ -3078,6 +3237,19 @@
}
});
+ // Initialize custom reset handlers
+ $(document).on('reset', '[data-ams-reset-handler]', function(e) {
+ var form = $(this);
+ var data = form.data();
+ if (data.amsResetHandler) {
+ if (data.amsResetKeepDefault !== true)
+ e.preventDefault();
+ var callback = ams.getFunctionByName(data.amsResetHandler);
+ if (callback !== undefined)
+ callback.call(form, data.amsResetHandlerOptions);
+ }
+ });
+
// Handle update on file upload placeholder
$(document).on('change', 'input[type="file"]', function(e) {
e.preventDefault();
@@ -3117,6 +3289,9 @@
if ((window.location.hash == '') || (ams.getQueryVar(window.location.href, 'came_from') != false))
ams.initContent(document);
+ // Add unload event listener to check for modified forms
+ $(window).on('beforeunload', ams.form.checkBeforeUnload);
+
};
@@ -3143,6 +3318,7 @@
ams.plugins.init(element);
ams.callbacks.init(element);
ams.events.init(element);
+ ams.form.init(element);
// Initialize widgets
if (ams.device === 'desktop')
@@ -3183,12 +3359,14 @@
BTN_CANCEL: "Cancel",
BTN_YES: "Yes",
BTN_NO: "No",
+ BTN_OK_CANCEL: "[OK][Cancel]",
+ FORM_CHANGED_WARNING: "Some changes were not saved. These updates will be lost if you leave this page.",
NO_UPDATE: "No changes were applied.",
DATA_UPDATED: "Data successfully updated.",
HOME: "Home",
- LOGOUT: "Logout ?",
+ LOGOUT: "Logout?",
LOGOUT_COMMENT: "You can improve your security further after logging out by closing this opened browser",
SELECT2_PLURAL: 's',