diff --git a/dev/App/User.js b/dev/App/User.js index 546aea389..6400c0b75 100644 --- a/dev/App/User.js +++ b/dev/App/User.js @@ -494,7 +494,7 @@ class AppUser extends AbstractApp if (item.userId) { email.clear(); - email.mailsoParse(item.userId.userid); + email.parse(item.userId.userid); if (email.validate()) { aEmails.push(email.email); diff --git a/dev/Common/Utils.js b/dev/Common/Utils.js index 7382a1f16..f2d12c4c0 100644 --- a/dev/Common/Utils.js +++ b/dev/Common/Utils.js @@ -1517,14 +1517,14 @@ export function resizeAndCrop(url, value, fCallback) /** * @param {string} mailToUrl - * @param {Function} PopupComposeVoreModel + * @param {Function} PopupComposeViewModel * @returns {boolean} */ -export function mailToHelper(mailToUrl, PopupComposeVoreModel) +export function mailToHelper(mailToUrl, PopupComposeViewModel) { if (mailToUrl && 'mailto:' === mailToUrl.toString().substr(0, 7).toLowerCase()) { - if (!PopupComposeVoreModel) + if (!PopupComposeViewModel) { return true; } @@ -1540,28 +1540,22 @@ export function mailToHelper(mailToUrl, PopupComposeVoreModel) const email = mailToUrl.replace(/\?.+$/, ''), query = mailToUrl.replace(/^[^\?]*\?/, ''), - 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); + EmailModel = require('Model/Email').default; - to = fParseEmailLine(email); + to = EmailModel.parseEmailLine(email); params = simpleQueryParser(query); if (!isUnd(params.cc)) { - cc = fParseEmailLine(decodeURIComponent(params.cc)); + cc = EmailModel.parseEmailLine(decodeURIComponent(params.cc)); } 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, isUnd(params.subject) ? null : pString(decodeURIComponent(params.subject)), isUnd(params.body) ? null : plainToHtml(pString(decodeURIComponent(params.body))) diff --git a/dev/External/ko.js b/dev/External/ko.js index 21b82c040..3ef28aa30 100644 --- a/dev/External/ko.js +++ b/dev/External/ko.js @@ -884,6 +884,7 @@ ko.bindingHandlers.emailsTags = { fValue = fValueAccessor(), fAllBindings = fAllBindingsAccessor(), fAutoCompleteSource = fAllBindings.autoCompleteSource || null, + inputDelimiters = [',', ';', '\n'], fFocusCallback = (value) => { if (fValue && fValue.focused) { @@ -895,26 +896,26 @@ ko.bindingHandlers.emailsTags = { parseOnBlur: true, allowDragAndDrop: true, focusCallback: fFocusCallback, - inputDelimiters: [',', ';', '\n'], + inputDelimiters: inputDelimiters, autoCompleteSource: fAutoCompleteSource, - // elementHook: (el, item) => { - // if (el && item) - // { - // el.addClass('pgp'); - // } - // }, - parseHook: (input) => _.map(input, (inputValue) => { - const value = Utils.trim(inputValue); - if ('' !== value) - { - const email = new EmailModel(); - email.mailsoParse(value); - return [email.toLine(false), email]; + splitHook: (value) => { + const v = Utils.trim(value); + if (v && -1 < inputDelimiters.indexOf(v.substr(-1))) { + return EmailModel.splitEmailLine(value); } - return [value, null]; - - }), - 'change': (event) => { + return null; + }, + parseHook: (input) => _.map( + _.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); fValue(event.target.value); } diff --git a/dev/Model/Email.js b/dev/Model/Email.js index 830b2acb3..d6071f02a 100644 --- a/dev/Model/Email.js +++ b/dev/Model/Email.js @@ -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 { @@ -34,46 +36,6 @@ class EmailModel 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} */ @@ -118,32 +80,6 @@ class EmailModel 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 * @returns {boolean} @@ -212,165 +148,68 @@ class EmailModel 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} */ - mailsoParse($sEmailAddress) { - $sEmailAddress = trim($sEmailAddress); - if ('' === $sEmailAddress) + parse(emailAddress) { + emailAddress = trim(emailAddress); + if ('' === emailAddress) { return false; } - const substr = (str, start, len) => { - str = pString(str); - 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) + const result = addressparser.parse(emailAddress); + if (isNonEmptyArray(result) && result[0]) { - switch ($sEmailAddress.substr($iCurrentIndex, 1)) - { - case '"': - 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); - } + this.name = result[0].name || ''; + this.email = result[0].address || ''; + this.clearDuplicateName(); - $bInAddress = 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; + return true; } - if (0 === $sEmail.length) - { - $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; + return false; } } diff --git a/dev/View/Popup/Compose.js b/dev/View/Popup/Compose.js index 48e39e4df..1ff83d327 100644 --- a/dev/View/Popup/Compose.js +++ b/dev/View/Popup/Compose.js @@ -110,6 +110,8 @@ class ComposePopupView extends AbstractViewNext this.replyTo = ko.observable(''); this.replyTo.focused = ko.observable(false); + // this.to.subscribe((v) => console.log(v)); + ko.computed(() => { switch (true) { diff --git a/dev/View/Popup/ComposeOpenPgp.js b/dev/View/Popup/ComposeOpenPgp.js index 0324c098b..7c126ab05 100644 --- a/dev/View/Popup/ComposeOpenPgp.js +++ b/dev/View/Popup/ComposeOpenPgp.js @@ -409,7 +409,7 @@ class ComposeOpenPgpPopupView extends AbstractViewNext rec = rec.join(', ').split(','); rec = _.compact(_.map(rec, (value) => { email.clear(); - email.mailsoParse(trim(value)); + email.parse(trim(value)); return '' === email.email ? false : email.email; })); diff --git a/dev/View/User/MailBox/MessageView.js b/dev/View/User/MailBox/MessageView.js index abe8b950d..0a894fce3 100644 --- a/dev/View/User/MailBox/MessageView.js +++ b/dev/View/User/MailBox/MessageView.js @@ -539,7 +539,7 @@ class MessageViewMailBoxUserView extends AbstractViewNext // fParseEmailLine = function(sLine) { // return sLine ? _.compact(_.map([window.decodeURIComponent(sLine)], function(sItem) { // var oEmailModel = new EmailModel(); - // oEmailModel.mailsoParse(sItem); + // oEmailModel.parse(sItem); // return '' !== oEmailModel.email ? oEmailModel : null; // })) : null; // } diff --git a/package.json b/package.json index cc98964ed..c79871aa2 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "classnames": "2.2.5", "copy-webpack-plugin": "4.0.1", "element-dataset": "2.2.6", + "emailjs-addressparser": "1.0.1", "es6-promise-polyfill": "1.2.0", "eslint": "4.7.2", "eslint-plugin-compat": "1.0.4", diff --git a/vendors/inputosaurus/inputosaurus.js b/vendors/inputosaurus/inputosaurus.js index 08a15b8d9..a10c70d37 100644 --- a/vendors/inputosaurus/inputosaurus.js +++ b/vendors/inputosaurus/inputosaurus.js @@ -218,14 +218,23 @@ parseInput : function(ev) { var widget = (ev && ev.data.widget) || this, val, + hook, delimiterFound = false, values = []; 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); } else if(!ev || ev.which === $.ui.keyCode.ENTER && !$('.ui-menu-item .ui-state-focus').size() && !$('#ui-active-menuitem').size()){ values.push(val); @@ -456,7 +465,7 @@ v = $.trim(a[0]); - $.each(self._chosenValues, function(kk,vv) { + $.each(self._chosenValues, function(kk, vv) { if (vv.value === self.elements.lastEdit) { lastIndex = kk; @@ -465,7 +474,7 @@ 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.value = v; @@ -499,7 +508,7 @@ value = ''; $.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; @@ -551,7 +560,9 @@ $.each(this._chosenValues, function(k, v) { 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.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) { this._chosenValues = []; diff --git a/yarn.lock b/yarn.lock index 8968f0a6a..98d09c103 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1698,6 +1698,14 @@ elliptic@^6.0.0: minimalistic-assert "^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: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"