Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion reyal_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.0.11"
__version__ = "0.0.12"
4 changes: 2 additions & 2 deletions reyal_core/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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:

Expand Down
30 changes: 5 additions & 25 deletions reyal_core/public/css/notification_row_delete_v5.css
Original file line number Diff line number Diff line change
@@ -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. */
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down
100 changes: 0 additions & 100 deletions reyal_core/public/js/notification_row_delete_v5.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 <img>).
*/
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 $("<div/>").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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
Loading