Skip to content

Commit

Permalink
First attempt at providing visual feedback via autocomplete as to whi…
Browse files Browse the repository at this point in the history
…ch addresses are invalid

Not sure if I am sold on the architecture of this yet, but it is a
start.
  • Loading branch information
slusarz committed Oct 16, 2013
1 parent 4f37ae4 commit e82990c
Show file tree
Hide file tree
Showing 8 changed files with 156 additions and 10 deletions.
24 changes: 24 additions & 0 deletions imp/js/compose-base.js
Expand Up @@ -140,6 +140,30 @@ var ImpComposeBase = {
}

return val;
},

autocompleteHandlers: function()
{
var handlers = {};
$(document).fire('AutoComplete:handlers', handlers);
return handlers;
},

autocompleteItems: function()
{
var out = [];

$H(this.autocompleteHandlers()).each(function(pair) {
$H(pair.value.toObject()).each(function(pair2) {
out.push({
addr: pair2.value,
id: pair.key,
itemid: pair2.key
});
});
});

return out;
}

};
17 changes: 16 additions & 1 deletion imp/js/compose-dimp.js
Expand Up @@ -184,6 +184,7 @@ var DimpCompose = {
uniqueSubmit: function(action)
{
var c = (action == 'redirectMessage') ? $('redirect') : $('compose'),
form = $H(),
sc = ImpComposeBase.getSpellChecker();

if (sc && sc.isActive()) {
Expand All @@ -210,6 +211,8 @@ var DimpCompose = {
!window.confirm(DimpCore.text.nosubject)) {
return;
}

form.set('addr_ac', Object.toJSON(ImpComposeBase.autocompleteItems()));
// Fall-through

case 'saveDraft':
Expand Down Expand Up @@ -239,7 +242,7 @@ var DimpCompose = {

// Use an AJAX submit here so that we can do javascript-y stuff
// before having to close the window on success.
DimpCore.doAction(action, c.serialize(true), {
DimpCore.doAction(action, form.update(c.serialize(true)), {
ajaxopts: {
onFailure: this.uniqueSubmitFailure.bind(this)
},
Expand Down Expand Up @@ -318,6 +321,18 @@ var DimpCompose = {
this.old_action = d.action;
eval(d.encryptjs.join(';'));
}

$H(ImpComposeBase.autocompleteHandlers()).each(function(pair) {
$H(pair.value.toObject(true)).each(function(pair2) {
if (d.addr_ac &&
d.addr_ac[pair.key] &&
d.addr_ac[pair.key].indexOf(pair2.key) !== -1) {
pair2.value.addClassName('impACListItemBad');
} else {
pair2.value.removeClassName('impACListItemBad');
}
});
});
}

this.setDisabled(false);
Expand Down
26 changes: 23 additions & 3 deletions imp/js/prettyautocomplete.js
Expand Up @@ -3,9 +3,11 @@
* (completed elements are stored in separate DIV elements).
*
* Events handled by this class:
* - AutoCompleter:focus
* - AutoCompleter:reset
* - AutoCompleter:submit
* -----------------------------
* - AutoComplete:focus
* - AutoComplete:handlers
* - AutoComplete:reset
* - AutoComplete:submit
*
*
* Copyright 2008-2013 Horde LLC (http://www.horde.org/)
Expand All @@ -14,6 +16,7 @@
* did not receive this file, see http://www.horde.org/licenses/lgpl21.
*
* @author Michael J Rubinsky <mrubinsk@horde.org>
* @author Michael Slusarz <slusarz@horde.org>
*/
var IMP_PrettyAutocompleter = Class.create({

Expand All @@ -22,6 +25,8 @@ var IMP_PrettyAutocompleter = Class.create({
// input,
// lastinput,

itemid: 0,

initialize: function(elt, params)
{
var ac, active, p_clone;
Expand Down Expand Up @@ -106,6 +111,9 @@ var IMP_PrettyAutocompleter = Class.create({
e.stop();
}
}.bindAsEventListener(this));
document.observe('AutoComplete:handlers', function(e) {
e.memo[this.elt.identify()] = this;
}.bind(this));
document.observe('AutoComplete:reset', this.reset.bind(this));
document.observe('AutoComplete:submit', this.processInput.bind(this));
},
Expand Down Expand Up @@ -206,6 +214,7 @@ var IMP_PrettyAutocompleter = Class.create({
})
)
.store('raw', value)
.store('itemid', ++this.itemid)
});

// Add to hidden input field.
Expand Down Expand Up @@ -259,6 +268,17 @@ var IMP_PrettyAutocompleter = Class.create({
});
},

toObject: function(elt)
{
var ob = {};

this.currentEntries().each(function(c) {
ob[c.retrieve('itemid')] = elt ? c : c.retrieve('raw');
});

return ob;
},

/* Event handlers. */

clickHandler: function(e)
Expand Down
37 changes: 37 additions & 0 deletions imp/lib/Ajax/Application/Handler/Common.php
Expand Up @@ -469,6 +469,7 @@ public function cancelCompose()
*
* See the list of variables needed for
* IMP_Ajax_Application#composeSetup(). Additional variables used:
* - addr_ac: (string) TODO
* - encrypt: (integer) The encryption method to use (IMP ENCRYPT
* constants).
* - html: (integer) In HTML compose mode?
Expand Down Expand Up @@ -537,6 +538,10 @@ public function sendMessage()
)
);
$notification->push(empty($headers['subject']) ? _("Message sent successfully.") : sprintf(_("Message \"%s\" sent successfully."), Horde_String::truncate($headers['subject'])), 'horde.success');
} catch (IMP_Compose_Exception_Address $e) {
$this->_handleBadComposeAddr($e, $result);
$result->success = 0;
return $result;
} catch (IMP_Compose_Exception $e) {
$result->success = 0;

Expand Down Expand Up @@ -683,4 +688,36 @@ public function showMessage()
return $result;
}

/* Internal methods. */

/**
* Handle bad addresses entered during a compose.
*
* @param IMP_Compose_Exception_Address $e The address exception.
* @param object $result The return object.
*/
protected function _handleBadComposeAddr(
IMP_Compose_Exception_Address $e, $result
)
{
global $notification;

if ($this->vars->addr_ac) {
print $this->vars->addr_ac;
$addr_ac = json_decode($this->vars->addr_ac, true);
$result->addr_ac = array();
} else {
$addr_ac = array();
}

foreach ($e->addresses as $key => $val) {
$notification->push(sprintf(_("Invalid e-mail address (%s)."), $key), 'horde.warning');
foreach ($addr_ac as $val2) {
if ($key == $val2['addr']) {
$result->addr_ac[$val2['id']][] = $val2['itemid'];
}
}
}
}

}
16 changes: 13 additions & 3 deletions imp/lib/Compose.php
Expand Up @@ -698,6 +698,7 @@ public function hasDrafts()
*
* @throws Horde_Exception
* @throws IMP_Compose_Exception
* @throws IMP_Compose_Exception_Address
* @throws IMP_Exception
*/
public function buildAndSendMessage(
Expand Down Expand Up @@ -834,6 +835,8 @@ public function buildAndSendMessage(

/* Store history information. */
$sentmail->log($senttype, $headers->getValue('message-id'), $val['recipients'], true);
} catch (IMP_Compose_Exception_Address $e) {
throw $e;
} catch (IMP_Compose_Exception $e) {
/* Unsuccessful send. */
if ($e->log()) {
Expand Down Expand Up @@ -1157,11 +1160,12 @@ protected function _prepSendMessageAssert(Horde_Mail_Rfc822_List $email,
*
* @return string The encoded $email list.
*
* @throws IMP_Compose_Exception
* @throws IMP_Compose_Exception_Address
*/
protected function _prepSendMessageEncode(Horde_Mail_Rfc822_List $email,
$charset)
{
$exception = null;
$out = array();

foreach ($email as $val) {
Expand All @@ -1179,11 +1183,17 @@ protected function _prepSendMessageEncode(Horde_Mail_Rfc822_List $email,
IMP::parseAddressList($tmp, array(
'validate' => true
));
$out[] = $tmp;
} catch (Horde_Mail_Exception $e) {
throw new IMP_Compose_Exception(sprintf(_("Invalid e-mail address (%s)."), $val->writeAddress()));
if (is_null($exception)) {
$exception = new IMP_Compose_Exception_Address();
}
$exception->addresses[$val->writeAddress()] = $e;
}
}

$out[] = $tmp;
if ($exception) {
throw $exception;
}

return implode(', ', $out);
Expand Down
34 changes: 34 additions & 0 deletions imp/lib/Compose/Exception/Address.php
@@ -0,0 +1,34 @@
<?php
/**
* Copyright 2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file COPYING for license information (GPL). If you
* did not receive this file, see http://www.horde.org/licenses/gpl.
*
* @category Horde
* @copyright 2013 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*/

/**
* Extension of IMP_Compose_Exception that handles the situation of invalid
* address input. Allows details of individual e-mail address errors to be
* communicated to the user.
*
* @author Michael Slusarz <slusarz@horde.org>
* @category Horde
* @copyright 2013 Horde LLC
* @license http://www.horde.org/licenses/gpl GPL
* @package IMP
*/
class IMP_Compose_Exception_Address extends IMP_Compose_Exception
{
/**
* The list of addresses (keys) and Horde_Mail_Exception objects (values).
*
* @var array
*/
public $addresses = array();

}
8 changes: 5 additions & 3 deletions imp/package.xml
Expand Up @@ -22,7 +22,7 @@
<email>chuck@horde.org</email>
<active>yes</active>
</lead>
<date>2013-10-15</date>
<date>2013-10-16</date>
<version>
<release>6.2.0</release>
<api>6.1.0</api>
Expand Down Expand Up @@ -87,7 +87,6 @@
</dir> <!-- /js/ckeditor -->
<dir name="external">
<file name="base64.js" role="horde" />
<file name="mailcheck.js" role="horde" />
<file name="murmurhash3.js" role="horde" />
</dir> <!-- /js/external -->
<dir name="jquery.mobile">
Expand Down Expand Up @@ -186,6 +185,9 @@
<file name="Linked.php" role="horde" />
<file name="Storage.php" role="horde" />
</dir> <!-- /lib/Compose/Attachment -->
<dir name="Exception">
<file name="Address.php" role="horde" />
</dir> <!-- /lib/Compose/Exception -->
<file name="Attachment.php" role="horde" />
<file name="Exception.php" role="horde" />
<file name="Link.php" role="horde" />
Expand Down Expand Up @@ -1527,7 +1529,6 @@
<install as="imp/js/ckeditor/pasteattachment.js" name="js/ckeditor/pasteattachment.js" />
<install as="imp/js/ckeditor/pasteignore.js" name="js/ckeditor/pasteignore.js" />
<install as="imp/js/external/base64.js" name="js/external/base64.js" />
<install as="imp/js/external/mailcheck.js" name="js/external/mailcheck.js" />
<install as="imp/js/external/murmurhash3.js" name="js/external/murmurhash3.js" />
<install as="imp/js/jquery.mobile/plugins/listviewtaphold.js" name="js/jquery.mobile/plugins/listviewtaphold.js" />
<install as="imp/js/jquery.mobile/plugins/textchange.js" name="js/jquery.mobile/plugins/textchange.js" />
Expand Down Expand Up @@ -1606,6 +1607,7 @@
<install as="imp/lib/Compose/Attachment/Linked/Metadata.php" name="lib/Compose/Attachment/Linked/Metadata.php" />
<install as="imp/lib/Compose/Attachment/Storage/Vfs.php" name="lib/Compose/Attachment/Storage/Vfs.php" />
<install as="imp/lib/Compose/Attachment/Storage/VfsLinked.php" name="lib/Compose/Attachment/Storage/VfsLinked.php" />
<install as="imp/lib/Compose/Exception/Address.php" name="lib/Compose/Exception/Address.php" />
<install as="imp/lib/Contacts/Image.php" name="lib/Contacts/Image.php" />
<install as="imp/lib/Contacts/Avatar/Addressbook.php" name="lib/Contacts/Avatar/Addressbook.php" />
<install as="imp/lib/Contacts/Avatar/Backend.php" name="lib/Contacts/Avatar/Backend.php" />
Expand Down
4 changes: 4 additions & 0 deletions imp/themes/default/screen.css
Expand Up @@ -566,6 +566,10 @@ span.mimePartInfoSize {
.impACList li.hordeACListItem {
font-size: 100%;
}
.impACListItemBad {
background-color: #ff6347;
border: 1px solid darkred;
}
.impACItemRemove {
padding-left: 3px;
}
Expand Down

0 comments on commit e82990c

Please sign in to comment.