diff --git a/src/MailPanel.body.latte b/src/MailPanel.body.latte
index 5e65711..0bc62f0 100644
--- a/src/MailPanel.body.latte
+++ b/src/MailPanel.body.latte
@@ -1,2 +1,2 @@
-{* Little magic here. Create iframe and then render message into it (needed because HTML messages) *}
+{* Render a standalone HTML preview document or fragment. *}
{$message|previewHtml|noescape}
diff --git a/src/MailPanel.latte b/src/MailPanel.latte
index 158fef0..68c10cd 100644
--- a/src/MailPanel.latte
+++ b/src/MailPanel.latte
@@ -108,7 +108,7 @@
{/foreach}
@@ -129,22 +129,18 @@
var iframe = document.createElement('iframe');
preview.appendChild(iframe);
- iframe.contentWindow.document.write(preview.dataset.content);
- iframe.contentWindow.document.close();
- delete preview.dataset.content;
-
- var baseTag = iframe.contentWindow.document.createElement('base');
- baseTag.target = '_parent';
- iframe.contentWindow.document.body.appendChild(baseTag);
-
var fixHeight = function (ev) {
+ var iframeDocument = iframe.contentWindow.document;
+ var iframeBody = iframeDocument.body || iframeDocument.documentElement;
iframe.style.height = 0;
- iframe.style.height = iframe.contentWindow.document.body.scrollHeight + 'px';
+ iframe.style.height = iframeBody.scrollHeight + 'px';
iframe.contentWindow.removeEventListener(ev.type, fixHeight);
};
iframe.contentWindow.addEventListener('load', fixHeight);
iframe.contentWindow.addEventListener('resize', fixHeight);
+ iframe.src = preview.dataset.src;
+ delete preview.dataset.src;
actions.removeEventListener('tracy-toggle', initHtmlPreview);
actions.removeEventListener('click', initHtmlPreview);
};
diff --git a/src/MailPanel.php b/src/MailPanel.php
index a6b4f1a..a701f0b 100644
--- a/src/MailPanel.php
+++ b/src/MailPanel.php
@@ -240,7 +240,10 @@ private function tryHandleRequest(): void
$messageId = $this->request->getQuery('nextras-mail-panel-message-id');
$attachmentId = $this->request->getQuery('nextras-mail-panel-attachment-id');
- if ($action === 'detail' && is_string($messageId)) {
+ if ($action === 'preview' && is_string($messageId)) {
+ $this->handlePreview($messageId);
+
+ } elseif ($action === 'detail' && is_string($messageId)) {
$this->handleDetail($messageId);
} elseif ($action === 'source' && is_string($messageId)) {
@@ -264,7 +267,18 @@ private function handleDetail(string $messageId): void
$message = $this->mailer->getMessage($messageId);
header('Content-Type: text/html');
- $this->getLatte()->render(__DIR__ . '/MailPanel.body.latte', ['message' => $message]);
+ echo $this->renderMessagePreview($message);
+ exit;
+ }
+
+
+ private function handlePreview(string $messageId): void
+ {
+ assert($this->mailer !== null);
+ $message = $this->mailer->getMessage($messageId);
+
+ header('Content-Type: text/html');
+ echo $this->addParentBaseTarget($this->renderMessagePreview($message));
exit;
}
@@ -280,6 +294,36 @@ private function handleSource(string $messageId): void
}
+ private function renderMessagePreview(MimePart $message): string
+ {
+ return $this->getLatte()->renderToString(__DIR__ . '/MailPanel.body.latte', ['message' => $message]);
+ }
+
+
+ private function addParentBaseTarget(string $html): string
+ {
+ $baseTag = '';
+
+ if (preg_match('~]*)?>~i', $html) === 1) {
+ return $html;
+ }
+
+ if (preg_match('~]*)?>~i', $html, $match, PREG_OFFSET_CAPTURE) === 1) {
+ $headTag = $match[0][0];
+ $position = $match[0][1] + strlen($headTag);
+ return substr($html, 0, $position) . $baseTag . substr($html, $position);
+ }
+
+ if (preg_match('~]*)?>~i', $html, $match, PREG_OFFSET_CAPTURE) === 1) {
+ $htmlTag = $match[0][0];
+ $position = $match[0][1] + strlen($htmlTag);
+ return substr($html, 0, $position) . '' . $baseTag . '' . substr($html, $position);
+ }
+
+ return '' . $baseTag . '' . $html . '';
+ }
+
+
private function handleAttachment(string $messageId, int $attachmentId): void
{
assert($this->mailer !== null);
diff --git a/tests/MailPanelTest.phpt b/tests/MailPanelTest.phpt
index 452c096..f4a710d 100644
--- a/tests/MailPanelTest.phpt
+++ b/tests/MailPanelTest.phpt
@@ -33,7 +33,7 @@ class MailPanelTest extends TestCase
}
- public function testPanelStoresEscapedHtmlPreviewInDataAttribute(): void
+ public function testPanelStoresPreviewEndpointInDataAttribute(): void
{
$message = (new Message())
->setSubject('Panel preview')
@@ -42,10 +42,22 @@ class MailPanelTest extends TestCase
$panel = $this->createPanel(new ArrayPersistentMailer(['message-id' => $message]));
$output = $panel->getPanel();
- Assert::contains('data-content="<h1>Hello from HTML</h1>"', $output);
+ Assert::contains('data-src="index.php?nextras-mail-panel-action=preview&nextras-mail-panel-message-id=message-id"', $output);
}
+ public function testPreviewPreservesExistingBaseTag(): void
+ {
+ $message = (new Message())
+ ->setSubject('Panel preview')
+ ->setHtmlBody('
');
+
+ $output = $this->renderPreviewHtml($message);
+
+ Assert::contains('', $output);
+ Assert::notContains('', $output);
+ }
+
private function renderMessageBody(Message $message): string
{
$panel = $this->createPanel(new NullPersistentMailer());
@@ -58,6 +70,19 @@ class MailPanelTest extends TestCase
}
+ private function renderPreviewHtml(Message $message): string
+ {
+ $panel = $this->createPanel(new NullPersistentMailer());
+
+ $renderMessagePreview = new ReflectionMethod(MailPanel::class, 'renderMessagePreview');
+ $renderMessagePreview->setAccessible(true);
+ $addParentBaseTarget = new ReflectionMethod(MailPanel::class, 'addParentBaseTarget');
+ $addParentBaseTarget->setAccessible(true);
+
+ return $addParentBaseTarget->invoke($panel, $renderMessagePreview->invoke($panel, $message));
+ }
+
+
private function createPanel(IPersistentMailer $mailer): MailPanel
{
return new MailPanel(