diff --git a/CHANGELOG.md b/CHANGELOG.md index 48a0ad6..37177f5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file. The format is based on Keep a Changelog. +## [0.0.12] - 2026-09-03 + +### Changed + +- Restore Frappe v15's native notification message rendering and vertical row spacing; retain Reyal's per-row controls and avatar grid + ## [0.0.11] - 2026-08-29 ### Changed diff --git a/reyal_core/__init__.py b/reyal_core/__init__.py index b2f0155..6e2648a 100644 --- a/reyal_core/__init__.py +++ b/reyal_core/__init__.py @@ -1 +1 @@ -__version__ = "0.0.11" +__version__ = "0.0.12" diff --git a/reyal_core/hooks.py b/reyal_core/hooks.py index 1937e6a..5bf4bb0 100644 --- a/reyal_core/hooks.py +++ b/reyal_core/hooks.py @@ -6,8 +6,8 @@ app_license = "mit" # Include custom Desk behaviour: -app_include_js = "/assets/reyal_core/js/notification_row_delete_v5.js?v=20260810_05" -app_include_css = "/assets/reyal_core/css/notification_row_delete_v5.css?v=20260810_05" +app_include_js = "/assets/reyal_core/js/notification_row_delete_v5.js?v=20260903_02" +app_include_css = "/assets/reyal_core/css/notification_row_delete_v5.css?v=20260903_02" # Install / migrate hooks: diff --git a/reyal_core/public/css/notification_row_delete_v5.css b/reyal_core/public/css/notification_row_delete_v5.css index 60fa0a7..2842bd1 100644 --- a/reyal_core/public/css/notification_row_delete_v5.css +++ b/reyal_core/public/css/notification_row_delete_v5.css @@ -1,14 +1,13 @@ /* - * Compact Desk notifications dropdown. - * Keep delete/mark-as-read chrome + denser row layout. Rich HTML is sanitized - * in JS so the avatar|message grid cannot reintroduce the column skew. + * Desk notifications with Reyal row actions. + * Keep Frappe v15's row spacing while reserving room for the added controls. */ .recent-item.notification-item { position: relative; - /* Stock Frappe uses 10px padding + 10px margin — reclaim that vertical space. */ - padding: 6px 28px 6px 0 !important; - margin: 4px 8px !important; + /* Match Frappe v15 vertically; retain extra right inset for Reyal controls. */ + padding: 10px 28px 10px 0 !important; + margin: 10px !important; } /* Avatar | message only. Description lives inside .message, never as a grid item. */ @@ -41,15 +40,6 @@ display: none !important; } -/* Comment/email media must never expand a dropdown row. */ -.recent-item.notification-item .notification-body .message img, -.recent-item.notification-item .notification-body .message video, -.recent-item.notification-item .notification-body .message iframe, -.recent-item.notification-item .notification-body .message svg, -.recent-item.notification-item .notification-body .message picture { - display: none !important; -} - .recent-item.notification-item .notification-body > .user-avatar, .recent-item.notification-item .notification-body > .avatar { grid-column: 1; @@ -105,16 +95,6 @@ max-width: 100%; } -.recent-item.notification-item .notification-description { - display: -webkit-box; - -webkit-box-orient: vertical; - -webkit-line-clamp: 2; - line-clamp: 2; - overflow: hidden; - overflow-wrap: anywhere; - word-break: break-word; -} - .recent-item.notification-item .notification-timestamp { line-height: 1.2; } diff --git a/reyal_core/public/js/notification_row_delete_v5.js b/reyal_core/public/js/notification_row_delete_v5.js index adb2413..3f5c41a 100644 --- a/reyal_core/public/js/notification_row_delete_v5.js +++ b/reyal_core/public/js/notification_row_delete_v5.js @@ -177,98 +177,6 @@ return $delete; } - /** - * Frappe injects Notification Log.description as raw HTML. That is fine - * for the Notification Log form, but the Desk bell dropdown must stay - * compact. Catch email bodies, Quill comment markup, and bare media - * (comment mentions often store just an ). - */ - function looks_like_rich_html(html) { - if (!html) return false; - return /<(img|video|iframe|figure|svg|picture|audio|source|p|ul|ol|table|div|br|h[1-6]|blockquote|pre|hr|section|article)\b/i.test( - html - ); - } - - function plain_text_from_html(html) { - if (typeof strip_html === "function") { - return strip_html(html).replace(/\s+/g, " ").trim(); - } - return $("
").html(html).text().replace(/\s+/g, " ").trim(); - } - - function plain_preview(html, max_length) { - const text = plain_text_from_html(html); - if (!text) return ""; - const limit = max_length || 140; - return frappe.ellipsis ? frappe.ellipsis(text, limit) : text.slice(0, limit); - } - - /** - * Collapse rich/media HTML in a rendered notification row (fallback for - * rows already in the DOM, realtime inserts, etc.). - */ - function sanitize_notification_item_body($item) { - const $body = $item.children(".notification-body").first(); - const $message = $body.children(".message").first(); - if (!$message.length) return; - - const $description = $message.children(".notification-description").first(); - if ($description.length && looks_like_rich_html($description.html())) { - const text = plain_preview($description.html(), 140); - if (text) { - $description.text(text); - } else { - $description.remove(); - } - } - - $message.children("div").not(".notification-description, .notification-timestamp").each(function () { - const $block = $(this); - const html = $block.html() || ""; - if (!looks_like_rich_html(html)) return; - const text = plain_preview(html, 140); - if (text) { - // Preserve Frappe's subject HTML when it is only lightweight - // markup; rewrite only when block/media content leaked in. - if (/<(img|video|iframe|figure|svg|picture|p|ul|ol|table|div)\b/i.test(html)) { - $block.text(text); - } - } - }); - - // Belt-and-suspenders: drop any leftover media under the message. - $message.find("img, video, iframe, svg, picture, audio").remove(); - $message.children(".notification-description").filter(function () { - return !($(this).text() || "").trim(); - }).remove(); - } - - /** - * Sanitize the log payload before Frappe builds the row HTML so giant - * comment images never flash into the dropdown. - */ - function sanitize_notification_log(notification_log) { - if (!notification_log) return notification_log; - const log = Object.assign({}, notification_log); - - if (log.description && looks_like_rich_html(log.description)) { - log.description = plain_preview(log.description, 140); - } - - ["title", "subject"].forEach((field) => { - if (log[field] && looks_like_rich_html(log[field])) { - // Keep Frappe's subject-title bold wrappers when present; only - // strip when media / block markup leaked into the title. - if (/<(img|video|iframe|figure|svg|picture)\b/i.test(log[field])) { - log[field] = plain_preview(log[field], 100) || log[field]; - } - } - }); - - return log; - } - function decorate_notification_item($item, notifications) { const docname = $item.attr("data-name"); if (!docname) return; @@ -280,7 +188,6 @@ const is_unread = $item.hasClass("unread"); $item.css({ position: "relative", "padding-right": "34px" }); - sanitize_notification_item_body($item); let $controls = $item.children(".reyal-notification-controls").first(); if (!$controls.length) { @@ -356,13 +263,6 @@ const view = get_notifications_view(notifications); if (!view || view[VIEW_PATCH_FLAG]) return; - const original_item_html = view.get_dropdown_item_html; - if (original_item_html) { - view.get_dropdown_item_html = function (notification_log) { - return original_item_html.call(this, sanitize_notification_log(notification_log)); - }; - } - const original_render = view.render_notifications_dropdown; view.render_notifications_dropdown = function () { original_render.call(this);