Skip to content

Commit

Permalink
Merge pull request #666 from henochit/feat-add-contact
Browse files Browse the repository at this point in the history
[Feat] Better workflow for adding contacts from emails
  • Loading branch information
kroky authored Oct 18, 2023
2 parents eff30c8 + 2a2a9e0 commit a528575
Show file tree
Hide file tree
Showing 8 changed files with 262 additions and 16 deletions.
2 changes: 2 additions & 0 deletions lib/output.php
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ public static function __callStatic(string $method, array $parameters)
public static $trash = 'data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20x%3D%220px%22%20y%3D%220px%22%0D%0Awidth%3D%228%22%20height%3D%228%22%0D%0AviewBox%3D%220%200%2024%2024%22%3E%0D%0A%20%20%20%20%3Cpath%20d%3D%22M%2010%202%20L%209%203%20L%204%203%20L%204%205%20L%207%205%20L%2017%205%20L%2020%205%20L%2020%203%20L%2015%203%20L%2014%202%20L%2010%202%20z%20M%205%207%20L%205%2022%20L%2019%2022%20L%2019%207%20L%205%207%20z%22%3E%3C%2Fpath%3E%0D%0A%3C%2Fsvg%3E';
public static $draft = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEI0lEQVR4nO2dTW7UQBCFn2BWLIEowClga0dhjTThEPkB8ZNkLpQhCgqKlKwQh2CFiJAYOAFixx6SRpZsaWK5Pe6Z7qrq7npSLazOOG1/rmq/GscBVCqVSqXyJ6OBIeeATAoECiTGi4BM3AdqIgkFAn4ICgT8Jz4aIAWAMuNxcUCqyW5kPE4m19TNNcjEfaAmkmAH0q6puW0baUDaNTW3bSMNiAYUiBF8IYjLEG4fUKgP6V9TchsnE3cpMJGEAgE/BFFAuH1AoT7kJhBuH1CqD+EvC0ZwsJcsDcgGwu0DCvUhsnxAqT5Ey5apz8EXiSUr1/gK4J4EINw+oBDgQy4B3O84Z485gHD7gJJ5+xuAtY7zNQFwDeCQGkjO8QPAQwuM5mcqKAcKBMFhzAA8WABjHso+V4Zw+4CCYHzDAcY8lLccQLh9QBl4vBqDI4x5KG+ogeRYpsYO+6igvFYg8LKAP7KcyNsA3jtCWbl82XbO7QMKgm3bmtGGcuoI5VUIINw+oAy8bVszqjI16oBy4gjlpW8gKcd3S5lqFvDzDii3ALyjWFNMhr2ptR4YTZzWmdGG8tERyl4oIBJ8QulhvKtRuGX5zEkHlGeOF8AVgN0QQFL1GajL07nlc8d1ZjTadwTSQNnBQJmMfcZQKJ8APK/L2p8l51BB2cYA5Qpj3LFw90HxERWUzWWBpOwzJj13UyGhHLXKnxOQVH3GpHWcVFAGwegDklNv6twC5YIaBjJbwEcAzhyg3AHwixKGCxApPsL0jK/am+qC8pkShguQWH3G2LE3dVFnRqWnAP5SwnABEvPXrmcdjvt2bfq69ve7fhbrHzUMZPQd+KmH3lRwGH1AYvYZWwF7U0Fh9AGJ1WdQ9KaCwYDndM2pN2VCwIgRyExQb8o7DBcgkn3GRHJvKhQQqT5jIr03FQoIZ8xi7k2lBmQWe2/KFxDJPiOq3pSrbL9cqs8Yx9abcpURGJcA1lPpTblKIoy7KfWmXDV0YlQ+Yz213pSrhk4u5eemjBQY8Jzey8Ys5d6Uq6TCGAvqTbXnEVS2ielzUzcvAnYg+twUbmQkOxCuMmWE9Kba5ZFMUmBI6k11rVVkGjrxXJ6bGlluHMg0dPI5PDc16rmLI5MhiBiemxotuKUmEzcMI6A3NcTfkMk2AYq/zzACelMNjOT/f8iy7w45JuxNzWfGojWQTIb5FUeGqTfl2oYhk28Y15ZX4D2px0JcACYwjOh9iC1DDomhHDnAEL+GrOpDbFAOiKAcOWZG0mtIEz8t7xR5ERjKtANGdff2YYV9kskkBmUaAEZSQPqg7HmGEgpGckAWQbkSDiNJICGhTAPDSBZIH5TdJaFQwCAFIkm7jlC6YKg8a2cgFIUhCMpUM4Ne2xYoCkMQlKlmhhwoU4UhR5sKQ6VSqcCt/0kPcucfMlnUAAAAAElFTkSuQmCC';

public static $arrow_drop_down = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDBWMHoiLz48cGF0aCBkPSJNNyAxMGw1IDUgNS01SDd6Ii8+PC9zdmc+';
public static $arrow_drop_up = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0Ij48cGF0aCBmaWxsPSJub25lIiBkPSJNMCAwaDI0djI0SDBWMHoiLz48cGF0aCBkPSJNNyAxNGw1LTUgNSA1SDd6Ii8+PC9zdmc+';
}

/**
Expand Down
21 changes: 17 additions & 4 deletions modules/contacts/hm-contacts.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,24 @@ public function add_contact($data) {
return true;
}

public function get($id, $default=false) {
if (!array_key_exists($id, $this->contacts)) {
return $default;
public function get($id, $default=false, $email_address=""){
if(array_key_exists($id, $this->contacts)) {
return $this->contacts[$id];
}
return $this->contacts[$id];

if(!empty($email_address)){
$res = false;
foreach ($this->contacts as $id => $contact) {
if ($contact->value('email_address') == $email_address) {
$res = $contact;
break;
}
}

return $res;
}

return $default;
}

public function search($flds) {
Expand Down
41 changes: 39 additions & 2 deletions modules/contacts/site.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,49 @@ var delete_contact = function(id, source, type) {
var add_contact_from_message_view = function() {
var contact = $('#add_contact').val();
var source = $('#contact_source').val();

if (contact) {
Hm_Ajax.request(
[
{ name: 'hm_ajax_hook', value: 'ajax_add_contact' },
{ name: 'contact_value', value: contact },
{ name: 'contact_source', value: source },
],
function (res) {
$('.add_contact_controls').toggle();
window.location.reload();
remove_message_content();
}
);
}
};

var add_contact_from_popup = function(event) {
event.stopPropagation()
var source = 'local:local';
var contact = $('#contact_info').text().replace('>','').replace('<','');


if (contact) {
var emailRegex = /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g;
var email = contact.match(emailRegex)[0];
var name = contact.replace(emailRegex, "");

var saveContactContent = `<div><table>
<tr><td><strong>Name :</strong></td><td>${name}</td></tr>
<tr><td><strong>Email :</strong></td><td>${email}</td></tr>
<tr><td><strong>Source :</strong></td><td>Local</td></tr>
</table></div>`

Hm_Ajax.request(
[{'name': 'hm_ajax_hook', 'value': 'ajax_add_contact'},
{'name': 'contact_value', 'value': contact},
{'name': 'contact_source', 'value': source}],
function(res) { $('.add_contact_controls').toggle(); }
function (res) {
$("#contact_popup_body").html(saveContactContent);
sessionStorage.removeItem(`${window.location.pathname}imap_4_${hm_list_path()}`);
sessionStorage.removeItem(`${window.location.pathname}${hm_msg_uid()}_${hm_list_path()}`);
}
);
}
};
Expand Down Expand Up @@ -60,7 +97,7 @@ var autocomplete_contact = function(e, class_name, list_div) {
$(list_div).html('');
for (i in res.contact_suggestions) {
var suggestion = JSON.parse(res.contact_suggestions[i].replace(/&quot;/g, '"'))

div.html(suggestion.contact);
if ($(class_name).val().match(div.text())) {
continue;
Expand Down
2 changes: 1 addition & 1 deletion modules/imap/functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ function imap_data_sources($callback, $custom=array()) {
}}

/**
* Prepare and format message list data
* Prepare and format message list data
* @subpackage imap/functions
* @param array $msgs list of message headers to format
* @param object $mod Hm_Output_Module
Expand Down
85 changes: 81 additions & 4 deletions modules/imap/output_modules.php
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,83 @@ protected function output() {
$value = sprintf('%s (%s)', $dt->format('c Z'), human_readable_interval($value));
} catch (Exception $e) {}
$txt .= '<tr class="header_'.$fld.'"><th>'.$this->trans($name).'</th><td>'.$this->html_safe($value).'</td></tr>';
}
elseif($fld == 'from'){

$regexp = '/\s*(.*[^\s])\s*<\s*(.*[^\s])\s*>/';

$contact_email = "";
$contact_name = "";

if(preg_match($regexp, $value, $matches)){
$contact_name = $matches[1];
$contact_email = $matches[2];
}else{
$EmailRegexp = "/[\._a-zA-Z0-9-]+@[\._a-zA-Z0-9-]+/i";
if(preg_match($EmailRegexp, $value, $matches)){
$contact_email = $matches[0][0];
}
}

$contact = ($this->get('contact_store'))->get(null, false, $contact_email);
$contact_exists = !empty($contact);

$txt .= '<tr class="header_'.$fld.'"><th>'.$this->trans($name).'
</th>
<td>
<div class="popup" onclick="imap_show_add_contact_popup(event)">
<span id="contact_info">' . $this->html_safe($value) . '
</span>
<img alt="" class="icon_arrow_up" src="'.Hm_Image_Sources::$arrow_drop_up.'" width="20" height="20" />
<img alt="" class="icon_arrow_down" src="'.Hm_Image_Sources::$arrow_drop_down.'" width="20" height="20" />
<div class="popup-container" id="contact_popup">
<div class="popup-container_header">
<a onclick="imap_show_add_contact_popup()">x</a>
</div>
<div id="contact_popup_body">';

if($contact_exists){
$txt .= '<div>
<table>
<tr>
<td><strong>Name :</strong></td>
<td>
'.$this->html_safe($contact->value('display_name')).'
</td>
</tr>
<tr>
<td><strong>Email :</strong></td>
<td>
'.$this->html_safe($contact->value('email_address')).'
</td>
</tr>
<tr>
<td><strong>Tel :</strong></td>
<td>
<a href="tel:'.$this->html_safe($contact->value('phone_number')).'">'.
$this->html_safe($contact->value('phone_number')).'</a>
</td>
</tr>
<tr>
<td><strong>Source :</strong></td>
<td>
'.$this->html_safe($contact->value('source')).'
</td>
</tr>
</table>
</div>';
} else {
$txt .= '<div class="popup-container_footer">
<button onclick="return add_contact_from_popup(event)" class="add_contact_btn" type="button" value="">'.$this->trans('Add local contacts').'
</button>
</div>';
}

$txt .= ' </div>
</div>
</div>
</td>
</tr>';
}
else {
if (strtolower($name) == 'flags') {
Expand Down Expand Up @@ -234,7 +311,7 @@ protected function output() {
if ($this->get('list_headers')) {
$txt .= format_list_headers($this);
}
$lc_headers = lc_headers($headers);
$lc_headers = lc_headers($headers);
if (array_key_exists('to', $lc_headers)) {
$addr_list = process_address_fld($lc_headers['to']);
$size = count($addr_list);
Expand All @@ -252,7 +329,7 @@ protected function output() {
});
$size += count($addr_list);
}

$txt .= '<tr><td class="header_space" colspan="2"></td></tr>';
$txt .= '<tr><th colspan="2" class="header_links">';
$txt .= '<div class="msg_move_to">'.
Expand Down Expand Up @@ -287,7 +364,7 @@ protected function output() {
$txt .= ' | <a class="delete_link hlink" id="delete_message" href="#">'.$this->trans('Delete').'</a>';
$txt .= ' | <a class="hlink" id="copy_message" href="#">'.$this->trans('Copy').'</a>';
$txt .= ' | <a class="hlink" id="move_message" href="#">'.$this->trans('Move').'</a>';
$txt .= ' | <a class="archive_link hlink" id="archive_message" href="#">'.$this->trans('Archive').'</a>';
$txt .= ' | <a class="archive_link hlink" id="archive_message" href="#">'.$this->trans('Archive').'</a>';
$txt .= ' | ' . snooze_dropdown($this, isset($headers['X-Snoozed']));

if ($this->get('sieve_filters_enabled')) {
Expand Down Expand Up @@ -379,7 +456,7 @@ protected function output() {
$default_value = '';
if (isset($vals['sieve_config_host'])) {
$default_value = $vals['sieve_config_host'];

$res .= '<span><label class="screen_reader" for="imap_sieve_host_'.$index.'">'.$this->trans('Sieve Host').'</label>'.
'<input '.$disabled.' id="imap_sieve_host_'.$index.'" class="credentials imap_sieve_host_input" placeholder="Sieve Host" type="text" name="imap_sieve_host" value="'.$default_value.'"></span>';
}
Expand Down
1 change: 1 addition & 0 deletions modules/imap/setup.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,3 +414,4 @@
)
);


105 changes: 105 additions & 0 deletions modules/imap/site.css
Original file line number Diff line number Diff line change
Expand Up @@ -111,3 +111,108 @@
.snooze_date_picker { display: block; padding: 8px 15px; color: #333; font-size: 1rem; cursor: pointer; }
.unsnooze { color: teal; }
.header_x-snoozed .unsnooze { margin-left: 20px; }


/* Popup container - can be anything you want */
.popup {
position: relative;
display: inline-block;
cursor: pointer;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
display: flex;
align-items: center;
}

/* The actual popup */
.popup > .popup-container {
visibility: hidden;
min-width: 250px;
background-color: #fff;
border: 1px #0000004d solid;
box-shadow: rgba(99, 99, 99, 0.2) 0px 2px 8px 0px;
border-radius: 6px;
padding: 5px 10px;
position: absolute;
z-index: 1;
top: 125%;
}

/* Popup arrow */
.popup > .popup-container::after {
content: "";
position: absolute;
bottom: 100%;
left: 50%;
margin-left: -5px;
border-width: 5px;
border-style: solid;
border-color: transparent transparent #555 transparent;
}

.popup > .icon_arrow_up {
display: none;
}

.popup > .icon_arrow_down {
display: block;
}


/* Toggle this class - hide and show the popup */
.show.popup-container {
visibility: visible;
-webkit-animation: fadeIn 1s;
animation: fadeIn 1s;
}

.show.icon_arrow_up {
display: block;
}

.show.icon_arrow_down {
display: none;
}

.popup-container_header {
display: flex;
justify-content: end;
margin-bottom: 10px;
}

.popup-container_footer {
display: flex;
justify-content: center;
}


/* Add animation (fade in the popup) */
@-webkit-keyframes fadeIn {
from {opacity: 0;}
to {opacity: 1;}
}

@keyframes fadeIn {
from {opacity: 0;}
to {opacity:1 ;}
}

@keyframes fadeOut {
0% { opacity: 1; }
100% { opacity: 0; }
}

.fade {
animation-duration: 0.5s;
animation-fill-mode: forwards;
}

.fade-out {
animation-name: fadeOut;
}

.fade-in {
animation-name: fadeIn;
}
Loading

0 comments on commit a528575

Please sign in to comment.