Skip to content

Commit 6fc33b5

Browse files
committed
feat: break long words, remove large width settings
1 parent 408dc6d commit 6fc33b5

9 files changed

Lines changed: 119 additions & 18 deletions

analysis_options.yaml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ linter:
9292
- prefer_const_literals_to_create_immutables
9393
- prefer_constructors_over_static_methods
9494
- prefer_contains
95-
- prefer_equal_for_default_values
9695
- prefer_expression_function_bodies
9796
- prefer_final_fields
9897
- prefer_final_in_for_each

lib/src/dom/dark_mode_transformer.dart

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ class DarkModeTransformer extends DomTransformer {
1414
if (configuration.enableDarkMode) {
1515
ensureDocumentHeadIsAvailable(document);
1616
final style = Element.html(
17-
'<style type="text/css">body {color: #FFFFFF; margin: 4px;}</style>');
18-
document.head!.append(style);
17+
'<style type="text/css">body {color: #FFFFFF; margin: 4px;}</style>',
18+
);
19+
document.head?.append(style);
1920
}
2021
}
2122
}

lib/src/dom/image_transformers.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,11 @@ class ImageTransformer extends DomTransformer {
1212
const ImageTransformer();
1313

1414
@override
15-
void process(Document document, MimeMessage message,
16-
TransformConfiguration configuration) {
15+
void process(
16+
Document document,
17+
MimeMessage message,
18+
TransformConfiguration configuration,
19+
) {
1720
final imageElements = document.getElementsByTagName('img');
1821
final usedContentIds = <String>[];
1922
for (final imageElement in imageElements) {

lib/src/dom/link_transformers.dart

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,11 @@ class EnsureRelationNoreferrerTransformer extends DomTransformer {
99
const EnsureRelationNoreferrerTransformer();
1010

1111
@override
12-
void process(Document document, MimeMessage message,
13-
TransformConfiguration configuration) {
12+
void process(
13+
Document document,
14+
MimeMessage message,
15+
TransformConfiguration configuration,
16+
) {
1417
final linkElements = document.getElementsByTagName('a');
1518
for (final linkElement in linkElements) {
1619
linkElement.attributes['rel'] = 'noopener noreferrer';

lib/src/dom/meta_transformers.dart

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ class ViewPortTransformer extends DomTransformer {
1515
Element.html('<meta name="viewport" content="$_viewPortContent">');
1616
static final Element _contentTypeMetaElement = Element.html(
1717
'<meta http-equiv="Content-Type" content="text/html; charset=utf-8">');
18-
static final Element _wordWrapStyleElement =
19-
Element.html('<style type="text/css">* {word-wrap: break-word;}</style>');
18+
static final Element _wordWrapStyleElement = Element.html(
19+
'<style type="text/css">* {word-wrap: break-word; word-break: break-word;}</style>');
2020

2121
@override
22-
void process(Document document, MimeMessage message,
23-
TransformConfiguration configuration) {
22+
void process(
23+
Document document,
24+
MimeMessage message,
25+
TransformConfiguration configuration,
26+
) {
2427
final metaElements = document.getElementsByTagName('meta');
2528
var viewportNeedsToBeAdded = true;
2629
var contentTypeNeedsToBeAdded = true;

lib/src/dom/script_transformers.dart

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,14 @@ import '../enough_mail_html_base.dart';
55

66
/// Removes script references from a DOM
77
class RemoveScriptTransformer extends DomTransformer {
8-
/// Craetes a new script removing transformer
8+
/// Creates a new script removing transformer
99
const RemoveScriptTransformer();
1010
@override
11-
void process(Document document, MimeMessage message,
12-
TransformConfiguration configuration) {
11+
void process(
12+
Document document,
13+
MimeMessage message,
14+
TransformConfiguration configuration,
15+
) {
1316
final scriptElements = document.getElementsByTagName('script');
1417
for (final scriptElement in scriptElements) {
1518
scriptElement.remove();
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import 'package:enough_mail/mime.dart';
2+
import 'package:html/dom.dart';
3+
4+
import '../enough_mail_html_base.dart';
5+
6+
/// Removes any width attributes that are larger than the maxWidth
7+
class WidthTransformer extends DomTransformer {
8+
/// Creates a [WidthTransformer]
9+
const WidthTransformer();
10+
11+
@override
12+
void process(
13+
Document document,
14+
MimeMessage message,
15+
TransformConfiguration configuration,
16+
) {
17+
final body = document.body;
18+
if (body != null) {
19+
_processElement(body, message, configuration);
20+
}
21+
final styleElements = document.getElementsByTagName('style');
22+
for (final styleElement in styleElements) {
23+
var text = styleElement.text;
24+
int startIndex;
25+
while ((startIndex = text.indexOf('-webkit-background-size:')) != -1) {
26+
final endIndex =
27+
text.indexOf(';', startIndex + '-webkit-background-size:'.length);
28+
if (endIndex == -1) {
29+
break;
30+
}
31+
text = startIndex == 0
32+
? text.substring(endIndex + 1)
33+
: text.substring(0, startIndex) + text.substring(endIndex + 1);
34+
}
35+
styleElement.text = text;
36+
}
37+
}
38+
39+
void _processElement(
40+
Element element,
41+
MimeMessage message,
42+
TransformConfiguration configuration,
43+
) {
44+
final widthAttribute = element.attributes['width'];
45+
if (widthAttribute != null) {
46+
final width = int.tryParse(widthAttribute);
47+
if (width != null) {
48+
final maxWidth = configuration.attributeWidthMax;
49+
if (width > maxWidth) {
50+
element.attributes.remove('width');
51+
}
52+
}
53+
}
54+
final styleAttribute = element.attributes['style'];
55+
if (styleAttribute != null) {
56+
final widthIndex = styleAttribute.indexOf('width:');
57+
if (widthIndex != -1) {
58+
final semicolonIndex =
59+
styleAttribute.indexOf(';', widthIndex + 'width:'.length);
60+
if (semicolonIndex != -1) {
61+
final newStyleAttribute = widthIndex == 0
62+
? styleAttribute.substring(semicolonIndex + 1)
63+
: styleAttribute.substring(0, widthIndex) +
64+
styleAttribute.substring(semicolonIndex + 1);
65+
element.attributes['style'] = newStyleAttribute;
66+
}
67+
}
68+
}
69+
for (final element in element.children) {
70+
_processElement(element, message, configuration);
71+
}
72+
}
73+
}

lib/src/enough_mail_html_base.dart

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import 'dom/image_transformers.dart';
88
import 'dom/link_transformers.dart';
99
import 'dom/meta_transformers.dart';
1010
import 'dom/script_transformers.dart';
11+
import 'dom/width_transformers.dart';
1112
import 'text/convert_tags_text_transformer.dart';
1213
import 'text/linebreak_text_transformer.dart';
1314
import 'text/links_text_transformer.dart';
@@ -28,6 +29,7 @@ class TransformConfiguration {
2829
this.enableDarkMode = false,
2930
this.emptyMessageText = standardEmptyMessageText,
3031
this.plainTextHtmlTemplate = standardPlainTextHtmlTemplate,
32+
this.attributeWidthMax = standardAttributeMaxWidth,
3133
this.customValues,
3234
});
3335

@@ -44,6 +46,7 @@ class TransformConfiguration {
4446
String plainTextHtmlTemplate = standardPlainTextHtmlTemplate,
4547
List<DomTransformer>? customDomTransformers,
4648
List<TextTransformer>? customTextTransformers,
49+
int attributeWidthMax = standardAttributeMaxWidth,
4750
Map<String, dynamic>? customValues,
4851
}) {
4952
final domTransformers = (customDomTransformers != null)
@@ -53,6 +56,7 @@ class TransformConfiguration {
5356
? [...standardTextTransformers, ...customTextTransformers]
5457
: standardTextTransformers;
5558
maxImageWidth ??= standardMaxImageWidth;
59+
5660
return TransformConfiguration(
5761
blockExternalImages: blockExternalImages,
5862
preferPlainText: preferPlainText,
@@ -62,6 +66,7 @@ class TransformConfiguration {
6266
domTransformers: domTransformers,
6367
textTransformers: textTransformers,
6468
plainTextHtmlTemplate: plainTextHtmlTemplate,
69+
attributeWidthMax: attributeWidthMax,
6570
customValues: customValues,
6671
);
6772
}
@@ -96,6 +101,9 @@ class TransformConfiguration {
96101
/// before a plain text message without HTML part is converted into HTML
97102
final List<TextTransformer> textTransformers;
98103

104+
/// The maximum value for width attributes, defaults to 400.
105+
final int attributeWidthMax;
106+
99107
/// Optional custom values, `null` unless specified.
100108
final Map<String, dynamic>? customValues;
101109

@@ -111,6 +119,7 @@ class TransformConfiguration {
111119
domTransformers: standardDomTransformers,
112120
textTransformers: standardTextTransformers,
113121
plainTextHtmlTemplate: standardPlainTextHtmlTemplate,
122+
attributeWidthMax: standardAttributeMaxWidth,
114123
);
115124

116125
/// The standard maximum image width is `null`, ie not restricted.
@@ -129,13 +138,17 @@ class TransformConfiguration {
129138
static const String standardEmptyMessageText =
130139
'This message has no contents.';
131140

141+
/// The standard maximum width for attributes is 400.
142+
static const int standardAttributeMaxWidth = 400;
143+
132144
/// The list of default DOM transformers
133145
static const List<DomTransformer> standardDomTransformers = [
134146
ViewPortTransformer(),
135147
RemoveScriptTransformer(),
136148
ImageTransformer(),
137149
EnsureRelationNoreferrerTransformer(),
138150
DarkModeTransformer(),
151+
WidthTransformer(),
139152
];
140153

141154
/// The list of default text transformers
@@ -155,8 +168,11 @@ abstract class DomTransformer {
155168
/// Transforms the [document] of the [message] using [configuration].
156169
///
157170
/// All changes will be visible to subsequent transformers.
158-
void process(Document document, MimeMessage message,
159-
TransformConfiguration configuration);
171+
void process(
172+
Document document,
173+
MimeMessage message,
174+
TransformConfiguration configuration,
175+
);
160176

161177
/// Adds a HEAD element if necessary
162178
void ensureDocumentHeadIsAvailable(Document document) {

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ version: 2.0.1
44
homepage: https://github.com/Enough-Software/enough_mail_html
55

66
environment:
7-
sdk: '>=2.18.0 <4.0.0'
7+
sdk: '>=3.0.0 <4.0.0'
88

99
dependencies:
1010
enough_mail: ^2.0.0
@@ -19,5 +19,5 @@ dependency_overrides:
1919
# path: ../enough_mail/
2020

2121
dev_dependencies:
22-
lints: ^2.0.0
22+
lints: ^3.0.0
2323
test: ^1.16.7

0 commit comments

Comments
 (0)