mirror of
https://github.com/the-djmaze/snappymail.git
synced 2024-09-20 07:35:55 +08:00
Embed cleaner node modules
This commit is contained in:
parent
e7180a86ce
commit
aaf4933b0a
16
README.md
16
README.md
|
@ -75,23 +75,23 @@ Things might work in Edge 15-18, Firefox 47-62 and Chrome 54-68 due to one polyf
|
|||
|
||||
|js/* |1.14.0 |native |gzip 1.14 |gzip |
|
||||
|----------- |--------: |--------: |--------: |--------: |
|
||||
|admin.js |2.130.942 |1.172.413 | 485.481 | 291.715 |
|
||||
|app.js |4.184.455 |2.888.668 | 932.725 | 682.438 |
|
||||
|boot.js | 671.522 | 44.394 | 169.502 | 15.460 |
|
||||
|admin.js |2.130.942 |1.133.275 | 485.481 | 274.632 |
|
||||
|app.js |4.184.455 |2.844.189 | 932.725 | 664.075 |
|
||||
|boot.js | 671.522 | 44.029 | 169.502 | 15.460 |
|
||||
|libs.js | 647.614 | 431.049 | 194.728 | 132.315 |
|
||||
|polyfills.js | 325.834 | 0 | 71.825 | 0 |
|
||||
|TOTAL js |7.960.367 |4.537.200 |1.854.261 |1.121.928 |
|
||||
|TOTAL js |7.960.367 |4.452.542 |1.854.261 |1.086.482 |
|
||||
|
||||
|js/min/* |1.14.0 |native |gzip 1.14 |gzip |
|
||||
|--------------- |--------: |--------: |--------: |--------: |
|
||||
|admin.min.js | 252.147 | 153.689 | 73.657 | 44.000 |
|
||||
|app.min.js | 511.202 | 380.294 |140.462 |100.236 |
|
||||
|admin.min.js | 252.147 | 153.095 | 73.657 | 43.734 |
|
||||
|app.min.js | 511.202 | 378.695 |140.462 | 99.511 |
|
||||
|boot.min.js | 66.007 | 5.589 | 22.567 | 2.333 |
|
||||
|libs.min.js | 572.545 | 387.636 |176.720 |122.519 |
|
||||
|polyfills.min.js | 32.452 | 0 | 11.312 | 0 |
|
||||
|TOTAL js/min |1.434.353 | 927.208 |424.718 |269.088 |
|
||||
|TOTAL js/min |1.434.353 | 925.015 |424.718 |268.097 |
|
||||
|
||||
507.145 bytes (155.630 gzip) is not much, but it feels faster.
|
||||
509.338 bytes (156.621 gzip) is not much, but it feels faster.
|
||||
|
||||
|
||||
|css/* |1.14.0 |native |
|
||||
|
|
|
@ -1,6 +1,114 @@
|
|||
import Cookies from 'js-cookie';
|
||||
import { CLIENT_SIDE_STORAGE_INDEX_NAME } from 'Common/Consts';
|
||||
|
||||
var Cookies = (() => {
|
||||
function extend (...args) {
|
||||
var result = {};
|
||||
args.forEach(attributes => {
|
||||
for (var key in attributes) {
|
||||
result[key] = attributes[key];
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
function decode (s) {
|
||||
return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent);
|
||||
}
|
||||
|
||||
function set (key, value, attributes) {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
attributes = extend({
|
||||
path: '/'
|
||||
}, attributes);
|
||||
|
||||
if (typeof attributes.expires === 'number') {
|
||||
attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5);
|
||||
}
|
||||
|
||||
// We're using "expires" because "max-age" is not supported by IE
|
||||
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||
|
||||
try {
|
||||
var result = JSON.stringify(value);
|
||||
if (/^[{[]/.test(result)) {
|
||||
value = result;
|
||||
}
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
value = encodeURIComponent(String(value))
|
||||
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||
|
||||
key = encodeURIComponent(String(key))
|
||||
.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent)
|
||||
.replace(/[()]/g, escape);
|
||||
|
||||
var stringifiedAttributes = '';
|
||||
for (var attributeName in attributes) {
|
||||
if (!attributes[attributeName]) {
|
||||
continue;
|
||||
}
|
||||
stringifiedAttributes += '; ' + attributeName;
|
||||
if (attributes[attributeName] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Considers RFC 6265 section 5.2:
|
||||
// ...
|
||||
// 3. If the remaining unparsed-attributes contains a %x3B (";")
|
||||
// character:
|
||||
// Consume the characters of the unparsed-attributes up to,
|
||||
// not including, the first %x3B (";") character.
|
||||
// ...
|
||||
stringifiedAttributes += '=' + attributes[attributeName].split(';')[0];
|
||||
}
|
||||
|
||||
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||
}
|
||||
|
||||
function get (key) {
|
||||
if (typeof document === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
var jar = {};
|
||||
// To prevent the for loop in the first place assign an empty array
|
||||
// in case there are no cookies at all.
|
||||
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||
var i = 0;
|
||||
|
||||
for (; i < cookies.length; i++) {
|
||||
var parts = cookies[i].split('=');
|
||||
var cookie = parts.slice(1).join('=');
|
||||
|
||||
try {
|
||||
var name = decode(parts[0]);
|
||||
cookie = decode(cookie);
|
||||
|
||||
try {
|
||||
cookie = JSON.parse(cookie);
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
|
||||
jar[name] = cookie;
|
||||
|
||||
if (key === name) {
|
||||
break;
|
||||
}
|
||||
} catch (e) {} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
return key ? jar[key] : jar;
|
||||
}
|
||||
|
||||
return {
|
||||
set: set,
|
||||
getJSON: key => get(key)
|
||||
};
|
||||
})();
|
||||
|
||||
|
||||
class CookieDriver {
|
||||
/**
|
||||
* @param {string} key
|
||||
|
|
|
@ -1,6 +1,267 @@
|
|||
import addressparser from 'emailjs-addressparser';
|
||||
import { encodeHtml, isNonEmptyArray } from 'Common/Utils';
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Parses structured e-mail addresses from an address field
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* "Name <address@domain>"
|
||||
*
|
||||
* will be converted to
|
||||
*
|
||||
* [{name: "Name", address: "address@domain"}]
|
||||
*
|
||||
* @param {String} str Address field
|
||||
* @return {Array} An array of address objects
|
||||
*/
|
||||
function addressparser(str) {
|
||||
var tokenizer = new Tokenizer(str);
|
||||
var tokens = tokenizer.tokenize();
|
||||
var addresses = [];
|
||||
var address = [];
|
||||
var parsedAddresses = [];
|
||||
|
||||
tokens.forEach(token => {
|
||||
if (token.type === 'operator' && (token.value === ',' || token.value === ';')) {
|
||||
if (address.length) {
|
||||
addresses.push(address);
|
||||
}
|
||||
address = [];
|
||||
} else {
|
||||
address.push(token);
|
||||
}
|
||||
});
|
||||
|
||||
if (address.length) {
|
||||
addresses.push(address);
|
||||
}
|
||||
|
||||
addresses.forEach(address => {
|
||||
address = _handleAddress(address);
|
||||
if (address.length) {
|
||||
parsedAddresses = parsedAddresses.concat(address);
|
||||
}
|
||||
});
|
||||
|
||||
return parsedAddresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts tokens for a single address into an address object
|
||||
*
|
||||
* @param {Array} tokens Tokens object
|
||||
* @return {Object} Address object
|
||||
*/
|
||||
function _handleAddress(tokens) {
|
||||
var isGroup = false;
|
||||
var state = 'text';
|
||||
var address = void 0;
|
||||
var addresses = [];
|
||||
var data = {
|
||||
address: [],
|
||||
comment: [],
|
||||
group: [],
|
||||
text: []
|
||||
|
||||
// Filter out <addresses>, (comments) and regular text
|
||||
};
|
||||
for (var i = 0, len = tokens.length; i < len; i++) {
|
||||
var token = tokens[i];
|
||||
|
||||
if (token.type === 'operator') {
|
||||
switch (token.value) {
|
||||
case '<':
|
||||
state = 'address';
|
||||
break;
|
||||
case '(':
|
||||
state = 'comment';
|
||||
break;
|
||||
case ':':
|
||||
state = 'group';
|
||||
isGroup = true;
|
||||
break;
|
||||
default:
|
||||
state = 'text';
|
||||
}
|
||||
} else {
|
||||
if (token.value) {
|
||||
data[state].push(token.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there is no text but a comment, replace the two
|
||||
if (!data.text.length && data.comment.length) {
|
||||
data.text = data.comment;
|
||||
data.comment = [];
|
||||
}
|
||||
|
||||
if (isGroup) {
|
||||
// http://tools.ietf.org/html/rfc2822#appendix-A.1.3
|
||||
data.text = data.text.join(' ');
|
||||
addresses.push({
|
||||
name: data.text || address && address.name,
|
||||
group: data.group.length ? addressparser(data.group.join(',')) : []
|
||||
});
|
||||
} else {
|
||||
// If no address was found, try to detect one from regular text
|
||||
if (!data.address.length && data.text.length) {
|
||||
for (var _i = data.text.length - 1; _i >= 0; _i--) {
|
||||
if (data.text[_i].match(/^[^@\s]+@[^@\s]+$/)) {
|
||||
data.address = data.text.splice(_i, 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var _regexHandler = function _regexHandler(address) {
|
||||
if (!data.address.length) {
|
||||
data.address = [address.trim()];
|
||||
return ' ';
|
||||
}
|
||||
return address;
|
||||
};
|
||||
|
||||
// still no address
|
||||
if (!data.address.length) {
|
||||
for (var _i2 = data.text.length - 1; _i2 >= 0; _i2--) {
|
||||
data.text[_i2] = data.text[_i2].replace(/\s*\b[^@\s]+@[^@\s]+\b\s*/, _regexHandler).trim();
|
||||
if (data.address.length) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If there's still is no text but a comment exixts, replace the two
|
||||
if (!data.text.length && data.comment.length) {
|
||||
data.text = data.comment;
|
||||
data.comment = [];
|
||||
}
|
||||
|
||||
// Keep only the first address occurence, push others to regular text
|
||||
if (data.address.length > 1) {
|
||||
data.text = data.text.concat(data.address.splice(1));
|
||||
}
|
||||
|
||||
// Join values with spaces
|
||||
data.text = data.text.join(' ');
|
||||
data.address = data.address.join(' ');
|
||||
|
||||
if (!data.address && isGroup) {
|
||||
return [];
|
||||
}
|
||||
address = {
|
||||
address: data.address || data.text || '',
|
||||
name: data.text || data.address || ''
|
||||
};
|
||||
|
||||
if (address.address === address.name) {
|
||||
if ((address.address || '').match(/@/)) {
|
||||
address.name = '';
|
||||
} else {
|
||||
address.address = '';
|
||||
}
|
||||
}
|
||||
|
||||
addresses.push(address);
|
||||
}
|
||||
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/*
|
||||
* Operator tokens and which tokens are expected to end the sequence
|
||||
*/
|
||||
var OPERATORS = {
|
||||
'"': '"',
|
||||
'(': ')',
|
||||
'<': '>',
|
||||
',': '',
|
||||
// Groups are ended by semicolons
|
||||
':': ';',
|
||||
// Semicolons are not a legal delimiter per the RFC2822 grammar other
|
||||
// than for terminating a group, but they are also not valid for any
|
||||
// other use in this context. Given that some mail clients have
|
||||
// historically allowed the semicolon as a delimiter equivalent to the
|
||||
// comma in their UI, it makes sense to treat them the same as a comma
|
||||
// when used outside of a group.
|
||||
';': ''
|
||||
};
|
||||
|
||||
class Tokenizer
|
||||
{
|
||||
constructor(str) {
|
||||
this.str = (str || '').toString();
|
||||
this.operatorCurrent = '';
|
||||
this.operatorExpecting = '';
|
||||
this.node = null;
|
||||
this.escaped = false;
|
||||
this.list = [];
|
||||
}
|
||||
|
||||
tokenize() {
|
||||
var list = [], i = this.str.length;
|
||||
while (i--) this.checkChar(this.str[i]);
|
||||
|
||||
this.list.forEach(node => {
|
||||
node.value = (node.value || '').toString().trim();
|
||||
if (node.value) {
|
||||
list.push(node);
|
||||
}
|
||||
});
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
checkChar(chr) {
|
||||
if ((chr in OPERATORS || chr === '\\') && this.escaped) {
|
||||
this.escaped = false;
|
||||
} else if (this.operatorExpecting && chr === this.operatorExpecting) {
|
||||
this.node = {
|
||||
type: 'operator',
|
||||
value: chr
|
||||
};
|
||||
this.list.push(this.node);
|
||||
this.node = null;
|
||||
this.operatorExpecting = '';
|
||||
this.escaped = false;
|
||||
return;
|
||||
} else if (!this.operatorExpecting && chr in OPERATORS) {
|
||||
this.node = {
|
||||
type: 'operator',
|
||||
value: chr
|
||||
};
|
||||
this.list.push(this.node);
|
||||
this.node = null;
|
||||
this.operatorExpecting = OPERATORS[chr];
|
||||
this.escaped = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.escaped && chr === '\\') {
|
||||
this.escaped = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.node) {
|
||||
this.node = {
|
||||
type: 'text',
|
||||
value: ''
|
||||
};
|
||||
this.list.push(this.node);
|
||||
}
|
||||
|
||||
if (this.escaped && chr !== '\\') {
|
||||
this.node.value += '\\';
|
||||
}
|
||||
|
||||
this.node.value += chr;
|
||||
this.escaped = false;
|
||||
}
|
||||
}
|
||||
|
||||
class EmailModel {
|
||||
email = '';
|
||||
name = '';
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import ko from 'ko';
|
||||
import classnames from 'classnames';
|
||||
|
||||
import { MessagePriority, SignedVerifyStatus } from 'Common/Enums';
|
||||
import { i18n } from 'Common/Translator';
|
||||
|
@ -456,7 +455,8 @@ class MessageModel extends AbstractModel {
|
|||
* @return string
|
||||
*/
|
||||
lineAsCss() {
|
||||
return classnames({
|
||||
let classes = [];
|
||||
Object.entries({
|
||||
'deleted': this.deleted(),
|
||||
'deleted-mark': this.deletedMark(),
|
||||
'selected': this.selected(),
|
||||
|
@ -473,7 +473,8 @@ class MessageModel extends AbstractModel {
|
|||
// 'hasChildrenMessage': 1 < this.threadsLen(),
|
||||
'hasUnseenSubMessage': this.hasUnseenSubMessage(),
|
||||
'hasFlaggedSubMessage': this.hasFlaggedSubMessage()
|
||||
});
|
||||
}).forEach(([key, value]) => value && classes.push(key));
|
||||
return classes.join(' ');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -55,10 +55,8 @@
|
|||
"autolinker": "3.13.0",
|
||||
"babel-eslint": "10.1.0",
|
||||
"babel-loader": "8.0.6",
|
||||
"classnames": "2.2.6",
|
||||
"copy-webpack-plugin": "5.1.1",
|
||||
"css-loader": "3.4.2",
|
||||
"emailjs-addressparser": "2.0.2",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-config-prettier": "6.10.0",
|
||||
"eslint-plugin-prettier": "3.1.2",
|
||||
|
@ -89,7 +87,6 @@
|
|||
"gulp-zip": "5.0.1",
|
||||
"ifvisible.js": "1.0.6",
|
||||
"jquery": "^3.5.1",
|
||||
"js-cookie": "2.2.1",
|
||||
"knockout": "3.4.2",
|
||||
"knockout-sortable": "1.2.0",
|
||||
"moment": "2.24.0",
|
||||
|
|
|
@ -1856,10 +1856,6 @@ class-utils@^0.3.5:
|
|||
isobject "^3.0.0"
|
||||
static-extend "^0.1.1"
|
||||
|
||||
classnames@2.2.6:
|
||||
version "2.2.6"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||
|
||||
clean-css@4.2.3:
|
||||
version "4.2.3"
|
||||
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.3.tgz#507b5de7d97b48ee53d84adb0160ff6216380f78"
|
||||
|
|
Loading…
Reference in a new issue