Fix crippled contact names (#1447)

This commit is contained in:
RainLoop 2017-09-27 20:58:15 +03:00
parent ed5685314e
commit d76fde37df
10 changed files with 123 additions and 257 deletions

View file

@ -494,7 +494,7 @@ class AppUser extends AbstractApp
if (item.userId) if (item.userId)
{ {
email.clear(); email.clear();
email.mailsoParse(item.userId.userid); email.parse(item.userId.userid);
if (email.validate()) if (email.validate())
{ {
aEmails.push(email.email); aEmails.push(email.email);

View file

@ -1517,14 +1517,14 @@ export function resizeAndCrop(url, value, fCallback)
/** /**
* @param {string} mailToUrl * @param {string} mailToUrl
* @param {Function} PopupComposeVoreModel * @param {Function} PopupComposeViewModel
* @returns {boolean} * @returns {boolean}
*/ */
export function mailToHelper(mailToUrl, PopupComposeVoreModel) export function mailToHelper(mailToUrl, PopupComposeViewModel)
{ {
if (mailToUrl && 'mailto:' === mailToUrl.toString().substr(0, 7).toLowerCase()) if (mailToUrl && 'mailto:' === mailToUrl.toString().substr(0, 7).toLowerCase())
{ {
if (!PopupComposeVoreModel) if (!PopupComposeViewModel)
{ {
return true; return true;
} }
@ -1540,28 +1540,22 @@ export function mailToHelper(mailToUrl, PopupComposeVoreModel)
const const
email = mailToUrl.replace(/\?.+$/, ''), email = mailToUrl.replace(/\?.+$/, ''),
query = mailToUrl.replace(/^[^\?]*\?/, ''), query = mailToUrl.replace(/^[^\?]*\?/, ''),
EmailModel = require('Model/Email').default, EmailModel = require('Model/Email').default;
emailObj = new EmailModel(),
fParseEmailLine = (line) => (line ? _.compact(_.map(decodeURIComponent(line).split(/[,]/), (item) => {
emailObj.clear();
emailObj.mailsoParse(item);
return '' !== emailObj.email ? emailObj : null;
})) : null);
to = fParseEmailLine(email); to = EmailModel.parseEmailLine(email);
params = simpleQueryParser(query); params = simpleQueryParser(query);
if (!isUnd(params.cc)) if (!isUnd(params.cc))
{ {
cc = fParseEmailLine(decodeURIComponent(params.cc)); cc = EmailModel.parseEmailLine(decodeURIComponent(params.cc));
} }
if (!isUnd(params.bcc)) if (!isUnd(params.bcc))
{ {
bcc = fParseEmailLine(decodeURIComponent(params.bcc)); bcc = EmailModel.parseEmailLine(decodeURIComponent(params.bcc));
} }
require('Knoin/Knoin').showScreenPopup(PopupComposeVoreModel, [ require('Knoin/Knoin').showScreenPopup(PopupComposeViewModel, [
ComposeType.Empty, null, to, cc, bcc, ComposeType.Empty, null, to, cc, bcc,
isUnd(params.subject) ? null : pString(decodeURIComponent(params.subject)), isUnd(params.subject) ? null : pString(decodeURIComponent(params.subject)),
isUnd(params.body) ? null : plainToHtml(pString(decodeURIComponent(params.body))) isUnd(params.body) ? null : plainToHtml(pString(decodeURIComponent(params.body)))

37
dev/External/ko.js vendored
View file

@ -884,6 +884,7 @@ ko.bindingHandlers.emailsTags = {
fValue = fValueAccessor(), fValue = fValueAccessor(),
fAllBindings = fAllBindingsAccessor(), fAllBindings = fAllBindingsAccessor(),
fAutoCompleteSource = fAllBindings.autoCompleteSource || null, fAutoCompleteSource = fAllBindings.autoCompleteSource || null,
inputDelimiters = [',', ';', '\n'],
fFocusCallback = (value) => { fFocusCallback = (value) => {
if (fValue && fValue.focused) if (fValue && fValue.focused)
{ {
@ -895,26 +896,26 @@ ko.bindingHandlers.emailsTags = {
parseOnBlur: true, parseOnBlur: true,
allowDragAndDrop: true, allowDragAndDrop: true,
focusCallback: fFocusCallback, focusCallback: fFocusCallback,
inputDelimiters: [',', ';', '\n'], inputDelimiters: inputDelimiters,
autoCompleteSource: fAutoCompleteSource, autoCompleteSource: fAutoCompleteSource,
// elementHook: (el, item) => { splitHook: (value) => {
// if (el && item) const v = Utils.trim(value);
// { if (v && -1 < inputDelimiters.indexOf(v.substr(-1))) {
// el.addClass('pgp'); return EmailModel.splitEmailLine(value);
// }
// },
parseHook: (input) => _.map(input, (inputValue) => {
const value = Utils.trim(inputValue);
if ('' !== value)
{
const email = new EmailModel();
email.mailsoParse(value);
return [email.toLine(false), email];
} }
return [value, null]; return null;
},
}), parseHook: (input) => _.map(
'change': (event) => { _.flatten(_.map(
input,
(inputValue) => {
const values = EmailModel.parseEmailLine(inputValue);
return values.length ? values : inputValue;
}
)),
(item) => (_.isObject(item) ? [item.toLine(false), item] : [item, null])
),
change: (event) => {
$el.data('EmailsTagsValue', event.target.value); $el.data('EmailsTagsValue', event.target.value);
fValue(event.target.value); fValue(event.target.value);
} }

View file

@ -1,5 +1,7 @@
import {trim, pString, encodeHtml} from 'Common/Utils'; import _ from '_';
import addressparser from 'emailjs-addressparser';
import {trim, encodeHtml, isNonEmptyArray} from 'Common/Utils';
class EmailModel class EmailModel
{ {
@ -34,46 +36,6 @@ class EmailModel
return email.initByJson(json) ? email : null; return email.initByJson(json) ? email : null;
} }
/**
* @static
* @param {string} line
* @param {string=} delimiter = ';'
* @returns {Array}
*/
static splitHelper(line, delimiter = ';') {
line = line.replace(/[\r\n]+/g, '; ').replace(/[\s]+/g, ' ');
let
index = 0,
len = 0,
at = false,
char = '',
result = '';
for (len = line.length; index < len; index++)
{
char = line.charAt(index);
switch (char)
{
case '@':
at = true;
break;
case ' ':
if (at)
{
at = false;
result += delimiter;
}
break;
// no default
}
result += char;
}
return result.split(delimiter);
}
/** /**
* @returns {void} * @returns {void}
*/ */
@ -118,32 +80,6 @@ class EmailModel
return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(query.toLowerCase()); return -1 < (this.name + ' ' + this.email).toLowerCase().indexOf(query.toLowerCase());
} }
/**
* @param {string} str
*/
parse(str) {
this.clear();
str = trim(str);
const
regex = /(?:"([^"]+)")? ?[<]?(.*?@[^>,]+)>?,? ?/g,
match = regex.exec(str);
if (match)
{
this.name = match[1] || '';
this.email = match[2] || '';
this.clearDuplicateName();
}
else if ((/^[^@]+@[^@]+$/).test(str))
{
this.name = '';
this.email = str;
}
}
/** /**
* @param {AjaxJsonEmail} oJsonEmail * @param {AjaxJsonEmail} oJsonEmail
* @returns {boolean} * @returns {boolean}
@ -212,165 +148,68 @@ class EmailModel
return result; return result;
} }
static splitEmailLine(line) {
const parsedResult = addressparser.parse(line);
if (isNonEmptyArray(parsedResult))
{
const result = [];
let exists = false;
parsedResult.forEach((item) => {
const address = item.address ? new EmailModel(
item.address.replace(/^[<]+(.*)[>]+$/g, '$1'),
item.name || ''
) : null;
if (address && address.email) {
exists = true;
}
result.push(address ? address.toLine(false) : item.name);
});
return exists ? result : null;
}
return null;
}
static parseEmailLine(line) {
const parsedResult = addressparser.parse(line);
if (isNonEmptyArray(parsedResult))
{
return _.compact(parsedResult.map(
(item) => (item.address ? new EmailModel(
item.address.replace(/^[<]+(.*)[>]+$/g, '$1'),
item.name || ''
) : null)
));
}
return [];
}
/** /**
* @param {string} $sEmailAddress * @param {string} emailAddress
* @returns {boolean} * @returns {boolean}
*/ */
mailsoParse($sEmailAddress) { parse(emailAddress) {
$sEmailAddress = trim($sEmailAddress); emailAddress = trim(emailAddress);
if ('' === $sEmailAddress) if ('' === emailAddress)
{ {
return false; return false;
} }
const substr = (str, start, len) => { const result = addressparser.parse(emailAddress);
str = pString(str); if (isNonEmptyArray(result) && result[0])
let end = str.length;
if (0 > start)
{
start += end;
}
end = 'undefined' === typeof len ? end : (0 > len ? len + end : len + start);
return start >= str.length || 0 > start || start > end ? false : str.slice(start, end);
};
const substrReplace = (str, replace, start, length) => {
str = pString(str);
if (0 > start)
{
start += str.length;
}
length = 'undefined' !== typeof length ? length : str.length;
if (0 > length)
{
length = length + str.length - start;
}
return str.slice(0, start) + replace.substr(0, length) + replace.slice(length) + str.slice(start + length);
};
let
$sName = '',
$sEmail = '',
$sComment = '',
$bInName = false,
$bInAddress = false,
$bInComment = false,
$aRegs = null,
$iStartIndex = 0,
$iEndIndex = 0,
$iCurrentIndex = 0;
while ($iCurrentIndex < $sEmailAddress.length)
{ {
switch ($sEmailAddress.substr($iCurrentIndex, 1)) this.name = result[0].name || '';
{ this.email = result[0].address || '';
case '"': this.clearDuplicateName();
if ((!$bInName) && (!$bInAddress) && (!$bInComment))
{
$bInName = true;
$iStartIndex = $iCurrentIndex;
}
else if ((!$bInAddress) && (!$bInComment))
{
$iEndIndex = $iCurrentIndex;
$sName = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInName = false;
}
break;
case '<':
if ((!$bInName) && (!$bInAddress) && (!$bInComment))
{
if (0 < $iCurrentIndex && 0 === $sName.length)
{
$sName = substr($sEmailAddress, 0, $iCurrentIndex);
}
$bInAddress = true; return true;
$iStartIndex = $iCurrentIndex;
}
break;
case '>':
if ($bInAddress)
{
$iEndIndex = $iCurrentIndex;
$sEmail = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInAddress = false;
}
break;
case '(':
if ((!$bInName) && (!$bInAddress) && (!$bInComment))
{
$bInComment = true;
$iStartIndex = $iCurrentIndex;
}
break;
case ')':
if ($bInComment)
{
$iEndIndex = $iCurrentIndex;
$sComment = substr($sEmailAddress, $iStartIndex + 1, $iEndIndex - $iStartIndex - 1);
$sEmailAddress = substrReplace($sEmailAddress, '', $iStartIndex, $iEndIndex - $iStartIndex + 1);
$iEndIndex = 0;
$iCurrentIndex = 0;
$iStartIndex = 0;
$bInComment = false;
}
break;
case '\\':
$iCurrentIndex += 1;
break;
// no default
}
$iCurrentIndex += 1;
} }
if (0 === $sEmail.length) return false;
{
$aRegs = $sEmailAddress.match(/[^@\s]+@\S+/i);
if ($aRegs && $aRegs[0])
{
$sEmail = $aRegs[0];
}
else
{
$sName = $sEmailAddress;
}
}
if (0 < $sEmail.length && 0 === $sName.length && 0 === $sComment.length)
{
$sName = $sEmailAddress.replace($sEmail, '');
}
$sEmail = trim($sEmail).replace(/^[<]+/, '').replace(/[>]+$/, '');
$sName = trim($sName).replace(/^["']+/, '').replace(/["']+$/, '');
$sComment = trim($sComment).replace(/^[(]+/, '').replace(/[)]+$/, '');
// Remove backslash
$sName = $sName.replace(/\\\\(.)/g, '$1');
$sComment = $sComment.replace(/\\\\(.)/g, '$1');
this.name = $sName;
this.email = $sEmail;
this.clearDuplicateName();
return true;
} }
} }

View file

@ -110,6 +110,8 @@ class ComposePopupView extends AbstractViewNext
this.replyTo = ko.observable(''); this.replyTo = ko.observable('');
this.replyTo.focused = ko.observable(false); this.replyTo.focused = ko.observable(false);
// this.to.subscribe((v) => console.log(v));
ko.computed(() => { ko.computed(() => {
switch (true) switch (true)
{ {

View file

@ -409,7 +409,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext
rec = rec.join(', ').split(','); rec = rec.join(', ').split(',');
rec = _.compact(_.map(rec, (value) => { rec = _.compact(_.map(rec, (value) => {
email.clear(); email.clear();
email.mailsoParse(trim(value)); email.parse(trim(value));
return '' === email.email ? false : email.email; return '' === email.email ? false : email.email;
})); }));

View file

@ -539,7 +539,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext
// fParseEmailLine = function(sLine) { // fParseEmailLine = function(sLine) {
// return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) { // return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) {
// var oEmailModel = new EmailModel(); // var oEmailModel = new EmailModel();
// oEmailModel.mailsoParse(sItem); // oEmailModel.parse(sItem);
// return '' !== oEmailModel.email ? oEmailModel : null; // return '' !== oEmailModel.email ? oEmailModel : null;
// })) : null; // })) : null;
// } // }

View file

@ -65,6 +65,7 @@
"classnames": "2.2.5", "classnames": "2.2.5",
"copy-webpack-plugin": "4.0.1", "copy-webpack-plugin": "4.0.1",
"element-dataset": "2.2.6", "element-dataset": "2.2.6",
"emailjs-addressparser": "1.0.1",
"es6-promise-polyfill": "1.2.0", "es6-promise-polyfill": "1.2.0",
"eslint": "4.7.2", "eslint": "4.7.2",
"eslint-plugin-compat": "1.0.4", "eslint-plugin-compat": "1.0.4",

View file

@ -218,14 +218,23 @@
parseInput : function(ev) { parseInput : function(ev) {
var widget = (ev && ev.data.widget) || this, var widget = (ev && ev.data.widget) || this,
val, val,
hook,
delimiterFound = false, delimiterFound = false,
values = []; values = [];
val = widget.elements.input.val(); val = widget.elements.input.val();
val && (delimiterFound = widget._containsDelimiter(val)); if (val) {
if ($.isFunction(widget.options.splitHook)) {
hook = widget.options.splitHook(val);
} else {
delimiterFound = widget._containsDelimiter(val);
}
}
if(delimiterFound !== false){ if (hook) {
values = hook;
} else if(delimiterFound !== false){
values = val.split(delimiterFound); values = val.split(delimiterFound);
} else if(!ev || ev.which === $.ui.keyCode.ENTER && !$('.ui-menu-item .ui-state-focus').size() && !$('#ui-active-menuitem').size()){ } else if(!ev || ev.which === $.ui.keyCode.ENTER && !$('.ui-menu-item .ui-state-focus').size() && !$('#ui-active-menuitem').size()){
values.push(val); values.push(val);
@ -456,7 +465,7 @@
v = $.trim(a[0]); v = $.trim(a[0]);
$.each(self._chosenValues, function(kk,vv) { $.each(self._chosenValues, function(kk, vv) {
if (vv.value === self.elements.lastEdit) if (vv.value === self.elements.lastEdit)
{ {
lastIndex = kk; lastIndex = kk;
@ -465,7 +474,7 @@
vv.value === v && (exists = true); vv.value === v && (exists = true);
}); });
if(v !== '' && (!exists || self.options.allowDuplicates)){ if(v !== '' && a && a[1] && (!exists || self.options.allowDuplicates)){
obj.key = 'mi_' + Math.random().toString( 16 ).slice( 2, 10 ); obj.key = 'mi_' + Math.random().toString( 16 ).slice( 2, 10 );
obj.value = v; obj.value = v;
@ -499,7 +508,7 @@
value = ''; value = '';
$.each(this._chosenValues, function(k,v) { $.each(this._chosenValues, function(k,v) {
value += value.length ? widget.options.outputDelimiter + v.value : v.value; value += value.length ? widget.options.outputDelimiter + v.value : v.value;
}); });
return value; return value;
@ -551,7 +560,9 @@
$.each(this._chosenValues, function(k, v) { $.each(this._chosenValues, function(k, v) {
var el = self._createTag(v.value, v.key, v.obj); var el = self._createTag(v.value, v.key, v.obj);
self.elements.ul.find('li.inputosaurus-input').before(el); if (el) {
self.elements.ul.find('li.inputosaurus-input').before(el);
}
}); });
}, },
@ -632,7 +643,17 @@
values = []; values = [];
values.push(val); values.push(val);
delim && (values = val.split(delim));
if (val) {
if ($.isFunction(this.options.splitHook)) {
var hook = this.options.splitHook(val);
if (hook) {
values = hook;
}
} else {
delim && (values = val.split(delim));
}
}
if (values.length) { if (values.length) {
this._chosenValues = []; this._chosenValues = [];

View file

@ -1698,6 +1698,14 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0" minimalistic-crypto-utils "^1.0.0"
email-addresses@3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.0.1.tgz#c1fc20c189e7f96d4012d375db5feaccdd24391c"
emailjs-addressparser@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/emailjs-addressparser/-/emailjs-addressparser-1.0.1.tgz#8b19b38f6ee67ba176a31a97f45678dc12e549cf"
emojis-list@^2.0.0: emojis-list@^2.0.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"