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

1797 lines
51 KiB
JavaScript

/**
* jQuery Mobile UI application logic.
*
* @author Michael Slusarz <slusarz@horde.org>
* @copyright 2005-2015 Horde LLC
* @license GPL-2 (http://www.horde.org/licenses/gpl)
*/
var ImpMobile = {
// Vars used and defaulting to null/false:
//
// /* Attachment data for the current message. */
// atc,
//
// /* BUID of the currently displayed message. */
// buid,
//
// /* The current list of compose attachments. */
// composeatc,
//
// /* The current compose type. */
// composetype,
//
// /* Flag information. */
// flags,
//
// /* Has the folders list been loaded? */
// foldersLoaded,
//
// /* Header data for the current message. */
// headers,
//
// /* Is the current message from a list? */
// listmsg,
//
// /* The current mailbox. */
// mailbox,
//
// /* Cache ID for the current mailbox view. */
// mailboxCache,
//
// /* The current message data. */
// message,
//
// /* Current handle for the refresh interval action. */
// refresh,
//
// /* Current row UID of the displayed message. */
// rowid,
//
// /* Search parameters for the viewPort Ajax request. */
// search,
// Mailbox data cache.
cache: {},
// The scroll location of the current mailbox.
mailboxTop: 0,
// Rows per mailbox slice.
mbox_slice: 30,
// 'INBOX' base64url encoded
INBOX: 'SU5CT1g',
/**
* Event handler for the pagebeforechange event that implements loading of
* deep-linked pages.
*
* @param object e Event object.
* @param object data Event data.
*/
toPage: function(e, data)
{
var tmp, view = data.options.parsedUrl.view;
if ($.type(data.toPage) !== "string") {
switch (HordeMobile.currentPage()) {
case 'folders':
ImpMobile.mailboxTop = 0;
break;
case 'mailbox':
ImpMobile.mailboxTop = $(window).scrollTop();
break;
}
return;
}
switch (view) {
case 'compose':
$('#imp-compose-to-addr,#imp-compose-cc-addr,#imp-redirect-to-addr').empty();
if (!IMP.conf.disable_compose) {
$('#imp-compose-cache,#imp-compose-hmac').val('');
ImpMobile.compose(data);
}
e.preventDefault();
break;
case 'compose-attach':
ImpMobile.composeAttachRefresh();
$('#imp-compose-attach').popup('open');
e.preventDefault();
break;
case 'compose-cancel':
case 'compose-discard':
HordeMobile.doAction('cancelCompose', {
discard: ~~(view == 'compose-discard'),
imp_compose: $('#imp-compose-cache').val()
});
ImpMobile.closeCompose();
e.preventDefault();
break;
case 'compose-delete-addr':
data.options.link.next().remove();
data.options.link.remove();
e.preventDefault();
break;
case 'compose-draft':
case 'compose-submit':
ImpMobile.uniqueSubmit(
(view == 'compose-draft')
? 'saveDraft'
: ($('#imp-compose-form').is(':hidden') ? 'redirectMessage' : 'smartmobileSendMessage')
);
e.preventDefault();
break;
case 'copymove':
if (IMP.conf.allow_folders) {
ImpMobile.copymove(data);
}
e.preventDefault();
break;
case 'copymove-submit':
ImpMobile.copymoveSelected();
e.preventDefault();
break;
case 'folders-refresh':
$('#folders :jqmData(role=footer) a[href$="refresh"]').removeClass($.mobile.activeBtnClass).blur();
e.preventDefault();
// Fall-through
case 'folders':
if (ImpMobile.foldersLoaded) {
HordeMobile.doAction('poll', {
poll: JSON.stringify([])
});
}
break;
case 'folders-showall':
case 'folders-showpoll':
$('#folders :jqmData(role=footer) a[href*="folders-show"]').toggle();
ImpMobile.loadFolders();
e.preventDefault();
break;
case 'mailbox':
ImpMobile.toMailbox(data);
e.preventDefault();
break;
case 'mailbox-delete':
ImpMobile.deleteMessage(
(data.options.data || data.options.link).jqmData('buid')
);
e.preventDefault();
break;
case 'mailbox-innocent':
case 'mailbox-spam':
ImpMobile.reportSpam(
view.match(/spam$/) ? 'spam' : 'innocent',
(data.options.data || data.options.link).jqmData('buid')
);
e.preventDefault();
break;
case 'mailbox-more':
ImpMobile.cache[ImpMobile.mailbox].slice += ImpMobile.mbox_slice;
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: ImpMobile.mailbox
}), {
data: { force: true }
});
e.preventDefault();
break;
case 'mailbox-refresh':
ImpMobile.refreshMailbox();
e.preventDefault();
$('#mailbox :jqmData(role=footer) a[href$="refresh"]').removeClass($.mobile.activeBtnClass).blur();
break;
case 'message':
ImpMobile.toMessage(data);
e.preventDefault();
break;
case 'message-delete':
ImpMobile.deleteMessage(ImpMobile.buid);
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: ImpMobile.mailbox
}), {
data: { noajax: true }
});
e.preventDefault();
return;
case 'message-forward':
$.mobile.changePage(HordeMobile.createUrl('compose', {
buid: ImpMobile.buid,
mbox: ImpMobile.mailbox,
type: 'forward_auto'
}));
e.preventDefault();
break;
case 'message-next':
case 'message-prev':
ImpMobile.navigateMessage(view.match(/next$/) ? 1 : -1);
e.preventDefault();
break;
case 'message-redirect':
$.mobile.changePage(HordeMobile.createUrl('compose', {
buid: ImpMobile.buid,
mbox: ImpMobile.mailbox,
type: 'forward_redirect'
}));
e.preventDefault();
break;
case 'message-reply-all':
case 'message-reply-auto':
case 'message-reply-list':
case 'message-reply-sender':
tmp = 'reply';
switch (view) {
case 'message-reply-all':
tmp += '_all';
break;
case 'message-reply-auto':
tmp += '_auto';
break;
case 'message-reply-list':
tmp += '_list';
break;
}
$.mobile.changePage(HordeMobile.createUrl('compose', {
buid: ImpMobile.buid,
mbox: ImpMobile.mailbox,
type: tmp
}));
e.preventDefault();
break;
case 'message-innocent':
case 'message-spam':
$(view.match(/innocent/) ? '#imp-innocent-confirm' : '#imp-spam-confirm').popup('open');
e.preventDefault();
break;
case 'message-innocent-confirm':
case 'message-spam-confirm':
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: ImpMobile.mailbox
}), {
data: { noajax: true }
});
ImpMobile.reportSpam(
(view.match(/innocent/) ? 'innocent' : 'spam'),
ImpMobile.buid
);
e.preventDefault();
break;
case 'search-exit':
$('#mailbox .smartmobile-back').removeClass($.mobile.activeBtnClass).blur();
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: data.options.parsedUrl.params.mbox
}));
e.preventDefault();
break;
case 'search-submit':
ImpMobile.search = {
qsearch: $('#imp-search-input').val(),
qsearchfield: $('#imp-search-by').val(),
qsearchmbox: (ImpMobile.search ? ImpMobile.search.qsearchmbox : ImpMobile.mailbox)
};
delete ImpMobile.mailboxCache;
delete ImpMobile.cache[IMP.conf.qsearchid];
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: IMP.conf.qsearchid
}));
e.preventDefault();
break;
case 'unblock-image':
IMP_JS.unblockImages(data.options.link.closest('DIV.mimePartBase').find('IFRAME.htmlMsgData'));
data.options.link.remove();
e.preventDefault();
break;
}
},
/**
*/
beforeShow: function(undefined, data)
{
switch (HordeMobile.currentPage()) {
case 'compose':
if (!$('#compose-more ul').children().size()) {
$('#compose :jqmData(role=footer) a[href$="compose-more"]').hide();
}
break;
case 'copymove':
if (!$('#imp-copymove-list').children().size()) {
HordeMobile.doAction(
'copyMoveMailboxList',
{},
function(r) {
$('#imp-copymove-list')
.html(r)
.change(function() {
$.fn[$(this[this.selectedIndex]).hasClass('flistCreate') ? 'show' : 'hide'].call($('#imp-copymove-newdiv'));
})
.find('.flistMailboxes OPTION[value=""]').attr('disabled', true);
},
{ async: false }
);
}
$('#imp-copymove')[0].reset();
$('#imp-copymove-action,#imp-copymove-list').selectmenu('refresh', true);
$('#imp-copymove-action').selectmenu(ImpMobile.cache[ImpMobile.mailbox].readonly ? 'disable' : 'enable');
$('#imp-copymove-newdiv').hide();
break;
case 'search':
if (!ImpMobile.search) {
$('#imp-search-form').trigger('reset').find('select').selectmenu('refresh');
}
break;
}
},
/**
*/
pageShow: function()
{
switch (HordeMobile.currentPage()) {
case 'folders':
if (!ImpMobile.foldersLoaded) {
ImpMobile.loadFolders();
}
break;
case 'mailbox':
$.mobile.silentScroll(ImpMobile.mailboxTop);
// Need to do here since Exit Search does not trigger beforeShow.
$.fn[ImpMobile.search ? 'hide' : 'show'].call($('#imp-mailbox-search'));
$.fn[ImpMobile.search ? 'show' : 'hide'].call($('#imp-mailbox-searchedit'));
break;
case 'message':
$('#imp-message-headers,#imp-message-atc').trigger('collapse');
break;
}
},
/**
* Switches to the mailbox view and loads a mailbox.
*
* @param object data Page change data object.
*/
toMailbox: function(data)
{
var purl = data.options.parsedUrl,
mailbox = purl.params.mbox || ImpMobile.INBOX,
noajax = purl.params.noajax || (data.options.data && data.options.data.noajax),
title = $('#imp-mailbox-' + mailbox).text(),
params, ob;
document.title = title;
$('#mailbox .smartmobile-title').text(title);
if (ImpMobile.mailbox != mailbox) {
$('#imp-mailbox-list').empty();
if (mailbox == IMP.conf.qsearchid) {
if (!ImpMobile.search) {
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: ImpMobile.INBOX
}));
return;
}
$('#mailbox .smartmobile-back').attr(
'href',
HordeMobile.createUrl('search-exit', {
mbox: ImpMobile.search.qsearchmbox
})
).find('.ui-btn-text').text(IMP.text.exitsearch);
} else if (ImpMobile.search) {
delete ImpMobile.search;
$('#mailbox .smartmobile-back').attr('href', '#folders')
.find('.ui-btn-text').text(IMP.text.folders);
HordeMobile.updateHash(purl);
}
ImpMobile.mailbox = mailbox;
}
params = ImpMobile.search || {};
HordeMobile.changePage('mailbox', data);
if ((!data.options.data || !data.options.data.force) &&
(ob = ImpMobile.cache[mailbox])) {
ImpMobile.refreshMailbox(ob);
if (noajax) {
return;
}
params.checkcache = 1;
}
HordeMobile.doAction(
'viewport',
ImpMobile.addViewportParams($.extend(params, {
view: mailbox
}))
);
},
/**
*/
addViewportParams: function(params)
{
params = params || {};
var p, slice,
ob = ImpMobile.cache[ImpMobile.mailbox];
if (ob) {
params.cache = ImpMobile.toUidString(ob.cachedIds());
params.cacheid = ob.cacheid;
slice = ob.slice;
} else {
params.initial = 1;
params.force = 1;
slice = ImpMobile.mbox_slice;
}
if (!params.search) {
params.slice = '1:' + slice;
}
p = {
view: params.view,
viewport: JSON.stringify(params)
};
if (!ImpMobile.flags) {
p.flag_config = 1;
}
return p;
},
/**
* Callback method to update viewport information.
*
* @param object r The Ajax response object.
*/
viewport: function(r)
{
var ob;
if (!(ob = ImpMobile.cache[r.view])) {
ob = ImpMobile.cache[r.view] = $.extend(true, {}, ImpMobileMbox);
ob.slice = ImpMobile.mbox_slice;
if (r.metadata.readonly || r.metadata.nodelete) {
ob.readonly = 1;
}
ob.innocent = r.metadata.innocent_show;
ob.label = r.metadata.slabel
? r.metadata.slabel
: r.label;
ob.spam = r.metadata.spam_show;
}
ob.cacheid = r.cacheid;
if (r.data_reset) {
ob.data = {};
}
if (r.rowlist_reset) {
ob.rowlist = {};
ob.totalrows = 0;
}
if (r.data) {
ob.update(r.data, r.rowlist, r.totalrows);
}
if (r.disappear) {
ob.disappear(r.disappear);
}
ImpMobile.resetRefresh();
ImpMobile.refreshMailbox(ob);
},
/**
* Refresh the current mailbox.
*
* @param object ob If ob is not present, triggers an AJAX refresh.
* Otherwise, rebuilds mailbox using ob.
*/
refreshMailbox: function(ob)
{
if (!ob) {
if (HordeMobile.currentPage() != 'folders') {
HordeMobile.doAction(
'viewPort',
ImpMobile.addViewportParams({
checkcache: 1,
view: ImpMobile.mailbox
})
);
}
return;
}
if (HordeMobile.currentPage() != 'mailbox') {
return;
}
var list, tmp,
cid = ImpMobile.mailbox + '|' + ob.cacheid + '|' + ob.slice;
if (cid == ImpMobile.mailboxCache) {
return;
}
ImpMobile.mailboxCache = cid;
document.title = ob.label;
$('#mailbox .smartmobile-title').text(ob.label);
list = $('#imp-mailbox-list')
.empty()
.append(tmp = $('<li data-role="list-divider"></li>'));
switch (ob.totalrows) {
case 0:
tmp.text(IMP.text.message_0);
break;
case 1:
tmp.text(IMP.text.message_1);
break;
default:
tmp.text(IMP.text.message_2.replace('%d', ob.totalrows));
break;
}
$.each(ob.rows(), function(key, val) {
var c = $('<li class="imp-message"></li>')
.jqmData('buid', val.buid),
labels = [],
tmp,
url = HordeMobile.createUrl('message', {
buid: val.buid,
mbox: ImpMobile.mailbox
});
if (val.data.flag) {
$.each(val.data.flag, function(k, flag) {
switch (flag) {
case IMP.conf.flags.deleted:
c.addClass('imp-mailbox-deleted');
break;
case IMP.conf.flags.draft:
url = HordeMobile.createUrl('compose', {
buid: val.buid,
mbox: ImpMobile.mailbox,
type: 'resume'
});
break;
case IMP.conf.flags.seen:
c.addClass('imp-mailbox-seen');
break;
default:
/* All other flags are added as labels. */
if (ImpMobile.flags[flag]) {
tmp = ImpMobile.flags[flag];
if (tmp.s) {
labels.push(
$('<span></span>')
.addClass('imp-mailbox-label')
.css({
background: (tmp.b ? tmp.b : ''),
color: tmp.f
})
.text(tmp.l)
);
}
}
break;
}
});
}
list.append(
c.append(
$('<a href="' + url + '"></a>').text(val.data.subject)
).append(
$('<div class="imp-mailbox-secondrow"></div>').append(
$('<span class="imp-mailbox-date"></span>').text(
val.data.date
)
).append(
$('<span class="imp-mailbox-from"></span>').text(
val.data.from
).append(labels)
)
)
);
});
if (ob.totalrows > ob.slice) {
list.append($('<li class="imp-mailbox-more"></li>').append(
$('<a href="#mailbox-more"></a>').text(
IMP.text.more_msgs)));
}
list.listview('refresh');
},
/**
* Resets the current mailbox refresh interval.
*/
resetRefresh: function()
{
if (IMP.conf.refresh_time) {
window.clearInterval(ImpMobile.refresh);
ImpMobile.refresh = window.setInterval(
ImpMobile.refreshMailbox,
IMP.conf.refresh_time * 1000
);
}
},
/**
* Switches to the message view and loads a message.
*
* @param object data Page change data object.
*/
toMessage: function(data)
{
var purl = data.options.parsedUrl,
params = {};
if (!ImpMobile.mailbox) {
ImpMobile.mailbox = purl.params.mbox;
}
HordeMobile.changePage('message', data);
// Page is cached.
if (ImpMobile.buid == purl.params.buid &&
ImpMobile.mailbox == purl.params.mbox) {
document.title = $('#message .smartmobile-title').text();
return;
}
$('#message :jqmData(role=content)').hide();
$('#message .smartmobile-title').text('');
document.title = '';
HordeMobile.doAction(
'showMessage',
$.extend(ImpMobile.addViewportParams($.extend(params, {
view: purl.params.mbox
})), {
buid: purl.params.buid
}),
ImpMobile.messageLoaded
);
},
/**
* Navigates to the next/previous message page.
*
* @param integer dir Jump length.
*/
navigateMessage: function(dir)
{
var buid,
ob = ImpMobile.cache[ImpMobile.mailbox],
pos = ob.rowlist[ImpMobile.rowid] + dir;
if (pos > 0 &&
pos <= ob.totalrows &&
(buid = ob.rowToBuid(pos))) {
$.mobile.changePage(HordeMobile.createUrl('message', {
buid: buid,
mbox: ImpMobile.mailbox
}));
}
},
/**
* Callback method after the message has been loaded.
*
* @param object r The Ajax response object.
*/
messageLoaded: function(r)
{
// TODO: Error handling.
if (r.error ||
!ImpMobile.message ||
(r.view != ImpMobile.mailbox)) {
return;
}
var cache = ImpMobile.cache[ImpMobile.mailbox],
data = ImpMobile.message,
tmp;
// TODO: Remove once we can pass viewport parameters directly to the
// showMessage request.
if (!cache) {
window.setTimeout(function() { ImpMobile.messageLoaded(r); }, 0);
return;
}
ImpMobile.buid = r.buid;
document.title = data.title;
$('#message .smartmobile-title').text(data.title);
tmp = (ImpMobile.mailbox == IMP.conf.qsearchid);
$('#message .smartmobile-back').attr(
'href',
HordeMobile.createUrl('mailbox', {
mbox: (tmp ? IMP.conf.qsearchid : ImpMobile.mailbox),
noajax: 1
})
).find('.ui-btn-text').text(
tmp ? IMP.text.searchresults : cache.label
);
$('#imp-message-from').text(
data.from
? (data.from.raw || data.from.addr[0].g || data.from.addr[0].p || data.from.addr[0].b)
: IMP.text.nofrom
);
if (data.atc_label) {
$('#imp-message-atc').show();
$('#imp-message-atclabel').text(data.atc_label);
ImpMobile.atc = data.atc_list;
} else {
$('#imp-message-atc').hide();
delete ImpMobile.atc;
}
$('#imp-message-body').html(data.msgtext);
$('#imp-message-date').text('');
$.each(data.headers, function(k, v) {
if (v.id == 'Date') {
$('#imp-message-date').text(v.value);
}
});
data.headers.push({ name: IMP.text.subject, value: data.subject });
ImpMobile.headers = {
Cc: data.cc,
From: data.from,
headers: data.headers,
To: data.to
};
ImpMobile.listmsg = (data.list_info && data.list_info.exists);
ImpMobile.rowid = r.buid;
$.fn[cache.readonly ? 'hide' : 'show'].call($('#imp-message-delete'));
if (data.js) {
$.each(data.js, function(k, js) {
$.globalEval(js);
});
}
$('#message :jqmData(role=content)').show();
tmp = $('#imp-message-headers');
$.mobile.silentScroll(parseInt(tmp.position().top, 10) + parseInt(tmp.height(), 10) - $('#message > :jqmData(role=header)').height());
delete ImpMobile.message;
},
/**
*/
messageMorePopup: function()
{
var cache = ImpMobile.cache[ImpMobile.mailbox],
list = $('#message-more :jqmData(role=listview)'),
row = cache.rowlist[ImpMobile.rowid];
list.children().each(function() {
var elt = $(this),
a = elt.find('a:first'),
id = a.attr('id');
if (id) {
switch (id) {
case 'imp-message-copymove':
/* Need to manually set href parameters for dialog links,
* since there is no way to programatically open one. */
a.attr('href', HordeMobile.createUrl('copymove', {
buid: ImpMobile.buid,
mbox: ImpMobile.mailbox
}));
break;
case 'imp-message-innocent':
$.fn[!cache.innocent ? 'hide' : 'show'].call(elt);
break;
case 'imp-message-next':
$.fn[(row == cache.maxRow()) ? 'hide' : 'show'].call(elt);
break;
case 'imp-message-prev':
$.fn[(row == 1) ? 'hide' : 'show'].call(elt);
break;
case 'imp-message-spam':
$.fn[!cache.spam ? 'hide' : 'show'].call(elt);
break;
}
}
});
list.listview('refresh');
},
/**
*/
messageReplyPopup: function()
{
var list = $('#message-reply :jqmData(role=listview)');
$.fn[ImpMobile.listmsg ? 'show' : 'hide'].call(list.find('a[href$="message-reply-list"]').parents('li'));
list.listview('refresh');
},
/**
*/
fullHeaders: function()
{
if (!ImpMobile.headers) {
return;
}
var h = $('#imp-message-headers-full tbody');
h.children().remove();
$.each(ImpMobile.headers.headers, function(k, header) {
var td, tmp;
if (header.value) {
td = $('<td class="imp-header-label-value"></td>');
switch (header.id) {
case 'Cc':
case 'From':
case 'To':
tmp = ImpMobile.headers[header.id];
if (tmp.raw) {
td.html(tmp.raw);
} else {
$.each(tmp.addr, function(k2, addr) {
if (addr.g) {
} else if (addr.p || addr.b) {
td.append(
$('<a></a>')
.attr('href', HordeMobile.createUrl('compose', { to: addr.b }))
.attr('data-role', 'button')
.attr('data-theme', 'b')
.text(addr.p ? (addr.p + ' <' + addr.b + '>') : addr.b)
.button()
);
}
});
}
break;
default:
td.html(header.value);
break;
}
h.append($('<tr></tr>')
.append($('<td class="imp-header-label"></td>')
.html(header.name + ':'))
.append(td)
);
}
});
delete ImpMobile.headers;
},
/**
*/
showAttachments: function()
{
if (!ImpMobile.atc) {
return;
}
var list = $('#imp-message-atclist').empty();
$.each(ImpMobile.atc, function(k, v) {
list.append(
$('<li class="imp-message-atc"></li>').append(
$('<a></a>').attr({
href: v.download_url,
rel: 'external'
}).append(
$(v.icon).addClass('ui-li-icon')
).append(
document.createTextNode(v.description_raw + ' (' + v.size + ')')
)
)
);
});
list.listview('refresh');
delete ImpMobile.atc;
// TODO: Workaround bug(?) in jQuery Mobile where inset style is not
// applied until listview is visible.
window.setTimeout(function() { list.listview('refresh'); }, 0);
},
/**
*/
deleteMessage: function(buid)
{
HordeMobile.doAction(
'deleteMessages',
$.extend(ImpMobile.addViewportParams({
checkcache: 1,
force: 1,
view: ImpMobile.mailbox
}), {
buid: buid
})
);
},
/**
*/
reportSpam: function(action, buid)
{
HordeMobile.doAction(
'reportSpam',
$.extend(ImpMobile.addViewportParams({
checkcache: 1,
force: 1,
view: ImpMobile.mailbox
}), {
buid: buid,
spam: ~~(action == 'spam')
})
);
},
/**
* Switches to the compose view and loads a message if replying or
* forwarding.
*
* @param object data Page change data object.
*/
compose: function(data)
{
var func,
params = {},
purl = data.options.parsedUrl;
$('#compose .smartmobile-title').html(IMP.text.new_message);
if (purl.params.to || purl.params.cc) {
ImpMobile.addAddress('compose-to', purl.params.to);
ImpMobile.addAddress('compose-cc', purl.params.cc);
}
$('#imp-compose-form').show();
$('#imp-redirect-form').hide();
ImpMobile.composeatc = [];
ImpMobile.composetype = purl.params.type;
switch (purl.params.type) {
case 'reply':
case 'reply_all':
case 'reply_auto':
case 'reply_list':
func = 'getReplyData';
params.format = 'text';
break;
case 'forward_auto':
func = 'smartmobileGetForwardData';
params.format = 'text';
break;
case 'forward_redirect':
$('#imp-compose-form').hide();
$('#imp-redirect-form').show();
func = 'getRedirectData';
break;
case 'resume':
case 'template':
func = 'getResumeData';
params.format = 'text';
break;
default:
HordeMobile.changePage('compose', data);
return;
}
HordeMobile.doAction(
func,
$.extend(params, {
buid: purl.params.buid,
type: purl.params.type,
view: purl.params.mbox
}),
function(r) { ImpMobile.composeLoaded(r, data); }
);
},
/**
* Callback method after the compose content has been loaded.
*
* @param object r The Ajax response object.
* @param object data Page change data object.
*/
composeLoaded: function(r, data)
{
if (r.type != 'forward_redirect') {
if (!r.opts) {
r.opts = {};
}
r.opts.noupdate = true;
var id = (r.identity === null)
? $('#imp-compose-identity').val()
: r.identity;
$('#imp-compose-identity,#imp-compose-last-identity').val(id);
// The first selectmenu() call is necessary to actually create the
// selectmenu if the compose window is opened for the first time,
// the second call to update the menu in case the selected index
// changed.
$('#imp-compose-identity').selectmenu()
.selectmenu('refresh', true);
if (r.addr) {
$.each(r.addr.to, function(k, v) {
ImpMobile.addAddress('compose-to', v);
});
$.each(r.addr.cc, function(k, v) {
ImpMobile.addAddress('compose-cc', v);
});
}
$('#imp-compose-subject').val(r.subject);
$('#imp-compose-message').val(r.body);
$('#imp-compose-' + (r.opts.focus || 'to').replace(/composeMessage/, 'message'))[0].focus();
}
HordeMobile.changePage('compose', data);
},
/**
*/
composeMorePopup: function()
{
var list = $('#compose-more :jqmData(role=listview)');
list.children().each(function() {
var elt = $(this),
id = elt.find('a:first').attr('id');
switch (id) {
case 'imp-compose-discard':
$.fn[(ImpMobile.composetype != 'resume') ? 'hide' : 'show'].call(elt);
break;
}
});
list.listview('refresh');
},
/**
*/
composeAttachRefresh: function()
{
var list = $('#imp-compose-attach :jqmData(role=listview)').empty();
$.each(ImpMobile.composeatc, function(k, v) {
list.append(
$('<li class="imp-compose-atc"></li>').append(
$('<img></img>')
.addClass('ui-li-icon')
.attr('src', v.icon)
).append(
v.name + ' (' + v.size + ')'
)
);
});
list.listview('refresh').siblings('FORM')[0].reset();
},
/**
*/
addAddress: function(f, addr)
{
if (addr) {
$('#imp-' + f + '-addr').prepend(
$('<input></input>')
.attr('name', (f == 'redirect-to' ? 'redirect_to' : f.substr(8)) + '[]')
.attr('type', 'hidden')
.val(addr)
).prepend(
$('<a></a>')
.attr('href', '#compose-delete-addr')
.attr('data-role', 'button')
.attr('data-icon', 'delete')
.attr('data-iconpos', 'right')
.attr('data-theme', 'b')
.text(addr)
.button()
);
}
},
/**
*/
processComposeAddress: function(e, prev)
{
var chr, pos = 0, tmp,
val = $(this).val();
if (val.length > prev.length) {
// Optimization when only one character was added
if (val.length - prev.length == 1) {
tmp = val.charAt(val.length - 1);
if (tmp != ',' && tmp != ';') {
return;
}
}
chr = val.charAt(pos);
while (chr !== "") {
switch (chr) {
case ',':
case ';':
if (!pos) {
val = val.substr(1);
} else if (val.charAt(pos - 1) != '\\') {
ImpMobile.addAddress($(this).attr('id').substr(4), $.trim(val.substr(0, chr == ';' ? pos + 1 : pos)));
val = val.substr(pos + 2);
pos = 0;
}
break;
default:
++pos;
break;
}
chr = val.charAt(pos);
}
$(this).val($.trim(val));
}
},
/**
* Load the folders list.
*/
loadFolders: function()
{
ImpMobile.foldersLoaded = false;
HordeMobile.doAction(
'smartmobileFolderTree',
{ all: ImpMobile.showAllFolders() },
function(r) {
$('#imp-folders-list').html(r).listview('refresh');
ImpMobile.foldersLoaded = true;
}
);
},
uniqueSubmit: function(action)
{
var form = (action == 'redirectMessage')
? $('#imp-redirect-form')
: $('#imp-compose-form');
if (action == 'sendMessage' &&
$('#imp-compose-subject').val().empty() &&
!window.confirm(IMP.text.nosubject)) {
return;
}
HordeMobile.doAction(
action,
HordeJquery.formToObject(form),
ImpMobile.uniqueSubmitCallback
);
},
uniqueSubmitCallback: function(d)
{
if (d && d.success) {
ImpMobile.closeCompose();
}
},
closeCompose: function()
{
$.each($('#imp-compose-form,#imp-redirect-form'), function(k, form) {
form.reset();
});
$.each($('#imp-compose-to,#imp-compose-cc,#imp-redirect-to'), function(undefined, v) {
$(v).autocomplete('clear');
});
window.history.back();
},
/**
* Opens a copy/move message dialog.
*
* @param object data Page change data object.
*/
copymove: function(data)
{
var purl = data.options.parsedUrl;
HordeMobile.changePage('copymove');
$('#imp-copymove-buid').val(purl.params.buid);
$('#imp-copymove-mbox').val(purl.params.mbox);
},
/**
* Moves or copies a message to a selected mailbox.
*/
copymoveSelected: function()
{
var opts = {},
cmlist = $('#imp-copymove-list'),
source = $('#imp-copymove-mbox').val(),
move = ($('#imp-copymove-action').val() == 'move');
if (cmlist.find(':selected').hasClass('flistCreate')) {
opts.newmbox = $.trim($('#imp-copymove-new').val());
if (opts.newmbox === "") {
window.alert(IMP.text.move_nombox);
return;
}
} else {
opts.mboxto = cmlist.val();
}
HordeMobile.doAction(
move ? 'moveMessages' : 'copyMessages',
$.extend(ImpMobile.addViewportParams({
checkcache: 1,
force: ~~(move),
view: source
}), opts, {
buid: $('#imp-copymove-buid').val()
})
);
if (IMP.conf.mailbox_return || move) {
$.mobile.changePage(HordeMobile.createUrl('mailbox', {
mbox: source
}), {
data: { noajax: true }
});
} else {
$('#copymove').dialog('close');
}
},
/**
* Update message flags.
*
* @param object r The Ajax response object.
*/
updateFlags: function(r)
{
$.each(r, function(k, v) {
$.each(v.buids, function(k2, v2) {
var c = ImpMobile.cache[k2];
if (c) {
$.each(ImpMobile.fromUidString(v2), function(k3, v3) {
if (c.data[v3]) {
var ob = c.data[v3].flag, tmp = [];
if (v.add) {
$.merge(ob, v.add);
$.each(ob, function(i, v4) {
if ($.inArray(v4, tmp) === -1) {
tmp.push(v4);
}
});
ob = tmp;
}
if (v.remove) {
ob = $.grep(ob, function(n) {
return $.inArray(n, v.remove) < 0;
});
}
}
});
}
});
});
},
/**
* Update unseen message count for folders.
*
* @param object r The Ajax response object.
*/
updateFolders: function(r)
{
/* If redrawing the folders via smartmobileFolderTree action, this
* task will be executed before the list is refreshed. */
if (!ImpMobile.foldersLoaded &&
(HordeMobile.currentPage() == 'folders')) {
window.setTimeout(function() { ImpMobile.updateFolders(r); }, 100);
}
$.each(r, function(key, value) {
var elt = $('#imp-mailbox-' + key);
if (value) {
if (!elt.siblings('.ui-li-count').size()) {
elt.after('<span class="ui-li-count"></span>');
}
elt.siblings('.ui-li-count').text(value);
} else if (!value) {
elt.siblings('.ui-li-count').remove();
}
});
if (HordeMobile.currentPage() == 'folders') {
$('#imp-folders-list').listview('refresh');
}
},
/**
* Are all folders shown?
*
* @return integer 1 if all folders are shown.
*/
showAllFolders: function()
{
return $('#folders :jqmData(role=footer) a[href$="folders-showpoll"]').filter(':visible').length;
},
/**
* Converts an array to a UID range string.
*
* @param array uids Array of UIDs.
*
* @return string The UID range string.
*/
toUidString: function(uids)
{
var u = uids.numericSort(),
first = u.shift(),
last = first,
out = [];
$.each(u, function(n, k) {
if (last + 1 == k) {
last = k;
} else {
out.push(first + (last == first ? '' : (':' + last)));
first = last = k;
}
});
out.push(first + (last == first ? '' : (':' + last)));
return out.join(',');
},
/**
* Converts a UID range string to an array.
*
* @param string str UID range string.
*
* @return array UID array.
*/
fromUidString: function(str)
{
var out = [];
$.each($.trim(str).split(','), function(n, e) {
var i, r = e.split(':');
if (r.length == 1) {
out.push(Number(e));
} else {
for (i = Number(r[0]); i <= Number(r[1]); ++i) {
out.push(Number(i));
}
}
});
return out;
},
/**
*/
runTasks: function(e, d)
{
var v;
if ((v = d['imp:compose'])) {
$.fn[v.atclimit ? 'hide' : 'show'].call($('#imp-compose-attach-form'));
if (v.cacheid) {
if ($('#imp-redirect-form').css('display') != 'none') {
$('#imp-redirect-cache').val(v.cacheid);
} else {
$('#imp-compose-cache').val(v.cacheid);
$('#imp-compose-hmac').val(v.hmac);
}
}
}
if ((v = d['imp:compose-atc'])) {
ImpMobile.composeatc = ImpMobile.composeatc.concat(v);
}
if ((v = d['imp:flag'])) {
ImpMobile.updateFlags(v);
// Force a viewport update.
ImpMobile.mailboxCache = null;
}
if ((v = d['imp:flag-config'])) {
ImpMobile.flags = {};
$.each(v, function(undefined, value) {
ImpMobile.flags[value.id] = value;
});
}
if ((v = d['imp:message'])) {
ImpMobile.message = v.shift().data;
}
if (d['imp:mailbox']) {
ImpMobile.foldersLoaded = false;
}
if ((v = d['imp:poll'])) {
ImpMobile.updateFolders(v);
}
if ((v = d['imp:viewport'])) {
ImpMobile.viewport(v);
}
},
/**
*/
swipeButtons: function(e, ob)
{
$.each($($('#imp-mailbox-buttons').children()), function(k, v) {
v = $(v);
if (ImpMobile.mailboxAction(v)) {
ob.buttons.push(v.clone(true));
}
});
},
/**
*/
mailboxAction: function(v)
{
switch (v.attr('href')) {
case '#mailbox-delete':
return !ImpMobile.cache[ImpMobile.mailbox].readonly;
case '#mailbox-innocent':
return ImpMobile.cache[ImpMobile.mailbox].innocent;
case '#mailbox-spam':
return ImpMobile.cache[ImpMobile.mailbox].spam;
default:
return true;
}
},
/**
*/
mailboxTaphold: function(e)
{
$.each($('#imp-mailbox-taphold li'), function(k, v) {
v = $(v);
if (ImpMobile.mailboxAction(v.find('a'))) {
v.show().find('a').jqmData('buid', $(e.currentTarget).jqmData('buid'));
} else {
v.hide();
}
});
$('#imp-mailbox-taphold ul').listview('refresh');
},
/**
* Event handler for the document-ready event, responsible for the initial
* setup.
*/
onDocumentReady: function()
{
$('#imp-mailbox-list')
.swipebutton()
.on('swipebutton', 'li.imp-message', ImpMobile.swipeButtons)
.listviewtaphold({ popupElt: $('#imp-mailbox-taphold') })
.on('listviewtaphold', 'li.imp-message', ImpMobile.mailboxTaphold);
ImpMobile.resetRefresh();
$('#message').on('swipeleft', function() {
$.mobile.changePage('#message-next');
}).on('swiperight', function() {
$.mobile.changePage('#message-prev');
}).on('popupbeforeposition', function(r) {
switch ($(r.target).attr('id')) {
case 'message-more':
ImpMobile.messageMorePopup();
break;
case 'message-reply':
ImpMobile.messageReplyPopup();
break;
}
});
$('#imp-message-headers').on('expand', ImpMobile.fullHeaders);
$('#imp-message-atc').on('expand', ImpMobile.showAttachments);
$('#compose').on('popupbeforeposition', function() {
ImpMobile.composeMorePopup();
});
if (!IMP.conf.disable_compose) {
$('#imp-compose-upload-container a').on('click', function(e) {
$('#imp-compose-upload-container input').trigger('click');
e.preventDefault();
});
$('#imp-compose-upload-container input').on('change', function() {
HordeMobile.doAction('addAttachment', {
composeCache: $('#imp-compose-cache').val(),
json_return: true
}, ImpMobile.composeAttachRefresh, {
submit: $(this).closest('FORM')
});
});
$.each([ 'compose-to', 'compose-cc', 'redirect-to' ], function(undefined, v) {
$('#imp-' + v)
.autocomplete({
callback: function(e) {
ImpMobile.addAddress(v, $.trim($(e.currentTarget).text()));
$('#imp-' + v).val('');
},
link: '#',
minLength: 3,
source: 'smartmobileAutocomplete',
target: $('#imp-' + v + '-suggestions')
})
// textchange plugin requires bind()
.bind('textchange', ImpMobile.processComposeAddress);
});
}
}
};
// JQuery Mobile setup
$(ImpMobile.onDocumentReady);
$(document).on('pagebeforechange', ImpMobile.toPage)
.on('pagebeforeshow', ImpMobile.beforeShow)
.on('pagechange', ImpMobile.pageShow)
.on('HordeMobile:runTasks', ImpMobile.runTasks);
var ImpMobileMbox = {
// Vars used: cacheid, label, readonly
data: {},
rowlist: {},
slice: 0,
totalrows: 0,
update: function(data, rowlist, totalrows)
{
if (data.length !== 0) {
$.extend(this.data, data);
}
if (rowlist.length !== 0) {
$.extend(this.rowlist, rowlist);
}
this.totalrows = totalrows;
},
cachedIds: function()
{
var ids = [];
$.each(this.data, function(key) {
ids.push(key);
});
return ids;
},
disappear: function(ids)
{
if (!ids.length) {
return;
}
var t = this;
$.each(ids, function(key, value) {
delete t.data[value];
});
},
rows: function()
{
var mbox_data = this.data;
return $.map($.map(this.rowlist, function(value, key) {
return { sort: value, buid: key };
}).sort(function(a, b) {
return (a.sort < b.sort) ? -1 : 1;
}), function(value) {
return {
buid: value.buid,
data: mbox_data[value.buid]
};
});
},
rowToBuid: function(row)
{
var buid;
$.each(this.rowlist, function(b, p) {
if (p == row) {
buid = b;
return;
}
});
return buid;
},
maxRow: function()
{
return Math.min(this.slice, this.totalrows);
}
};
var IMP_JS = {
iframeInject: function(id, data)
{
id = $('#' + id);
var d = id.get(0).contentWindow.document;
id.one('load', function() {
window.setTimeout(function() { IMP_JS.iframeResize(id); }, 0);
});
d.open();
d.write(data);
d.close();
/* Catch compose links within HTML IFRAME data. */
$(d).on('click', 'a', function(e) {
var href = $(e.target).attr('href');
if (href.match(/\#compose[\?$]/)) {
$.mobile.changePage(href);
e.preventDefault();
}
});
id.show().prev().remove();
},
iframeResize: function(id)
{
id = $(id);
id.height(id.contents().height());
},
/**
* Use DOM manipulation to un-block images.
*/
unblockImages: function(iframe)
{
var doc = $(iframe.get(0).contentWindow.document),
imgload = false;
$.each(doc.find('[htmlimgblocked]'), function(k, v) {
v = $(v);
var src = v.attr('htmlimgblocked');
v.removeAttr('htmlimgblocked');
if (v.attr('src')) {
v.one('load', function() { IMP_JS.iframeResize(iframe); });
v.attr('src', src);
imgload = true;
} else {
if (v.attr('background')) {
v.attr('background', src);
}
if (v.css('background-image')) {
v.css('background-image', 'url(' + src + ')');
}
}
});
$.each(doc.find('[htmlimgblocked_srcset]'), function(k, v) {
v = $(v);
v.attr('srcset', v.attr('htmlimgblocked_srcset'));
v.removeAttr('htmlimgblocked_srcset');
});
$.each(doc.find('[htmlcssblocked]'), function(k, v) {
v = $(v);
v.attr('href', v.attr('htmlcssblocked'));
v.removeAttr('htmlcssblocked');
});
doc.find('STYLE[type="text/x-imp-cssblocked"]')
.attr('type', 'text/css');
if (!imgload) {
IMP_JS.iframeResize(iframe);
}
}
};