TF-2520 Create some class to handle html
Signed-off-by: dab246 <tdvu@linagora.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
|
||||
import 'package:core/data/network/dio_client.dart';
|
||||
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
||||
import 'package:core/presentation/utils/html_transformer/html_template.dart';
|
||||
import 'package:core/utils/html/html_template.dart';
|
||||
import 'package:html/dom.dart';
|
||||
|
||||
class AddTooltipLinkTransformer extends DomTransformer {
|
||||
@@ -28,9 +28,9 @@ class AddTooltipLinkTransformer extends DomTransformer {
|
||||
final innerHtml = element.innerHtml;
|
||||
final tagClass = element.attributes['class'];
|
||||
if (tagClass != null) {
|
||||
element.attributes['class'] = '$tagClass $nameClassToolTip';
|
||||
element.attributes['class'] = '$tagClass ${HtmlTemplate.nameClassToolTip}';
|
||||
} else {
|
||||
element.attributes['class'] = nameClassToolTip;
|
||||
element.attributes['class'] = HtmlTemplate.nameClassToolTip;
|
||||
}
|
||||
element.innerHtml = innerHtml + textHasToolTip(url);
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
|
||||
import 'package:core/data/network/dio_client.dart';
|
||||
import 'package:core/presentation/utils/html_transformer/base/dom_transformer.dart';
|
||||
import 'package:core/presentation/utils/html_transformer/html_template.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:core/utils/html/html_template.dart';
|
||||
import 'package:html/dom.dart';
|
||||
|
||||
class RemoveTooltipLinkTransformer extends DomTransformer {
|
||||
@@ -15,11 +15,11 @@ class RemoveTooltipLinkTransformer extends DomTransformer {
|
||||
required DioClient dioClient,
|
||||
Map<String, String>? mapUrlDownloadCID,
|
||||
}) async {
|
||||
final linkElements = document.querySelectorAll('a.$nameClassToolTip');
|
||||
final linkElements = document.querySelectorAll('a.${HtmlTemplate.nameClassToolTip}');
|
||||
await Future.wait(linkElements.map((linkElement) async {
|
||||
final classAttribute = linkElement.attributes['class'];
|
||||
if (classAttribute != null) {
|
||||
final newClassAttribute = classAttribute.replaceFirst(nameClassToolTip, '');
|
||||
final newClassAttribute = classAttribute.replaceFirst(HtmlTemplate.nameClassToolTip, '');
|
||||
linkElement.attributes['class'] = newClassAttribute;
|
||||
}
|
||||
final listSpanTag = linkElement.querySelectorAll('span.tooltiptext');
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
|
||||
class HtmlEventAction {
|
||||
static const scrollRightEndAction = 'ScrollRightEndAction';
|
||||
static const scrollLeftEndAction = 'ScrollLeftEndAction';
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
const nameClassToolTip = 'tmail-tooltip';
|
||||
|
||||
const tooltipLinkCss = '''
|
||||
.$nameClassToolTip .tooltiptext {
|
||||
visibility: hidden;
|
||||
max-width: 400px;
|
||||
background-color: black;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
padding: 5px 8px 5px 8px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
.$nameClassToolTip:hover .tooltiptext {
|
||||
visibility: visible;
|
||||
}
|
||||
''';
|
||||
|
||||
String generateHtml(String content, {
|
||||
double? minHeight,
|
||||
double? minWidth,
|
||||
String? styleCSS,
|
||||
String? javaScripts,
|
||||
bool hideScrollBar = true,
|
||||
TextDirection? direction
|
||||
}) {
|
||||
return '''
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<style>
|
||||
.tmail-content {
|
||||
min-height: ${minHeight ?? 0}px;
|
||||
min-width: ${minWidth ?? 0}px;
|
||||
overflow: auto;
|
||||
}
|
||||
${hideScrollBar ? '''
|
||||
.tmail-content::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
.tmail-content {
|
||||
-ms-overflow-style: none; /* IE and Edge */
|
||||
scrollbar-width: none; /* Firefox */
|
||||
}
|
||||
''' : ''}
|
||||
${styleCSS ?? ''}
|
||||
</style>
|
||||
</head>
|
||||
<body ${direction == TextDirection.rtl ? 'dir="rtl"' : ''} style = "overflow-x: hidden">
|
||||
<div class="tmail-content">$content</div>
|
||||
${javaScripts ?? ''}
|
||||
</body>
|
||||
</html>
|
||||
''';
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
|
||||
import 'package:core/presentation/extensions/html_extension.dart';
|
||||
import 'package:core/presentation/utils/html_transformer/html_event_action.dart';
|
||||
import 'package:core/utils/app_logger.dart';
|
||||
import 'package:core/utils/platform_info.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class HtmlUtils {
|
||||
|
||||
static const scrollEventJSChannelName = 'ScrollEventListener';
|
||||
static const contentSizeChangedEventJSChannelName = 'ContentSizeChangedEventListener';
|
||||
|
||||
static const runScriptsHandleScrollEvent = '''
|
||||
let contentElement = document.getElementsByClassName('tmail-content')[0];
|
||||
var xDown = null;
|
||||
var yDown = null;
|
||||
|
||||
contentElement.addEventListener('touchstart', handleTouchStart, false);
|
||||
contentElement.addEventListener('touchmove', handleTouchMove, false);
|
||||
|
||||
function getTouches(evt) {
|
||||
return evt.touches || evt.originalEvent.touches;
|
||||
}
|
||||
|
||||
function handleTouchStart(evt) {
|
||||
const firstTouch = getTouches(evt)[0];
|
||||
xDown = firstTouch.clientX;
|
||||
yDown = firstTouch.clientY;
|
||||
}
|
||||
|
||||
function handleTouchMove(evt) {
|
||||
if (!xDown || !yDown) {
|
||||
return;
|
||||
}
|
||||
|
||||
var xUp = evt.touches[0].clientX;
|
||||
var yUp = evt.touches[0].clientY;
|
||||
|
||||
var xDiff = xDown - xUp;
|
||||
var yDiff = yDown - yUp;
|
||||
|
||||
if (Math.abs(xDiff) > Math.abs(yDiff)) {
|
||||
let newScrollLeft = contentElement.scrollLeft;
|
||||
let scrollWidth = contentElement.scrollWidth;
|
||||
let offsetWidth = contentElement.offsetWidth;
|
||||
let maxOffset = Math.round(scrollWidth - offsetWidth);
|
||||
let scrollLeftRounded = Math.round(newScrollLeft);
|
||||
|
||||
if (xDiff > 0) {
|
||||
if (maxOffset === scrollLeftRounded ||
|
||||
maxOffset === (scrollLeftRounded + 1) ||
|
||||
maxOffset === (scrollLeftRounded - 1)) {
|
||||
window.flutter_inappwebview.callHandler('$scrollEventJSChannelName', '${HtmlEventAction.scrollRightEndAction}');
|
||||
}
|
||||
} else {
|
||||
if (scrollLeftRounded === 0) {
|
||||
window.flutter_inappwebview.callHandler('$scrollEventJSChannelName', '${HtmlEventAction.scrollLeftEndAction}');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
xDown = null;
|
||||
yDown = null;
|
||||
}
|
||||
''';
|
||||
|
||||
static const scriptsHandleContentSizeChanged = '''
|
||||
<script>
|
||||
const bodyResizeObserver = new ResizeObserver(entries => {
|
||||
window.flutter_inappwebview.callHandler('$contentSizeChangedEventJSChannelName', '');
|
||||
})
|
||||
|
||||
bodyResizeObserver.observe(document.body)
|
||||
</script>
|
||||
''';
|
||||
|
||||
static const scriptsHandleLazyLoadingBackgroundImage = '''
|
||||
<script>
|
||||
const lazyImages = document.querySelectorAll('[lazy]');
|
||||
const lazyImageObserver = new IntersectionObserver((entries, observer) => {
|
||||
entries.forEach((entry) => {
|
||||
if (entry.isIntersecting) {
|
||||
const lazyImage = entry.target;
|
||||
const src = lazyImage.dataset.src;
|
||||
lazyImage.tagName.toLowerCase() === 'img'
|
||||
? lazyImage.src = src
|
||||
: lazyImage.style.backgroundImage = "url(\'" + src + "\')";
|
||||
lazyImage.removeAttribute('lazy');
|
||||
observer.unobserve(lazyImage);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
lazyImages.forEach((lazyImage) => {
|
||||
lazyImageObserver.observe(lazyImage);
|
||||
});
|
||||
</script>
|
||||
''';
|
||||
|
||||
static String customCssStyleHtmlEditor({TextDirection direction = TextDirection.ltr}) {
|
||||
if (PlatformInfo.isWeb) {
|
||||
return '''
|
||||
<style>
|
||||
.note-editable {
|
||||
direction: ${direction.name};
|
||||
}
|
||||
|
||||
.note-editable .tmail-signature {
|
||||
text-align: ${direction == TextDirection.rtl ? 'right' : 'left'};
|
||||
}
|
||||
</style>
|
||||
''';
|
||||
} else if (PlatformInfo.isMobile) {
|
||||
return '''
|
||||
#editor {
|
||||
direction: ${direction.name};
|
||||
}
|
||||
|
||||
#editor .tmail-signature {
|
||||
text-align: ${direction == TextDirection.rtl ? 'right' : 'left'};
|
||||
}
|
||||
''';
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
static String validateHtmlImageResourceMimeType(String mimeType) {
|
||||
if (mimeType.endsWith('svg')) {
|
||||
mimeType = 'image/svg+xml';
|
||||
}
|
||||
log('HtmlUtils::validateHtmlImageResourceMimeType:mimeType: $mimeType');
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
static String convertBase64ToImageResourceData({
|
||||
required String base64Data,
|
||||
required String mimeType
|
||||
}) {
|
||||
mimeType = validateHtmlImageResourceMimeType(mimeType);
|
||||
if (!base64Data.endsWith('==')) {
|
||||
base64Data.append('==');
|
||||
}
|
||||
final imageResource = 'data:$mimeType;base64,$base64Data';
|
||||
log('HtmlUtils::convertBase64ToImageResourceData:imageResource: $imageResource');
|
||||
return imageResource;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user