345 lines
9.4 KiB
JavaScript
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);
|