Files
server/usr/share/psa-horde/js/smartmobile.js
2026-01-07 20:52:11 +01:00

345 lines
9.4 KiB
JavaScript

/**
* Base logic for all jQuery Mobile applications.
*
* @author Michael J. Rubinsky <mrubinsk@horde.org>
* @author Jan Schneider <jan@horde.org>
* @author Michael Slusarz <slusarz@horde.org>
* @copyright 2010-2015 Horde LLC
* @license LGPL-2.1 (http://www.horde.org/licenses/lgpl21)
*/
var HordeMobile = {
notify_handler: function(m) { return HordeMobile.showNotifications(m); },
// page_init: false,
// regenerate_sid: false,
serverError: 0,
loading: 0,
/**
* Common URLs.
*
* Set by Horde_PageOutput:
* - ajax_url: AJAX endpoint.
* - logout_url: Logout URL.
* - token: AJAX session token.
*/
conf: {},
/**
* Debug.
*/
debug: function(label, e)
{
if (!HordeMobile.is_logout && window.console && window.console.error) {
window.console.error(label, navigator.userAgent.indexOf("Gecko") > -1 ? e : jQuery.makeArray(e));
}
},
/**
* Perform an Ajax action
*
* @param string action The AJAX request method.
* @param object params The parameter hash for the AJAX request.
* @param function callback A callback function for successful request.
* @param object opts Additional options for jQuery.ajax(). Also:
* - submit: (jQuery object) Send action via a submit action (since
* 2.5.0). Value is the form element. The 'form.js' plugin
* must be loaded before this can be called.
*
* @return jqXHR jQuery XHR object.
*/
doAction: function(action, params, callback, opts)
{
opts = opts || {};
params = params || {};
params.token = HordeMobile.conf.token;
if (HordeMobile.conf.sid) {
$.extend(params, HordeMobile.conf.sid.toQueryParams());
}
if (HordeMobile.regenerate_sid) {
params.regenerate_sid = 1;
opts.async = false;
delete HordeMobile.regenerate_sid;
}
HordeMobile.loading++;
$.mobile.loading('show');
opts = $.extend({
data: params,
error: $.noop,
success: function(d) {
HordeMobile.doActionComplete(action, d, callback);
},
type: 'post',
url: HordeMobile.conf.ajax_url + action
}, opts);
if (opts.submit) {
var tmp = opts.submit, tmp2;
delete opts.submit;
tmp2 = tmp.ajaxSubmit(opts);
return tmp2.data('jqxhr');
} else {
return $.ajax(opts);
}
},
doActionComplete: function(action, d, callback)
{
var r = d.response;
HordeMobile.inAjaxCallback = true;
if (d.reload) {
if (d.reload === true) {
window.location.reload();
} else {
window.location.assign(d.reload);
}
return;
}
HordeMobile.notify_handler(d.msgs || []);
if (d.tasks) {
$(document).trigger('HordeMobile:runTasks', d.tasks);
}
if (r) {
$(document).trigger('HordeMobile:doActionCompleteBefore', {
action: action,
response: r
});
if ($.isFunction(callback)) {
try {
callback(r);
} catch (e) {
HordeMobile.debug('doActionComplete', e);
}
}
$(document).trigger('HordeMobile:doActionCompleteAfter', {
action: action,
response: r
});
}
HordeMobile.inAjaxCallback = false;
if (!(--HordeMobile.loading)) {
$.mobile.loading('hide');
}
},
/**
* Output a notification.
*
* @param object msgs
*/
showNotifications: function(msgs)
{
if (!msgs.length || HordeMobile.is_logout) {
return;
}
if (!$.mobile.pageContainer) {
window.setTimeout(function() {
HordeMobile.showNotifications(msgs);
}, 100);
return;
}
$.each(msgs, function(key, m) {
switch (m.type) {
case 'horde.ajaxtimeout':
HordeMobile.logout(m.message);
return false;
case 'horde.error':
case 'horde.message':
case 'horde.success':
case 'horde.warning':
$('#horde-notification').growler('notify', m.message, m.type, {
raw: (m.flags && $.inArray('content.raw', m.flags) != -1),
sticky: (m.type == 'horde.error')
});
break;
}
});
},
/**
* Run tasks.
*/
runTasks: function(e, d)
{
var v;
if (d['horde:regenerate_sid']) {
HordeMobile.regenerate_sid = true;
}
if ((v = d['horde:sid'])) {
HordeMobile.conf.sid = v;
}
},
/**
* Logout.
*
* @param string url Use this URL instead of the default.
*/
logout: function(url)
{
HordeMobile.is_logout = true;
window.location = (url || HordeMobile.conf.logout_url);
},
/**
* Wrapper around $.mobile.changePage() to do Horde framework specifc
* tasks.
*
* @param string|object page The page to navigate to.
* @param object data The request data object.
* @param object opts Options to pass to $.mobile.changePage.
*/
changePage: function(page, data, opts)
{
opts = opts || {};
if (data) {
opts.dataUrl = data.toPage;
}
opts.changeHash = false;
$.mobile.changePage($('#' + page), opts);
},
/**
* Returns the current page ID.
*
* @return string The page ID, or null if no page is loaded.
*/
currentPage: function(page)
{
return $.mobile.activePage
? $.mobile.activePage.attr('id')
: null;
},
/**
* Create a URL to a smartmobile page.
*
* @param string page The page name.
* @param object params URL parameters.
*/
createUrl: function(page, params)
{
var url = '#' + page, tmp = [];
params = params || {};
if (!$.isEmptyObject(params)) {
$.each(params, function(k, v) {
tmp.push(k + '=' + (typeof(v) == 'undefined' ? '' : v));
});
url += '?' + tmp.join('&');
}
return url;
},
/**
* Manually update hash: jqm exits too early if calling changePage() with
* the same page but different hash parameters.
*
* @param object url A parsed URL object.
*/
updateHash: function(url)
{
$.mobile.urlHistory.ignoreNextHashChange = true;
$.mobile.path.set(url.parsed.hash);
},
/**
* Commands to run when changing a page.
*/
onPageBeforeChange: function(e, data)
{
/* This code is needed for deep hash linking with parameters, since
* the jquery mobile code will consider these hashes invalid and will
* load the first page instead. */
if (!this.page_init &&
!$.mobile.activePage &&
typeof data.toPage !== 'string') {
data.toPage = location.href;
}
/* Add view/parameter data to dataUrl:
* - params: (object) List of URL parameters.
* - parsed: (object) Parsed URL object.
* - view: (string) The current view (URL hash value). */
if (typeof data.toPage === 'string') {
var parsed = $.mobile.path.parseUrl(data.toPage),
match = /^#([^?]*)/.exec(parsed.hash);
/* Sanity checking - make sure view exists. */
if (!this.page_init && match && !$(match[0]).size()) {
data.toPage = parsed.hrefNoHash;
parsed = $.mobile.path.parseUrl(data.toPage);
match = undefined;
}
data.options.parsedUrl = {
params: $.extend({}, parsed.search.toQueryParams(), parsed.hash.toQueryParams()),
parsed: parsed,
view: match ? match[1] : ($.mobile.firstPage ? $.mobile.firstPage.attr('id') : undefined)
};
} else {
data.options.parsedUrl = {};
if (typeof(data.toPage) != 'undefined' &&
data.toPage.attr('data-role') == 'dialog') {
data.options.changeHash = false;
}
}
this.page_init = true;
},
onPageChange: function(e, data)
{
$.mobile.navigate(data.options.dataUrl || ('#' + HordeMobile.currentPage()), {}, true);
},
/**
* Commands to run when the DOM is ready.
*/
onDocumentReady: function()
{
// Global ajax options.
$.ajaxSetup({
dataFilter: function(data) {
// Remove json security token
filter = /^\/\*-secure-([\s\S]*)\*\/s*$/;
return data.replace(filter, "$1");
}
});
// Setup notifications
$('#horde-notification').growler();
// Fix swipe threshold.
$.event.special.swipe.horizontalDistanceThreshold = 50;
}
};
$(HordeMobile.onDocumentReady);
$(document).on('pagebeforechange', HordeMobile.onPageBeforeChange)
.on('pagechange', HordeMobile.onPageChange)
.on('HordeMobile:runTasks', HordeMobile.runTasks);