From 78e468a7ae10464036be985bd36d1a67a99c0f18 Mon Sep 17 00:00:00 2001 From: Michael M Slusarz Date: Sun, 30 Nov 2008 23:35:28 -0700 Subject: [PATCH] Merge DIMP with IMP. None of this works yet. --- imp/compose-dimp.php | 347 ++++ imp/config/conf.xml | 77 + imp/config/hooks.php.dist | 118 ++ imp/config/menu.php.dist | 4 +- imp/config/portal.php.dist | 49 + imp/config/prefs.php.dist | 28 +- imp/docs/CREDITS | 8 + imp/docs/INSTALL | 54 +- imp/imp-dimp.php | 720 ++++++++ imp/imple.php | 41 +- imp/index-dimp.php | 78 + imp/js/ContextSensitive.js | 1 + imp/js/DimpBase.js | 1 + imp/js/DimpCore.js | 1 + imp/js/DimpSlider.js | 1 + imp/js/ViewPort.js | 1 + imp/js/compose-dimp.js | 1 + imp/js/dragdrop.js | 1 + imp/js/fullmessage-dimp.js | 1 + imp/js/src/ContextSensitive.js | 226 +++ imp/js/src/DimpBase.js | 2165 +++++++++++++++++++++++ imp/js/src/DimpCore.js | 650 +++++++ imp/js/src/DimpSlider.js | 208 +++ imp/js/src/ViewPort.js | 1607 +++++++++++++++++ imp/js/src/compose-dimp.js | 718 ++++++++ imp/js/src/dragdrop.js | 469 +++++ imp/js/src/fullmessage-dimp.js | 108 ++ imp/lib/Block/foldersummary.php | 77 + imp/lib/Block/newmail.php | 72 + imp/lib/DIMP.php | 530 ++++++ imp/lib/Notification/Listener/status-dimp.php | 87 + imp/lib/Views/Compose.php | 107 ++ imp/lib/Views/ListMessages.php | 353 ++++ imp/lib/Views/ShowMessage.php | 328 ++++ imp/lib/api.php | 10 +- imp/lib/base.php | 64 +- imp/message-dimp.php | 96 + imp/templates/chunks/compose.php | 154 ++ imp/templates/chunks/message.php | 129 ++ imp/templates/imp/compose.html | 10 + imp/templates/imp/portal.html | 9 + imp/templates/index/index.inc | 489 +++++ imp/templates/javascript/mailbox.js | 28 + imp/themes/bluewhite/screen-dimp.css | 10 + imp/themes/graphics/add_contact.png | Bin 0 -> 713 bytes imp/themes/graphics/arrow_collapsed.png | Bin 0 -> 186 bytes imp/themes/graphics/arrow_expanded.png | Bin 0 -> 188 bytes imp/themes/graphics/backhead_orderby.png | Bin 0 -> 132 bytes imp/themes/graphics/backhead_r.png | Bin 0 -> 208 bytes imp/themes/graphics/backhead_s2.png | Bin 0 -> 140 bytes imp/themes/graphics/backhead_shadow.png | Bin 0 -> 100 bytes imp/themes/graphics/blacklist.png | Bin 0 -> 477 bytes imp/themes/graphics/checkbox_off.png | Bin 0 -> 191 bytes imp/themes/graphics/checkbox_on.png | Bin 0 -> 416 bytes imp/themes/graphics/checkbox_over.png | Bin 0 -> 387 bytes imp/themes/graphics/checkmail.png | Bin 0 -> 236 bytes imp/themes/graphics/checkmail_menu.png | Bin 0 -> 236 bytes imp/themes/graphics/compose_menu.png | Bin 0 -> 479 bytes imp/themes/graphics/delete_menu.png | Bin 0 -> 788 bytes imp/themes/graphics/dimp.png | Bin 0 -> 334 bytes imp/themes/graphics/drafts.png | Bin 0 -> 348 bytes imp/themes/graphics/drafts_menu.png | Bin 0 -> 348 bytes imp/themes/graphics/dragHandle.png | Bin 0 -> 95 bytes imp/themes/graphics/error.png | Bin 0 -> 298 bytes imp/themes/graphics/folder.png | Bin 0 -> 368 bytes imp/themes/graphics/folder_create.png | Bin 0 -> 233 bytes imp/themes/graphics/folder_drafts.png | Bin 0 -> 348 bytes imp/themes/graphics/folder_inbox.png | Bin 0 -> 334 bytes imp/themes/graphics/folder_minus.png | Bin 0 -> 251 bytes imp/themes/graphics/folder_plus.png | Bin 0 -> 315 bytes imp/themes/graphics/folder_sent.png | Bin 0 -> 395 bytes imp/themes/graphics/folder_spam.png | Bin 0 -> 262 bytes imp/themes/graphics/folder_trash.png | Bin 0 -> 461 bytes imp/themes/graphics/forward.png | Bin 0 -> 355 bytes imp/themes/graphics/forward_menu.png | Bin 0 -> 355 bytes imp/themes/graphics/ham.png | Bin 0 -> 598 bytes imp/themes/graphics/ham_menu.png | Bin 0 -> 598 bytes imp/themes/graphics/ico_message_off.png | Bin 0 -> 635 bytes imp/themes/graphics/ie6_or_less-dimp.css | 77 + imp/themes/graphics/ie7-dimp.css | 65 + imp/themes/graphics/key_down.png | Bin 0 -> 348 bytes imp/themes/graphics/key_up.png | Bin 0 -> 346 bytes imp/themes/graphics/logo.png | Bin 0 -> 2797 bytes imp/themes/graphics/logout.png | Bin 0 -> 385 bytes imp/themes/graphics/mail_forwarded.png | Bin 358 -> 355 bytes imp/themes/graphics/message.png | Bin 0 -> 477 bytes imp/themes/graphics/message_source.png | Bin 0 -> 334 bytes imp/themes/graphics/newwin.png | Bin 0 -> 296 bytes imp/themes/graphics/plus_menu.png | Bin 0 -> 216 bytes imp/themes/graphics/preview.png | Bin 0 -> 169 bytes imp/themes/graphics/print-dimp.css | 52 + imp/themes/graphics/reply.png | Bin 0 -> 395 bytes imp/themes/graphics/reply_menu.png | Bin 0 -> 395 bytes imp/themes/graphics/replyall.png | Bin 0 -> 395 bytes imp/themes/graphics/sbcursor_bottom.png | Bin 0 -> 215 bytes imp/themes/graphics/sbcursor_top.png | Bin 0 -> 211 bytes imp/themes/graphics/screen-dimp.css | 1186 +++++++++++++ imp/themes/graphics/scroller.png | Bin 0 -> 180 bytes imp/themes/graphics/scroller_back.png | Bin 0 -> 183 bytes imp/themes/graphics/select.png | Bin 0 -> 805 bytes imp/themes/graphics/sortdown.png | Bin 0 -> 117 bytes imp/themes/graphics/sortup.png | Bin 0 -> 119 bytes imp/themes/graphics/spam.png | Bin 0 -> 262 bytes imp/themes/graphics/spam_menu.png | Bin 0 -> 262 bytes imp/themes/graphics/spellcheck_menu.png | Bin 0 -> 199 bytes imp/themes/graphics/success.png | Bin 0 -> 360 bytes imp/themes/graphics/tick.png | Bin 0 -> 355 bytes imp/themes/graphics/warning.png | Bin 0 -> 227 bytes imp/themes/graphics/whitelist.png | Bin 0 -> 441 bytes imp/themes/silver/graphics/add_contact.png | Bin 0 -> 661 bytes imp/themes/silver/graphics/arrow_collapsed.png | Bin 0 -> 209 bytes imp/themes/silver/graphics/arrow_expanded.png | Bin 0 -> 207 bytes imp/themes/silver/graphics/backhead_orderby.png | Bin 0 -> 132 bytes imp/themes/silver/graphics/backhead_r.png | Bin 0 -> 208 bytes imp/themes/silver/graphics/backhead_s2.png | Bin 0 -> 140 bytes imp/themes/silver/graphics/backhead_shadow.png | Bin 0 -> 100 bytes imp/themes/silver/graphics/blacklist.png | Bin 0 -> 655 bytes imp/themes/silver/graphics/checkmail.png | Bin 0 -> 761 bytes imp/themes/silver/graphics/checkmail_menu.png | Bin 0 -> 761 bytes imp/themes/silver/graphics/compose.png | Bin 761 -> 756 bytes imp/themes/silver/graphics/compose_menu.png | Bin 0 -> 756 bytes imp/themes/silver/graphics/delete.png | Bin 0 -> 715 bytes imp/themes/silver/graphics/delete_menu.png | Bin 0 -> 715 bytes imp/themes/silver/graphics/dimp.png | Bin 0 -> 811 bytes imp/themes/silver/graphics/drafts.png | Bin 0 -> 645 bytes imp/themes/silver/graphics/drafts_menu.png | Bin 0 -> 645 bytes imp/themes/silver/graphics/dragHandle.png | Bin 0 -> 95 bytes imp/themes/silver/graphics/error.png | Bin 0 -> 701 bytes imp/themes/silver/graphics/folder.png | Bin 0 -> 537 bytes imp/themes/silver/graphics/folder_create.png | Bin 0 -> 668 bytes imp/themes/silver/graphics/folder_delete.png | Bin 0 -> 666 bytes imp/themes/silver/graphics/folder_drafts.png | Bin 0 -> 645 bytes imp/themes/silver/graphics/folder_edit.png | Bin 0 -> 733 bytes imp/themes/silver/graphics/folder_inbox.png | Bin 0 -> 641 bytes imp/themes/silver/graphics/folder_minus.png | Bin 0 -> 628 bytes imp/themes/silver/graphics/folder_open.png | Bin 0 -> 537 bytes imp/themes/silver/graphics/folder_plus.png | Bin 0 -> 635 bytes imp/themes/silver/graphics/folder_sent.png | Bin 0 -> 694 bytes imp/themes/silver/graphics/folder_spam.png | Bin 0 -> 647 bytes imp/themes/silver/graphics/folder_trash.png | Bin 0 -> 476 bytes imp/themes/silver/graphics/forward.png | Bin 0 -> 754 bytes imp/themes/silver/graphics/forward_menu.png | Bin 0 -> 754 bytes imp/themes/silver/graphics/ham.png | Bin 0 -> 730 bytes imp/themes/silver/graphics/ham_menu.png | Bin 0 -> 730 bytes imp/themes/silver/graphics/logo.png | Bin 0 -> 2797 bytes imp/themes/silver/graphics/logout.png | Bin 0 -> 693 bytes imp/themes/silver/graphics/message.png | Bin 0 -> 778 bytes imp/themes/silver/graphics/message_source.png | Bin 0 -> 799 bytes imp/themes/silver/graphics/newwin.png | Bin 0 -> 533 bytes imp/themes/silver/graphics/plus_menu.png | Bin 0 -> 733 bytes imp/themes/silver/graphics/preview.png | Bin 0 -> 520 bytes imp/themes/silver/graphics/reply.png | Bin 0 -> 744 bytes imp/themes/silver/graphics/reply_menu.png | Bin 0 -> 744 bytes imp/themes/silver/graphics/replyall.png | Bin 0 -> 744 bytes imp/themes/silver/graphics/select.png | Bin 0 -> 805 bytes imp/themes/silver/graphics/sortdown.png | Bin 0 -> 302 bytes imp/themes/silver/graphics/sortup.png | Bin 0 -> 302 bytes imp/themes/silver/graphics/spam.png | Bin 0 -> 701 bytes imp/themes/silver/graphics/spam_menu.png | Bin 0 -> 701 bytes imp/themes/silver/graphics/spellcheck_menu.png | Bin 0 -> 603 bytes imp/themes/silver/graphics/success.png | Bin 0 -> 781 bytes imp/themes/silver/graphics/tick.png | Bin 0 -> 549 bytes imp/themes/silver/graphics/warning.png | Bin 0 -> 666 bytes imp/themes/silver/graphics/whitelist.png | Bin 0 -> 537 bytes imp/themes/silver/screen-dimp.css | 87 + imp/themes/tango-blue/screen-dimp.css | 20 + 166 files changed, 11685 insertions(+), 38 deletions(-) create mode 100644 imp/compose-dimp.php create mode 100644 imp/config/portal.php.dist create mode 100644 imp/imp-dimp.php create mode 100644 imp/index-dimp.php create mode 100644 imp/js/ContextSensitive.js create mode 100644 imp/js/DimpBase.js create mode 100644 imp/js/DimpCore.js create mode 100644 imp/js/DimpSlider.js create mode 100644 imp/js/ViewPort.js create mode 100644 imp/js/compose-dimp.js create mode 100644 imp/js/dragdrop.js create mode 100644 imp/js/fullmessage-dimp.js create mode 100644 imp/js/src/ContextSensitive.js create mode 100644 imp/js/src/DimpBase.js create mode 100644 imp/js/src/DimpCore.js create mode 100644 imp/js/src/DimpSlider.js create mode 100644 imp/js/src/ViewPort.js create mode 100644 imp/js/src/compose-dimp.js create mode 100644 imp/js/src/dragdrop.js create mode 100644 imp/js/src/fullmessage-dimp.js create mode 100644 imp/lib/Block/foldersummary.php create mode 100644 imp/lib/Block/newmail.php create mode 100644 imp/lib/DIMP.php create mode 100644 imp/lib/Notification/Listener/status-dimp.php create mode 100644 imp/lib/Views/Compose.php create mode 100644 imp/lib/Views/ListMessages.php create mode 100644 imp/lib/Views/ShowMessage.php create mode 100644 imp/message-dimp.php create mode 100644 imp/templates/chunks/compose.php create mode 100644 imp/templates/chunks/message.php create mode 100644 imp/templates/imp/compose.html create mode 100644 imp/templates/imp/portal.html create mode 100644 imp/templates/index/index.inc create mode 100644 imp/templates/javascript/mailbox.js create mode 100644 imp/themes/bluewhite/screen-dimp.css create mode 100644 imp/themes/graphics/add_contact.png create mode 100644 imp/themes/graphics/arrow_collapsed.png create mode 100644 imp/themes/graphics/arrow_expanded.png create mode 100644 imp/themes/graphics/backhead_orderby.png create mode 100644 imp/themes/graphics/backhead_r.png create mode 100644 imp/themes/graphics/backhead_s2.png create mode 100644 imp/themes/graphics/backhead_shadow.png create mode 100644 imp/themes/graphics/blacklist.png create mode 100755 imp/themes/graphics/checkbox_off.png create mode 100755 imp/themes/graphics/checkbox_on.png create mode 100644 imp/themes/graphics/checkbox_over.png create mode 100644 imp/themes/graphics/checkmail.png create mode 100644 imp/themes/graphics/checkmail_menu.png create mode 100644 imp/themes/graphics/compose_menu.png create mode 100644 imp/themes/graphics/delete_menu.png create mode 100644 imp/themes/graphics/dimp.png create mode 100644 imp/themes/graphics/drafts.png create mode 100644 imp/themes/graphics/drafts_menu.png create mode 100644 imp/themes/graphics/dragHandle.png create mode 100644 imp/themes/graphics/error.png create mode 100644 imp/themes/graphics/folder.png create mode 100644 imp/themes/graphics/folder_create.png create mode 100644 imp/themes/graphics/folder_drafts.png create mode 100644 imp/themes/graphics/folder_inbox.png create mode 100644 imp/themes/graphics/folder_minus.png create mode 100644 imp/themes/graphics/folder_plus.png create mode 100644 imp/themes/graphics/folder_sent.png create mode 100644 imp/themes/graphics/folder_spam.png create mode 100644 imp/themes/graphics/folder_trash.png create mode 100644 imp/themes/graphics/forward.png create mode 100644 imp/themes/graphics/forward_menu.png create mode 100644 imp/themes/graphics/ham.png create mode 100644 imp/themes/graphics/ham_menu.png create mode 100644 imp/themes/graphics/ico_message_off.png create mode 100644 imp/themes/graphics/ie6_or_less-dimp.css create mode 100644 imp/themes/graphics/ie7-dimp.css create mode 100644 imp/themes/graphics/key_down.png create mode 100644 imp/themes/graphics/key_up.png create mode 100644 imp/themes/graphics/logo.png create mode 100644 imp/themes/graphics/logout.png create mode 100644 imp/themes/graphics/message.png create mode 100644 imp/themes/graphics/message_source.png create mode 100644 imp/themes/graphics/newwin.png create mode 100644 imp/themes/graphics/plus_menu.png create mode 100644 imp/themes/graphics/preview.png create mode 100644 imp/themes/graphics/print-dimp.css create mode 100644 imp/themes/graphics/reply.png create mode 100644 imp/themes/graphics/reply_menu.png create mode 100644 imp/themes/graphics/replyall.png create mode 100644 imp/themes/graphics/sbcursor_bottom.png create mode 100644 imp/themes/graphics/sbcursor_top.png create mode 100644 imp/themes/graphics/screen-dimp.css create mode 100644 imp/themes/graphics/scroller.png create mode 100644 imp/themes/graphics/scroller_back.png create mode 100644 imp/themes/graphics/select.png create mode 100644 imp/themes/graphics/sortdown.png create mode 100644 imp/themes/graphics/sortup.png create mode 100644 imp/themes/graphics/spam.png create mode 100644 imp/themes/graphics/spam_menu.png create mode 100644 imp/themes/graphics/spellcheck_menu.png create mode 100644 imp/themes/graphics/success.png create mode 100644 imp/themes/graphics/tick.png create mode 100644 imp/themes/graphics/warning.png create mode 100644 imp/themes/graphics/whitelist.png create mode 100644 imp/themes/silver/graphics/add_contact.png create mode 100644 imp/themes/silver/graphics/arrow_collapsed.png create mode 100644 imp/themes/silver/graphics/arrow_expanded.png create mode 100644 imp/themes/silver/graphics/backhead_orderby.png create mode 100644 imp/themes/silver/graphics/backhead_r.png create mode 100644 imp/themes/silver/graphics/backhead_s2.png create mode 100644 imp/themes/silver/graphics/backhead_shadow.png create mode 100644 imp/themes/silver/graphics/blacklist.png create mode 100644 imp/themes/silver/graphics/checkmail.png create mode 100644 imp/themes/silver/graphics/checkmail_menu.png create mode 100644 imp/themes/silver/graphics/compose_menu.png create mode 100644 imp/themes/silver/graphics/delete.png create mode 100644 imp/themes/silver/graphics/delete_menu.png create mode 100644 imp/themes/silver/graphics/dimp.png create mode 100644 imp/themes/silver/graphics/drafts.png create mode 100644 imp/themes/silver/graphics/drafts_menu.png create mode 100644 imp/themes/silver/graphics/dragHandle.png create mode 100644 imp/themes/silver/graphics/error.png create mode 100644 imp/themes/silver/graphics/folder.png create mode 100644 imp/themes/silver/graphics/folder_create.png create mode 100644 imp/themes/silver/graphics/folder_delete.png create mode 100644 imp/themes/silver/graphics/folder_drafts.png create mode 100644 imp/themes/silver/graphics/folder_edit.png create mode 100644 imp/themes/silver/graphics/folder_inbox.png create mode 100644 imp/themes/silver/graphics/folder_minus.png create mode 100644 imp/themes/silver/graphics/folder_open.png create mode 100644 imp/themes/silver/graphics/folder_plus.png create mode 100644 imp/themes/silver/graphics/folder_sent.png create mode 100644 imp/themes/silver/graphics/folder_spam.png create mode 100644 imp/themes/silver/graphics/folder_trash.png create mode 100644 imp/themes/silver/graphics/forward.png create mode 100644 imp/themes/silver/graphics/forward_menu.png create mode 100644 imp/themes/silver/graphics/ham.png create mode 100644 imp/themes/silver/graphics/ham_menu.png create mode 100644 imp/themes/silver/graphics/logo.png create mode 100644 imp/themes/silver/graphics/logout.png create mode 100644 imp/themes/silver/graphics/message.png create mode 100644 imp/themes/silver/graphics/message_source.png create mode 100644 imp/themes/silver/graphics/newwin.png create mode 100644 imp/themes/silver/graphics/plus_menu.png create mode 100644 imp/themes/silver/graphics/preview.png create mode 100644 imp/themes/silver/graphics/reply.png create mode 100644 imp/themes/silver/graphics/reply_menu.png create mode 100644 imp/themes/silver/graphics/replyall.png create mode 100644 imp/themes/silver/graphics/select.png create mode 100644 imp/themes/silver/graphics/sortdown.png create mode 100644 imp/themes/silver/graphics/sortup.png create mode 100644 imp/themes/silver/graphics/spam.png create mode 100644 imp/themes/silver/graphics/spam_menu.png create mode 100644 imp/themes/silver/graphics/spellcheck_menu.png create mode 100644 imp/themes/silver/graphics/success.png create mode 100644 imp/themes/silver/graphics/tick.png create mode 100644 imp/themes/silver/graphics/warning.png create mode 100644 imp/themes/silver/graphics/whitelist.png create mode 100644 imp/themes/silver/screen-dimp.css create mode 100644 imp/themes/tango-blue/screen-dimp.css diff --git a/imp/compose-dimp.php b/imp/compose-dimp.php new file mode 100644 index 000000000..bcd67418b --- /dev/null +++ b/imp/compose-dimp.php @@ -0,0 +1,347 @@ + + * @author Michael Slusarz + */ + +function _removeAutoSaveDraft($index) +{ + if (empty($index)) { + return; + } + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $idx_array = array($index . IMP_IDX_SEP . IMP::folderPref($GLOBALS['prefs']->getValue('drafts_folder'), true)); + $imp_message->delete($idx_array, true); +} + +$load_imp = true; +@define('DIMP_BASE', dirname(__FILE__)); +require_once DIMP_BASE . '/lib/base.php'; +require_once 'Horde/Identity.php'; + +/* The headers of the message. */ +$header = array(); +foreach (array('to', 'cc', 'bcc', 'subject', 'in_reply_to', 'references') as $v) { + $header[$v] = rawurldecode(Util::getFormData($v, '')); +} + +$action = Util::getFormData('action'); +$get_sig = true; +$msg = ''; + +$identity = &Identity::singleton(array('imp', 'imp')); +if (!$prefs->isLocked('default_identity')) { + $identity_id = Util::getFormData('identity'); + if ($identity_id !== null) { + $identity->setDefault($identity_id); + } +} + +/* Set the current time zone. */ +NLS::setTimeZone(); + +/* Initialize the IMP_Compose:: object. */ +require_once IMP_BASE . '/lib/Compose.php'; +$imp_compose = &IMP_Compose::singleton(Util::getFormData('composeCache')); + +/* Init IMP_UI_Compose:: object. */ +require_once IMP_BASE . '/lib/UI/Compose.php'; +$imp_ui = new IMP_UI_Compose(); + +if (count($_POST)) { + $result = new stdClass; + $result->action = $action; + $result->success = false; + + /* Update the file attachment information. */ + if ($action == 'add_attachment') { + if ($_SESSION['imp']['file_upload'] && + $imp_compose->addFilesFromUpload('file_')) { + $info = DIMP::getAttachmentInfo($imp_compose); + $result->success = true; + $result->info = end($info); + $result->imp_compose = $imp_compose->getMessageCacheId(); + } + IMP::sendHTTPResponse(DIMP::prepareResponse($result, true, false), 'js-json'); + exit; + } + + /* Set the default charset. */ + $charset = NLS::getEmailCharset(); + if (!$prefs->isLocked('sending_charset')) { + $charset = Util::getFormData('charset', $charset); + } + + switch ($action) { + case 'auto_save_draft': + case 'save_draft': + /* Set up the From address based on the identity. */ + $from = $identity->getFromLine(null, Util::getFormData('from')); + if (is_a($from, 'PEAR_Error')) { + $notification->push($from); + break; + } + $header['from'] = $from; + + /* Save the draft. */ + $res = $imp_compose->saveDraft($header, Util::getFormData('message', ''), NLS::getCharset(), Util::getFormData('html')); + if (is_a($res, 'PEAR_Error')) { + $notification->push($res->getMessage(), 'horde.error'); + } else { + $result->success = true; + + /* Delete existing draft. */ + _removeAutoSaveDraft(Util::getFormData('draft_index')); + + if ($action == 'auto_save_draft') { + /* Just update the last draft index so subsequent + * drafts are properly replaced. */ + $result->draft_index = (int)$imp_compose->saveDraftIndex(); + } else { + $notification->push($res); + } + } + break; + + case 'send_message': + $from = $identity->getFromLine(null, Util::getFormData('from')); + if (is_a($from, 'PEAR_Error')) { + $notification->push($from); + break; + } + $header['from'] = $from; + $header['replyto'] = $identity->getValue('replyto_addr'); + + $header['to'] = $imp_ui->getAddressList(Util::getFormData('to'), Util::getFormData('to_list'), Util::getFormData('to_field'), Util::getFormData('to_new')); + if ($prefs->getValue('compose_cc')) { + $header['cc'] = $imp_ui->getAddressList(Util::getFormData('cc'), Util::getFormData('cc_list'), Util::getFormData('cc_field'), Util::getFormData('cc_new')); + } + if ($prefs->getValue('compose_bcc')) { + $header['bcc'] = $imp_ui->getAddressList(Util::getFormData('bcc'), Util::getFormData('bcc_list'), Util::getFormData('bcc_field'), Util::getFormData('bcc_new')); + } + + $message = Util::getFormData('message'); + $html = Util::getFormData('html'); + + $result->reply_type = Util::getFormData('reply_type'); + $result->index = Util::getFormData('index'); + $result->reply_folder = Util::getFormData('folder'); + + /* Use IMP_Tree to determine whether the sent mail folder was + * created. */ + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $imptree->eltDiffStart(); + + /* Create the DIMP User-Agent string. */ + require_once DIMP_BASE . '/lib/version.php'; + $useragent = 'Dynamic Internet Messaging Program (DIMP) ' . DIMP_VERSION; + + $options = array( + 'save_sent' => (($prefs->isLocked('save_sent_mail')) + ? $identity->getValue('save_sent_mail') + : (bool)Util::getFormData('save_sent_mail')), + 'sent_folder' => $identity->getValue('sent_mail_folder'), + 'save_attachments' => Util::getFormData('save_attachments_select'), + 'reply_type' => $result->reply_type, + 'reply_index' => $result->index . IMP_IDX_SEP . $result->reply_folder, + 'readreceipt' => Util::getFormData('request_read_receipt'), + 'useragent' => $useragent + ); + $sent = $imp_compose->buildAndSendMessage($message, $header, $charset, $html, $options); + + if (is_a($sent, 'PEAR_Error')) { + $notification->push($sent, 'horde.error'); + break; + } + $result->success = true; + + /* Remove any auto-saved drafts. */ + if ($prefs->getValue('auto_save_drafts') || + $prefs->getValue('auto_delete_drafts')) { + _removeAutoSaveDraft(Util::getFormData('draft_index')); + $result->draft_delete = true; + } + + if ($sent && $prefs->getValue('compose_confirm')) { + $notification->push(_("Message sent successfully."), 'horde.success'); + } + + $res = DIMP::getFolderResponse($imptree); + if (!empty($res)) { + $result->folder = $res['a'][0]; + } + } + + IMP::sendHTTPResponse(DIMP::prepareResponse($result, !$result->success || !Util::getFormData('nonotify'), false), 'json'); + exit; +} + +/* Attach spellchecker & auto completer. */ +require_once DIMP_BASE . '/lib/Dimple.php'; +$imp_ui->attachAutoCompleter('Dimple', array('to', 'cc', 'bcc')); +$imp_ui->attachSpellChecker('dimp'); + +$type = Util::getFormData('type'); +$index = Util::getFormData('uid'); +$folder = Util::getFormData('folder'); +$show_editor = false; +$title = _("New Message"); + +if (in_array($type, array('reply', 'reply_all', 'reply_list', 'forward_all', 'forward_body', 'forward_attachments', 'resume'))) { + if (!$index || !$folder) { + $type = 'new'; + } + + require_once IMP_BASE . '/lib/MIME/Contents.php'; + $imp_contents = &IMP_Contents::singleton($index . IMP_IDX_SEP . $folder); + if (is_a($imp_contents, 'PEAR_Error')) { + $notification->push(_("Requested message not found."), 'horde.error'); + $index = $folder = null; + $type = 'new'; + } +} + +switch ($type) { +case 'reply': +case 'reply_all': +case 'reply_list': + $reply_msg = $imp_compose->replyMessage($type, $imp_contents, Util::getFormData('to')); + $msg = $reply_msg['body']; + $header = $reply_msg['headers']; + $header['replytype'] = 'reply'; + + if ($type == 'reply') { + $title = _("Reply:"); + } elseif ($type == 'reply_all') { + $title = _("Reply to All:"); + } elseif ($type == 'reply_list') { + $title = _("Reply to List:"); + } + $title .= ' ' . $header['subject']; + + if ($reply_msg['format'] == 'html') { + $show_editor = true; + } + + if (!$prefs->isLocked('default_identity') && !is_null($reply_msg['identity'])) { + $identity->setDefault($reply_msg['identity']); + } + break; + +case 'forward_all': +case 'forward_body': +case 'forward_attachments': + $fwd_msg = $imp_ui->getForwardData($imp_compose, $imp_contents, $type, $index . IMP_IDX_SEP . $folder); + if ($type == 'forward_all') { + $msg = ''; + } else { + $msg = $fwd_msg['body']; + } + $header = $fwd_msg['headers']; + $header['replytype'] = 'forward'; + $title = $header['title']; + if ($fwd_msg['format'] == 'html') { + $show_editor = true; + } + $type = 'forward'; + + if (!$prefs->isLocked('default_identity') && !is_null($fwd_msg['identity'])) { + $identity->setDefault($fwd_msg['identity']); + } + break; + +case 'resume': + $result = $imp_compose->resumeDraft($index . IMP_IDX_SEP . $folder); + if (is_a($result, 'PEAR_Error')) { + $notification->push($result->getMessage(), 'horde.error'); + } else { + if ($result['mode'] == 'html') { + $show_editor = true; + } + $msg = $result['msg']; + if (!is_null($result['identity']) && + !$prefs->isLocked('default_identity')) { + $identity->setDefault($result['identity']); + } + $header = array_merge($header, $result['header']); + } + $get_sig = false; + break; + +case 'new': + $rte = ($browser->hasFeature('rte') && $prefs->getValue('compose_html')); + if ($rte) { + $show_editor = true; + } + break; +} + +$sig = $identity->getSignature(); +if ($get_sig && !empty($sig)) { + if ($show_editor) { + $sig = '

' . $imp_compose->text2html(trim($sig)) . '

'; + } + + $msg = ($identity->getValue('sig_first')) + ? "\n" . $sig . $msg + : $msg . "\n" . $sig; +} + +$args = array( + 'folder' => $folder, + 'index' => $index, + 'composeCache' => $imp_compose->getCacheId(), + 'qreply' => false, +); + +require_once IMP_BASE . '/lib/Template.php'; +$t = new IMP_Template(DIMP_TEMPLATES . '/imp/'); +$t->setOption('gettext', true); +$t->set('title', $title); +$t->set('closelink', Horde::img('close.png', 'X', array('id' => 'compose_close'), $registry->getImageDir('horde'))); + +$compose_result = DIMP_Views_Compose::showCompose($args); +$t->set('compose_html', $compose_result['html']); + +/* Javscript variables to be set immediately. */ +$compose_result['js'][] = 'DIMP.conf_compose.show_editor = ' . intval($show_editor); +if (Util::getFormData('popup')) { + $compose_result['js'][] = 'DIMP.conf_compose.popup = true'; +} +IMP::addInlineScript($compose_result['js']); + +/* Some actions, like adding forwards, may return error messages so explicitly + * display those messages now. */ +IMP::addInlineScript(array(DIMP::notify()), 'dom'); + +/* Javascript to be run on window load. */ +require_once 'Horde/Serialize.php'; +$compose_result['js_onload'][] = 'DimpCompose.fillForm(' . Horde_Serialize::serialize($msg, SERIALIZE_JSON) . ', ' . Horde_Serialize::serialize($header, SERIALIZE_JSON) . ', "' . (($type == 'new' || $type == 'forward') ? 'to' : 'message') . '", true)'; +IMP::addInlineScript($compose_result['js_onload'], 'load'); + +$scripts = array( + array('compose.js', 'dimp', true) +); + +DIMP::header(_("Message Composition"), $scripts); +echo $t->fetch('compose.html'); +IMP::includeScriptFiles(); +IMP::outputInlineScript(); +echo $compose_result['jsappend']; +echo "\n"; diff --git a/imp/config/conf.xml b/imp/config/conf.xml index 36cadbbd2..cec9f2c49 100644 --- a/imp/config/conf.xml +++ b/imp/config/conf.xml @@ -457,4 +457,81 @@ them?">20 + + + Custom Hooks + + false + false + false + false + false + + + + + JavaScript Settings + + false + + + ViewPort Settings + + 5 + 35 + 12 + true + + + Search Settings + + false + + + + Menu Settings + + + + + + + diff --git a/imp/config/hooks.php.dist b/imp/config/hooks.php.dist index 00686e2e1..0fc0556da 100644 --- a/imp/config/hooks.php.dist +++ b/imp/config/hooks.php.dist @@ -555,3 +555,121 @@ if (!function_exists('_imp_hook_quota')) { return array($quota[1] * 1024, $quota[2] * 1024); } } + + + +// This is an example hook function for the DIMP mailbox view. This function +// is called for every message and allows additional information to be added +// to the array that is passed to the mailbox display template - +// dimp/templates/javascript/mailbox.js. The current entry array is passed +// in, the value returned should be the altered array to use in the +// template. If you are going to add new columns, you also have to update +// dimp/templates/index/index.inc to contain the new field in the header and +// dimp/themes/screen.css to specify the column width. + +// if (!function_exists('_dimp_hook_mailboxarray')) { +// function _dimp_hook_mailboxarray($msg, $ob) { +// $msg['foo'] = true; +// return $msg; +// } +// } + +// This is an example hook function for the DIMP message view. This function +// allows additional information to be added to the array that is passed to +// the message text display template - dimp/templates/chunks/message.html. +// The current entry array is passed in (see the showMessage() function in +// dimp/lib/Views/ShowMessage.php for the format). The value returned should +// be the altered array to use in the template. See the showMessage() function +// in dimp/lib/Views/ShowMessage for the base values contained in the original +// passed-in array. + +// if (!function_exists('_dimp_hook_messageview')) { +// function _dimp_hook_messageview($msg) { +// // Ex.: Add a new foo variable +// $msg['foo'] = '
BAR
'; +// return $msg; +// } +// } +// This is an example hook function for the DIMP preview view. This function +// allows additional information to be added to the preview view and its +// corresponding template - dimp/templates/index/index.inc. The current entry +// array is passed in (see the showMessage() function in +// dimp/lib/Views/ShowMessage.php for the format). Since the preview pane is +// dynamically updated via javascript, all updates other than the base +// entries must be provided in javascript code to be run at update time. The +// expected return is a 2 element array - the first element is the original +// array with any changes made to the initial data. The second element is an +// array of javascript commands, one command per array value. + +// if (!function_exists('_dimp_hook_previewview')) { +// function _dimp_hook_previewview($msg) { +// // Ex.: Alter the subject +// $msg['subject'] .= 'test'; +// +// // Ex.: Update the DOM ID 'foo' with the value 'bar'. 'foo' needs +// // to be manually added to the HTML template. +// $js_code = array( +// "$('foo').update('bar')" +// ); +// +// return array($msg, $js_code); +// } +// } + +// This is an example hook function for the address formatting in email +// message headers. The argument passed to the function is an object with the +// following possible properties: +// 'address' - Full address +// 'display' - Display address +// 'host' - Host name +// 'inner' - Trimmed, bare address +// 'personal' - Personal string +// The return value is the raw string to display for that address. This value +// must be properly escaped (i.e. htmlspecialchars() used on the portions of +// the string where appropriate). + +// if (!function_exists('_dimp_hook_addressformatting')) { +// function _dimp_hook_addressformatting($ob) { +// return empty($ob->personal) ? $ob->address : $ob->personal; +// } +// } + +// This is an example hook function for displaying additional message +// information in the message listing screen for a mailbox. This example hook +// will add a icon if the message contains attachments and will change the +// display of the message entry based on the X-Priority header. + +// if (!function_exists('_dimp_hook_msglist_format')) { +// function _dimp_hook_msglist_format($mailbox, $uid) +// { +// // Required return (array): +// // 'atc' - Attachment type (either 'signed', 'encrypted', or +// // 'attachment'). +// // 'class' - An array of CSS classnames that will be added to +// // the row. +// $ret = array('atc' => '', 'class' => array()); +// +// require_once IMP_BASE . '/lib/IMAP/MessageCache.php'; +// $cache = &IMP_MessageCache::singleton(); +// $cache_entry = $cache->retrieve($mailbox, array($uid), 8 | 32); +// $ob = reset($cache_entry); +// +// // Add attachment information +// require_once IMP_BASE . '/lib/UI/Mailbox.php'; +// $imp_ui = new IMP_UI_Mailbox(); +// $ret['atc'] = $imp_ui->getAttachmentType($ob->structure); +// +// // Add xpriority information +// switch ($ob->header->getXpriority()) { +// case 'high': +// $ret['class'][] = 'important'; +// break; +// +// case 'low': +// $ret['class'][] = 'unimportant'; +// break; +// } +// +// return $ret; +// } +// } diff --git a/imp/config/menu.php.dist b/imp/config/menu.php.dist index 59ec43464..dd9f84ce1 100644 --- a/imp/config/menu.php.dist +++ b/imp/config/menu.php.dist @@ -10,6 +10,7 @@ * * These attributes are optional: * + * 'action' The javascript code for the menu item (dimp only). * 'icon' The filename of an icon to use for the menu item. * 'icon_path' The path to the icon if it doesn't exist in the graphics/ * directory. @@ -24,7 +25,8 @@ * 'icon' => 'example.png', * 'icon_path' => 'http://www.example.com/images/', * 'target' => '_blank', - * 'onclick' => '' + * 'onclick' => '', + * 'action' => '' * ); * * You can also add a "separator" (a spacer) between menu items. To add a diff --git a/imp/config/portal.php.dist b/imp/config/portal.php.dist new file mode 100644 index 000000000..ab5d29102 --- /dev/null +++ b/imp/config/portal.php.dist @@ -0,0 +1,49 @@ + The Horde_Block object to display + * + * These entries are optional and will only be used if you need + * to customize the portal output: + * 'class' => A CSS class to assign to the containing block. + * Defaults to "headerbox". + * 'domid' => A DOM ID to assign to the containing block + * 'tag' => A tag name to add to the template array. Allows + * the use of in custom template files. + * + * $Horde: dimp/config/portal.php.dist,v 1.7 2008/08/22 04:19:29 slusarz Exp $ + */ + +require_once 'Horde/Block.php'; +require_once 'Horde/Block/Collection.php'; +$collection = new Horde_Block_Collection(); +$dimp_block_list = array(); + +// Show a folder summary of the mailbox. All polled folders are displayed. +require_once DIMP_BASE . '/lib/Block/foldersummary.php'; +$dimp_block_list[_("Folder Summary")] = array( + 'ob' => new Horde_Block_dimp_foldersummary(array()) +); + +// Alternate DIMP block - shows details of 'msgs_shown' number of the most +// recent unseen messages. +//require_once DIMP_BASE . '/lib/Block/newmail.php'; +//$dimp_block_list[_("Newest Unseen Messages")] = array( +// 'ob' => new Horde_Block_dimp_newmail(array('msgs_shown' => 3)) +//); + +// Show a contact search box. +// Must include 'turba' in $conf['menu']['apps'] +$dimp_block_list[$collection->getName('turba', 'minisearch')] = array( + 'ob' => $collection->getBlock('turba', 'minisearch', array()) +); + +// Display calendar events +// Must include 'kronolith' in $conf['menu']['apps'] +$dimp_block_list[$collection->getName('kronolith', 'summary')] = array( + 'ob' => $collection->getBlock('kronolith', 'summary', array()) +); diff --git a/imp/config/prefs.php.dist b/imp/config/prefs.php.dist index 42a4e2f80..9a6cf6c44 100644 --- a/imp/config/prefs.php.dist +++ b/imp/config/prefs.php.dist @@ -7,7 +7,7 @@ require_once dirname(__FILE__) . '/../lib/IMP.php'; require_once dirname(__FILE__) . '/../lib/IMAP.php'; require_once 'Horde/Imap/Client.php'; -$is_pop3 = isset($_SESSION['imp']) && $_SESSION['imp']['protocol'] == 'pop'; +$is_pop3 = isset($_SESSION['imp']) && ($_SESSION['imp']['protocol'] == 'pop'); $prefGroups['identities'] = array( 'column' => _("General Options"), @@ -194,6 +194,13 @@ $prefGroups['mimp'] = array( 'members' => array('mimp_preview_msg') ); +$prefGroups['dimp'] = array( + 'column' => _("Other Options"), + 'label' => _("DIMP Options"), + 'desc' => _("Configure DIMP Options."), + 'members' => array('login_view', 'show_preview') +); + // Personal Information preferences @@ -1446,6 +1453,25 @@ $_prefs['mimp_preview_msg'] = array( 'desc' => _("Display only the first 250 characters of a message initially?") ); +// Login preferences (dimp) +$_prefs['login_view'] = array( + 'value' => 'portal', + 'locked' => false, + 'shared' => false, + 'type' => 'enum', + 'enum' => array('portal' => _("Portal"), + 'inbox' => _("Inbox")), + 'desc' => _("The page to view immediately after login in DIMP.") +); + +// Other Implicit DIMP preferences +$_prefs['show_preview'] = array( + 'value' => true, + 'locked' => false, + 'shared' => false, + 'type' => 'implicit', +); + // Other entries (used internally in IMP) // virtual inbox identifier diff --git a/imp/docs/CREDITS b/imp/docs/CREDITS index c9e686ae7..3715a6def 100644 --- a/imp/docs/CREDITS +++ b/imp/docs/CREDITS @@ -1,3 +1,11 @@ +================== + Acknowledgements +================== + +Development of DIMP sponsored by Portugal Telecom's SAPO division +(http://softwarelivre.sapo.pt/). + + ====================== IMP Development Team ====================== diff --git a/imp/docs/INSTALL b/imp/docs/INSTALL index fd2dc4968..0834d9c23 100644 --- a/imp/docs/INSTALL +++ b/imp/docs/INSTALL @@ -2,8 +2,6 @@ Installing IMP 5.0 ==================== -:Last update: $Date: 2008/09/25 08:01:51 $ -:Revision: $Revision: 1.95 $ :Contact: imp@lists.horde.org .. contents:: Contents @@ -325,6 +323,21 @@ The following items are not required, but are strongly **RECOMMENDED**: create the information using other server variables, but this process is slower and less reliable. +8. PHP version 5.2.5+ (for dimp). + + If using the PHP built-in JSON encoder/decoder (highly recommended as it is + hundreds of times faster than the fallback PHP code-based version), you + should be using the latest version of PHP. The PECL json module is badly + out-of-date (as of version 1.2.1) and does not contain many bug fixes + for handling message data that contains invalid characters. Using older + versions of the JSON encoder may result in the JSON output to the browser + being prematurely terminated, resulting in incomplete or blank screens. + + If you still see this problem after upgrading PHP, your server may have + incorrect locale information. See `Bug #5955`_ for further information. + +.. _`Bug #5955`: http://bugs.horde.org/ticket/?id=5955#c13 + Installing IMP ============== @@ -546,6 +559,42 @@ Configuring IMP IMP's setup screen (``Administration/Setup/Webmail/Mailbox and Fetchmail``. +DIMP Troubleshooting +==================== + +DIMP differs from most traditional Horde applications in that it requires +javascript support and, in fact, javascript performs the bulk of the page +display. As such, debugging DIMP is more complex than with other Horde +applications. + +If you run into problems with DIMP, first follow the troubleshooting steps +for both Horde and IMP - namely checking PHP error logs and Horde debug logs, +to determine if the problem is located there. Since DIMP uses Horde and IMP +code extensively on the server side, most server-based errors will be logged +in the traditional manner. + +Only if traditional debugging is unsuccessful will you need to move to +javascript debugging. It is highly recommended to use Mozilla Firefox with +the `Firebug`_ extension installed in order to better track javascript errors +- it is what the developers use and makes deciphering error codes and error +line numbers much easier. Next, it is also recommended to set the ``debug`` +parameter in ``dimp/conf/conf.php`` to ``true`` (no quotes) - this will popup +javascript exceptions that may not be able to be caught by Firebug. Next you +will want to turn off javascript caching, if on, in ``dimp/conf/conf.php``. +Finally, you need to change ``horde/conf/registry.php`` to serve the +javascript files from the ``js/src/`` directory rather than the ``js/`` +directory (we compress javascript files to reduce network load, but this +results in all javascript errors occurring on line 1 which is not very useful +to diagnose the problem). + +If you do find a javascript error, it would be great if you could fix the +issue and provide a patch :) Absent that, before reporting to the mailing +list, IRC room, or bug tracker make sure you have a valid javascript error, +the file the error is being caused in, the line number of the error, and a +reliable way to reproduce the error. Developers/other interested folks will +be much more likely to help you if all this information is provided. + + Obtaining Support ================= @@ -581,3 +630,4 @@ The IMP team .. _`horde/docs/SECURITY`: ../../horde/docs/?f=SECURITY.html .. _`horde/docs/TRANSLATIONS`: ../../horde/docs/?f=TRANSLATIONS.html .. _`File Uploads`: http://wiki.horde.org/FAQ/Admin/FileUploads +.. _`Firebug`: http://www.getfirebug.com/ diff --git a/imp/imp-dimp.php b/imp/imp-dimp.php new file mode 100644 index 000000000..6807f121a --- /dev/null +++ b/imp/imp-dimp.php @@ -0,0 +1,720 @@ +folder = $folder; + $result->uids = IMP::toRangeString($indices); + $result->remove = ($GLOBALS['prefs']->getValue('hide_deleted') || + $GLOBALS['prefs']->getValue('use_trash')); + $result->cacheid = _cacheID($folder); + + if ($change) { + $result->viewport = _getListMessages($folder, true); + } + + $poll = _getPollInformation($folder); + if (!empty($poll)) { + $result->poll = $poll; + } + + return $result; +} + +function _cacheID($folder) +{ + require_once IMP_BASE . '/lib/Mailbox.php'; + $imp_mailbox = &IMP_Mailbox::singleton($folder); + return $imp_mailbox->getCacheId(); +} + +function _changed($folder, $compare, $indices = array(), $nothread = false) +{ + if ($GLOBALS['imp_search']->isVFolder($folder) || + (_cacheID($folder) != $compare)) { + return true; + } + + return (!empty($indices) && + (!$nothread && _threadUidChanged($folder, $indices))); +} + +function _threadUidChanged($folder, $indices) +{ + $sort = IMP::getSort($folder); + if ($sort['by'] == SORTTHREAD) { + require_once IMP_BASE . '/lib/Mailbox.php'; + foreach ($indices as $mbox => $mbox_array) { + $imp_mailbox = &IMP_Mailbox::singleton($mbox); + $threadob = $imp_mailbox->getThreadOb(); + foreach ($mbox_array as $val) { + if ($threadob->getThreadBase($val) !== false) { + return true; + } + } + } + } + + return false; +} + +function _getListMessages($folder, $change) +{ + $args = array( + 'cacheid' => Util::getPost('cacheid'), + 'filter' => Util::getPost('filter'), + 'folder' => $folder, + 'searchfolder' => Util::getPost('searchfolder'), + 'searchmsg' => Util::getPost('searchmsg'), + ); + + $search = Util::getPost('search'); + if (!empty($search)) { + require_once 'Horde/Serialize.php'; + $search = Horde_Serialize::unserialize($search, SERIALIZE_JSON); + $args += array( + 'search_uid' => $search->imapuid, + 'search_before' => intval(Util::getPost('search_before')), + 'search_after' => intval(Util::getPost('search_size')) + ); + } else { + $args += array( + 'slice_rownum' => intval(Util::getPost('rownum')), + 'slice_start' => intval(Util::getPost('slice_start')), + 'slice_end' => intval(Util::getPost('slice_end')) + ); + } + + require_once DIMP_BASE . '/lib/Views/ListMessages.php'; + $list_msg = new DIMP_Views_ListMessages(); + $res = $list_msg->ListMessages($args); + // TODO: This can potentially be optimized for arrival time sort - if the + // cache ID changes, we know the changes must occur at end of mailbox. + if (Util::getPost('purge') || $change) { + $res->update = true; + } + $res->request_id = Util::getPost('request_id'); + return $res; +} + +function _getIdxString($indices) +{ + $i = each($indices); + return reset($i['value']) . IMP_IDX_SEP . $i['key']; +} + +function _getPollInformation($mbox) +{ + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $elt = $imptree->get($mbox); + if ($imptree->isPolled($elt)) { + $info = $imptree->getElementInfo($mbox); + return array($mbox => isset($info['unseen']) ? $info['unseen'] : 0); + } + return array(); +} + +// Need to load Util:: to give us access to Util::getPathInfo(). +if (!defined('HORDE_BASE')) { + define('HORDE_BASE', dirname(__FILE__) . '/..'); +} +require_once HORDE_BASE . '/lib/core.php'; +$action = basename(Util::getPathInfo()); +if (empty($action)) { + // This is the only case where we really don't return anything, since + // the frontend can be presumed not to make this request on purpose. + // Other missing data cases we return a response of boolean false. + exit; +} + +// The following actions do not need write access to the session and +// should be opened read-only for performance reasons. +if (in_array($action, array('chunkContent', 'Html2Text', 'Text2Html', 'GetReplyData'))) { + $session_control = 'readonly'; +} + +$authentication = 'none'; +$dimp_logout = ($action == 'LogOut'); +$load_imp = true; +$session_timeout = 'json'; +@define('AUTH_HANDLER', true); +@define('DIMP_BASE', dirname(__FILE__)); +require_once DIMP_BASE . '/lib/base.php'; + +// Process common request variables. +$folder = Util::getPost('folder'); +$indices = IMP::parseRangeString(Util::getPost('uid')); +$cacheid = Util::getPost('cacheid'); + +// Open an output buffer to ensure that we catch errors that might break JSON +// encoding. +ob_start(); + +$result = false; + +switch ($action) { +case 'CreateFolder': +case 'CreateSubfolder': + if (empty($folder)) { + break; + } + + $parent = Util::getPost('parent'); + if (($action == 'CreateSubfolder') && !$parent) { + break; + } + + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $imptree->eltDiffStart(); + + require_once IMP_BASE . '/lib/Folder.php'; + $imp_folder = &IMP_Folder::singleton(); + + $new = String::convertCharset($folder, NLS::getCharset(), 'UTF7-IMAP'); + $new = $imptree->createMailboxName($parent, $new); + if (is_a($new, 'PEAR_Error')) { + $notification->push($new, 'horde.error'); + $result = false; + } else { + $result = $imp_folder->create($new, $prefs->getValue('subscribe')); + if ($result) { + $result = DIMP::getFolderResponse($imptree); + } + } + break; + +case 'DeleteFolder': + if (empty($folder)) { + break; + } + + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $imptree->eltDiffStart(); + + require_once IMP_BASE . '/lib/Folder.php'; + $imp_folder = &IMP_Folder::singleton(); + $result = $imp_folder->delete(array($folder)); + if ($result) { + $result = DIMP::getFolderResponse($imptree); + } + break; + +case 'RenameFolder': + $old = Util::getPost('old_name'); + $new_parent = Util::getPost('new_parent'); + $new = Util::getPost('new_name'); + if (!$old || !$new) { + break; + } + + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $imptree->eltDiffStart(); + + require_once IMP_BASE . '/lib/Folder.php'; + $imp_folder = &IMP_Folder::singleton(); + + $new = $imptree->createMailboxName($new_parent, $new); + if (is_a($new, 'PEAR_Error')) { + $notification->push($new, 'horde.error'); + $result = false; + } else { + require_once 'Horde/String.php'; + $new = String::convertCharset($new, NLS::getCharset(), 'UTF7-IMAP'); + if ($old != $new) { + $result = $imp_folder->rename($old, $new); + if ($result) { + $result = DIMP::getFolderResponse($imptree); + } + } + } + break; + +case 'EmptyFolder': + if (empty($folder)) { + break; + } + + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $imp_message->emptyMailbox(array($folder)); + $result = new stdClass; + $result->mbox = $folder; + break; + +case 'MarkFolderSeen': +case 'MarkFolderUnseen': + if (empty($folder)) { + break; + } + + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $result = $imp_message->flagAllInMailbox(array('seen'), + array($folder), + $action == 'MarkFolderSeen'); + if ($result) { + $result = new stdClass; + $result->mbox = $folder; + + $poll = _getPollInformation($folder); + if (!empty($poll)) { + $result->poll = array($folder => $poll[$folder]['u']); + } + } + break; + +case 'ListFolders': + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + $result = DIMP::getFolderResponse($imptree, array('a' => $imptree->folderList(IMPTREE_FLIST_CONTAINER | IMPTREE_FLIST_VFOLDER), 'c' => array(), 'd' => array())); + break; + +case 'PollFolders': + $result = new stdClass; + + require_once IMP_BASE . '/lib/Fetchmail.php'; + $fm_account = new IMP_Fetchmail_Account(); + $fm_count = $fm_account->count(); + if (!empty($fm_count)) { + IMP_Fetchmail::fetchMail(range(0, $fm_count - 1)); + } + + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + + $result->poll = array(); + foreach ($imptree->getPollList(true) as $val) { + if ($info = $imptree->getElementInfo($val)) { + $result->poll[$val] = $info['unseen']; + } + } + + if (!empty($folder) && _changed($folder, $cacheid)) { + $result->viewport = _getListMessages($folder, true); + } + + if (isset($_SESSION['imp']['quota']) && + is_array($_SESSION['imp']['quota'])) { + $quotadata = IMP::quotaData(false); + if (!empty($quotadata)) { + $result->quota = array('p' => round($quotadata['percent']), 'm' => $quotadata['message']); + } + } + break; + +case 'ListMessages': + if (empty($folder)) { + break; + } + + /* Change sort preferences if necessary. */ + $sortby = Util::getPost('sortby'); + $sortdir = Util::getPost('sortdir'); + if (!is_null($sortby) || !is_null($sortdir)) { + IMP::setSort($sortby, $sortdir, $folder); + } + + $result = new stdClass; + + if (Util::getPost('rangeslice')) { + require_once DIMP_BASE . '/lib/Views/ListMessages.php'; + $list_msg = new DIMP_Views_ListMessages(); + $result->viewport = $list_msg->getSlice($folder, intval(Util::getPost('start')) - 1, intval(Util::getPost('length'))); + $result->viewport->request_id = Util::getPost('request_id'); + $result->viewport->type = 'slice'; + } else { + $changed = _changed($folder, $cacheid); + if (!Util::getPost('checkcache') || $changed) { + $result->viewport = _getListMessages($folder, $changed); + } + } + break; + +case 'MoveMessage': +case 'CopyMessage': + $to = Util::getPost('tofld'); + if (!$to || empty($indices)) { + break; + } + + if ($action == 'MoveMessage') { + $change = _changed($folder, $cacheid, $indices); + } + + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $result = $imp_message->copy($to, + $action == 'MoveMessage' + ? IMP_MESSAGE_MOVE + : IMP_MESSAGE_COPY, + $indices); + if ($result) { + if ($action == 'MoveMessage') { + $result = _generateDeleteResult($folder, $indices, $change); + // Need to manually set remove to 'true' since we want to remove + // message from the list no matter the current pref settings. + $result->remove = true; + } + + // Update poll information for destination folder if necessary. + // Poll information for current folder will be added by + // _generateDeleteResult() call above. + $poll = _getPollInformation($to); + if (!empty($poll)) { + if (!isset($result->poll)) { + $result->poll = array(); + } + $result->poll = array_merge($result->poll, $poll); + } + } + break; + +case 'MarkMessage': + $flag = Util::getPost('messageFlag'); + if (!$flag || empty($indices)) { + break; + } + if ($flag[0] == '-') { + $flag = substr($flag, 1); + $set = false; + } else { + $set = true; + } + + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $result = $imp_message->flag(array($flag), $indices, $set); + if ($result) { + $result = new stdClass; + } + break; + +case 'DeleteMessage': +case 'UndeleteMessage': + if (empty($indices)) { + break; + } + + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + if ($action == 'DeleteMessage') { + $change = _changed($folder, $cacheid, $indices, !$prefs->getValue('hide_deleted') && !$prefs->getValue('use_trash')); + $result = $imp_message->delete($indices); + if ($result) { + $result = _generateDeleteResult($folder, $indices, $change); + } + } else { + $result = $imp_message->undelete($indices); + if ($result) { + $result = new stdClass; + } + } + break; + +case 'AddContact': + $email = Util::getPost('email'); + $name = Util::getPost('name'); + // Allow $name to be empty. + if (empty($email)) { + break; + } + + $result = IMP::addAddress($email, $name); + if (is_a($result, 'PEAR_Error')) { + $notification->push($result, 'horde.error'); + $result = false; + } else { + $result = true; + $notification->push(sprintf(_("%s was successfully added to your address book."), $name ? $name : $email), 'horde.success'); + } + break; + +case 'ReportSpam': +case 'ReportHam': + $change = _changed($folder, $cacheid, $indices); + require_once IMP_BASE . '/lib/Spam.php'; + $spam = new IMP_Spam(); + $result = $spam->reportSpam($indices, + $action == 'ReportSpam' ? 'spam' : 'notspam'); + if ($result) { + $result = _generateDeleteResult($folder, $indices, $change); + // If $result is non-zero, then we know the message has been removed + // from the current mailbox. + $result->remove = true; + } + break; + +case 'Blacklist': +case 'Whitelist': + if (empty($indices)) { + break; + } + + require_once IMP_BASE . '/lib/Filter.php'; + $imp_filter = new IMP_Filter(); + if ($action == 'Whitelist') { + $imp_filter->whitelistMessage($indices, false); + } else { + $change = _changed($folder, $cacheid, $indices); + if ($imp_filter->blacklistMessage($indices, false)) { + $result = _generateDeleteResult($folder, $indices, $change); + } + } + break; + +case 'ShowPreview': + if (count($indices) != 1) { + break; + } + + $ptr = each($indices); + $args = array( + 'folder' => $ptr['key'], + 'index' => reset($ptr['value']), + 'preview' => true, + ); + + require_once DIMP_BASE . '/lib/Views/ShowMessage.php'; + $show_msg = new DIMP_Views_ShowMessage(); + $result = (object) $show_msg->showMessage($args); + break; + +case 'Html2Text': + require_once 'Horde/Text/Filter.php'; + $result = new stdClass; + // Need to replace line endings or else IE won't display line endings + // properly. + $result->text = str_replace("\n", "\r\n", Text_Filter::filter(Util::getPost('text'), 'html2text')); + break; + +case 'Text2Html': + require_once 'Horde/Text/Filter.php'; + $result = new stdClass; + $result->text = Text_Filter::filter(Util::getPost('text'), 'text2html', array('parselevel' => TEXT_HTML_MICRO_LINKURL, 'class' => null, 'callback' => null)); + break; + +case 'GetForwardData': + require_once IMP_BASE . '/lib/Compose.php'; + require_once IMP_BASE . '/lib/MIME/Contents.php'; + require_once IMP_BASE . '/lib/UI/Compose.php'; + require_once 'Horde/MIME/Message.php'; + $header = array(); + $msg = $header = null; + $idx_string = _getIdxString($indices); + + $imp_compose = &IMP_Compose::singleton(Util::getPost('imp_compose')); + $imp_contents = &IMP_Contents::singleton($idx_string); + $imp_ui = new IMP_UI_Compose(); + $fwd_msg = $imp_ui->getForwardData($imp_compose, $imp_contents, Util::getPost('type'), $idx_string); + $header = $fwd_msg['headers']; + $header['replytype'] = 'forward'; + + $result = new stdClass; + // Can't open read-only since we need to store the message cache id. + $result->imp_compose = $imp_compose->getMessageCacheId(); + $result->fwd_list = DIMP::getAttachmentInfo($imp_compose); + $result->body = $fwd_msg['body']; + $result->header = $header; + $result->format = $fwd_msg['format']; + $result->identity = $fwd_msg['identity']; + break; + +case 'GetReplyData': + require_once IMP_BASE . '/lib/Compose.php'; + require_once IMP_BASE . '/lib/MIME/Contents.php'; + $imp_compose = &IMP_Compose::singleton(Util::getPost('imp_compose')); + $imp_contents = &IMP_Contents::singleton(_getIdxString($indices)); + $reply_msg = $imp_compose->replyMessage(Util::getPost('type'), $imp_contents); + $header = $reply_msg['headers']; + $header['replytype'] = 'reply'; + + $result = new stdClass; + $result->format = $reply_msg['format']; + $result->body = $reply_msg['body']; + $result->header = $header; + $result->identity = $reply_msg['identity']; + break; + +case 'DeleteDraft': + $index = Util::getPost('index'); + if (empty($indices)) { + break; + } + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $idx_array = array($index . IMP_IDX_SEP . IMP::folderPref($prefs->getValue('drafts_folder'), true)); + $imp_message->delete($idx_array, true); + break; + +case 'DeleteAttach': + $atc = Util::getPost('atc_indices'); + if (!is_null($atc)) { + require_once IMP_BASE . '/lib/Compose.php'; + $imp_compose = &IMP_Compose::singleton(Util::getPost('imp_compose')); + $imp_compose->deleteAttachment($atc); + } + break; + +case 'ShowPortal': + // Load the block list. Blocks are located in $dimp_block_list. + // KEY: Block label VALUE: Horde_Block object + require DIMP_BASE . '/config/portal.php'; + + $blocks = $linkTags = array(); + $css_load = array('dimp' => true); + foreach ($dimp_block_list as $title => $block) { + if (is_a($block['ob'], 'Horde_Block')) { + $app = $block['ob']->getApp(); + $content = ((empty($css_load[$app])) ? Horde::styleSheetLink($app, '', false) : '') . $block['ob']->getContent(); + $css_load[$app] = true; + // Don't do substitutions on our own blocks. + if ($app != 'dimp') { + $content = preg_replace('//', + $content, $links)) { + $content = str_replace($links[0], '', $content); + foreach ($links[0] as $link) { + if (preg_match('/href="(.*?)"/', $link, $href)) { + $linkOb = new stdClass; + $linkOb->href = $href[1]; + if (preg_match('/media="(.*?)"/', $link, $media)) { + $linkOb->media = $media[1]; + } + $linkTags[] = $linkOb; + } + } + } + } + if (!empty($content)) { + $entry = array( + 'app' => $app, + 'content' => $content, + 'title' => $title, + 'class' => empty($block['class']) ? 'headerbox' : $block['class'], + ); + if (!empty($block['domid'])) { + $entry['domid'] = $block['domid']; + } + if (!empty($block['tag'])) { + $entry[$block['tag']] = true; + } + $blocks[] = $entry; + } + } + } + + $result = new stdClass; + $result->portal = ''; + if (!empty($blocks)) { + require_once IMP_BASE . '/lib/Template.php'; + $t = new IMP_Template(DIMP_TEMPLATES . '/imp/'); + $t->set('block', $blocks); + $result->portal = $t->fetch('portal.html'); + } + $result->linkTags = $linkTags; + break; + +case 'chunkContent': + $chunk = basename(Util::getPost('chunk')); + if (!empty($chunk)) { + $result = new stdClass; + $result->chunk = Util::bufferOutput('include', DIMP_TEMPLATES . '/chunks/' . $chunk . '.php'); + } + break; + +case 'PurgeDeleted': + $change = _changed($folder, $cacheid, $indices); + if (!$change) { + $sort = IMP::getSort($folder); + $change = ($sort['by'] == SORTTHREAD); + } + require_once IMP_BASE . '/lib/Message.php'; + $imp_message = &IMP_Message::singleton(); + $expunged = $imp_message->expungeMailbox(array($folder => 1)); + if (!empty($expunged[$folder])) { + $expunge_count = count($expunged[$folder]); + $display_folder = IMP::displayFolder($folder); + if ($expunge_count == 1) { + $notification->push(sprintf(_("1 message was purged from \"%s\"."), $display_folder), 'horde.success'); + } else { + $notification->push(sprintf(_("%s messages were purged from \"%s\"."), $expunge_count, $display_folder), 'horde.success'); + } + $result = _generateDeleteResult($folder, $expunged, $change); + // Need to manually set remove to 'true' since we want to remove + // message from the list no matter the current pref settings. + $result->remove = true; + } + break; + +case 'ModifyPollFolder': + if (empty($folder)) { + break; + } + + $add = Util::getPost('add'); + + require_once IMP_BASE . '/lib/IMAP/Tree.php'; + $imptree = &IMP_Tree::singleton(); + + $result = new stdClass; + $result->add = (bool) $add; + $result->folder = $folder; + + if ($add) { + $imptree->addPollList($folder); + if ($info = $imptree->getElementInfo($folder)) { + $result->poll = array($folder => $info['unseen']); + } + } else { + $imptree->removePollList($folder); + } + break; + +case 'SendMDN': + $index = Util::getPost('index'); + if (empty($folder) || empty($index)) { + break; + } + + /* Get the IMP_Headers:: object. */ + require_once IMP_BASE . '/lib/IMAP/MessageCache.php'; + $msg_cache = &IMP_MessageCache::singleton(); + $cache_entry = $msg_cache->retrieve($folder, array($index), 32); + $ob = reset($cache_entry); + if ($ob === false) { + break; + } + + require_once IMP_BASE . '/lib/UI/Message.php'; + $imp_ui = new IMP_UI_Message(); + $imp_ui->MDNCheck($ob->header, true); + break; +} + +// Clear the output buffer that we started above, and log any unexpected +// output at a DEBUG level. +$errors = ob_get_clean(); +if ($errors) { + Horde::logMessage('DIMP: unexpected output: ' . + $errors, __FILE__, __LINE__, PEAR_LOG_DEBUG); +} + +// Send the final result. +IMP::sendHTTPResponse(DIMP::prepareResponse($result), 'json'); diff --git a/imp/imple.php b/imp/imple.php index 4888274f8..b147f6304 100644 --- a/imp/imple.php +++ b/imp/imple.php @@ -8,21 +8,42 @@ * @author Michael Slusarz */ +// As of right now, imples don't need read/write session access. +$session_control = 'readonly'; +$session_timeout = 'none'; + @define('IMP_BASE', dirname(__FILE__)); $authentication = 'horde'; require_once IMP_BASE . '/lib/base.php'; -if (!($path = Util::getFormData('imple'))) { - exit; -} -if ($path[0] == '/') { - $path = substr($path, 1); -} -$path = explode('/', $path); -$impleName = array_shift($path); +if ($_SESSION['imp']['view'] == 'dimp') { + $path_info = Util::getPathInfo(); + if (empty($path_info)) { + IMP::sendHTTPResponse(new stdClass(), 'json'); + } + + if ($path_info[0] == '/') { + $path_info = substr($path_info, 1); + } + $path = explode('/', $path_info); + $impleName = array_shift($path); -if (!($imple = IMP_Imple::factory($impleName))) { - exit; + if (!($imple = IMP_Imple::factory($impleName))) { + IMP::sendHTTPResponse(new stdClass(), 'json'); + } +} else { + if (!($path = Util::getFormData('imple'))) { + exit; + } + if ($path[0] == '/') { + $path = substr($path, 1); + } + $path = explode('/', $path); + $impleName = array_shift($path); + + if (!($imple = IMP_Imple::factory($impleName))) { + exit; + } } $args = array(); diff --git a/imp/index-dimp.php b/imp/index-dimp.php new file mode 100644 index 000000000..21062f24c --- /dev/null +++ b/imp/index-dimp.php @@ -0,0 +1,78 @@ + + */ + +@define('DIMP_BASE', dirname(__FILE__)); +$dimp_configured = (is_readable(DIMP_BASE . '/config/conf.php') && + is_readable(DIMP_BASE . '/config/portal.php') && + is_readable(DIMP_BASE . '/config/prefs.php')); + +if (!$dimp_configured) { + require DIMP_BASE . '/../lib/Test.php'; + Horde_Test::configFilesMissing('DIMP', DIMP_BASE, + array('conf.php', 'prefs.php'), + array('portal.php' => 'This file controls the blocks that appear in DIMP\'s portal')); +} + +$load_imp = true; +require_once DIMP_BASE . '/lib/base.php'; + +$scripts = array( + array('DimpBase.js', 'dimp', true), + array('ContextSensitive.js', 'dimp', true), + array('ViewPort.js', 'dimp', true), + array('dragdrop.js', 'dimp', true), + array('dhtmlHistory.js', 'horde', true), + array('redbox.js', 'horde', true), + array('mailbox.js', 'dimp'), + array('DimpSlider.js', 'dimp', true), + array('unblockImages.js', 'imp', true) +); + +/* Get site specific menu items. */ +$js_code = $site_menu = array(); +if (is_readable(DIMP_BASE . '/config/menu.php')) { + include DIMP_BASE . '/config/menu.php'; +} + +/* Add the site specific javascript now. */ +if (!empty($site_menu)) { + foreach ($site_menu as $key => $menu_item) { + if ($menu_item == 'separator') { + continue; + } + $js_code[] = 'DimpCore.clickObserveHandler({ d: $(\'menu' . $key . '\'), f: function() { ' . $menu_item['action'] . ' } })'; + $js_code[] = 'DimpCore.clickObserveHandler({ d: $(\'tab' . $key . '\'), f: function() { ' . $menu_item['action'] . ' } })'; + } +} + +IMP::addInlineScript($js_code, true); +DIMP::header('', $scripts); + +/* Get application folders list. */ +$application_folders = array(); +foreach (DIMP::menuList() as $app) { + if ($registry->get('status', $app) != 'inactive' && + $registry->hasPermission($app, PERMS_SHOW)) { + $application_folders[] = array( + 'name' => htmlspecialchars($registry->get('name', $app)), + 'icon' => $registry->get('icon', $app), + 'app' => rawurlencode($app) + ); + } +} + +echo "\n"; +require DIMP_TEMPLATES . '/index/index.inc'; +IMP::includeScriptFiles(); +IMP::outputInlineScript(); +$notification->notify(array('listeners' => array('javascript'))); +echo "\n"; diff --git a/imp/js/ContextSensitive.js b/imp/js/ContextSensitive.js new file mode 100644 index 000000000..2dbe02014 --- /dev/null +++ b/imp/js/ContextSensitive.js @@ -0,0 +1 @@ +var ContextSensitive=Class.create({initialize:function(){this.current=this.target=null;this.elements=$H();document.observe("contextmenu",this.rightClickHandler.bindAsEventListener(this));document.observe("click",this.leftClickHandler.bindAsEventListener(this));document.observe(Prototype.Browser.Gecko?"DOMMouseScroll":"mousescroll",this.close.bind(this))},addElement:function(D,C,A){var B=Boolean(A.left);if(D&&!this.validElement(D,B)){this.elements.set(D+Number(B),new ContextSensitive.Element(D,C,A))}},removeElement:function(A){this.elements.unset(A+"0");this.elements.unset(A+"1")},close:function(A){if(this.current){if(A){this.current.hide()}else{Effect.Fade(this.current,{duration:0.2})}this.current=this.target=null}},element:function(){return this.target},currentmenu:function(){if(this.current&&this.current.visible()){return this.current}},validElement:function(B,A){return this.elements.get(B+Number(Boolean(A)))},disable:function(D,C,A){var B=this.validElement(D,C);if(B){B.disable=A}},leftClickHandler:function(A){if(A.isRightClick()){return}this.rightClickHandler(A,true)},rightClickHandler:function(B,A){if(this.trigger(B.element(),A,B.pointerX(),B.pointerY())){B.stop()}},trigger:function(F,E,H,G){var J,B,D,C,K,I,A;[F].concat(F.ancestors()).find(function(L){J=this.validElement(L.id,E);return J},this);if(!J||J.disable){this.close();return false}B=$(J.ctx);if(!B){this.close();return false}else{if(E&&B==this.current){return false}}this.current=B;this.target=$(J.id);D=J.opts.offset;if(!D&&(Object.isUndefined(H)||Object.isUndefined(G))){D=F.id}D=$(D);if(D){C=D.viewportOffset();A=document.viewport.getScrollOffsets();H=C[0]+A.left;G=C[1]+D.getHeight()+A.top}I=document.viewport.getDimensions();K=B.getDimensions();if((G+K.height)>I.height){G=I.height-K.height-10}if((H+K.width)>I.width){H=I.width-K.width-10}if(J.opts.onShow){J.opts.onShow(J)}Effect.Appear(B.setStyle({left:H+"px",top:G+"px"}),{duration:0.2});return true}});ContextSensitive.Element=Class.create({initialize:function(C,B,A){this.id=C;this.ctx=B;this.opts=A;this.opts.left=Boolean(A.left);this.disable=false}}); \ No newline at end of file diff --git a/imp/js/DimpBase.js b/imp/js/DimpBase.js new file mode 100644 index 000000000..532afb41c --- /dev/null +++ b/imp/js/DimpBase.js @@ -0,0 +1 @@ +var DimpBase={bcache:$H(),lastrow:-1,mo_sidebar:{},pivotrow:-1,ppcache:{},ppfifo:[],showPreview:DIMP.conf.preview_pref,sfiltersfolder:$H({sf_all:"all",sf_current:"current"}),sfilters:$H({sf_msgall:"msgall",sf_from:"from",sf_to:"to",sf_subject:"subject"}),_select:function(C,A){var B=C.get("rownum");if(B.size()==1){this.lastrow=this.pivotrow=B.first()}this.toggleButtons();if($("previewPane").visible()){if(A.right){this.clearPreviewPane()}else{if(A.delay){(this.bcache.get("initPP")||this.bcache.set("initPP",this.initPreviewPane.bind(this))).delay(A.delay)}else{this.initPreviewPane()}}}},_deselect:function(D,B){var C=this.viewport.getSelected(),A=C.size();if(!A){this.lastrow=this.pivotrow=-1}this.toggleButtons();if(B.right||!A){this.clearPreviewPane()}else{if((A==1)&&$("previewPane").visible()){this._loadPreview(C.get("dataob").first())}}},msgSelect:function(G,C){var B,E=this.viewport.createSelection("domid",G),A=E.get("rownum").first(),D=this.isSelected("domid",G),F=this.selectedCount();this.lastrow=A;$("msgList_filter").blur();if(C.shift){if(F){if(!D||F!=1){B=[A,this.pivotrow];this.viewport.select($A($R(B.min(),B.max())),{range:true})}return}}else{if(C.ctrl){this.pivotrow=A;if(D){this.viewport.deselect(E,{right:C.right});return}else{if(C.right||F){this.viewport.select(E,{add:true,right:C.right});return}}}}this.viewport.select(E,{right:C.right})},selectAll:function(){this.viewport.select($A($R(1,this.viewport.getMetaData("total_rows"))),{range:true})},isSelected:function(B,A){return this.viewport.getSelected().contains(B,A)},selectedCount:function(){return(this.viewport)?this.viewport.getSelected().size():0},resetSelected:function(){if(this.viewport){this.viewport.deselect(this.viewport.getSelected(),{clearall:true})}this.toggleButtons();this.clearPreviewPane()},moveSelected:function(A,G){var E,D,F,B,C;if(G){if(!this.viewport.getMetaData("total_rows")){return}E=A}else{if(A==0){return}C=this.viewport.getSelected();switch(C.size()){case 0:E=this.viewport.currentOffset()+1;break;case 1:D=C.get("dataob").first();E=D.rownum+A;break;default:C=C.get("rownum");E=(A>0?C.max():C.min())+A;break}E=(A>0)?Math.min(E,this.viewport.getMetaData("total_rows")):Math.max(E,1)}F=this.viewport.createSelection("rownum",E);if(F.size()){B=F.get("dataob").first();if(!D||B.imapuid!=D.imapuid){this.viewport.scrollTo(B.rownum);this.viewport.select(F,{delay:0.3})}}else{this.offset=E;this.viewport.requestContentRefresh(E-1)}},go:function(E,B){var D,A,C;if(E.startsWith("compose:")){return}if(E.startsWith("msg:")){C=E.indexOf(":",4);A=E.substring(4,C);this.uid=E.substring(C+1);E="folder:"+A}if(E.startsWith("folder:")){A=E.substring(7);if(this.folder!=A||!$("dimpmain_folder").visible()){this.highlightSidebar(this.getFolderId(A));if(!$("dimpmain_folder").visible()){$("dimpmain_portal").hide();$("dimpmain_folder").show()}if(!Object.isUndefined(this.folder)){this._addHistory(E)}}this.loadFolder(A);return}this.folder=null;$("dimpmain_folder").hide();$("dimpmain_portal").update(DIMP.text.loading).show();if(E.startsWith("app:")){D=E.substr(4);if(D=="imp"||D=="dimp"){this.go("folder:INBOX");return}this.highlightSidebar("app"+D);this._addHistory(E,B);if(B){this.iframeContent(E,B)}else{if(DIMP.conf.app_urls[D]){this.iframeContent(E,DIMP.conf.app_urls[D])}}return}switch(E){case"portal":this.highlightSidebar("appportal");this._addHistory(E);DimpCore.setTitle(DIMP.text.portal);DimpCore.doAction("ShowPortal",{},null,this.bcache.get("portalC")||this.bcache.set("portalC",this._portalCallback.bind(this)));break;case"options":this.highlightSidebar("appoptions");this._addHistory(E);DimpCore.setTitle(DIMP.text.prefs);this.iframeContent(E,DIMP.conf.prefs_url);break}},_addHistory:function(B,A){if(Horde.dhtmlHistory.getCurrentLocation()!=B){Horde.dhtmlHistory.add(B,A)}},highlightSidebar:function(B){if($("foldersLoading").visible()){this.highlightSidebar.bind(this,B).defer();return}$("sidebarPanel").select(".on").invoke("removeClassName","on");var A=$(B);if(!A){return}if(!A.match("LI")){A=A.up();if(!A){return}}A.addClassName("on");A.ancestors().find(function(C){if(C.hasClassName("subfolders")){this._toggleSubFolder(C.id.substring(3),"exp")}else{return(C.id=="foldersSidebar")}},this)},iframeContent:function(B,D){if(B===null){B=D}var A=$("dimpmain_portal"),C;if(!A){DimpCore.showNotifications([{type:"horde.error",message:"Bad portal!"}]);return}C=new Element("IFRAME",{id:"iframe"+B,className:"iframe",frameBorder:0,src:D});this._resizeIE6Iframe(C);if(B=="options"){C.observe("load",function(){$("iframeoptions").contentWindow.document.getElementById("menu").style.display="none"})}A.insert(C)},msgWindow:function(B){this.updateUnseenUID(B,0);var A=DIMP.conf.message_url;A+=(A.include("?")?"&":"?")+$H({folder:B.view,uid:B.imapuid}).toQueryString();DimpCore.popupWindow(A,"msgview"+B.view+B.imapuid)},composeMailbox:function(A){var B=this.viewport.getSelected();if(!B.size()){return}B.get("dataob").each(function(C){DimpCore.compose(A,{folder:C.view,uid:C.imapuid})})},loadFolder:function(B,A){if(!this.viewport){this._createViewPort()}if(!A){this.resetSelected();if(this.folder==B){this.searchfilterClear(false);return}this.searchfilterClear(true);$("folderName").update(DIMP.text.loading);$("msgHeader").update();this.folderswitch=true;this.folder=B}this.viewport.loadView(B,{folder:B},this.uid?{imapuid:this.uid,view:B}:null,A)},_createViewPort:function(){var B=$("msgList_filter"),A=this.setMessageListTitle.bind(this);this.viewport=new ViewPort({content_container:"msgList",empty_container:"msgList_empty",error_container:"msgList_error",fetch_action:"ListMessages",template:this.message_list_template,buffer_pages:DIMP.conf.buffer_pages,limit_factor:DIMP.conf.limit_factor,viewport_wait:DIMP.conf.viewport_wait,show_split_pane:this.showPreview,split_pane:"previewPane",splitbar:"splitBar",content_class:"msglist",row_class:"msgRow",selected_class:"selectedRow",ajaxRequest:DimpCore.doAction.bind(DimpCore),norows:true,onScrollIdle:A,onSlide:A,onViewChange:function(){DimpCore.addGC(this.viewport.visibleRows())}.bind(this),onContent:function(F){var E,D,C=((this.viewport.getMetaData("sortby")==DIMP.conf.sortthread)&&this.viewport.getMetaData("thread"));if(this.viewport.isFiltering()){D=this.sfilters.get(this._getSearchfilterField()).capitalize();E=new RegExp("("+$F("msgList_filter")+")","i")}F.get("dataob").each(function(K){var H,I,G,J=$(K.domid);if(C&&C[K.imapuid]){H=J.down(".msgSubject");I=H.cloneNode(false);G=C[K.imapuid];$R(0,G.length,true).each(function(L){I.insert($($("thread_img_"+G.charAt(L)).cloneNode(false)).writeAttribute("id",""))});H.replace(I.insert(H.getText().escapeHTML()))}if(K.atc){J.down(".msgSize").insert({top:$($("atc_img_"+K.atc).cloneNode(false)).writeAttribute("id","")})}DimpCore.addMouseEvents({id:K.domid,type:K.menutype});if(D=="From"||D=="Subject"){H=J.down(".msg"+D);H.update(H.getText().escapeHTML().gsub(E,'#{1}'))}},this);this.setMessageListTitle()}.bind(this),onComplete:function(){var E,C,D=this.viewport.getMetaData("label");if(this.uid){E=this.viewport.getViewportSelection().search({imapuid:{equal:[this.uid]},view:{equal:[this.folder]}});if(E.size()){this.viewport.scrollTo(E.get("rownum").first());this.viewport.select(E)}}else{if(this.offset){this.viewport.select(this.viewport.createSelection("rownum",this.offset))}}this.offset=this.uid=null;D=this.viewport.getMetaData("label");if(D){$("folderName").update(D)}if(this.folderswitch){this.folderswitch=false;if(this.folder==DIMP.conf.spam_folder){if(!DIMP.conf.spam_spamfolder&&DimpCore.buttons.indexOf("button_spam")!=-1){[$("button_spam").up(),$("ctx_message_spam")].invoke("hide")}if(DimpCore.buttons.indexOf("button_ham")!=-1){[$("button_ham").up(),$("ctx_message_ham")].invoke("show")}}else{if(DimpCore.buttons.indexOf("button_spam")!=-1){[$("button_spam").up(),$("ctx_message_spam")].invoke("show")}if(DimpCore.buttons.indexOf("button_ham")!=-1){if(DIMP.conf.ham_spamfolder){[$("button_ham").up(),$("ctx_message_ham")].invoke("hide")}else{[$("button_ham").up(),$("ctx_message_ham")].invoke("show")}}}}else{if(this.filtertoggle){if(this.filtertoggle==1&&this.viewport.getMetaData("sortby")==DIMP.conf.sortthread){C=DIMP.conf.sortdate}this.filtertoggle=0}}this.setSortColumns(C);if(this.viewport.isFiltering()){this.resetSelected()}else{this.setFolderLabel(this.folder,this.viewport.getMetaData("unseen")||0)}this.updateTitle()}.bind(this),onFetch:this.msgListLoading.bind(this,true),onEndFetch:this.msgListLoading.bind(this,false),onWait:function(){if($("dimpmain_folder").visible()){DimpCore.showNotifications([{type:"horde.warning",message:DIMP.text.listmsg_wait}])}},onFail:function(){if($("dimpmain_folder").visible()){DimpCore.showNotifications([{type:"horde.error",message:DIMP.text.listmsg_timeout}])}this.msgListLoading(false)}.bind(this),onFirstContent:function(){this.clearPreviewPane();$("msgList").observe("dblclick",this._handleMsgListDblclick.bindAsEventListener(this))}.bind(this),onClearRows:function(C){C.each(function(D){var E=$(D).down("div.msCheck");if(E){DimpCore.addGC(E)}if(D.id){DimpCore.removeMouseEvents(D)}})},onBeforeResize:function(){var C=this.viewport.getSelected();this.isvisible=(C.size()==1)&&(this.viewport.isVisible(C.get("rownum").first())==0)}.bind(this),onAfterResize:function(){if(this.isvisible){this.viewport.scrollTo(this.viewport.getSelected().get("rownum").first())}}.bind(this),selectCallback:this._select.bind(this),deselectCallback:this._deselect.bind(this)});if(!this.showPreview){$("msgList").addClassName("msglistNoPreview")}this.viewport.addFilter("ListMessages",this._addSearchfilterParams.bind(this));B.observe("keyup",this._searchfilterOnKeyup.bind(this));B.observe("focus",this._searchfilterOnFocus.bind(this));B.observe("blur",this._searchfilterOnBlur.bind(this));B.addClassName("msgFilterDefault")},_addMouseEvents:function(B,C){var A;switch(C.type){case"draft":case"message":new Drag(C.id,this._msgDragConfig);A=$(C.id).down("div.msCheck");if(A.visible()){A.observe("mousedown",this.bcache.get("handleMLC")||this.bcache.set("handleMLC",this._handleMsgListCheckbox.bindAsEventListener(this)));A.observe("contextmenu",Event.stop)}break;case"container":case"folder":new Drag(C.id,this._folderDragConfig);break;case"special":C.type="folder";break;case"vcontainer":case"virtual":$(C.id).observe("contextmenu",Event.stop);break}C.onShow=this.bcache.get("onMS")||this.bcache.set("onMS",this._onMenuShow.bind(this));B(C)},_removeMouseEvents:function(B,A){var C,D=$(A).readAttribute("id");if(D&&(C=DragDrop.Drags.get_drag(D))){C.destroy()}B(A)},_onMenuShow:function(A){var E,C,B,D;switch(A.ctx){case"ctx_folder":E=$("ctx_folder_create","ctx_folder_rename","ctx_folder_delete");C=DimpCore.DMenu.element();if(C.readAttribute("mbox")=="INBOX"){E.invoke("hide")}else{if(DIMP.conf.fixed_folders.indexOf(C.readAttribute("mbox"))!=-1){E.shift();E.invoke("hide")}else{E.invoke("show")}}if(C.hasAttribute("u")){$("ctx_folder_poll").hide();$("ctx_folder_nopoll").show()}else{$("ctx_folder_poll").show();$("ctx_folder_nopoll").hide()}break;case"ctx_message":[$("ctx_message_reply_list")].invoke(this.viewport.createSelection("domid",A.id).get("dataob").first().listmsg?"show":"hide");break;case"ctx_reply":D=this.viewport.getSelected();if(D.size()==1){B=D.get("dataob").first()}[$("ctx_reply_reply_list")].invoke(B&&B.listmsg?"show":"hide");break;case"ctx_otheractions":$("oa_seen","oa_unseen","oa_flagged","oa_clear","oa_sep1","oa_blacklist","oa_whitelist","oa_sep2").compact().invoke(this.viewport.getSelected().size()?"show":"hide");break}return true},_onResize:function(B,A){if(this.viewport){this.viewport.onResize(B,A)}this._resizeIE6()},_handleMsgListDblclick:function(B){var A=this._getMsgRow(B),C;if(!A){return}C=this.viewport.createSelection("domid",A.id).get("dataob").first();C.draft?DimpCore.compose("resume",{folder:C.view,uid:C.imapuid}):this.msgWindow(C);B.stop()},_handleMsgListCheckbox:function(B){var A=this._getMsgRow(B);if(!A){return}this.msgSelect(A.readAttribute("id"),{ctrl:true,right:true});B.stop()},_getMsgRow:function(A){A=A.element();if(A&&!A.hasClassName("msgRow")){A=A.up(".msgRow")}return A},updateTitle:function(){var B,A,C;if(this.viewport.isFiltering()){A=DIMP.text.search+" :: "+this.viewport.getMetaData("total_rows")+" "+DIMP.text.resfound}else{B=$(this.getFolderId(this.folder));if(B){C=B.readAttribute("u");A=B.readAttribute("l");if(C>0){A+=" ("+C+")"}}else{A=this.viewport.getMetaData("label")}}DimpCore.setTitle(A)},sort:function(D){if(this.viewport.getMetaData("sortlimit")){return}var B,C,A=D.element();if(!A.hasAttribute("sortby")){A=A.up("[sortby]");if(!A){return}}C=parseInt(A.readAttribute("sortby"),10);if(C==this.viewport.getMetaData("sortby")){B={sortdir:(this.viewport.getMetaData("sortdir")?0:1)};this.viewport.setMetaData({sortdir:B.sortdir})}else{B={sortby:C};this.viewport.setMetaData({sortby:B.sortby})}this.setSortColumns(C);this.viewport.reload(B)},setSortColumns:function(C){var B,A=$("msglistHeader");if(Object.isUndefined(C)){C=this.viewport.getMetaData("sortby")}B=A.down("small[sortby="+C+"]");if(B&&B.up().visible()){B.up(1).childElements().invoke("toggle")}B=A.down("div.msgFrom a");if((this.viewport.isFiltering()&&this.fspecial)||this.viewport.getMetaData("special")){B.hide().next().show()}else{B.show().next().hide()}B=A.down("div.msgSubject a");if(this.viewport.isFiltering()||this.viewport.getMetaData("nothread")||this.viewport.getMetaData("sortlimit")){B.show().next().hide();B.down().hide()}else{B.down().show()}A.childElements().invoke("removeClassName","sortup").invoke("removeClassName","sortdown");A.down("div a[sortby="+C+"]").up().addClassName(this.viewport.getMetaData("sortdir")?"sortup":"sortdown")},togglePreviewPane:function(){this.showPreview=!this.showPreview;$("previewtoggle").setText(this.showPreview?DIMP.text.hide_preview:DIMP.text.show_preview);[$("msgList")].invoke(this.showPreview?"removeClassName":"addClassName","msglistNoPreview");new Ajax.Request(DimpCore.addSID(DIMP.conf.URI_PREFS),{parameters:{app:"dimp",pref:"show_preview",value:this.showPreview?1:0}});this.viewport.showSplitPane(this.showPreview);if(this.showPreview){this.initPreviewPane()}},_loadPreview:function(C){var A=$("previewPane"),B;if(!A.visible()){return}if(this.pp&&this.pp==C){return}this.pp=C;if(this.ppfifo.indexOf(C.vp_id)!=-1){return this._loadPreviewCallback(this.ppcache[C.vp_id])}B=A.positionedOffset();$("msgLoading").setStyle({position:"absolute",top:(B.top+10)+"px",left:(B.left+10)+"px"}).show();DimpCore.doAction("ShowPreview",{},this.viewport.createSelection("dataob",C),this.bcache.get("loadPC")||this.bcache.set("loadPC",this._loadPreviewCallback.bind(this)))},_loadPreviewCallback:function(resp){var row,search,tmp,tmp2,pm=$("previewMsg"),r=resp.response,t=$("msgHeadersContent").down("THEAD");if(!r.error){search=this.viewport.getViewportSelection(r.view).search({vp_id:{equal:[r.uid]}});if(search.size()){row=search.get("dataob").first();this.updateUnseenUID(row,0)}}if(this.pp&&this.pp.vp_id!=r.uid){return}if(r.error||this.viewport.getSelected().size()!=1){if(r.error){DimpCore.showNotifications([{type:r.errortype,message:r.error}])}this.clearPreviewPane();return}this._expirePPCache([r.uid]);this.ppcache[r.uid]=resp;this.ppfifo.push(r.uid);DimpCore.removeAddressLinks(pm);DIMP.conf.msg_index=r.index;DIMP.conf.msg_folder=r.folder;tmp=pm.select(".subject");tmp.invoke("update",r.subject);switch(r.priority){case"high":case"low":tmp.invoke("insert",{top:$($(r.priority+"_priority_img").cloneNode(false)).writeAttribute("id",false)});break}$("msgHeadersColl").select(".date").invoke("update",r.minidate);$("msgHeaderDate").select(".date").invoke("update",r.fulldate);["from","to","cc"].each(function(a){if(r[a]){(a=="from"?pm.select("."+a):[t.down("."+a)]).each(function(elt){elt.replace(DimpCore.buildAddressLinks(r[a],elt.cloneNode(false)))})}[$("msgHeader"+a.capitalize())].invoke(r[a]?"show":"hide")});$("toggleHeaders").select(".attachmentImage").invoke(r.atc_label?"show":"hide");if(r.atc_label){tmp=$("msgAtc").show().down(".label");tmp2=$("partlist");tmp2.hide().previous().update(r.atc_label+" "+r.atc_download);if(r.atc_list){$("partlist_col").show();$("partlist_exp").hide();tmp.down().hide().next().show();tmp2.update(r.atc_list)}else{tmp.down().show().next().hide()}}else{$("msgAtc").hide()}$("msgBody").down().update(r.msgtext);$("msgLoading","previewInfo").invoke("hide");$("previewPane").scrollTop=0;pm.show();if(r.js){eval(r.js.join(";"))}this._addHistory("msg:"+row.view+":"+row.imapuid)},initPreviewPane:function(){var A=this.viewport.getSelected();if(A.size()!=1){this.clearPreviewPane()}else{this._loadPreview(A.get("dataob").first())}},clearPreviewPane:function(){$("msgLoading","previewMsg").invoke("hide");$("previewInfo").show();this.pp=null},_expirePPCache:function(A){this.ppfifo=this.ppfifo.without(A);A.each(function(B){delete this.ppcache[B]},this);if(this.ppfifo.size()>20){delete this.ppcache[this.ppfifo.shift()]}},updateUnseenUID:function(B,E){var C,D,A;if(!B.bg){return false}A=B.bg.indexOf("unseen")!=-1;if((E&&A)||(!E&&!A)){return false}C=this.viewport.createSelection("dataob",B);D=parseInt($(this.getFolderId(B.view)).readAttribute("u"),10);if(E){this.viewport.updateFlag(C,"unseen",true);++D}else{this.viewport.updateFlag(C,"unseen",false);--D}this.updateUnseenStatus(B.view,D)},updateUnseenStatus:function(B,A){if(this.viewport){this.viewport.setMetaData({unseen:A},B)}this.setFolderLabel(B,A);if(this.folder==B){this.updateTitle()}},setMessageListTitle:function(){var B,A=this.viewport.getMetaData("total_rows");if(A>0){B=this.viewport.currentOffset();$("msgHeader").update(DIMP.text.messages+" "+(B+1)+" - "+(Math.min(B+this.viewport.getPageSize(),A))+" "+DIMP.text.of+" "+A)}else{$("msgHeader").update(DIMP.text.nomessages)}},setFolderLabel:function(B,C){var A,D=this.getFolderId(B);A=$(D);if(!A||!A.hasAttribute("u")){return}C=parseInt(C);A.writeAttribute("u",C);if(B=="INBOX"&&window.fluid){window.fluid.setDockBadge(C?C:"")}$(D+"_label").update((C>0)?new Element("STRONG").insert(A.readAttribute("l")).insert(" ").insert(new Element("SPAN",{className:"count",dir:"ltr"}).insert("("+C+")")):A.readAttribute("l"))},getFolderId:function(A){return"fld"+decodeURIComponent(A).replace(/_/g,"__").replace(/\W/g,"_")},getSubFolderId:function(A){return"sub"+A},pollFolders:function(){this.setPollFolders();var A={};if(this.folder&&$("dimpmain_folder").visible()){A=this.viewport.addRequestParams({})}$("checkmaillink").down("A").update("["+DIMP.text.check+"]");DimpCore.doAction("PollFolders",A,null,this.bcache.get("pollFC")||this.bcache.set("pollFC",this._pollFoldersCallback.bind(this)))},_pollFoldersCallback:function(B){var C,A;B=B.response;if(B.poll){A=this;$H(B.poll).each(function(D){A.updateUnseenStatus(D.key,D.value)})}if(B.quota){C=$("quota").cleanWhitespace();C.setText(B.quota.m);C.down("SPAN.used IMG").writeAttribute({width:99-B.quota.p})}$("checkmaillink").down("A").update(DIMP.text.getmail)},setPollFolders:function(){if(DIMP.conf.refresh_time){if(this.pollPE){this.pollPE.stop()}this.pollPE=new PeriodicalExecuter(this.pollFolders.bind(this),DIMP.conf.refresh_time)}},_portalCallback:function(B){if(B.response.linkTags){var A=$$("HEAD").first();B.response.linkTags.each(function(C){var D=new Element("LINK",{type:"text/css",rel:"stylesheet",href:C.href});if(C.media){D.media=C.media}A.insert(D)})}$("dimpmain_portal").update(B.response.portal);$("dimpmain_portal").select("h1.header a").each(this.bcache.get("portalClkLink")||this.bcache.set("portalClkLink",function(C){C.observe("click",function(D,E){this.go("app:"+E.readAttribute("app"));D.stop()}.bindAsEventListener(this,C))}.bind(this)))},_searchfilterOnKeyup:function(){if(this.searchobserve){clearTimeout(this.searchobserve)}this.searchobserve=(this.bcache.get("searchfilterR")||this.bcache.set("searchfilterR",this.searchfilterRun.bind(this))).delay(0.5)},searchfilterRun:function(){if(!this.viewport.isFiltering()){this.filtertoggle=1;this.fspecial=this.viewport.getMetaData("special")}this.viewport.runFilter($F("msgList_filter"))},_searchfilterOnFocus:function(){var A=$("qoptions").up();if($("msgList_filter").hasClassName("msgFilterDefault")){this._setFilterText(false)}if(!A.visible()){$("sf_current").update(this.viewport.getMetaData("label"));this._setSearchfilterParams(this.viewport.getMetaData("special")?"to":"from","msg");this._setSearchfilterParams("current","folder");$(document.documentElement).setStyle({overflowY:"hidden"});Effect.SlideDown(A,{duration:0.5,afterFinish:function(){this._onResize(false,true);$(document.documentElement).setStyle({overflowY:"auto"})}.bind(this)})}},_searchfilterOnBlur:function(){if(!$F("msgList_filter")){this._setFilterText(true)}},searchfilterClear:function(A){var B=$("qoptions").up();if(!B.visible()){return}if(this.searchobserve){clearTimeout(this.searchobserve);this.searchobserve=null}this._setFilterText(true);Effect.SlideUp(B,{duration:0.5,afterFinish:this._onResize.bind(this,A)});this.filtertoggle=2;this.resetSelected();this.viewport.stopFilter(A)},_setFilterText:function(B){var A=$("msgList_filter");if(B){A.setValue(DIMP.text.search);A.addClassName("msgFilterDefault")}else{A.setValue("");A.removeClassName("msgFilterDefault")}},_setSearchfilterParams:function(C,A){var B=(A=="folder")?this.sfiltersfolder:this.sfilters;B.keys().each(function(D){$(D).writeAttribute("className",(C==B.get(D))?"qselected":"")})},updateSearchfilter:function(B,A){this._setSearchfilterParams(B,A);if($F("msgList_filter")){this.viewport.runFilter()}},_addSearchfilterParams:function(){var A=this.sfiltersfolder.keys().find(function(B){return $(B).hasClassName("qselected")});return{searchfolder:this.sfiltersfolder.get(A),searchmsg:this.sfilters.get(this._getSearchfilterField())}},_getSearchfilterField:function(){return this.sfilters.keys().find(function(A){return $(A).hasClassName("qselected")})},toggleButtons:function(){var A=(this.selectedCount()==0);DimpCore.buttons.each(function(B){var C=$(B);if(C){[C.up()].invoke(A?"addClassName":"removeClassName","disabled");DimpCore.DMenu.disable(B+"_img",true,A)}})},_folderDropHandler:function(C,D,H){var G,F,E,B=C.readAttribute("mbox"),A=C.readAttribute("ftype");if(D.hasClassName("folder")){G=(C==$("dropbase"));if(G||(A!="special"&&!this.isSubfolder(D,C))){DimpCore.doAction("RenameFolder",{old_name:D.readAttribute("mbox"),new_parent:G?"":B,new_name:D.readAttribute("l")},null,this.bcache.get("folderC")||this.bcache.set("folderC",this._folderCallback.bind(this)))}}else{if(A!="container"){F=this.viewport.getSelected();if(F.size()){E=F}else{if(D.readAttribute("mbox")!=B){E=this.viewport.createSelection("domid",D.id)}}if(E.size()){if(H.ctrlKey){DimpCore.doAction("CopyMessage",this.viewport.addRequestParams({tofld:B}),E,this.bcache.get("pollFC")||this.bcache.set("pollFC",this._pollFoldersCallback.bind(this)))}else{if(this.folder!=B){this.viewport.updateFlag(E,"deletedmsg",true);DimpCore.doAction("MoveMessage",this.viewport.addRequestParams({tofld:B}),E,this.bcache.get("deleteC")||this.bcache.set("deleteC",this._deleteCallback.bind(this)))}}}}}},_dragCaption:function(){var A=this.selectedCount();return A+" "+(A==1?DIMP.text.message:DIMP.text.messages)},_keydownHandler:function(E){if(!$("dimpmain_folder").visible()||E.findElement("FORM")||RedBox.overlayVisible()){return}var H,G,B,F,D,A=E.keyCode||E.charCode,C=this.viewport.getSelected();switch(A){case Event.KEY_DELETE:case Event.KEY_BACKSPACE:if(C.size()==1){B=C.get("dataob").first();if(E.shiftKey){this.moveSelected(B.rownum+((B.rownum==this.viewport.getMetaData("total_rows"))?-1:1),true)}this.flag("deleted",B)}else{this.flag("deleted")}E.stop();break;case Event.KEY_UP:case Event.KEY_DOWN:if(E.shiftKey&&this.lastrow!=-1){F=this.viewport.createSelection("rownum",this.lastrow+((A==Event.KEY_UP)?-1:1));if(F.size()){F=F.get("dataob").first();this.viewport.scrollTo(F.rownum);this.msgSelect(F.domid,{shift:true})}}else{this.moveSelected(A==Event.KEY_UP?-1:1)}E.stop();break;case Event.KEY_PAGEUP:case Event.KEY_PAGEDOWN:if(!E.ctrlKey&&!E.shiftKey&&!E.altKey&&!E.metaKey){G=this.viewport.getPageSize()-1;move=G*(A==Event.KEY_PAGEUP?-1:1);if(C.size()==1){H=this.viewport.currentOffset();D=C.get("rownum").first()-1;switch(A){case Event.KEY_PAGEUP:if(H!=D){move=H-D}break;case Event.KEY_PAGEDOWN:if((H+G)!=D){move=H+G-D}break}}this.moveSelected(move);E.stop()}break;case Event.KEY_HOME:case Event.KEY_END:this.moveSelected(A==Event.KEY_HOME?1:this.viewport.getMetaData("total_rows"),true);E.stop();break;case Event.KEY_RETURN:if(!E.element().match("input")){if(C.size()==1){this.msgWindow(C.get("dataob").first())}}E.stop();break;case 65:case 97:if(E.ctrlKey){this.selectAll();E.stop()}break}},renameFolder:function(A){if(Object.isUndefined(A)){return}A=$(A);var B=this._createFolderForm(function(C){this._folderAction(A,C,"rename");return false}.bindAsEventListener(this),DIMP.text.rename_prompt);B.down("input").setValue(A.readAttribute("l"))},createBaseFolder:function(){this._createFolderForm(function(A){this._folderAction("",A,"create");return false}.bindAsEventListener(this),DIMP.text.create_prompt)},createSubFolder:function(A){if(Object.isUndefined(A)){return false}this._createFolderForm(function(B){this._folderAction($(A),B,"createsub");return false}.bindAsEventListener(this),DIMP.text.createsub_prompt)},_createFolderForm:function(A,B){var C=new Element("FORM",{action:"#",id:"RB_folder"}).insert(new Element("P").insert(B)).insert(new Element("INPUT",{type:"text",size:15})).insert(new Element("INPUT",{type:"button",className:"button",value:DIMP.text.ok}).observe("click",A)).insert(new Element("INPUT",{type:"button",className:"button",value:DIMP.text.cancel}).observe("click",this.bcache.get("closeRB")||this.bcache.set("closeRB",this._closeRedBox.bind(this)))).observe("keydown",function(D){if((D.keyCode||D.charCode)==Event.KEY_RETURN){D.stop();A(D)}});RedBox.overlay=true;RedBox.onDisplay=Form.focusFirstElement.curry(C);RedBox.showHtml(C);return C},_closeRedBox:function(){var A=RedBox.getWindowContents();DimpCore.addGC([A,A.descendants()].flatten());RedBox.close()},_folderAction:function(B,D,G){this._closeRedBox();var C,F,E,A=D.findElement("form");E=$F(A.down("input"));if(E){switch(G){case"rename":if(B.readAttribute("l")!=E){C="RenameFolder";F={old_name:B.readAttribute("mbox"),new_parent:B.up().hasClassName("folderlist")?"":B.up(1).previous().readAttribute("mbox"),new_name:E}}break;case"create":case"createsub":C="CreateFolder";F={folder:E};if(G=="createsub"){F.parent=B.readAttribute("mbox")}break}if(C){DimpCore.doAction(C,F,null,this.bcache.get("folderC")||this.bcache.set("folderC",this._folderCallback.bind(this)))}}},_folderCallback:function(A){A=A.response;if(A.d){A.d.each(this.bcache.get("deleteFolder")||this.bcache.set("deleteFolder",this.deleteFolder.bind(this)))}if(A.c){A.c.each(this.bcache.get("changeFolder")||this.bcache.set("changeFolder",this.changeFolder.bind(this)))}if(A.a){A.a.each(this.bcache.get("createFolder")||this.bcache.set("createFolder",this.createFolder.bind(this)))}},_deleteCallback:function(C){var A,B=[];this.msgListLoading(false);this._pollFoldersCallback(C);C=C.response;if(!C.uids||C.folder!=this.folder){return}$H(DimpCore.parseRangeString(C.uids)).each(function(D){D.value.each(function(E){B.push(E+D.key)})});A=this.viewport.getViewportSelection().search({vp_id:{equal:B}});if(A.size()){if(C.remove){this.viewport.remove(A,{cacheid:C.cacheid,noupdate:C.viewport});this._expirePPCache(A.get("uid"))}else{this.viewport.updateFlag(A,"deletedmsg",true)}}},_emptyFolderCallback:function(A){if(A.response.mbox){if(this.folder==A.response.mbox){this.viewport.reload();this.clearPreviewPane()}this.setFolderLabel(A.response.mbox,0)}},_flagAllCallback:function(A){if(A.response.mbox){this.setFolderLabel(A.response.mbox,A.response.u)}},_folderLoadCallback:function(B){this._folderCallback(B);var D=$("specialfolders","normalfolders").compact(),C=$("normalfolders"),A=C.getStyle("max-height");D.invoke("observe","click",this._handleFolderMouseEvent.bindAsEventListener(this,"click"));D.invoke("observe","mouseover",this._handleFolderMouseEvent.bindAsEventListener(this,"over"));if(DIMP.conf.is_ie6){D.invoke("observe","mouseout",this._handleFolderMouseEvent.bindAsEventListener(this,"out"))}$("foldersLoading").hide();$("foldersSidebar").show();if(A!==null||(Prototype.Browser.IE&&Object.isUndefined(A)&&(C.getStyle("height")=="0px"))){this._sizeFolderlist();Event.observe(window,"resize",this._sizeFolderlist.bind(this))}},_handleFolderMouseEvent:function(E,D){var C,B=E.element(),A=B.up(".folder")||B.up(".custom");if(!A){return}C=A.readAttribute("ftype");switch(D){case"over":if(DIMP.conf.is_ie6){A.addClassName("over")}if(C&&!this.mo_sidebar[A.id]){DimpCore.addMouseEvents({id:A.id,type:C});this.mo_sidebar[A.id]=1}break;case"out":A.removeClassName("over");break;case"click":if(B.hasClassName("exp")||B.hasClassName("col")){this._toggleSubFolder(A.id,"tog")}else{switch(C){case"container":case"vcontainer":E.stop();break;case"folder":case"special":case"virtual":E.stop();return this.go("folder:"+A.readAttribute("mbox"));break}}break}},_toggleSubFolder:function(C,D){C=$(C);var B={duration:0.2},A=$(this.getSubFolderId(C.id));if(A&&(D=="tog"||(D=="exp"&&!A.visible())||(D=="col"&&A.visible()))){if(C.descendantOf("specialfolders")){B.afterFinish=this._sizeFolderlist}C.firstDescendant().writeAttribute({className:A.visible()?"exp":"col"});if(A.visible()){Effect.BlindUp(A,B)}else{Effect.BlindDown(A,B)}}},createFolder:function(C){var B,F,I,G,H,E=this.getFolderId(C.m),A=decodeURIComponent(C.m),D=this.getSubFolderId(E),J=$(D);I=new Element("LI",{className:"folder",id:E,l:C.l,mbox:A,ftype:(C.v?(C.co?"vcontainer":"virtual"):(C.co?"container":(C.s?"special":"folder")))});B=new Element("DIV",{className:C.cl||"base",id:E+"_div"});if(C.i){B.update(C.i)}if(C.ch){B.writeAttribute({className:"exp"}).observe("mouseover",this.bcache.get("mo_folder")||this.bcache.set("mo_folder",function(K){K=K.element();if(DragDrop.Drags.drag&&K.hasClassName("exp")){this._toggleSubFolder(K.up(),"exp")}}.bindAsEventListener(this)))}I.insert(B).insert(new Element("A",{id:E+"_label",title:C.l}).insert(C.l));if(J){if(J.insert({before:I}).visible()){B.removeClassName("exp").addClassName("col")}}else{if(C.s){H=$("specialfolders")}else{H=$(this.getSubFolderId(this.getFolderId(C.pa)));H=(H)?H.down("UL"):$("normalfolders")}G=A.toLowerCase();F=H.childElements().find(function(K){var L=K.readAttribute("mbox");return L&&(!C.s||L!="INBOX")&&(G=3){B.msgs.push({type:"horde.success",message:DIMP.text.ajax_recover})}this.server_error=0;if(!B.msgs_noauto){this.showNotifications(B.msgs)}if(this.onDoActionComplete){this.onDoActionComplete(B)}this.inAjaxCallback=false},setTitle:function(A){document.title=DIMP.conf.name+" :: "+A},showNotifications:function(A){if(!A.size()||this.is_logout){return}A.find(function(D){switch(D.type){case"dimp.timeout":this.is_logout=true;this.redirect(DIMP.conf.timeout_url);return true;case"horde.error":case"horde.message":case"horde.success":case"horde.warning":case"imp.reply":case"imp.forward":case"imp.redirect":case"dimp.request":case"dimp.sticky":var H,I,K,E,J,F,G=$("alerts"),B=new Element("DIV",{className:D.type.replace(".","-")}),C=D.message;if(!G){G=new Element("DIV",{id:"alerts"});$(document.body).insert(G)}if($w("dimp.request dimp.sticky").indexOf(D.type)==-1){C=C.unescapeHTML().unescapeHTML()}G.insert(B.update(C));if(DIMP.conf.is_ie6){K=new Element("DIV",{className:"ie6alertsfix"}).clonePosition(B,{setLeft:false,setTop:false});H=K;K.insert(B.remove());G.insert(K)}else{H=B}I=Effect.Fade.bind(this,B,{duration:1.5,afterFinish:this.removeAlert.bind(this)});H.observe("click",I);if($w("horde.error dimp.request dimp.sticky").indexOf(D.type)==-1){I.delay(D.type=="horde.warning"?10:3)}if(D.type=="dimp.request"){J=function(){I();document.stopObserving("click",J)};document.observe("click",J)}if(F=$("alertslog")){switch(D.type){case"horde.error":E=DIMP.text.alog_error;break;case"horde.message":E=DIMP.text.alog_message;break;case"horde.success":E=DIMP.text.alog_success;break;case"horde.warning":E=DIMP.text.alog_warning;break}if(E){F=F.down("DIV UL");if(F.down().hasClassName("noalerts")){F.down().remove()}F.insert(new Element("LI").insert(new Element("P",{className:"label"}).insert(E)).insert(new Element("P",{className:"indent"}).insert(C).insert(new Element("SPAN",{className:"alertdate"}).insert("["+(new Date).toLocaleString()+"]"))))}}}},this)},toggleAlertsLog:function(){var A=$("alertsloglink").down("A"),C=$("alertslog").down("DIV"),B={duration:0.5};if(C.visible()){Effect.BlindUp(C,B);A.update(DIMP.text.showalog)}else{Effect.BlindDown(C,B);A.update(DIMP.text.hidealog)}},removeAlert:function(C){try{var A=$(C.element),B=A.up();if(B&&B.parentNode){this.addGC(A.remove());if(!B.childElements().size()&&B.hasClassName("ie6alertsfix")){this.addGC(B.remove())}}}catch(D){this.debug("removeAlert",D)}},compose:function(C,B){var A=DIMP.conf.compose_url;B=B||{};if(C){B.type=C}this.popupWindow(this.addURLParam(A,B),"compose"+new Date().getTime())},popupWindow:function(B,A){if(!(window.open(B,A.replace(/\W/g,"_"),"width="+DIMP.conf.popup_width+",height="+DIMP.conf.popup_height+",status=1,scrollbars=yes,resizable=yes"))){this.showNotifications([{type:"horde.warning",message:DIMP.text.popup_block}])}},closePopup:function(){if(this.inAjaxCallback){this.closePopup.bind(this).defer()}else{window.close()}},logout:function(){this.is_logout=true;this.redirect(DIMP.conf.URI_IMP+"/LogOut")},redirect:function(A){A=this.addSID(A);if(parent.frames.horde_main){parent.location=A}else{window.location=A}},addMouseEvents:function(A){this.DMenu.addElement(A.id,"ctx_"+A.type,A)},removeMouseEvents:function(A){this.DMenu.removeElement($(A).readAttribute("id"));this.addGC(A)},addPopdown:function(B,A){var C=$(B);C.insert({after:$($("popdown_img").cloneNode(false)).writeAttribute("id",B+"_img").show()});this.addMouseEvents({id:B+"_img",type:A,offset:C.up(),left:true})},buildAddressLinks:function(D,A){var E,C,B=D.size();if(B>15){C=$("largeaddrspan").cloneNode(true);A.insert(C);E=C.down(".dispaddrlist");C=C.down();this.clickObserveHandler({d:C,f:function(F){[F.down(),F.down(1),F.next()].invoke("toggle")}.curry(C)});C=C.down();C.setText(C.getText().replace("%d",B))}else{E=A}D.each(function(H,G){var F;if(H.raw){F=H.raw}else{F=new Element("A",{className:"address",id:"addr"+this.acount++,personal:H.personal,email:H.inner,address:H.address}).insert(H.display?H.display:H.address);F.observe("mouseover",function(){F.stopObserving("mouseover");this.addMouseEvents({id:F.id,type:"contacts",offset:F,left:true})}.bind(this))}E.insert(F);if(G+1!=B){E.insert(", ")}},this);return A},removeAddressLinks:function(A){[A.select(".address"),A.select(".largeaddrtoggle")].flatten().compact().each(this.removeMouseEvents.bind(this))},messageOnLoad:function(){var B=this.clickObserveHandler,A;if($("partlist")){B({d:$("partlist_col").up(),f:function(){$("partlist","partlist_col","partlist_exp").invoke("toggle")}})}if(A=$("msg_print")){B({d:A,f:function(){window.print()}})}if(A=$("msg_view_source")){B({d:A,f:function(){view(DimpCore.addSID(DIMP.conf.URI_VIEW)+"&index="+DIMP.conf.msg_index+"&mailbox="+DIMP.conf.msg_folder,DIMP.conf.msg_index+"|"+DIMP.conf.msg_folder)}})}B({d:$("ctx_contacts_new"),f:function(){this.compose("new",{to:this.DMenu.element().readAttribute("address")})}.bind(this),ns:true});B({d:$("ctx_contacts_add"),f:function(){this.doAction("AddContact",{name:this.DMenu.element().readAttribute("personal"),email:this.DMenu.element().readAttribute("email")},null,true)}.bind(this),ns:true});if($("alertslog")){B({d:$("alertsloglink"),f:this.toggleAlertsLog.bind(this)})}},addGC:function(A){this.remove_gc=this.remove_gc.concat(A)},clickObserveHandler:function(A){return A.d.observe("click",DimpCore._clickFunc.curry(A))},_clickFunc:function(B,A){B.p?B.f(A):B.f();if(!B.ns){A.stop()}},addSID:function(A){if(!DIMP.conf.SESSION_ID){return A}return this.addURLParam(A,DIMP.conf.SESSION_ID.toQueryParams())},addURLParam:function(A,C){var B=A.indexOf("?");if(B!=-1){C=$H(A.toQueryParams()).merge(C).toObject();A=A.substring(0,B)}return A+"?"+Object.toQueryString(C)}};if(typeof ContextSensitive!="undefined"){DimpCore.DMenu=new ContextSensitive()}document.observe("dom:loaded",function(){try{if(parent.opener&&parent.opener.location.host==window.location.host&&parent.opener.DimpCore){DIMP.baseWindow=parent.opener.DIMP.baseWindow||parent.opener}}catch(A){}if(!DIMP.conf.spam_reporting){DimpCore.buttons=DimpCore.buttons.without("button_spam")}if(!DIMP.conf.ham_reporting){DimpCore.buttons=DimpCore.buttons.without("button_ham")}new PeriodicalExecuter(function(){if(DimpCore.remove_gc.size()){try{$A(DimpCore.remove_gc.splice(0,75)).compact().invoke("stopObserving")}catch(B){DimpCore.debug("remove_gc[].stopObserving",B)}}},10)});Event.observe(window,"load",function(){DimpCore.window_load=true});Element.addMethods({setText:function(B,C){var A=0;$A(B.childNodes).each(function(D){if(D.nodeType==3){if(A++){Element.remove(D)}else{D.nodeValue=C}}});if(!A){$(B).insert(C)}},getText:function(B,A){var C="";$A(B.childNodes).each(function(D){if(D.nodeType==3){C+=D.nodeValue}else{if(A&&D.hasChildNodes()){C+=$(D).getText(true)}}});return C}});Object.extend(Array.prototype,{numericSort:function(){return this.sort(function(B,A){if(B>A){return 1}else{if(B(B+this.getPageSize("current")))?1:0)},reload:function(A){if(this.isFiltering()){this.filter.filter(null,A)}else{this._fetchBuffer({offset:this.currentOffset(),purge:true,params:A})}},remove:function(F,C){if(this.isbusy){this.remove.bind(this,F,cacheid,view).defer();return}if(!F.size()){return}C=C||{};this.isbusy=true;var A,B=0,E=F.get("div"),D=E.size();this.deselect(F);if(C.cacheid){this.setMetaData({cacheid:C.cacheid},C.view)}if(D){A={duration:0.3,to:0.01};E.each(function(G){if(++B==D){A.afterFinish=this._removeids.bind(this,F,C)}Effect.Fade(G,A)},this)}else{this._removeids(F,C)}},_removeids:function(B,A){this.setMetaData({total_rows:this.getMetaData("total_rows",A.view)-B.size()},A.view);if(this.opts.onRemoveRows){this.opts.onRemoveRows(B)}this._getBuffer().remove(B.get("rownum"));if(!A.noupdate){this.requestContentRefresh(this.currentOffset())}this.isbusy=false},addFilter:function(A,B){this.filter=new ViewPort_Filter(this,A,B)},runFilter:function(B,A){if(this.filter){this.filter.filter(Object.isUndefined(B)?null:B,A)}},isFiltering:function(){return this.filter?this.filter.isFiltering():false},stopFilter:function(A){if(this.filter){this.filter.clear(A)}},onResize:function(B,A){if(!this.uc_run||!this.opts.content.visible()){return}if(this.resizefunc){clearTimeout(this.resizefunc)}if(A){this._onResize(B)}else{this.resizefunc=this._onResize.bind(this,B).delay(0.1)}},_onResize:function(A){if(this.opts.onBeforeResize){this.opts.onBeforeResize()}this._renderViewport(A);if(this.opts.onAfterResize){this.opts.onAfterResize()}},requestContentRefresh:function(B){if(this._updateContent(B)){var A=this._getBuffer().isNearingLimit(B);if(A){this._fetchBuffer({offset:B,background:true,nearing:A})}return true}return false},_fetchBuffer:function(A){if(this.isbusy){this._fetchBuffer.bind(this,A).defer();return}this.isbusy=true;if(this.opts.onFetch&&!A.background){this.opts.onFetch()}var L=(A.view||this.view),G=this.opts.fetch_action,E,M=this._getBuffer(L),I,C,F=$H(A.params),D,P,Q,O,K,B,J,N,H;if(A.purge){F.set("purge",true)}if(A.search){J="search";N=A.search;C=this._lookbehind(L);F.update({search_before:C,search_after:M.bufferSize()-C})}else{J="rownum";N=A.offset+1;E=M.getAllRows();B=this._getSliceBounds(N,A.nearing,L);K=$A($R(B.start,B.end)).diff(E);if(!A.purge&&!K.size()){this.isbusy=false;return}F.update({slice_start:B.start,slice_end:B.end})}F.set(J,Object.toJSON(N));O=[L,J,N];if(this.isFiltering()){G=this.filter.getAction();F=this.filter.addFilterParams(F);O.push(F)}P=O.toJSON();D=this.fetch_hash.get(P);I=this.current_req.get(L);if(I){if(D&&I.get(D)){if(++I.get(D).count==4){this._displayFetchError();this._removeRequest(L,D);this.isbusy=false;return}}else{if(J=="rownum"){H=$A($R(N,N+this.getPageSize())).diff(E);if(!H.size()){this.isbusy=false;return}Q=I.keys().numericSort().find(function(R){var S=I.get(R).rlist;H=H.diff(S);if(!H.size()){return true}K=K.diff(S)});if(Q){if(!A.background){this._addRequest(L,Q,{background:false,offset:N-1})}this.isbusy=false;return}else{if(!A.background){I.keys().each(function(R){this._addRequest(L,R,{background:true})},this)}}}}}if(!this.opts.norows&&K){F.set("rows",K.toJSON())}if(!D){D=this.fetch_hash.set(P,this.request_num++)}F.set("request_id",D);this._addRequest(L,D,{background:A.background,offset:N-1,rlist:K});this.opts.ajaxRequest(G,this.addRequestParams(F,{noslice:true,view:L}));this._handleWait();this.isbusy=false},_getSliceBounds:function(C,D,A){var E=this._getBuffer(A).bufferSize(),B={};switch(D){case"bottom":B.start=C+this.getPageSize();B.end=B.start+E;break;case"top":B.start=Math.max(C-E,1);B.end=C;break;default:B.start=Math.max(C-this._lookbehind(A),1);B.end=B.start+E;break}return B},_lookbehind:function(A){return parseInt(0.4*this._getBuffer(A).bufferSize(),10)},addRequestParams:function(A,B){B=B||{};var E=this.getMetaData("cacheid",B.view),C=this.getMetaData("additional_params",B.view),D;if(E){C.update({cacheid:E})}if(!B.noslice){D=this._getSliceBounds(this.currentOffset(),null,B.view);C.update({slice_start:D.start,slice_end:D.end})}return C.merge(A)},ajaxResponse:function(E){if(this.isbusy){this.ajaxResponse.bind(this,E).defer();return}this.isbusy=true;this._clearWait();var A,D,B,F,C,H,G={};if(E.type=="slice"){F=E.data;C=Object.keys(F);C.each(function(I){F[I].view=E.id;G[I]=F[I].rownum});A=this._getBuffer(E.id);A.update(F,G,{slice:true});if(this.opts.onEndFetch){this.opts.onEndFetch()}D=this.slice_hash.get(E.request_id);if(D){D(new ViewPort_Selection(A,"uid",C));this.slice_hash.unset(E.request_id)}this.isbusy=false;return}H=(E.request_id)?this.current_req_lookup.get(E.request_id):E.id;D=this.current_req.get(H);if(D&&E.request_id){B=D.get(E.request_id)}if(this.viewport_init){this.viewport_init=2}A=this._getBuffer(H);A.update(E.data,E.rowlist,{update:E.update});A.setMetaData($H(E.other).merge({cacheid:E.cacheid,label:E.label,total_rows:E.totalrows}));if(E.request_id){this._removeRequest(H,E.request_id)}this.isbusy=false;if(!(this.view==H||E.search)||(B&&B.background)||!this._updateContent((B&&B.offset)?B.offset:(E.rownum?parseInt(E.rownum)-1:this.currentOffset()))){return}if(this.opts.onComplete){this.opts.onComplete()}if(this.opts.onEndFetch){this.opts.onEndFetch()}},_addRequest:function(A,B,E){var D=this.current_req.get(A),C;if(!D){D=this.current_req.set(A,$H())}C=D.get(B);if(!C){C=D.set(B,{count:1})}["background","offset","rlist"].each(function(F){if(!Object.isUndefined(E[F])){C[F]=E[F]}});this.current_req_lookup.set(B,A)},_removeRequest:function(A,B){var C=this.current_req.get(A);if(C){C.unset(B);if(!C.size()){this.current_req.unset(A)}}this.current_req_lookup.unset(B)},_updateContent:function(F,C){C=C||{};if(!this._getBuffer(C.view).sliceLoaded(F)){this._fetchBuffer($H(C).merge({offset:F}).toObject());return false}if(!this.uc_run){this.uc_run=true;if(this.opts.onFirstContent){this.opts.onFirstContent()}}var G=this.opts.content,A=[],B=this.getPageSize(),E,D=this.getSelected();if(this.opts.onClearRows){this.opts.onClearRows(G.childElements())}this.scroller.updateSize();this.scrollTo(F+1,true);F=this.currentOffset();E=this.createSelection("rownum",$A($R(F+1,F+B)));if(E.size()){E.get("dataob").each(function(I){var H=Object.clone(I);if(H.bg){H.bg=I.bg.clone();if(D.contains("uid",H.vp_id)){H.bg.push(this.opts.selected_class)}H.bg_string=H.bg.join(" ")}A.push(this.template.evaluate(H))},this);G.update(A.join(""))}else{G.update((this.opts.empty&&this.viewport_init!=1)?this.opts.empty.innerHTML:"")}if(this.opts.onContent){this.opts.onContent(E)}return true},_displayFetchError:function(){if(this.opts.onFail){this.opts.onFail()}if(this.opts.error){this.opts.content.update(this.opts.error.innerHTML)}},_getSlice:function(B,E){var D={rangeslice:1,start:B.min(),length:B.size()},A,C;C=this.createSelection("rownum",B);if(B.size()==C.size()){return C}if(this.opts.onFetch){this.opts.onFetch()}if(E){A=this.request_num++;D.request_id=A;this.slice_hash.set(A,E)}this.opts.ajaxRequest(this.opts.fetch_action,this.addRequestParams(D,{noslice:true}));return false},_handleWait:function(A){this._clearWait();if(A&&this.opts.onWait){this.opts.onWait()}if(this.opts.viewport_wait){this.waitHandler=this._handleWait.bind(this,true).delay(this.opts.viewport_wait)}},_clearWait:function(){if(this.waitHandler){clearTimeout(this.waitHandler);this.waitHandler=null}},visibleRows:function(){return this.opts.content.childElements()},getMetaData:function(B,A){return this._getBuffer(A).getMetaData(B)},setMetaData:function(B,A){this._getBuffer(A).setMetaData(B)},_getBuffer:function(B,C){if(!C){var A=this.views.get(B||this.view);if(A){return A.buffer}}return new ViewPort_Buffer(this,this.opts.buffer_pages,this.opts.limit_factor)},currentOffset:function(){return this.scroller.currentOffset()},updateFlag:function(C,A,B){this._updateFlag(C,A,B,this.isFiltering());this._updateClass(C,A,B)},_updateFlag:function(D,A,C,B){D.get("dataob").each(function(E){if(C){E.bg.push(A)}else{E.bg.splice(E.bg.indexOf(A),1)}if(B){this._updateFlag(this.createSelection("uid",E.vp_id,E.view),A,C)}},this)},_updateClass:function(C,A,B){C.get("div").each(function(D){if(B){D.addClassName(A)}else{D.removeClassName(A)}})},_getLineHeight:function(){if(this.line_height){return this.line_height}var A=new Element("DIV",{className:this.opts.content_class}).insert(new Element("DIV",{className:this.opts.row_class})).hide();$(document.body).insert(A);this.line_height=A.getHeight();A.remove();return this.line_height},getPageSize:function(A){switch(A){case"current":return Math.min(this.page_size,this.getMetaData("total_rows"));case"default":return Math.max(parseInt(this.getPageSize("max")*0.45),5);case"max":return parseInt(this._getMaxHeight()/this._getLineHeight());default:return this.page_size}},_getMaxHeight:function(){return document.viewport.getHeight()-this.opts.content.viewportOffset()[1]},showSplitPane:function(A){this.show_split_pane=A;this.onResize(false,true)},_renderViewport:function(D){if(!this.viewport_init){return}if(!this.opts.content.offsetHeight){return this._renderViewport.bind(this,D).defer()}var E,B,H,C,G=$(this.opts.content),F=document.documentElement,A=this._getLineHeight();if(this.opts.split_pane){H=$(this.opts.split_pane);if(this.show_split_pane){if(!H.visible()){this._initSplitBar();this.page_size=(this.splitbar_loc)?this.splitbar_loc:this.getPageSize("default")}C=true}else{if(H.visible()){this.splitbar_loc=this.page_size;$(H,this.splitbar).invoke("hide")}}}if(!C){this.page_size=this.getPageSize("max")}B=A*this.page_size;G.setStyle({height:B+"px"});if(C){H.setStyle({height:(this._getMaxHeight()-B-A)+"px"}).show();this.splitbar.show()}else{if(E=F.scrollHeight-F.clientHeight){G.setStyle({height:(A*(this.page_size-1))+"px"})}}if(!D){this.scroller.onResize()}},_initSplitBar:function(){if(this.splitbar){return}this.splitbar=$(this.opts.splitbar);new Drag(this.splitbar,{constraint:"vertical",ghosting:true,onStart:function(){var A=this._getLineHeight();this.sp={lh:A,pos:$(this.opts.content).positionedOffset()[1],max:parseInt((this._getMaxHeight()-100)/A),lines:this.page_size}}.bind(this),snap:function(A,D,C){var B=parseInt((D-this.sp.pos)/this.sp.lh);if(B<1){B=1}else{if(B>this.sp.max){B=this.sp.max}}this.sp.lines=B;return[A,this.sp.pos+(B*this.sp.lh)]}.bind(this),onEnd:function(){this.page_size=this.sp.lines;this._renderViewport()}.bind(this)});this.splitbar.observe("dblclick",function(){this.page_size=this.getPageSize("default");this._renderViewport()}.bind(this))},createSelection:function(D,C,B){var A=this._getBuffer(B);return A?new ViewPort_Selection(A,D,C):new ViewPort_Selection(this._getBuffer(this.view))},getViewportSelection:function(B){var A=this._getBuffer(B);return this.createSelection("uid",A?A.getAllUIDs():[],B)},select:function(D,B){B=B||{};if(B.range){D=this._getSlice(D,this.select.bind(this));if(D===false){return}}var A=this._getBuffer(),C;if(!B.add){C=this.getSelected();A.deselect(C,true);this._updateClass(C,this.opts.selected_class,false)}A.select(D);this._updateClass(D,this.opts.selected_class,true);if(this.opts.selectCallback){this.opts.selectCallback(D,B)}},deselect:function(B,A){A=A||{};if(!B.size()){return}if(this._getBuffer().deselect(B,A&&A.clearall)){this._updateClass(B,this.opts.selected_class,false);if(this.opts.deselectCallback){this.opts.deselectCallback(B,A)}}},getSelected:function(){return Object.clone(this._getBuffer().getSelected())}}),ViewPort_Scroller=Class.create({initialize:function(A){this.vp=A},_createScrollBar:function(){if(this.scrollDiv){return false}var A=this.vp.opts.content;this.scrollDiv=new Element("DIV",{className:"sbdiv",style:"height:"+A.getHeight()+"px;"}).hide();A.insert({after:this.scrollDiv}).setStyle({marginRight:"-"+this.scrollDiv.getWidth()+"px"});this.scrollbar=new DimpSlider(this.scrollDiv,{buttonclass:{up:"sbup",down:"sbdown"},cursorclass:"sbcursor",onChange:this._onScroll.bind(this),onSlide:this.vp.opts.onSlide?this.vp.opts.onSlide:null,pagesize:this.vp.getPageSize(),totalsize:this.vp.getMetaData("total_rows")});A.observe(Prototype.Browser.Gecko?"DOMMouseScroll":"mousewheel",function(C){if(Prototype.Browser.Gecko&&C.eventPhase==2){return}var B=this.vp.getPageSize();B=(B>3)?3:B;this.moveScroll(this.currentOffset()+((C.wheelDelta>=0||C.detail<0)?(-1*B):B))}.bindAsEventListener(this));return true},onResize:function(){if(!this.scrollDiv){return}this.scrollsize=this.vp.opts.content.getHeight();this.scrollDiv.setStyle({height:this.scrollsize+"px"});this.updateSize();this.vp.requestContentRefresh(this.currentOffset())},updateSize:function(){if(!this._createScrollBar()){this.scrollbar.updateHandleLength(this.vp.getPageSize(),this.vp.getMetaData("total_rows"))}},clear:function(){if(this.scrollDiv){this.scrollbar.updateHandleLength(0,0)}},moveScroll:function(A){this._createScrollBar();this.scrollbar.setScrollPosition(A)},_onScroll:function(){if(!this.noupdate){if(this.vp.opts.onScroll){this.vp.opts.onScroll()}this.vp.requestContentRefresh(this.currentOffset());if(this.vp.opts.onScrollIdle){this.vp.opts.onScrollIdle()}}},currentOffset:function(){return this.scrollbar?this.scrollbar.getValue():0}}),ViewPort_Buffer=Class.create({initialize:function(B,C,A){this.bufferPages=C;this.limitFactor=A;this.vp=B;this.clear()},_limitTolerance:function(){return Math.round(this.bufferSize()*(this.limitFactor/100))},bufferSize:function(){return Math.round(Math.max(this.vp.getPageSize("max")+1,this.bufferPages*this.vp.getPageSize()))},update:function(C,A,B){C=$H(C);A=$H(A);B=B||{};if(B.slice){C.each(function(D){if(!this.data.get(D.key)){this.data.set(D.key,D.value);this.inc.set(D.key,true)}},this)}else{if(this.data.size()){this.data.update(C);if(this.inc.size()){C.keys().each(function(D){this.inc.unset(D)},this)}}else{this.data=C}}this.uidlist=(B.update)?A:(this.uidlist.size()?this.uidlist.merge(A):A);if(B.update){this.rowlist=$H()}A.each(function(D){this.rowlist.set(D.value,D.key)},this)},sliceLoaded:function(A){return!this._rangeCheck($A($R(A+1,Math.min(A+this.vp.getPageSize()-1,this.getMetaData("total_rows")))))},isNearingLimit:function(A){if(this.uidlist.size()!=this.getMetaData("total_rows")){if(A!=0&&this._rangeCheck($A($R(Math.max(A+1-this._limitTolerance(),1),A)))){return"top"}else{if(this._rangeCheck($A($R(A+1,Math.min(A+this._limitTolerance()+this.vp.getPageSize()-1,this.getMetaData("total_rows")))).reverse())){return"bottom"}}}return false},_rangeCheck:function(A){var B=this.inc.size();return A.any(function(D){var C=this.rowlist.get(D);return(Object.isUndefined(C)||(B&&this.inc.get(C)))},this)},getData:function(A){return A.collect(function(B){var C=this.data.get(B);if(!Object.isUndefined(C)){C.domid="vp_row"+B;C.rownum=this.uidlist.get(B);C.vp_id=B;return C}},this).compact()},getAllUIDs:function(){return this.uidlist.keys()},getAllRows:function(){return this.rowlist.keys()},rowsToUIDs:function(A){return A.collect(function(B){return this.rowlist.get(B)},this).compact()},select:function(A){this.selected.add("uid",A.get("uid"))},deselect:function(C,B){var A=this.selected.size();if(B){this.selected.clear()}else{this.selected.remove("uid",C.get("uid"))}return A!=this.selected.size()},getSelected:function(){return this.selected},remove:function(B){var C,D=this.rowlist.size(),A=0;C=D-B.size();return $A($R(B.min(),D)).each(function(G){var F=this.rowlist.get(G),E;if(B.include(G)){this.data.unset(F);this.uidlist.unset(F);A++}else{E=G-A;this.rowlist.set(E,F);this.uidlist.set(F,E)}if(G>C){this.rowlist.unset(G)}},this)},clear:function(){this.data=$H();this.inc=$H();this.mdata=$H({total_rows:0});this.rowlist=$H();this.selected=new ViewPort_Selection(this);this.uidlist=$H()},getMetaData:function(A){return this.mdata.get(A)},setMetaData:function(A){this.mdata.update(A)}}),ViewPort_Filter=Class.create({initialize:function(A,B,C){this.vp=A;this.action=B;this.callback=C;this.filterid=0;this.filtering=this.last_filter=this.last_folder=this.last_folder_params=null},filter:function(C,B){B=B||{};if(C===null){C=this.last_filter}else{C=C.toLowerCase();if(C==this.last_filter){return}}if(!C){this.clear();return}this.last_filter=C;if(this.filtering){this.vp._fetchBuffer({offset:0,params:B});return}this.filtering=++this.filterid+"%search%";this.last_folder=this.vp.view;this.last_folder_params=this.vp.getMetaData("additional_params").merge(B);var D=this.vp.opts.content,A;A=D.childElements().findAll(function(E){return E.collectTextNodes().toLowerCase().indexOf(C)==-1});if(this.vp.opts.onClearRows){this.vp.opts.onClearRows(A)}A.invoke("remove");this.vp.scroller.clear();if(this.vp.opts.empty&&!D.childElements().size()){D.update(this.vp.opts.empty.innerHTML)}this.vp.loadView(this.filtering,this.last_folder_params)},isFiltering:function(){return this.filtering},getAction:function(){return this.action},addFilterParams:function(A){if(!this.filtering){return A}A.update({filter:this.last_filter});if(this.callback){A.update(this.callback())}return A},clear:function(A){if(this.filtering){this.filtering=null;if(!A){this.vp.loadView(this.last_folder,this.last_folder_params)}this.vp.deleteView(this.filtering);this.last_filter=this.last_folder=null}}}),ViewPort_Selection=Class.create({initialize:function(A,C,B){this.buffer=A;this.clear();if(!Object.isUndefined(C)){this.add(C,B)}this.viewport_selection=true},add:function(A,B){var C=this._convert(A,B);this.data=(this.data.size())?this.data.concat(C).uniq():C},remove:function(A,B){this.data=this.data.diff(this._convert(A,B))},_convert:function(A,B){B=Object.isArray(B)?B:[B];switch(A){case"dataob":return B.pluck("vp_id");case"div":return B.pluck("id").invoke("substring",6);case"domid":return B.invoke("substring",6);case"rownum":return this.buffer.rowsToUIDs(B);case"uid":return B}},clear:function(){this.data=[]},get:function(A){A=Object.isUndefined(A)?"uid":A;if(A=="uid"){return this.data}var B=this.buffer.getData(this.data);switch(A){case"dataob":return B;case"div":return B.pluck("domid").collect(function(C){return $(C)}).compact();case"domid":return B.pluck("domid");case"rownum":return B.pluck("rownum")}},contains:function(A,B){return this.data.include(this._convert(A,B).first())},search:function(A){return new ViewPort_Selection(this.buffer,"uid",this.get("dataob").findAll(function(B){return $H(A).all(function(C){return $H(C.value).all(function(D){switch(D.key){case"equal":case"not":var E=B[C.key]&&D.value.include(B[C.key]);return(D.key=="equal")?E:!E;case"regex":return B[C.key].match(D.value)}})})}).pluck("vp_id"))},size:function(){return this.data.size()},set:function(A){this.get("dataob").each(function(B){$H(A).each(function(C){B[C.key]=C.value})})}});Object.extend(Array.prototype,{diff:function(A){return this.select(function(B){return!A.include(B)})},numericSort:function(){return this.sort(function(B,A){return(B>A)?1:((B

";G="

"+D.sig.replace(/^ ?
\n/,"").replace(/ +/g," ")+"

";B=B.replace(/

\s*[\s\S]*?\s*<\/p>/,E)}else{B=$F(H).replace(/\r\n/g,"\n");E=I.sig;G=D.sig}F=(I.id[2])?B.indexOf(E):B.lastIndexOf(E);if(F!=-1){if(D.id[2]==I.id[2]){B=B.substring(0,F)+G+B.substring(F+E.length,B.length)}else{if(D.id[2]){B=G+B.substring(0,F)+B.substring(F+E.length,B.length)}else{B=B.substring(0,F)+B.substring(F+E.length,B.length)+G}}B=B.replace(/\r\n/g,"\n").replace(/\n/g,"\r\n");if(this.editor_on){FCKeditorAPI.GetInstance("message").SetHTML(B)}else{H.setValue(B)}$("last_identity").setValue(A)}},get_identity:function(B,A){A=Object.isUndefined(A)?this.editor_on:A;return{id:DIMP.conf_compose.identities[B],sig:DIMP.conf_compose.identities[B][(A?1:0)].replace(/^\n/,"")}},uniqueSubmit:function(B){var A,C,E,D=$("compose");if(DIMP.SpellCheckerObject){DIMP.SpellCheckerObject.resume();if(!this.textarea_ready){this.uniqueSubmit.bind(this,B).defer();return}}D.setStyle({cursor:"wait"});if(B=="send_message"||B=="save_draft"){this.button_pressed=true;switch(B){case"send_message":if(!this.sbtext){E=$("send_button");this.sbtext=E.getText();E.setText(DIMP.text_compose.sending)}break;case"save_draft":if(!this.dbtext){A=$("draft_button");this.dbtext=A.getText();A.setText(DIMP.text_compose.saving)}break}if(this.uploading){(function(){if(this.button_pressed){this.uniqueSubmit(B)}}).bind(this).delay(0.25);return}}$("action").setValue(B);if(B=="add_attachment"){this.uploading=true;D.submit()}else{if(this.editor_on){FCKeditorAPI.GetInstance("message").UpdateLinkedField()}C=D.serialize(true);if(!DIMP.baseWindow){C.nonotify=true}DimpCore.doAction("*"+DIMP.conf.compose_url,C,null,this.uniqueSubmitCallback.bind(this))}},uniqueSubmitCallback:function(B){var A,C=B.response;if(!C){return}if(C.imp_compose){$("composeCache").setValue(C.imp_compose)}if(C.success||C.action=="add_attachment"){switch(C.action){case"auto_save_draft":this.button_pressed=false;$("draft_index").setValue(C.draft_index);break;case"save_draft":this.button_pressed=false;if(DIMP.baseWindow){DIMP.baseWindow.DimpBase.pollFolders();DIMP.baseWindow.DimpCore.showNotifications(B.msgs)}if(DIMP.conf_compose.close_draft){return this._closeCompose()}break;case"send_message":this.button_pressed=false;if(DIMP.baseWindow){if(C.reply_type=="reply"){DIMP.baseWindow.DimpBase.flag("answered",C.index,C.reply_folder)}if(C.folder){DIMP.baseWindow.DimpBase.createFolder(C.folder)}if(C.draft_delete){DIMP.baseWindow.DimpBase.pollFolders()}DIMP.baseWindow.DimpCore.showNotifications(B.msgs)}return this._closeCompose();case"add_attachment":this.uploading=false;if(C.success){this.addAttach(C.info.number,C.info.name,C.info.type,C.info.size)}else{this.button_pressed=false}if(DIMP.conf_compose.attach_limit!=-1&&$("attach_list").childElements().size()>DIMP.conf_compose.attach_limit){$("upload").writeAttribute("disabled",false);A=new Element("DIV",[DIMP.text_compose.attachment_limit])}else{A=new Element("INPUT",{type:"file",name:"file_1"});A.observe("change",this.uploadAttachment.bind(this))}$("upload_wait").replace(A.writeAttribute("id","upload"));this.resizeMsgArea();break}}else{this.button_pressed=false}$("compose").setStyle({cursor:null});if(!this.button_pressed){if(this.sbtext){$("send_button").setText(this.sbtext)}if(this.dbtext){$("draft_button").setText(this.dbtext)}this.dbtext=this.sbtext=null}DimpCore.showNotifications(B.msgs)},toggleHtmlEditor:function(A){if(!DIMP.conf_compose.rte_avail){return}A=A||false;if(DIMP.SpellCheckerObject){DIMP.SpellCheckerObject.resume()}var C;if(this.editor_on){this.editor_on=false;C=FCKeditorAPI.GetInstance("message").GetHTML();$("messageParent").childElements().invoke("hide");$("message").show();DimpCore.doAction("Html2Text",{text:C},null,this.setMessageText.bind(this),{asynchronous:false})}else{this.editor_on=true;if(!A){DimpCore.doAction("Text2Html",{text:$F("message")},null,this.setMessageText.bind(this),{asynchronous:false})}oFCKeditor.Height=this.getMsgAreaHeight();try{FCKeditorAPI.GetInstance("message").SetHTML($F("message"));$("messageParent").childElements().invoke("show");$("message").hide()}catch(B){this._RTELoading("show");FCKeditor_OnComplete=this._RTELoading.curry("hide");oFCKeditor.ReplaceTextarea()}}$("htmlcheckbox").checked=this.editor_on;$("html").setValue(this.editor_on?1:0)},_RTELoading:function(B){var C,A;if(!$("rteloading")){A=new Element("DIV",{id:"rteloading"}).clonePosition($("messageParent"));$(document.body).insert(A);C=A.viewportOffset();$(document.body).insert(new Element("SPAN",{id:"rteloadingtxt"}).setStyle({top:(C.top+15)+"px",left:(C.left+15)+"px"}).insert(DIMP.text.loading))}$("rteloading","rteloadingtxt").invoke(B)},toggleHtmlCheckbox:function(){if(!this.editor_on||window.confirm(DIMP.text_compose.toggle_html)){this.toggleHtmlEditor()}},getMsgAreaHeight:function(){return document.viewport.getHeight()-$("messageParent").cumulativeOffset()[1]-this.mp_padding},initializeSpellChecker:function(){if(!DIMP.conf_compose.rte_avail){return}if(typeof DIMP.SpellCheckerObject!="object"){this.initializeSpellChecker.bind(this).defer();return}DIMP.SpellCheckerObject.onBeforeSpellCheck=function(){if(!this.editor_on){return}DIMP.SpellCheckerObject.htmlAreaParent="messageParent";DIMP.SpellCheckerObject.htmlArea=$("message").adjacent("iframe[id*=message]").first();$("message").setValue(FCKeditorAPI.GetInstance("message").GetHTML());this.textarea_ready=false}.bind(this);DIMP.SpellCheckerObject.onAfterSpellCheck=function(){if(!this.editor_on){return}DIMP.SpellCheckerObject.htmlArea=DIMP.SpellCheckerObject.htmlAreaParent=null;var A=FCKeditorAPI.GetInstance("message");A.SetHTML($F("message"));A.Events.AttachEvent("OnAfterSetHTML",function(){this.textarea_ready=true}.bind(this))}.bind(this)},setMessageText:function(B){var A=$("message");if(!A){$("messageParent").insert(new Element("TEXTAREA",{id:"message",name:"message",style:"width:100%;"}).insert(B.response.text))}else{A.setValue(B.response.text)}if(!this.editor_on){this.resizeMsgArea()}},fillForm:function(G,H,B,E){if(!this.resizeto){this.fillForm.bind(this,G,H,B,E).defer();return}var A,D,C=this.get_identity($F("last_identity")),F=$("message");if(!this.last_msg.empty()&&this.last_msg!=$F(F).replace(/\r/g,"")&&!window.confirm(DIMP.text_compose.fillform)){return}if(DIMP.conf_compose.auto_save_interval_val&&!this.auto_save_interval){this.auto_save_interval=new PeriodicalExecuter(function(){var I;if(this.editor_on){I=FCKeditorAPI.GetInstance("message").GetHTML()}else{I=$F(F)}I=I.replace(/\r/g,"");if(!I.empty()&&this.last_msg!=I){this.uniqueSubmit("auto_save_draft");this.last_msg=I}}.bind(this),DIMP.conf_compose.auto_save_interval_val*60)}if(this.editor_on){D=FCKeditorAPI.GetInstance("message");D.SetHTML(G);this.last_msg=D.GetHTML().replace(/\r/g,"")}else{F.setValue(G);this.setCursorPosition(F);this.last_msg=$F(F).replace(/\r/g,"")}$("to").setValue(H.to);this.resizeto.resizeNeeded();if(H.cc){$("cc").setValue(H.cc);this.resizecc.resizeNeeded()}if(DIMP.conf_compose.cc){this.toggleCC("cc")}if(H.bcc){$("bcc").setValue(H.bcc);this.resizebcc.resizeNeeded()}if(C.id[6]){A=$F("bcc");if(A){A+=", "}$("bcc").setValue(A+C.id[6])}if(DIMP.conf_compose.bcc){this.toggleCC("bcc")}$("subject").setValue(H.subject);$("in_reply_to").setValue(H.in_reply_to);$("references").setValue(H.references);$("reply_type").setValue(H.replytype);Field.focus(B||"to");this.resizeMsgArea();if(DIMP.conf_compose.show_editor){if(!this.editor_on){this.toggleHtmlEditor(E||false)}if(B=="message"){this.focusEditor()}}},focusEditor:function(){try{FCKeditorAPI.GetInstance("message").Focus()}catch(A){this.focusEditor.bind(this).defer()}},addAttach:function(E,B,D,C){var F=new Element("DIV").insert(B+" ["+D+"] ("+C+" KB) "),A=new Element("INPUT",{type:"button",atc_id:E,value:DIMP.text_compose.remove});F.insert(A);$("attach_list").insert(F);A.observe("click",this.removeAttach.bind(this,[A.up()]));this.resizeMsgArea()},removeAttach:function(B){var A=[];B.each(function(C){C=$(C);A.push(C.firstDescendant().readAttribute("atc_id"));C.remove()});DimpCore.doAction("DeleteAttach",{atc_indices:A,imp_compose:$F("composeCache")});this.resizeMsgArea()},resizeMsgArea:function(){var A,B,D=document.documentElement,C=$("message");if(!DimpCore.window_load){this.resizeMsgArea.bind(this).defer();return}if(this.editor_on){A=$("messageParent").select("iframe").last();if(A){A.setStyle({height:this.getMsgAreaHeight()+"px"})}else{this.resizeMsgArea.bind(this).defer()}return}this.mp_padding=$("messageParent").getHeight()-C.getHeight();if(!this.row_height){A=$(C.cloneNode(false)).writeAttribute({id:null,name:null}).setStyle({visibility:"hidden"});$(document.body).insert(A);A.writeAttribute("rows",1);this.row_height=A.getHeight();A.writeAttribute("rows",2);this.row_height=A.getHeight()-this.row_height;A.remove()}B=parseInt(this.getMsgAreaHeight()/this.row_height);C.writeAttribute({rows:B,disabled:false});if(D.scrollHeight-D.clientHeight){C.writeAttribute({rows:B-1})}$("composeloading").hide()},uploadAttachment:function(){var A=$("upload");$("submit_frame").observe("load",this.attachmentComplete.bind(this));this.uniqueSubmit("add_attachment");A.stopObserving("change").replace(new Element("DIV",{id:"upload_wait"}).insert(DIMP.text_compose.uploading+" "+$F(A)))},attachmentComplete:function(){var A=$("submit_frame"),B=A.contentDocument||A.contentWindow.document;A.stopObserving("load");DimpCore.doActionComplete({responseText:B.body.innerHTML},this.uniqueSubmitCallback.bind(this))},toggleCC:function(A){$("send"+A).show();$("toggle"+A).up().hide()},setCursorPosition:function(B){var C,A;switch(DIMP.conf_compose.compose_cursor){case"top":C=0;$("message").setValue("\n"+$F("message"));break;case"bottom":C=$F("message").length;break;case"sig":C=$F("message").replace(/\r\n/g,"\n").lastIndexOf(this.get_identity($F("last_identity")).sig)-1;break;default:return}if(B.setSelectionRange){Field.focus(B);B.setSelectionRange(C,C)}else{if(B.createTextRange){A=B.createTextRange();A.collapse(true);A.moveStart("character",C);A.moveEnd("character",0);Field.select(A);A.scrollIntoView(true)}}},openAddressbook:function(){window.open(DIMP.conf_compose.abook_url,"contacts","toolbar=no,location=no,status=no,scrollbars=yes,resizable=yes,width=550,height=300,left=100,top=100")}},ResizeTextArea=Class.create({maxRows:5,initialize:function(C,B){this.field=$(C);this.defaultRows=Math.max(this.field.readAttribute("rows"),1);this.onResize=B;var A=this.resizeNeeded.bindAsEventListener(this);this.field.observe("mousedown",A).observe("keyup",A);this.resizeNeeded()},resizeNeeded:function(){var A=$F(this.field).split("\n"),C=this.field.readAttribute("cols"),B=A.size(),D=this.field.readAttribute("rows");A.each(function(E){if(E.length>=C){B+=Math.floor(E.length/C)}});if(B!=D){this.field.writeAttribute("rows",(B>D)?Math.min(B,this.maxRows):Math.max(this.defaultRows,B));if(this.onResize){this.onResize()}}}});document.observe("dom:loaded",function(){var B,A=DimpCompose,D=A.resizeMsgArea.bind(A),E=DimpCore.clickObserveHandler;A.resizeMsgArea();A.initializeSpellChecker();$("upload").observe("change",A.uploadAttachment.bind(A));A.resizeto=new ResizeTextArea("to",D);A.resizecc=new ResizeTextArea("cc",D);A.resizebcc=new ResizeTextArea("bcc",D);if(Prototype.Browser.WebKit){$("submit_frame").writeAttribute({position:"absolute",width:"1px",height:"1px"}).setStyle({left:"-999px"}).show()}if(B=$("compose_close")){E({d:B,f:A.confirmCancel.bind(A)})}E({d:$("send_button"),f:A.uniqueSubmit.bind(A,"send_message")});E({d:$("draft_button"),f:A.uniqueSubmit.bind(A,"save_draft")});["cc","bcc"].each(function(C){E({d:$("toggle"+C),f:A.toggleCC.bind(A,C)})});if(B=$("htmlcheckbox")){E({d:B,f:A.toggleHtmlCheckbox.bind(A),ns:true})}if(B=$("compose_specialchars")){E({d:B,f:function(){window.open(DIMP.conf_compose.specialchars_url,"chars","height=220,width=400")}})}$("writemsg").select(".composeAddrbook").each(function(C){E({d:C,f:A.openAddressbook.bind(A)})});$("compose").observe("submit",Event.stop);$("identity").observe("change",A.change_identity.bind(A));$("togglecc").observe("click",D);$("togglebcc").observe("click",D);Event.observe(window,"resize",D)}); \ No newline at end of file diff --git a/imp/js/dragdrop.js b/imp/js/dragdrop.js new file mode 100644 index 000000000..01c7648c3 --- /dev/null +++ b/imp/js/dragdrop.js @@ -0,0 +1 @@ +var DragDrop={Drags:{drags:$H(),register:function(A){if(!this.drags.size()){if(!this.div){this.div=new Element("DIV",{className:A.options.classname}).hide()}$(document.body).insert(this.div)}this.drags.set(A.element.readAttribute("id"),A)},unregister:function(A){if(this.drag==A.element){this.drag.deactivate()}this.drags.unset(A.element.readAttribute("id"));if(!this.drags.size()&&this.div){this.div.remove()}},get_drag:function(A){return this.drags.get(Object.isElement(A)?$(A).readAttribute("id"):A)},activate:function(A){if(this.drag){this.deactivate()}this.drag=A;this.mousemoveE=A._mouseMove.bindAsEventListener(A);this.mouseupE=A._mouseUp.bindAsEventListener(A);document.observe("mousemove",this.mousemoveE);document.observe("mouseup",this.mouseupE)},deactivate:function(){if(this.drag){this.drag=null;document.stopObserving("mousemove",this.mousemoveE);document.stopObserving("mouseup",this.mouseupE)}}},Drops:{drops:$H(),register:function(A){this.drops.set(A.element.readAttribute("id"),A)},unregister:function(A){if(this.drop==A.element){this.drop=null}this.drops.unset(A.element.readAttribute("id"))},get_drop:function(A){return this.drops.get(Object.isElement(A)?$(A).readAttribute("id"):A)}},validDrop:function(A){var B=DragDrop.Drops.drop;return(B&&A&&A!=B.element&&(!B.options.accept.size()||B.options.accept.include(A.tagName)))}},Drag=Class.create({initialize:function(A){this.element=$(A);this.options=Object.extend({caption:"",classname:"drag",constraint:null,ghosting:false,scroll:null,snap:null,threshold:0,onDrag:null,onEnd:null,onStart:null},arguments[1]||{});this.mousedownE=this._mouseDown.bindAsEventListener(this);this.element.observe("mousedown",this.mousedownE);if(this.options.scroll){this.options.scroll=$(this.options.scroll)}DragDrop.Drags.register(this);if(Prototype.Browser.IE){this.element.observe("selectstart",Event.stop)}else{if(Prototype.Browser.Gecko){this.element.setStyle({MozUserSelect:"none"})}}},destroy:function(){this.element.stopObserving("mousedown",this.mousedownE);DragDrop.Drags.unregister(this)},_mouseDown:function(A){$(document.body).setStyle({cursor:"default"});DragDrop.Drags.activate(this);this.move=0;this.wasDragged=false;this.lastcaption=null;if(Object.isFunction(this.options.onStart)){this.options.onStart(this,A)}if(!Prototype.Browser.IE&&!Prototype.Browser.Gecko){A.stop()}},_mouseMove:function(E){var B,C,A,D;if(++this.move<=this.options.threshold){return}this.lastCoord=D=[E.pointerX(),E.pointerY()];if(this.options.ghosting){if(!this.ghost){B=this.element.offsetLeft;C=this.element.offsetTop;this.ghost=$(this.element.cloneNode(true)).writeAttribute("id",null).setOpacity(0.7).clonePosition(this.element,{setLeft:false,setTop:false}).setStyle({left:B+"px",position:"absolute",top:C+"px",zIndex:parseInt(this.element.getStyle("zIndex"))+1});this.element.insert({before:this.ghost});A=this.ghost.viewportOffset();this.ghostOffset=[A[0]-B,A[1]-C]}D[0]-=this.ghostOffset[0];D[1]-=this.ghostOffset[1];switch(this.options.constraint){case"horizontal":D[1]=this.ghost.offsetTop;break;case"vertical":D[0]=this.ghost.offsetLeft;break}if(this.options.snap){D=this.options.snap(D[0],D[1],this.element)}if(this.options.offset){D[0]+=this.options.offset.x;D[1]+=this.options.offset.y}this._setContents(this.ghost,D[0],D[1])}this._onMoveDrag(D,E);if(Object.isFunction(this.options.onDrag)){this.options.onDrag(this,E)}this.wasDragged=true;if(this.options.scroll){this._onMoveScroll()}},_mouseUp:function(A){var B=DragDrop.Drops.drop;this._stopScrolling();if(this.ghost){this.ghost.remove();this.ghost=null}DragDrop.Drags.div.hide();if(DragDrop.validDrop(this.element)&&Object.isFunction(B.options.onDrop)){B.options.onDrop(B.element,this.element,A)}DragDrop.Drags.deactivate();if(Object.isFunction(this.options.onEnd)){this.options.onEnd(this,A)}},_onMoveDrag:function(I,E){var G,H,D,C,F=DragDrop.Drops.drop,A=DragDrop.Drags.div,B=true;if(F&&DragDrop.validDrop(this.element)){C=F.options.caption;if(C){H=Object.isFunction(C)?C(F.element,this.element,E):C;if(H&&F.options.hoverclass){D=F.options.hoverclass}}else{B=false}}if(B){if(!H){G=this.options.caption;H=Object.isFunction(G)?G(this.element):G}if(H!=this.lastcaption){this.lastcaption=H;A.update(H).writeAttribute({className:D||this.options.classname});if(H.empty()){A.hide()}}}if(!this.lastcaption.empty()){this._setContents(A,I[0]+15,I[1]+(this.ghost?(this.ghost.getHeight()+5):5))}},_onMoveScroll:function(){this._stopScrolling();var E,D,B,A=this.options.scroll,C=A.getDimensions();if(A.scrollHeight==C.height){return}E=document.viewport.getScrollOffsets();D=A.viewportOffset(),B=[0,0];D[0]+=A.scrollLeft+E.left;D[2]=D[0]+C.width;if(this.lastCoord[0]>D[2]||this.lastCoord[0]D[3]){B[1]=this.lastCoord[1]-D[3]}if(B[0]||B[1]){this.lastScrolled=new Date();this.scrollInterval=setInterval(this._scroll.bind(this,B[0]*15,B[1]*15),10)}},_stopScrolling:function(){if(this.scrollInterval){clearInterval(this.scrollInterval);this.scrollInterval=null}},_scroll:function(A,E){var C=new Date(),D=C-this.lastScrolled,B=this.options.scroll;this.lastScrolled=C;B.scrollTop+=E*D/1000},_setContents:function(C,A,E){var D=document.viewport.getDimensions(),B=C.getDimensions();if((A+B.width>D.width)||(E+B.height>D.height)){C.hide()}else{C.setStyle({left:A+"px",top:E+"px"}).show()}}}),Drop=Class.create({initialize:function(A){this.element=$(A);this.options=Object.extend({accept:[],caption:"",hoverclass:"",onDrop:null,onOut:null,onOver:null},arguments[1]||{});this.mouseoverE=this._mouseOver.bindAsEventListener(this);this.mouseoutE=this._mouseOut.bindAsEventListener(this);this.element.observe("mouseover",this.mouseoverE);this.element.observe("mouseout",this.mouseoutE);DragDrop.Drops.register(this)},destroy:function(){this.element.stopObserving("mouseover",this.mouseoverE);this.element.stopObserving("mouseout",this.mouseoutE);DragDrop.Drops.unregister(this)},_mouseOver:function(A){if(DragDrop.Drags.drag){DragDrop.Drops.drop=this;if(Object.isFunction(this.options.onOver)){this.options.onOver(this.element,DragDrop.Drags.drag)}}},_mouseOut:function(A){if(Object.isFunction(this.options.onOut)){this.options.onOut(this.element,DragDrop.Drags.drag)}DragDrop.Drops.drop=null}}); \ No newline at end of file diff --git a/imp/js/fullmessage-dimp.js b/imp/js/fullmessage-dimp.js new file mode 100644 index 000000000..2b03e8a1f --- /dev/null +++ b/imp/js/fullmessage-dimp.js @@ -0,0 +1 @@ +var DimpFullmessage={quickreply:function(B){var C,A={};A[$F("folder")]=[$F("index")];$("msgData").hide();$("qreply").show();switch(B){case"reply":case"reply_all":case"reply_list":C="GetReplyData";break;case"forward_all":case"forward_body":case"forward_attachments":C="GetForwardData";break}DimpCore.doAction(C,{imp_compose:$F("composeCache"),type:B},A,this.msgTextCallback.bind(this))},msgTextCallback:function(B){if(!B.response){return}var D=B.response,A=((D.format=="html")&&!DimpCompose.editor_on),E=(D.identity===null)?$F("identity"):D.identity,C=DimpCompose.get_identity(E,A);$("identity","last_identity").invoke("setValue",E);DimpCompose.fillForm((C.id[2])?("\n"+C.sig+D.body):(D.body+"\n"+C.sig),D.header);if(D.fwd_list&&D.fwd_list.length){D.fwd_list.each(function(F){DimpCompose.addAttach(F.number,F.name,F.type,F.size)})}if(A){DimpCompose.toggleHtmlEditor(true)}if(D.imp_compose){$("composeCache").setValue(D.imp_compose)}}};document.observe("dom:loaded",function(){window.focus();DimpCore.messageOnLoad();DimpCore.addPopdown("reply_link","replypopdown");DimpCore.addPopdown("forward_link","fwdpopdown");["from","to","cc","bcc","replyTo"].each(function(B){if(DimpFullmessage[B]){var C=$("msgHeader"+B.charAt(0).toUpperCase()+B.substring(1)).down("TD",1);C.replace(DimpCore.buildAddressLinks(DimpFullmessage[B],C.cloneNode(false)))}});var A=DimpCore.clickObserveHandler;A({d:$("windowclose"),f:function(){window.close()}});A({d:$("reply_link"),f:DimpFullmessage.quickreply.bind(DimpFullmessage,"reply")});A({d:$("forward_link"),f:DimpFullmessage.quickreply.bind(DimpFullmessage,DIMP.conf.forward_default)});["spam","ham","deleted"].each(function(B){var C=$("button_"+B);if(C){A({d:C,f:function(D){DIMP.baseWindow.DimpBase.flag(D,DIMP.conf.msg_index,DIMP.conf.msg_folder);window.close()}.curry(B)})}});A({d:$("qreply").select("div.headercloseimg img").first(),f:DimpCompose.confirmCancel.bind(DimpCompose)});["reply","reply_all","reply_list"].each(function(B){var C=$("ctx_replypopdown_"+B);if(C){A({d:C,f:DimpFullmessage.quickreply.bind(DimpFullmessage,B),ns:true})}});["forward_all","forward_body","forward_attachments"].each(function(B){A({d:$("ctx_fwdpopdown_"+B),f:DimpFullmessage.quickreply.bind(DimpFullmessage,B),ns:true})})}); \ No newline at end of file diff --git a/imp/js/src/ContextSensitive.js b/imp/js/src/ContextSensitive.js new file mode 100644 index 000000000..5c7c3f1bd --- /dev/null +++ b/imp/js/src/ContextSensitive.js @@ -0,0 +1,226 @@ +/** + * ContextSensitive: a library for generating context-sensitive content on + * HTML elements. It will take over the click/oncontextmenu functions for the + * document, and works only where these are possible to override. It allows + * contextmenus to be created via both a left and right mouse click. + * + * Requires prototypejs 1.6+ and scriptaculous 1.8+ (effects.js only). + * + * Original code by Havard Eide (http://eide.org/) released under the MIT + * license. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * $Horde: dimp/js/src/ContextSensitive.js,v 1.66 2008/08/25 19:56:23 slusarz Exp $ + * + * @author Chuck Hagenbuch + * @author Michael Slusarz + */ + +var ContextSensitive = Class.create({ + + initialize: function() + { + this.current = this.target = null; + this.elements = $H(); + + document.observe('contextmenu', this.rightClickHandler.bindAsEventListener(this)); + document.observe('click', this.leftClickHandler.bindAsEventListener(this)); + document.observe(Prototype.Browser.Gecko ? 'DOMMouseScroll' : 'mousescroll', this.close.bind(this)); + }, + + /** + * Elements are of type ContextSensitive.Element. + */ + addElement: function(id, target, opts) + { + var left = Boolean(opts.left); + if (id && !this.validElement(id, left)) { + this.elements.set(id + Number(left), new ContextSensitive.Element(id, target, opts)); + } + }, + + /** + * Remove a registered element. + */ + removeElement: function(id) + { + this.elements.unset(id + '0'); + this.elements.unset(id + '1'); + }, + + /** + * Hide the current element. + */ + close: function(immediate) + { + if (this.current) { + if (immediate) { + this.current.hide(); + } else { + Effect.Fade(this.current, { duration: 0.2 }); + } + this.current = this.target = null; + } + }, + + /** + * Get the element that triggered the current context menu (if any). + */ + element: function() + { + return this.target; + }, + + /** + * Returns the current displayed menu element, if any. + */ + currentmenu: function() + { + if (this.current && this.current.visible()) { + return this.current; + } + }, + + /** + * Get a valid element (the ones that can be right-clicked) based + * on a element ID. + */ + validElement: function(id, left) + { + return this.elements.get(id + Number(Boolean(left))); + }, + + /** + * Set the disabled flag of an event. + */ + disable: function(id, left, disable) + { + var e = this.validElement(id, left); + if (e) { + e.disable = disable; + } + }, + + /** + * Called when a left click event occurs. Will return before the + * element is closed if we click on an element inside of it. + */ + leftClickHandler: function(e) + { + // Check for a right click. FF on Linux triggers an onclick event even + // w/a right click, so disregard. + if (e.isRightClick()) { + return; + } + + // Check if the mouseclick is registered to an element now. + this.rightClickHandler(e, true); + }, + + /** + * Called when a right click event occurs. + */ + rightClickHandler: function(e, left) + { + if (this.trigger(e.element(), left, e.pointerX(), e.pointerY())) { + e.stop(); + }; + }, + + /** + * Display context menu if valid element has been activated. + */ + trigger: function(target, leftclick, x, y) + { + var ctx, el, offset, offsets, size, v, voffsets; + + [ target ].concat(target.ancestors()).find(function(n) { + ctx = this.validElement(n.id, leftclick); + return ctx; + }, this); + + // Return if event not found or event is disabled. + if (!ctx || ctx.disable) { + this.close(); + return false; + } + + // Try to retrieve the context-sensitive element we want to + // display. If we can't find it we just return. + el = $(ctx.ctx); + if (!el) { + this.close(); + return false; + } else if (leftclick && el == this.current) { + return false; + } + + // Register the current element that will be shown and the + // element that was clicked on. + this.current = el; + this.target = $(ctx.id); + + // Get the base element positions. + offset = ctx.opts.offset; + if (!offset && (Object.isUndefined(x) || Object.isUndefined(y))) { + offset = target.id; + } + offset = $(offset); + + if (offset) { + offsets = offset.viewportOffset(); + voffsets = document.viewport.getScrollOffsets(); + x = offsets[0] + voffsets.left; + y = offsets[1] + offset.getHeight() + voffsets.top; + } + + // Get window/element dimensions + v = document.viewport.getDimensions(); + size = el.getDimensions(); + + // Make sure context window is entirely on screen + if ((y + size.height) > v.height) { + y = v.height - size.height - 10; + } + if ((x + size.width) > v.width) { + x = v.width - size.width - 10; + } + + if (ctx.opts.onShow) { + ctx.opts.onShow(ctx); + } + + Effect.Appear(el.setStyle({ left: x + 'px', top: y + 'px' }), { duration: 0.2 }); + + return true; + } +}); + +ContextSensitive.Element = Class.create({ + + // opts: 'left' -> monitor left click; 'offset' -> id of element used to + // determine offset placement + initialize: function(id, target, opts) + { + this.id = id; + this.ctx = target; + this.opts = opts; + this.opts.left = Boolean(opts.left); + this.disable = false; + } + +}); diff --git a/imp/js/src/DimpBase.js b/imp/js/src/DimpBase.js new file mode 100644 index 000000000..f3da4d4f8 --- /dev/null +++ b/imp/js/src/DimpBase.js @@ -0,0 +1,2165 @@ +/** + * DimpBase.js - Javascript used in the base DIMP page. + * + * $Horde: dimp/js/src/DimpBase.js,v 1.174 2008/11/24 21:53:41 slusarz Exp $ + * + * Copyright 2005-2008 The Horde Project (http://www.horde.org/) + * + * See the enclosed file COPYING for license information (GPL). If you + * did not receive this file, see http://www.fsf.org/copyleft/gpl.html. + */ + +var DimpBase = { + // Vars used and defaulting to null/false: + // filtertoggle, fl_visible, folder, folderswitch, fspecial, isvisible, + // message_list_template, offset, pollPE, pp, searchobserve, uid, + // viewport + bcache: $H(), + lastrow: -1, + mo_sidebar: {}, + pivotrow: -1, + ppcache: {}, + ppfifo: [], + showPreview: DIMP.conf.preview_pref, + + sfiltersfolder: $H({ sf_all: 'all', sf_current: 'current' }), + sfilters: $H({ sf_msgall: 'msgall', sf_from: 'from', sf_to: 'to', sf_subject: 'subject' }), + + // Message selection functions + + // vs = (ViewPort_Selection) A ViewPort_Selection object. + // opts = (object) Boolean options [delay, right] + _select: function(vs, opts) + { + var d = vs.get('rownum'); + if (d.size() == 1) { + this.lastrow = this.pivotrow = d.first(); + } + + this.toggleButtons(); + + if ($('previewPane').visible()) { + if (opts.right) { + this.clearPreviewPane(); + } else { + if (opts.delay) { + (this.bcache.get('initPP') || this.bcache.set('initPP', this.initPreviewPane.bind(this))).delay(opts.delay); + } else { + this.initPreviewPane(); + } + } + } + }, + + // vs = (ViewPort_Selection) A ViewPort_Selection object. + // opts = (object) Boolean options [right] + _deselect: function(vs, opts) + { + var sel = this.viewport.getSelected(), + count = sel.size(); + if (!count) { + this.lastrow = this.pivotrow = -1; + } + + this.toggleButtons(); + if (opts.right || !count) { + this.clearPreviewPane(); + } else if ((count == 1) && $('previewPane').visible()) { + this._loadPreview(sel.get('dataob').first()); + } + }, + + // id = (string) DOM ID + // opts = (Object) Boolean options [ctrl, right, shift] + msgSelect: function(id, opts) + { + var bounds, + row = this.viewport.createSelection('domid', id), + rownum = row.get('rownum').first(), + sel = this.isSelected('domid', id), + selcount = this.selectedCount(); + + this.lastrow = rownum; + + // Some browsers need to stop the mousedown event before it propogates + // down to the browser level in order to prevent text selection on + // drag/drop actions. Clicking on a message should always lose focus + // from the search input, because the user may immediately start + // keyboard navigation after that. Thus, we need to ensure that a + // message click loses focus on the search input. + $('msgList_filter').blur(); + + if (opts.shift) { + if (selcount) { + if (!sel || selcount != 1) { + bounds = [ rownum, this.pivotrow ]; + this.viewport.select($A($R(bounds.min(), bounds.max())), { range: true }); + } + return; + } + } else if (opts.ctrl) { + this.pivotrow = rownum; + if (sel) { + this.viewport.deselect(row, { right: opts.right }); + return; + } else if (opts.right || selcount) { + this.viewport.select(row, { add: true, right: opts.right }); + return; + } + } + + this.viewport.select(row, { right: opts.right }); + }, + + selectAll: function() + { + this.viewport.select($A($R(1, this.viewport.getMetaData('total_rows'))), { range: true }); + }, + + isSelected: function(format, data) + { + return this.viewport.getSelected().contains(format, data); + }, + + selectedCount: function() + { + return (this.viewport) ? this.viewport.getSelected().size() : 0; + }, + + resetSelected: function() + { + if (this.viewport) { + this.viewport.deselect(this.viewport.getSelected(), { clearall: true }); + } + this.toggleButtons(); + this.clearPreviewPane(); + }, + + // num = (integer) See absolute. + // absolute = Is num an absolute row number - from 1 -> page_size (true) - + // or a relative change from the current selected value (false) + // If no current selected value, the first message in the + // current viewport is selected. + moveSelected: function(num, absolute) + { + var curr, curr_row, row, row_data, sel; + + if (absolute) { + if (!this.viewport.getMetaData('total_rows')) { + return; + } + curr = num; + } else { + if (num == 0) { + return; + } + + sel = this.viewport.getSelected(); + switch (sel.size()) { + case 0: + curr = this.viewport.currentOffset() + 1; + break; + + case 1: + curr_row = sel.get('dataob').first(); + curr = curr_row.rownum + num; + break; + + default: + sel = sel.get('rownum'); + curr = (num > 0 ? sel.max() : sel.min()) + num; + break; + } + curr = (num > 0) ? Math.min(curr, this.viewport.getMetaData('total_rows')) : Math.max(curr, 1); + } + + row = this.viewport.createSelection('rownum', curr); + if (row.size()) { + row_data = row.get('dataob').first(); + if (!curr_row || row_data.imapuid != curr_row.imapuid) { + this.viewport.scrollTo(row_data.rownum); + this.viewport.select(row, { delay: 0.3 }); + } + } else { + this.offset = curr; + this.viewport.requestContentRefresh(curr - 1); + } + }, + // End message selection functions + + go: function(loc, data) + { + var app, f, separator; + + if (loc.startsWith('compose:')) { + return; + } + + if (loc.startsWith('msg:')) { + separator = loc.indexOf(':', 4); + f = loc.substring(4, separator); + this.uid = loc.substring(separator + 1); + loc = 'folder:' + f; + // Now fall through to the 'folder:' check below. + } + + if (loc.startsWith('folder:')) { + f = loc.substring(7); + if (this.folder != f || !$('dimpmain_folder').visible()) { + this.highlightSidebar(this.getFolderId(f)); + if (!$('dimpmain_folder').visible()) { + $('dimpmain_portal').hide(); + $('dimpmain_folder').show(); + } + // This catches the refresh case - no need to re-add to history + if (!Object.isUndefined(this.folder)) { + this._addHistory(loc); + } + } + this.loadFolder(f); + return; + } + + this.folder = null; + $('dimpmain_folder').hide(); + $('dimpmain_portal').update(DIMP.text.loading).show(); + + if (loc.startsWith('app:')) { + app = loc.substr(4); + if (app == 'imp' || app == 'dimp') { + this.go('folder:INBOX'); + return; + } + this.highlightSidebar('app' + app); + this._addHistory(loc, data); + if (data) { + this.iframeContent(loc, data); + } else if (DIMP.conf.app_urls[app]) { + this.iframeContent(loc, DIMP.conf.app_urls[app]); + } + return; + } + + switch (loc) { + case 'portal': + this.highlightSidebar('appportal'); + this._addHistory(loc); + DimpCore.setTitle(DIMP.text.portal); + DimpCore.doAction('ShowPortal', {}, null, this.bcache.get('portalC') || this.bcache.set('portalC', this._portalCallback.bind(this))); + break; + + case 'options': + this.highlightSidebar('appoptions'); + this._addHistory(loc); + DimpCore.setTitle(DIMP.text.prefs); + this.iframeContent(loc, DIMP.conf.prefs_url); + break; + } + }, + + _addHistory: function(loc, data) + { + if (Horde.dhtmlHistory.getCurrentLocation() != loc) { + Horde.dhtmlHistory.add(loc, data); + } + }, + + highlightSidebar: function(id) + { + // Folder bar may not be fully loaded yet. + if ($('foldersLoading').visible()) { + this.highlightSidebar.bind(this, id).defer(); + return; + } + + $('sidebarPanel').select('.on').invoke('removeClassName', 'on'); + + var elt = $(id); + if (!elt) { + return; + } + if (!elt.match('LI')) { + elt = elt.up(); + if (!elt) { + return; + } + } + elt.addClassName('on'); + + // Make sure all subfolders are expanded + elt.ancestors().find(function(n) { + if (n.hasClassName('subfolders')) { + this._toggleSubFolder(n.id.substring(3), 'exp'); + } else { + return (n.id == 'foldersSidebar'); + } + }, this); + }, + + iframeContent: function(name, loc) + { + if (name === null) { + name = loc; + } + + var container = $('dimpmain_portal'), iframe; + if (!container) { + DimpCore.showNotifications([ { type: 'horde.error', message: 'Bad portal!' } ]); + return; + } + + iframe = new Element('IFRAME', { id: 'iframe' + name, className: 'iframe', frameBorder: 0, src: loc }); + this._resizeIE6Iframe(iframe); + + // Hide menu in prefs pages. + if (name == 'options') { + iframe.observe('load', function() { $('iframeoptions').contentWindow.document.getElementById('menu').style.display = 'none'; }); + } + + container.insert(iframe); + }, + + // r = ViewPort row data + msgWindow: function(r) + { + this.updateUnseenUID(r, 0); + var url = DIMP.conf.message_url; + url += (url.include('?') ? '&' : '?') + + $H({ folder: r.view, + uid: r.imapuid }).toQueryString(); + DimpCore.popupWindow(url, 'msgview' + r.view + r.imapuid); + }, + + composeMailbox: function(type) + { + var sel = this.viewport.getSelected(); + if (!sel.size()) { + return; + } + sel.get('dataob').each(function(s) { + DimpCore.compose(type, { folder: s.view, uid: s.imapuid }); + }); + }, + + loadFolder: function(f, background) + { + if (!this.viewport) { + this._createViewPort(); + } + + if (!background) { + this.resetSelected(); + + if (this.folder == f) { + this.searchfilterClear(false); + return; + } + + this.searchfilterClear(true); + $('folderName').update(DIMP.text.loading); + $('msgHeader').update(); + this.folderswitch = true; + this.folder = f; + } + + this.viewport.loadView(f, { folder: f }, this.uid ? { imapuid: this.uid, view: f } : null, background); + }, + + _createViewPort: function() + { + var mf = $('msgList_filter'), + // No need to cache - this function only called once. + settitle = this.setMessageListTitle.bind(this); + + this.viewport = new ViewPort({ + content_container: 'msgList', + empty_container: 'msgList_empty', + error_container: 'msgList_error', + fetch_action: 'ListMessages', + template: this.message_list_template, + buffer_pages: DIMP.conf.buffer_pages, + limit_factor: DIMP.conf.limit_factor, + viewport_wait: DIMP.conf.viewport_wait, + show_split_pane: this.showPreview, + split_pane: 'previewPane', + splitbar: 'splitBar', + content_class: 'msglist', + row_class: 'msgRow', + selected_class: 'selectedRow', + ajaxRequest: DimpCore.doAction.bind(DimpCore), + norows: true, + onScrollIdle: settitle, + onSlide: settitle, + onViewChange: function() { + DimpCore.addGC(this.viewport.visibleRows()); + }.bind(this), + onContent: function(rows) { + var mf, search, + thread = ((this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) && this.viewport.getMetaData('thread')); + if (this.viewport.isFiltering()) { + search = this.sfilters.get(this._getSearchfilterField()).capitalize(); + mf = new RegExp("(" + $F('msgList_filter') + ")", "i"); + } + rows.get('dataob').each(function(row) { + var elt, tmp, u, + r = $(row.domid); + // Add thread graphics + if (thread && thread[row.imapuid]) { + elt = r.down('.msgSubject'); + tmp = elt.cloneNode(false); + u = thread[row.imapuid]; + $R(0, u.length, true).each(function(i) { + tmp.insert($($('thread_img_' + u.charAt(i)).cloneNode(false)).writeAttribute('id', '')); + }); + elt.replace(tmp.insert(elt.getText().escapeHTML())); + } + // Add attachment graphics + if (row.atc) { + r.down('.msgSize').insert({ top: $($('atc_img_' + row.atc).cloneNode(false)).writeAttribute('id', '') }); + } + + // Add context menu. + DimpCore.addMouseEvents({ id: row.domid, type: row.menutype }); + + // Highlight search terms + if (search == 'From' || search == 'Subject') { + elt = r.down('.msg' + search); + elt.update(elt.getText().escapeHTML().gsub(mf, '#{1}')); + } + }, this); + this.setMessageListTitle(); + }.bind(this), + onComplete: function() { + var row, ssc, + l = this.viewport.getMetaData('label'); + + if (this.uid) { + row = this.viewport.getViewportSelection().search({ imapuid: { equal: [ this.uid ] }, view: { equal: [ this.folder ] } }); + if (row.size()) { + this.viewport.scrollTo(row.get('rownum').first()); + this.viewport.select(row); + } + } else if (this.offset) { + this.viewport.select(this.viewport.createSelection('rownum', this.offset)); + } + this.offset = this.uid = null; + + // 'label' will not be set if there has been an error + // retrieving data from the server. + l = this.viewport.getMetaData('label'); + if (l) { + $('folderName').update(l); + } + + if (this.folderswitch) { + this.folderswitch = false; + if (this.folder == DIMP.conf.spam_folder) { + if (!DIMP.conf.spam_spamfolder && + DimpCore.buttons.indexOf('button_spam') != -1) { + [ $('button_spam').up(), $('ctx_message_spam') ].invoke('hide'); + } + if (DimpCore.buttons.indexOf('button_ham') != -1) { + [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show'); + } + } else { + if (DimpCore.buttons.indexOf('button_spam') != -1) { + [ $('button_spam').up(), $('ctx_message_spam') ].invoke('show'); + } + if (DimpCore.buttons.indexOf('button_ham') != -1) { + if (DIMP.conf.ham_spamfolder) { + [ $('button_ham').up(), $('ctx_message_ham') ].invoke('hide'); + } else { + [ $('button_ham').up(), $('ctx_message_ham') ].invoke('show'); + } + } + } + } else if (this.filtertoggle) { + if (this.filtertoggle == 1 && + this.viewport.getMetaData('sortby') == DIMP.conf.sortthread) { + ssc = DIMP.conf.sortdate; + } + this.filtertoggle = 0; + } + + this.setSortColumns(ssc); + + if (this.viewport.isFiltering()) { + this.resetSelected(); + } else { + this.setFolderLabel(this.folder, this.viewport.getMetaData('unseen') || 0); + } + this.updateTitle(); + }.bind(this), + onFetch: this.msgListLoading.bind(this, true), + onEndFetch: this.msgListLoading.bind(this, false), + onWait: function() { + if ($('dimpmain_folder').visible()) { + DimpCore.showNotifications([ { type: 'horde.warning', message: DIMP.text.listmsg_wait } ]); + } + }, + onFail: function() { + if ($('dimpmain_folder').visible()) { + DimpCore.showNotifications([ { type: 'horde.error', message: DIMP.text.listmsg_timeout } ]); + } + this.msgListLoading(false); + }.bind(this), + onFirstContent: function() { + this.clearPreviewPane(); + $('msgList').observe('dblclick', this._handleMsgListDblclick.bindAsEventListener(this)); + }.bind(this), + onClearRows: function(r) { + r.each(function(row) { + var c = $(row).down('div.msCheck'); + if (c) { + DimpCore.addGC(c); + } + if (row.id) { + DimpCore.removeMouseEvents(row); + } + }); + }, + onBeforeResize: function() { + var sel = this.viewport.getSelected(); + this.isvisible = (sel.size() == 1) && (this.viewport.isVisible(sel.get('rownum').first()) == 0); + }.bind(this), + onAfterResize: function() { + if (this.isvisible) { + this.viewport.scrollTo(this.viewport.getSelected().get('rownum').first()); + } + }.bind(this), + selectCallback: this._select.bind(this), + deselectCallback: this._deselect.bind(this) + }); + + // If starting in no preview mode, need to set the no preview class + if (!this.showPreview) { + $('msgList').addClassName('msglistNoPreview'); + } + + // Set up viewport filter events. + this.viewport.addFilter('ListMessages', this._addSearchfilterParams.bind(this)); + mf.observe('keyup', this._searchfilterOnKeyup.bind(this)); + mf.observe('focus', this._searchfilterOnFocus.bind(this)); + mf.observe('blur', this._searchfilterOnBlur.bind(this)); + mf.addClassName('msgFilterDefault'); + }, + + _addMouseEvents: function(parentfunc, p) + { + var elt; + + switch (p.type) { + case 'draft': + case 'message': + new Drag(p.id, this._msgDragConfig); + elt = $(p.id).down('div.msCheck'); + if (elt.visible()) { + elt.observe('mousedown', this.bcache.get('handleMLC') || this.bcache.set('handleMLC', this._handleMsgListCheckbox.bindAsEventListener(this))); + elt.observe('contextmenu', Event.stop); + } + break; + + case 'container': + case 'folder': + new Drag(p.id, this._folderDragConfig); + break; + + case 'special': + // For purposes of the contextmenu, treat special folders + // like regular folders. + p.type = 'folder'; + break; + + case 'vcontainer': + case 'virtual': + $(p.id).observe('contextmenu', Event.stop); + break; + } + + p.onShow = this.bcache.get('onMS') || this.bcache.set('onMS', this._onMenuShow.bind(this)); + parentfunc(p); + }, + + _removeMouseEvents: function(parentfunc, elt) + { + var d, id = $(elt).readAttribute('id'); + if (id && (d = DragDrop.Drags.get_drag(id))) { + d.destroy(); + } + parentfunc(elt); + }, + + _onMenuShow: function(ctx) + { + var elts, folder, ob, sel; + + switch (ctx.ctx) { + case 'ctx_folder': + elts = $('ctx_folder_create', 'ctx_folder_rename', 'ctx_folder_delete'); + folder = DimpCore.DMenu.element(); + if (folder.readAttribute('mbox') == 'INBOX') { + elts.invoke('hide'); + } else if (DIMP.conf.fixed_folders.indexOf(folder.readAttribute('mbox')) != -1) { + elts.shift(); + elts.invoke('hide'); + } else { + elts.invoke('show'); + } + + if (folder.hasAttribute('u')) { + $('ctx_folder_poll').hide(); + $('ctx_folder_nopoll').show(); + } else { + $('ctx_folder_poll').show(); + $('ctx_folder_nopoll').hide(); + } + break; + + case 'ctx_message': + [ $('ctx_message_reply_list') ].invoke(this.viewport.createSelection('domid', ctx.id).get('dataob').first().listmsg ? 'show' : 'hide'); + break; + + case 'ctx_reply': + sel = this.viewport.getSelected(); + if (sel.size() == 1) { + ob = sel.get('dataob').first(); + } + [ $('ctx_reply_reply_list') ].invoke(ob && ob.listmsg ? 'show' : 'hide'); + break; + + case 'ctx_otheractions': + $('oa_seen', 'oa_unseen', 'oa_flagged', 'oa_clear', 'oa_sep1', 'oa_blacklist', 'oa_whitelist', 'oa_sep2').compact().invoke(this.viewport.getSelected().size() ? 'show' : 'hide'); + break; + } + return true; + }, + + _onResize: function(noupdate, nowait) + { + if (this.viewport) { + this.viewport.onResize(noupdate, nowait); + } + this._resizeIE6(); + }, + + _handleMsgListDblclick: function(e) + { + var elt = this._getMsgRow(e), row; + if (!elt) { + return; + } + row = this.viewport.createSelection('domid', elt.id).get('dataob').first(); + row.draft ? DimpCore.compose('resume', { folder: row.view, uid: row.imapuid }) : this.msgWindow(row); + e.stop(); + }, + + _handleMsgListCheckbox: function(e) + { + var elt = this._getMsgRow(e); + if (!elt) { + return; + } + this.msgSelect(elt.readAttribute('id'), { ctrl: true, right: true }); + e.stop(); + }, + + _getMsgRow: function(e) + { + e = e.element(); + if (e && !e.hasClassName('msgRow')) { + e = e.up('.msgRow'); + } + return e; + }, + + updateTitle: function() + { + var elt, label, unseen; + if (this.viewport.isFiltering()) { + label = DIMP.text.search + ' :: ' + this.viewport.getMetaData('total_rows') + ' ' + DIMP.text.resfound; + } else { + elt = $(this.getFolderId(this.folder)); + if (elt) { + unseen = elt.readAttribute('u'); + label = elt.readAttribute('l'); + if (unseen > 0) { + label += ' (' + unseen + ')'; + } + } else { + label = this.viewport.getMetaData('label'); + } + } + DimpCore.setTitle(label); + }, + + sort: function(e) + { + // Don't change sort if we are past the sortlimit + if (this.viewport.getMetaData('sortlimit')) { + return; + } + + var s, sortby, + elt = e.element(); + if (!elt.hasAttribute('sortby')) { + elt = elt.up('[sortby]'); + if (!elt) { + return; + } + } + sortby = parseInt(elt.readAttribute('sortby'), 10); + + if (sortby == this.viewport.getMetaData('sortby')) { + s = { sortdir: (this.viewport.getMetaData('sortdir') ? 0 : 1) }; + this.viewport.setMetaData({ sortdir: s.sortdir }); + } else { + s = { sortby: sortby }; + this.viewport.setMetaData({ sortby: s.sortby }); + } + this.setSortColumns(sortby); + this.viewport.reload(s); + }, + + setSortColumns: function(sortby) + { + var tmp, + m = $('msglistHeader'); + + if (Object.isUndefined(sortby)) { + sortby = this.viewport.getMetaData('sortby'); + } + + tmp = m.down('small[sortby=' + sortby + ']'); + if (tmp && tmp.up().visible()) { + tmp.up(1).childElements().invoke('toggle'); + } + + tmp = m.down('div.msgFrom a'); + if ((this.viewport.isFiltering() && this.fspecial) || + this.viewport.getMetaData('special')) { + tmp.hide().next().show(); + } else { + tmp.show().next().hide(); + } + + tmp = m.down('div.msgSubject a'); + if (this.viewport.isFiltering() || + this.viewport.getMetaData('nothread') || + this.viewport.getMetaData('sortlimit')) { + tmp.show().next().hide(); + tmp.down().hide(); + } else { + tmp.down().show(); + } + + m.childElements().invoke('removeClassName', 'sortup').invoke('removeClassName', 'sortdown'); + m.down('div a[sortby=' + sortby + ']').up().addClassName(this.viewport.getMetaData('sortdir') ? 'sortup' : 'sortdown'); + }, + + // Preview pane functions + togglePreviewPane: function() + { + this.showPreview = !this.showPreview; + $('previewtoggle').setText(this.showPreview ? DIMP.text.hide_preview : DIMP.text.show_preview); + [ $('msgList') ].invoke(this.showPreview ? 'removeClassName' : 'addClassName', 'msglistNoPreview'); + new Ajax.Request(DimpCore.addSID(DIMP.conf.URI_PREFS), { parameters: { app: 'dimp', pref: 'show_preview', value: this.showPreview ? 1 : 0 } }); + this.viewport.showSplitPane(this.showPreview); + if (this.showPreview) { + this.initPreviewPane(); + } + }, + + _loadPreview: function(data) + { + var pp = $('previewPane'), pp_offset; + if (!pp.visible()) { + return; + } + if (this.pp && + this.pp == data) { + return; + } + this.pp = data; + + if (this.ppfifo.indexOf(data.vp_id) != -1) { + return this._loadPreviewCallback(this.ppcache[data.vp_id]); + } + + pp_offset = pp.positionedOffset(); + $('msgLoading').setStyle({ position: 'absolute', top: (pp_offset.top + 10) + 'px', left: (pp_offset.left + 10) + 'px' }).show(); + + DimpCore.doAction('ShowPreview', {}, this.viewport.createSelection('dataob', data), this.bcache.get('loadPC') || this.bcache.set('loadPC', this._loadPreviewCallback.bind(this))); + }, + + _loadPreviewCallback: function(resp) + { + var row, search, tmp, tmp2, + pm = $('previewMsg'), + r = resp.response, + t = $('msgHeadersContent').down('THEAD'); + + if (!r.error) { + search = this.viewport.getViewportSelection(r.view).search({ vp_id: { equal: [ r.uid ] } }); + if (search.size()) { + row = search.get('dataob').first(); + this.updateUnseenUID(row, 0); + } + } + + if (this.pp && + this.pp.vp_id != r.uid) { + return; + } + + if (r.error || this.viewport.getSelected().size() != 1) { + if (r.error) { + DimpCore.showNotifications([ { type: r.errortype, message: r.error } ]); + } + this.clearPreviewPane(); + return; + } + + // Store in cache. + this._expirePPCache([ r.uid ]); + this.ppcache[r.uid] = resp; + this.ppfifo.push(r.uid); + + DimpCore.removeAddressLinks(pm); + + DIMP.conf.msg_index = r.index; + DIMP.conf.msg_folder = r.folder; + + // Add subject/priority + tmp = pm.select('.subject'); + tmp.invoke('update', r.subject); + switch (r.priority) { + case 'high': + case 'low': + tmp.invoke('insert', { top: $($(r.priority + '_priority_img').cloneNode(false)).writeAttribute('id', false) }); + break; + } + + // Add date + $('msgHeadersColl').select('.date').invoke('update', r.minidate); + $('msgHeaderDate').select('.date').invoke('update', r.fulldate); + + // Add from/to/cc headers + [ 'from', 'to', 'cc' ].each(function(a) { + if (r[a]) { + (a == 'from' ? pm.select('.' + a) : [ t.down('.' + a) ]).each(function(elt) { + elt.replace(DimpCore.buildAddressLinks(r[a], elt.cloneNode(false))); + }); + } + [ $('msgHeader' + a.capitalize()) ].invoke(r[a] ? 'show' : 'hide'); + }); + + // Add attachment information + $('toggleHeaders').select('.attachmentImage').invoke(r.atc_label ? 'show' : 'hide'); + if (r.atc_label) { + tmp = $('msgAtc').show().down('.label'); + tmp2 = $('partlist'); + tmp2.hide().previous().update(r.atc_label + ' ' + r.atc_download); + if (r.atc_list) { + $('partlist_col').show(); + $('partlist_exp').hide(); + tmp.down().hide().next().show(); + tmp2.update(r.atc_list); + } else { + tmp.down().show().next().hide(); + } + } else { + $('msgAtc').hide(); + } + + $('msgBody').down().update(r.msgtext); + $('msgLoading', 'previewInfo').invoke('hide'); + $('previewPane').scrollTop = 0; + pm.show(); + + if (r.js) { + eval(r.js.join(';')); + } + this._addHistory('msg:' + row.view + ':' + row.imapuid); + }, + + initPreviewPane: function() + { + var sel = this.viewport.getSelected(); + if (sel.size() != 1) { + this.clearPreviewPane(); + } else { + this._loadPreview(sel.get('dataob').first()); + } + }, + + clearPreviewPane: function() + { + $('msgLoading', 'previewMsg').invoke('hide'); + $('previewInfo').show(); + this.pp = null; + }, + + _expirePPCache: function(ids) + { + this.ppfifo = this.ppfifo.without(ids); + ids.each(function(i) { + delete this.ppcache[i]; + }, this); + // Preview pane cache size is 20 entries. Given that a reasonable guess + // of an average e-mail size is 10 KB (including headers), also make + // an estimate that the JSON data size will be approx. 10 KB. 200 KB + // should be a fairly safe caching value for any recent browser. + if (this.ppfifo.size() > 20) { + delete this.ppcache[this.ppfifo.shift()]; + } + }, + + // Labeling functions + updateUnseenUID: function(r, setflag) + { + var sel, unseen, unseenset; + if (!r.bg) { + return false; + } + unseenset = r.bg.indexOf('unseen') != -1; + if ((setflag && unseenset) || (!setflag && !unseenset)) { + return false; + } + + sel = this.viewport.createSelection('dataob', r); + unseen = parseInt($(this.getFolderId(r.view)).readAttribute('u'), 10); + if (setflag) { + this.viewport.updateFlag(sel, 'unseen', true); + ++unseen; + } else { + this.viewport.updateFlag(sel, 'unseen', false); + --unseen; + } + + this.updateUnseenStatus(r.view, unseen); + }, + + updateUnseenStatus: function(mbox, unseen) + { + if (this.viewport) { + this.viewport.setMetaData({ unseen: unseen }, mbox); + } + this.setFolderLabel(mbox, unseen); + + if (this.folder == mbox) { + this.updateTitle(); + } + }, + + setMessageListTitle: function() + { + var offset, + rows = this.viewport.getMetaData('total_rows'); + if (rows > 0) { + offset = this.viewport.currentOffset(); + $('msgHeader').update(DIMP.text.messages + ' ' + (offset + 1) + ' - ' + (Math.min(offset + this.viewport.getPageSize(), rows)) + ' ' + DIMP.text.of + ' ' + rows); + } else { + $('msgHeader').update(DIMP.text.nomessages); + } + }, + + setFolderLabel: function(f, unseen) + { + var elt, fid = this.getFolderId(f); + elt = $(fid); + if (!elt || !elt.hasAttribute('u')) { + return; + } + + unseen = parseInt(unseen); + elt.writeAttribute('u', unseen); + + if (f == 'INBOX' && window.fluid) { + window.fluid.setDockBadge(unseen ? unseen : ''); + } + + $(fid + '_label').update((unseen > 0) ? + new Element('STRONG').insert(elt.readAttribute('l')).insert(' ').insert(new Element('SPAN', { className: 'count', dir: 'ltr' }).insert('(' + unseen + ')')) : + elt.readAttribute('l')); + }, + + getFolderId: function(f) + { + return 'fld' + decodeURIComponent(f).replace(/_/g,'__').replace(/\W/g, '_'); + }, + + getSubFolderId: function(f) + { + return 'sub' + f; + }, + + /* Folder list updates. */ + pollFolders: function() + { + // Reset poll folder counter. + this.setPollFolders(); + var args = {}; + if (this.folder && $('dimpmain_folder').visible()) { + args = this.viewport.addRequestParams({}); + } + $('checkmaillink').down('A').update('[' + DIMP.text.check + ']'); + DimpCore.doAction('PollFolders', args, null, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this))); + }, + + _pollFoldersCallback: function(r) + { + var q, that; + r = r.response; + if (r.poll) { + that = this; + $H(r.poll).each(function(u) { + that.updateUnseenStatus(u.key, u.value); + }); + } + if (r.quota) { + q = $('quota').cleanWhitespace(); + q.setText(r.quota.m); + q.down('SPAN.used IMG').writeAttribute({ width: 99 - r.quota.p }); + } + $('checkmaillink').down('A').update(DIMP.text.getmail); + }, + + setPollFolders: function() + { + if (DIMP.conf.refresh_time) { + if (this.pollPE) { + this.pollPE.stop(); + } + // Don't cache - this code is only run once. + this.pollPE = new PeriodicalExecuter(this.pollFolders.bind(this), DIMP.conf.refresh_time); + } + }, + + _portalCallback: function(r) + { + if (r.response.linkTags) { + var head = $$('HEAD').first(); + r.response.linkTags.each(function(newLink) { + var link = new Element('LINK', { type: 'text/css', rel: 'stylesheet', href: newLink.href }); + if (newLink.media) { + link.media = newLink.media; + } + head.insert(link); + }); + } + $('dimpmain_portal').update(r.response.portal); + + /* Link portal block headers to the application. */ + $('dimpmain_portal').select('h1.header a').each(this.bcache.get('portalClkLink') || this.bcache.set('portalClkLink', function(d) { + d.observe('click', function(e, d) { + this.go('app:' + d.readAttribute('app')); + e.stop(); + }.bindAsEventListener(this, d)); + }.bind(this))); + }, + + /* Search filter functions. */ + _searchfilterOnKeyup: function() + { + if (this.searchobserve) { + clearTimeout(this.searchobserve); + } + this.searchobserve = (this.bcache.get('searchfilterR') || this.bcache.set('searchfilterR', this.searchfilterRun.bind(this))).delay(0.5); + }, + + searchfilterRun: function() + { + if (!this.viewport.isFiltering()) { + this.filtertoggle = 1; + this.fspecial = this.viewport.getMetaData('special'); + } + this.viewport.runFilter($F('msgList_filter')); + }, + + _searchfilterOnFocus: function() + { + var q = $('qoptions').up(); + + if ($('msgList_filter').hasClassName('msgFilterDefault')) { + this._setFilterText(false); + } + + if (!q.visible()) { + $('sf_current').update(this.viewport.getMetaData('label')); + this._setSearchfilterParams(this.viewport.getMetaData('special') ? 'to' : 'from', 'msg'); + this._setSearchfilterParams('current', 'folder'); + $(document.documentElement).setStyle({ overflowY: 'hidden' }); + Effect.SlideDown(q, { duration: 0.5, afterFinish: function() { this._onResize(false, true); $(document.documentElement).setStyle({ overflowY: 'auto' }); }.bind(this) }); + } + }, + + _searchfilterOnBlur: function() + { + if (!$F('msgList_filter')) { + this._setFilterText(true); + } + }, + + // reset = (boolean) TODO + searchfilterClear: function(reset) + { + var q = $('qoptions').up(); + if (!q.visible()) { + return; + } + if (this.searchobserve) { + clearTimeout(this.searchobserve); + this.searchobserve = null; + } + this._setFilterText(true); + Effect.SlideUp(q, { duration: 0.5, afterFinish: this._onResize.bind(this, reset) }); + this.filtertoggle = 2; + this.resetSelected(); + this.viewport.stopFilter(reset); + }, + + // d = (boolean) Deactivate filter input? + _setFilterText: function(d) + { + var mf = $('msgList_filter'); + if (d) { + mf.setValue(DIMP.text.search); + mf.addClassName('msgFilterDefault'); + } else { + mf.setValue(''); + mf.removeClassName('msgFilterDefault'); + } + }, + + // type = 'folder' or 'msg' + _setSearchfilterParams: function(id, type) + { + var c = (type == 'folder') ? this.sfiltersfolder : this.sfilters; + c.keys().each(function(i) { + $(i).writeAttribute('className', (id == c.get(i)) ? 'qselected' : ''); + }); + }, + + updateSearchfilter: function(id, type) + { + this._setSearchfilterParams(id, type); + if ($F('msgList_filter')) { + this.viewport.runFilter(); + } + }, + + _addSearchfilterParams: function() + { + var sf = this.sfiltersfolder.keys().find(function(s) { + return $(s).hasClassName('qselected'); + }); + return { searchfolder: this.sfiltersfolder.get(sf), searchmsg: this.sfilters.get(this._getSearchfilterField()) }; + }, + + _getSearchfilterField: function() + { + return this.sfilters.keys().find(function(s) { + return $(s).hasClassName('qselected'); + }); + }, + + /* Enable/Disable DIMP action buttons as needed. */ + toggleButtons: function() + { + var disable = (this.selectedCount() == 0); + DimpCore.buttons.each(function(b) { + var elt = $(b); + if (elt) { + [ elt.up() ].invoke(disable ? 'addClassName' : 'removeClassName', 'disabled'); + DimpCore.DMenu.disable(b + '_img', true, disable); + } + }); + }, + + /* Drag/Drop handler. */ + _folderDropHandler: function(drop, drag, e) + { + var dropbase, sel, uids, + foldername = drop.readAttribute('mbox'), + ftype = drop.readAttribute('ftype'); + + if (drag.hasClassName('folder')) { + dropbase = (drop == $('dropbase')); + if (dropbase || + (ftype != 'special' && !this.isSubfolder(drag, drop))) { + DimpCore.doAction('RenameFolder', { old_name: drag.readAttribute('mbox'), new_parent: dropbase ? '' : foldername, new_name: drag.readAttribute('l') }, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); + } + } else if (ftype != 'container') { + sel = this.viewport.getSelected(); + + if (sel.size()) { + // Dragging multiple selected messages. + uids = sel; + } else if (drag.readAttribute('mbox') != foldername) { + // Dragging a single unselected message. + uids = this.viewport.createSelection('domid', drag.id); + } + + if (uids.size()) { + if (e.ctrlKey) { + DimpCore.doAction('CopyMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('pollFC') || this.bcache.set('pollFC', this._pollFoldersCallback.bind(this))); + } else if (this.folder != foldername) { + // Don't allow drag/drop to the current folder. + this.viewport.updateFlag(uids, 'deletedmsg', true); + DimpCore.doAction('MoveMessage', this.viewport.addRequestParams({ tofld: foldername }), uids, this.bcache.get('deleteC') || this.bcache.set('deleteC', this._deleteCallback.bind(this))); + } + } + } + }, + + _dragCaption: function() + { + var cnt = this.selectedCount(); + return cnt + ' ' + (cnt == 1 ? DIMP.text.message : DIMP.text.messages); + }, + + /* Keydown event handler */ + _keydownHandler: function(e) + { + // Only catch keyboard shortcuts in message list view. Disable catching + // when in form elements or the RedBox overlay is visible. + if (!$('dimpmain_folder').visible() || + e.findElement('FORM') || + RedBox.overlayVisible()) { + return; + } + + var co, ps, r, row, rowoff, + kc = e.keyCode || e.charCode, + sel = this.viewport.getSelected(); + + switch (kc) { + case Event.KEY_DELETE: + case Event.KEY_BACKSPACE: + if (sel.size() == 1) { + r = sel.get('dataob').first(); + if (e.shiftKey) { + this.moveSelected(r.rownum + ((r.rownum == this.viewport.getMetaData('total_rows')) ? -1 : 1), true); + } + this.flag('deleted', r); + } else { + this.flag('deleted'); + } + e.stop(); + break; + + case Event.KEY_UP: + case Event.KEY_DOWN: + if (e.shiftKey && this.lastrow != -1) { + row = this.viewport.createSelection('rownum', this.lastrow + ((kc == Event.KEY_UP) ? -1 : 1)); + if (row.size()) { + row = row.get('dataob').first(); + this.viewport.scrollTo(row.rownum); + this.msgSelect(row.domid, { shift: true }); + } + } else { + this.moveSelected(kc == Event.KEY_UP ? -1 : 1); + } + e.stop(); + break; + + case Event.KEY_PAGEUP: + case Event.KEY_PAGEDOWN: + if (!e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey) { + ps = this.viewport.getPageSize() - 1; + move = ps * (kc == Event.KEY_PAGEUP ? -1 : 1); + if (sel.size() == 1) { + co = this.viewport.currentOffset(); + rowoff = sel.get('rownum').first() - 1; + switch (kc) { + case Event.KEY_PAGEUP: + if (co != rowoff) { + move = co - rowoff; + } + break; + + case Event.KEY_PAGEDOWN: + if ((co + ps) != rowoff) { + move = co + ps - rowoff; + } + break; + } + } + this.moveSelected(move); + e.stop(); + } + break; + + case Event.KEY_HOME: + case Event.KEY_END: + this.moveSelected(kc == Event.KEY_HOME ? 1 : this.viewport.getMetaData('total_rows'), true); + e.stop(); + break; + + case Event.KEY_RETURN: + if (!e.element().match('input')) { + // Popup message window if single message is selected. + if (sel.size() == 1) { + this.msgWindow(sel.get('dataob').first()); + } + } + e.stop(); + break; + + case 65: // A + case 97: // a + if (e.ctrlKey) { + this.selectAll(); + e.stop(); + } + break; + } + }, + + /* Handle rename folder actions. */ + renameFolder: function(folder) + { + if (Object.isUndefined(folder)) { + return; + } + + folder = $(folder); + var n = this._createFolderForm(function(e) { this._folderAction(folder, e, 'rename'); return false; }.bindAsEventListener(this), DIMP.text.rename_prompt); + n.down('input').setValue(folder.readAttribute('l')); + }, + + /* Handle insert folder actions. */ + createBaseFolder: function() + { + this._createFolderForm(function(e) { this._folderAction('', e, 'create'); return false; }.bindAsEventListener(this), DIMP.text.create_prompt); + }, + + createSubFolder: function(folder) + { + if (Object.isUndefined(folder)) { + return false; + } + + this._createFolderForm(function(e) { this._folderAction($(folder), e, 'createsub'); return false; }.bindAsEventListener(this), DIMP.text.createsub_prompt); + }, + + _createFolderForm: function(action, text) + { + var n = new Element('FORM', { action: '#', id: 'RB_folder' }).insert( + new Element('P').insert(text) + ).insert( + new Element('INPUT', { type: 'text', size: 15 }) + ).insert( + new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.ok }).observe('click', action) + ).insert( + new Element('INPUT', { type: 'button', className: 'button', value: DIMP.text.cancel }).observe('click', this.bcache.get('closeRB') || this.bcache.set('closeRB', this._closeRedBox.bind(this))) + ).observe('keydown', function(e) { if ((e.keyCode || e.charCode) == Event.KEY_RETURN) { e.stop(); action(e); } }); + + RedBox.overlay = true; + RedBox.onDisplay = Form.focusFirstElement.curry(n); + RedBox.showHtml(n); + return n; + }, + + _closeRedBox: function() + { + var c = RedBox.getWindowContents(); + DimpCore.addGC([ c, c.descendants() ].flatten()); + RedBox.close(); + }, + + _folderAction: function(folder, e, mode) + { + this._closeRedBox(); + + var action, params, val, + form = e.findElement('form'); + val = $F(form.down('input')); + + if (val) { + switch (mode) { + case 'rename': + if (folder.readAttribute('l') != val) { + action = 'RenameFolder'; + params = { old_name: folder.readAttribute('mbox'), + new_parent: folder.up().hasClassName('folderlist') ? '' : folder.up(1).previous().readAttribute('mbox'), + new_name: val }; + } + break; + + case 'create': + case 'createsub': + action = 'CreateFolder'; + params = { folder: val }; + if (mode == 'createsub') { + params.parent = folder.readAttribute('mbox'); + } + break; + } + if (action) { + DimpCore.doAction(action, params, null, this.bcache.get('folderC') || this.bcache.set('folderC', this._folderCallback.bind(this))); + } + } + }, + + /* Folder action callback functions. */ + _folderCallback: function(r) + { + r = r.response; + if (r.d) { + r.d.each(this.bcache.get('deleteFolder') || this.bcache.set('deleteFolder', this.deleteFolder.bind(this))); + } + if (r.c) { + r.c.each(this.bcache.get('changeFolder') || this.bcache.set('changeFolder', this.changeFolder.bind(this))); + } + if (r.a) { + r.a.each(this.bcache.get('createFolder') || this.bcache.set('createFolder', this.createFolder.bind(this))); + } + }, + + _deleteCallback: function(r) + { + var search, uids = []; + + this.msgListLoading(false); + this._pollFoldersCallback(r); + + r = r.response; + if (!r.uids || r.folder != this.folder) { + return; + } + + // Need to convert uid list to listing of unique viewport IDs since + // we may be dealing with multiple mailboxes (i.e. virtual folders) + $H(DimpCore.parseRangeString(r.uids)).each(function(pair) { + pair.value.each(function(v) { + uids.push(v + pair.key); + }); + }); + + search = this.viewport.getViewportSelection().search({ vp_id: { equal: uids } }); + if (search.size()) { + if (r.remove) { + this.viewport.remove(search, { cacheid: r.cacheid, noupdate: r.viewport }); + this._expirePPCache(search.get('uid')); + } else { + // Need this to catch spam deletions. + this.viewport.updateFlag(search, 'deletedmsg', true); + } + } + }, + + _emptyFolderCallback: function(r) + { + if (r.response.mbox) { + if (this.folder == r.response.mbox) { + this.viewport.reload(); + this.clearPreviewPane(); + } + this.setFolderLabel(r.response.mbox, 0); + } + }, + + _flagAllCallback: function(r) + { + if (r.response.mbox) { + this.setFolderLabel(r.response.mbox, r.response.u); + } + }, + + _folderLoadCallback: function(r) + { + this._folderCallback(r); + + var elts = $('specialfolders', 'normalfolders').compact(), + nf = $('normalfolders'), + nfheight = nf.getStyle('max-height'); + + elts.invoke('observe', 'click', this._handleFolderMouseEvent.bindAsEventListener(this, 'click')); + elts.invoke('observe', 'mouseover', this._handleFolderMouseEvent.bindAsEventListener(this, 'over')); + if (DIMP.conf.is_ie6) { + elts.invoke('observe', 'mouseout', this._handleFolderMouseEvent.bindAsEventListener(this, 'out')); + } + + $('foldersLoading').hide(); + $('foldersSidebar').show(); + + // Fix for IE6 - which doesn't support max-height. We need to search + // for height: 0px instead (comment in IE 6 CSS explains this is + // needed for auto sizing). + if (nfheight !== null || + (Prototype.Browser.IE && + Object.isUndefined(nfheight) && + (nf.getStyle('height') == '0px'))) { + this._sizeFolderlist(); + Event.observe(window, 'resize', this._sizeFolderlist.bind(this)); + } + }, + + _handleFolderMouseEvent: function(e, action) + { + var type, + elt = e.element(), + li = elt.up('.folder') || elt.up('.custom'); + if (!li) { + return; + } + type = li.readAttribute('ftype'); + + switch (action) { + case 'over': + if (DIMP.conf.is_ie6) { + li.addClassName('over'); + } + if (type && !this.mo_sidebar[li.id]) { + DimpCore.addMouseEvents({ id: li.id, type: type }); + this.mo_sidebar[li.id] = 1; + } + break; + + case 'out': + li.removeClassName('over'); + break; + + case 'click': + if (elt.hasClassName('exp') || elt.hasClassName('col')) { + this._toggleSubFolder(li.id, 'tog'); + } else { + switch (type) { + case 'container': + case 'vcontainer': + e.stop(); + break; + + case 'folder': + case 'special': + case 'virtual': + e.stop(); + return this.go('folder:' + li.readAttribute('mbox')); + break; + } + } + break; + } + }, + + _toggleSubFolder: function(base, mode) + { + base = $(base); + var opts = { duration: 0.2 }, + s = $(this.getSubFolderId(base.id)); + if (s && + (mode == 'tog' || + (mode == 'exp' && !s.visible()) || + (mode == 'col' && s.visible()))) { + if (base.descendantOf('specialfolders')) { + opts.afterFinish = this._sizeFolderlist; + } + base.firstDescendant().writeAttribute({ className: s.visible() ? 'exp' : 'col' }); + if (s.visible()) { + Effect.BlindUp(s, opts); + } else { + Effect.BlindDown(s, opts); + } + } + }, + + // Folder actions. + // For format of the ob object, see DIMP::_createFolderElt(). + createFolder: function(ob) + { + var div, f_node, li, ll, parent_e, + fid = this.getFolderId(ob.m), + mbox = decodeURIComponent(ob.m), + submboxid = this.getSubFolderId(fid), + submbox = $(submboxid); + + li = new Element('LI', { className: 'folder', id: fid, l: ob.l, mbox: mbox, ftype: (ob.v ? (ob.co ? 'vcontainer' : 'virtual') : (ob.co ? 'container' : (ob.s ? 'special' : 'folder'))) }); + + div = new Element('DIV', { className: ob.cl || 'base', id: fid + '_div' }); + if (ob.i) { + div.update(ob.i); + } + if (ob.ch) { + div.writeAttribute({ className: 'exp' }).observe('mouseover', this.bcache.get('mo_folder') || this.bcache.set('mo_folder', function(e) { + e = e.element(); + if (DragDrop.Drags.drag && e.hasClassName('exp')) { + this._toggleSubFolder(e.up(), 'exp'); + } + }.bindAsEventListener(this))); + } + + li.insert(div).insert(new Element('A', { id: fid + '_label', title: ob.l }).insert(ob.l)); + + // Now walk through the parent