Skip to content

Improve sharing via Print#7728

Merged
Alkarex merged 4 commits intoFreshRSS:edgefrom
Inverle:print-improvements
Aug 6, 2025
Merged

Improve sharing via Print#7728
Alkarex merged 4 commits intoFreshRSS:edgefrom
Inverle:print-improvements

Conversation

@Inverle
Copy link
Member

@Inverle Inverle commented Jul 10, 2025

List of changes:

  • The temporary document for printing is now in an <iframe> instead of a new tab
  • The whole <head> element is copied to the temporary document, except for <script> tags to copy over the <meta> tags as well
  • URLs that contain the instance base URL are now removed from the printed PDF
  • The saved filename (PDF) will now default to the article title
  • <details> is auto expanded
  • Styling:
    • The main document's <html> class is copied over to preserve some styling that might use those classes
    • Instead of writing content_el.innerHTML to the temporary document, content_el.outerHTML is now written instead to apply the styles that select .content
    • .dropdown-menu is now hidden in the printed document, because it can't be expanded anyway
    • Headers and footers are hidden in the printed document
  • The printed document will now display correctly all the time, by waiting for it to load before calling print()
    • Before, the stylesheets might've not finished loading and the document was broken
  • Better browser support on mobile for this feature
    • Before, the document would fail to print on Chrome Mobile

Tested on:

  • Firefox - both desktop and mobile, works ✅
  • Chrome - both desktop and mobile, works ✅
  • Opera - desktop, works (same as Chrome) ✅
  • Brave - both desktop and mobile (same as Chrome), works ✅
  • Safari - both desktop and mobile, works✅
  • Microsoft Edge - both desktop and mobile, works ✅
  • GNOME Web - desktop, works ✅
  • SeaMonkey - desktop, works ✅

Known issues:

  • Images may not finish loading the first time the print dialog is opened

TODO:

  • Test on Safari
  • Try to fix GNOME Web

@Alkarex Alkarex added this to the 1.27.0 milestone Jul 14, 2025
Comment on lines 1301 to 1309
tmp_window.onafterprint = () => {
const isFirefoxMobile = navigator.userAgent.includes('Firefox') && navigator.userAgent.includes('Mobile');
if (isFirefoxMobile) {
// Setting location.hash here crashes the tab on Firefox Mobile
return;
}
// Required for `mouseover` to trigger after print dialog is no longer open
location.hash = 'close';
};
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The temporary document for printing is now in an <iframe> instead of a new tab

Perhaps this is one of those personal preference things but I'm not overly fond of that. I wasn't going to say anything because it didn't sound like a big deal, but um, well, these lines kind of speak for themselves. What is the reason for wanting to use an iframe exactly?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, these lines kind of speak for themselves

Sure having to check for the user agent is a bit ridiculous but it was a quick fix, if that's what you mean.
I'll try something else instead, maybe I don't have to set location.hash at all.

What is the reason for wanting to use an iframe exactly?

  • The temporary document for printing is now in an <iframe> instead of a new tab

So, the reason is I don't like that printing causes a new tab to be opened.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this any better?

FreshRSS/p/scripts/main.js

Lines 1294 to 1316 in 7790e64

function afterPrint() {
print_frame.remove();
document.title = prevTitle;
prevTitle = '';
window.removeEventListener('focus', afterPrint);
}
print_frame.onload = () => {
const tmp_window = print_frame.contentWindow;
// Needed for Chrome
tmp_window.matchMedia('print').onchange = (e) => {
// UA check is needed to not trigger on Chrome Mobile
if (!e.matches && !navigator.userAgent.includes('Mobi')) {
afterPrint();
}
};
tmp_window.print();
};
// Needed for Firefox and Chrome Mobile
window.addEventListener('focus', afterPrint);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, the reason is I don't like that printing causes a new tab to be opened.

Well sure, but I prefer a new tab to be opened for printing and I don't quite understand why you don't. :-) I'd much prefer it didn't automatically close! You don't even notice it opens a new tab and I think that's a bad thing. The print view is perfect to save as HTML too for example. Just a single line removal to get rid of the auto-close would make it much more user-friendly in that sense. The fact that save page as works in print preview in most browsers nowadays feels more like a fluke than something well thought out. And mind, after testing I realized save page doesn't save the print preview from an iframe but sticks to the parent page.

So from my perspective you have a lesser user experience at the cost of lower quality code with unnecessary hacks and complexities.

As a compromise, perhaps it should be separated into "print" and "show print view" or something to that effect. Though I've always thought auto-print but don't auto-close serves both purposes well enough. But given the code above I don't see any role for an iframe there, only a question of whether to auto-print and auto-close.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well sure, but I prefer a new tab to be opened for printing and I don't quite understand why you don't. :-)

The page that is currently being open for printing looks odd, because you can see a blank page behind the print dialog and the tab doesn't have a title.

The print view is perfect to save as HTML too for example

I didn't realize it's possible to do that in the print preview. I guess that makes opening a new tab a better option automatically.

Just a single line removal to get rid of the auto-close would make it much more user-friendly in that sense

I think that this should be configurable (as a matter of preference)

So from my perspective you have a lesser user experience at the cost of lower quality code with unnecessary hacks and complexities.

That's the worst part, it shouldn't be this hard to print from an iframe.
It's probably also not guaranteed that this will continue working after browser updates.

As a compromise, perhaps it should be separated into "print" and "show print view" or something to that effect. Though I've always thought auto-print but don't auto-close serves both purposes well enough. But given the code above I don't see any role for an iframe there, only a question of whether to auto-print and auto-close.

That's an option too, but maybe something like Save as HTML instead of show print view?

Also, for showing a print view, maybe it should just be a separate .phtml view instead of opening it with JS

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the worst part, it shouldn't be this hard to print from an iframe.

It does surprise me.

That's an option too, but maybe something like Save as HTML instead of show print view?

Possibly. I'd say the point is simply "show single article" (in clean print view) and what the user does is up to them, regardless if I've thought of it. Put another way, I wouldn't really want someone to optimize the saving by using blob for example, because then that's all you can do. Though granted, you could then do whatever you want with the resulting file so maybe it doesn't matter too much.

Also, for showing a print view, maybe it should just be a separate .phtml view instead of opening it with JS

No objections here, but overall I'm totally fine with JS as in this PR as well. More than that, it seems done to me, besides the minor iframe detail.

Comment on lines 2789 to 2791
@top-left { content: ''; }

@bottom-left { content: ''; }
Copy link
Member

@Frenzie Frenzie Jul 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this interact with RTL?

Edit: I see, it doesn't at the moment.

Copy link
Member Author

@Inverle Inverle Jul 19, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give an example?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .rtl stylesheet hasn't swapped left and right.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just add @top-right here as well

Copy link
Member Author

@Inverle Inverle Jul 20, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this changes anything but I added @top-right and @bottom-right

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly

I do think it would be good to have it somewhere. But of course that needn't be the footer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking of which all URLs should be made explicit really. It's really simple with generated content but then it'd have to be immediately behind all links. For something more advanced like footnotes you'd need JS or PHP.

Anyway, that's not for this PR (unless you want it to be, heh).

Copy link
Member Author

@Inverle Inverle Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Speaking of which all URLs should be made explicit really. It's really simple with generated content but then it'd have to be immediately behind all links. For something more advanced like footnotes you'd need JS or PHP.

For the print of the whole page we already have this:
(doesn't apply to the JS print dialog because it doesn't include .flux_content)

.flux_content .content a::after {
content: " [" attr(href) "] ";
font-style: italic;
}

But it looks awful, so it would have to be footnotes if anything.

Anyway, that's not for this PR (unless you want it to be, heh).

This is yet again something that should be configurable, as footnotes wouldn't be needed in PDFs for example since you can just click/hover on links.
Note that footnotes could conflict with the actual contents of the article.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But it looks awful, so it would have to be footnotes if anything.

I think it looks reasonable enough for the most part. I prefer parentheses over square brackets though. And, well, not too fond of the italic really. I just mean the principle.

in PDFs for example since you can just click/hover on links.

Eh, that's debatable. It's one thing for navigational aids within the document but making it less useful when printed strikes me as somewhat besides the point.

Copy link
Member Author

@Inverle Inverle Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it looks reasonable enough for the most part. I prefer parentheses over square brackets though

I'm fine about going with this approach, but it needs to be configurable.
(turned off by default?)

@Alkarex
Copy link
Member

Alkarex commented Jul 16, 2025

For the record, I like to ensure basic support for SeaMonkey (seems to work, at a quick glance)

@Alkarex Alkarex merged commit 149136f into FreshRSS:edge Aug 6, 2025
1 check passed
@Inverle Inverle deleted the print-improvements branch August 6, 2025 20:24
alexlebens pushed a commit to alexlebens/infrastructure that referenced this pull request Aug 20, 2025
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| [freshrss/freshrss](https://freshrss.org/) ([source](https://github.com/FreshRSS/FreshRSS)) | minor | `1.26.3` -> `1.27.0` |

---

### Release Notes

<details>
<summary>FreshRSS/FreshRSS (freshrss/freshrss)</summary>

### [`v1.27.0`](https://github.com/FreshRSS/FreshRSS/blob/HEAD/CHANGELOG.md#2025-08-18-FreshRSS-1270)

[Compare Source](FreshRSS/FreshRSS@1.26.3...1.27.0)

- Features
  - Implement support for HTTP `429 Too Many Requests` and `503 Service Unavailable`, obey `Retry-After` [#&#8203;7760](FreshRSS/FreshRSS#7760)
  - Add sort by category title, or by feed title [#&#8203;7702](FreshRSS/FreshRSS#7702)
  - Add search operator `c:` for categories like `c:23,34` or `!c:45,56` [#&#8203;7696](FreshRSS/FreshRSS#7696)
  - Custom feed favicons [#&#8203;7646](FreshRSS/FreshRSS#7646), [#&#8203;7704](FreshRSS/FreshRSS#7704), [#&#8203;7717](FreshRSS/FreshRSS#7717),
    [#&#8203;7792](FreshRSS/FreshRSS#7792)
  - Rework fetch favicons for fewer HTTP requests [#&#8203;7767](FreshRSS/FreshRSS#7767)
  - Add more unicity criteria based on title and/or content [#&#8203;7789](FreshRSS/FreshRSS#7789)
  - Automatically restore user configuration from backup [#&#8203;7682](FreshRSS/FreshRSS#7682)
  - API add support for states in `s` parameter of `streamId` [#&#8203;7695](FreshRSS/FreshRSS#7695)
  - Improve sharing via Print [#&#8203;7728](FreshRSS/FreshRSS#7728)
  - Redirect to the login page from bookmarklet instead of 403 [#&#8203;7782](FreshRSS/FreshRSS#7782)
  - Clean local cache more often, when refreshing feeds [#&#8203;7827](FreshRSS/FreshRSS#7827)
- Security
  - Implement reauthentication (*sudo* mode) [#&#8203;7753](FreshRSS/FreshRSS#7753)
  - Add `Content-Security-Policy: frame-ancestors` [#&#8203;7677](FreshRSS/FreshRSS#7677)
  - Ensure CSP everywhere [#&#8203;7810](FreshRSS/FreshRSS#7810)
  - Show warning when unsafe CSP policy is in use [#&#8203;7804](FreshRSS/FreshRSS#7804)
  - Fix access rights when creating a new user [#&#8203;7783](FreshRSS/FreshRSS#7783)
  - Improve security of form for user details [#&#8203;7771](FreshRSS/FreshRSS#7771), [#&#8203;7786](FreshRSS/FreshRSS#7786)
  - Disallow setting non-existent theme [#&#8203;7722](FreshRSS/FreshRSS#7722)
  - Regenerate cookie ID after logging out [#&#8203;7762](FreshRSS/FreshRSS#7762)
  - Require current password when setting new password [#&#8203;7763](FreshRSS/FreshRSS#7763)
  - Add missing access checks for feed-related actions [#&#8203;7768](FreshRSS/FreshRSS#7768)
  - Strip more unsafe attributes such as `referrerpolicy`, `ping` [#&#8203;7770](FreshRSS/FreshRSS#7770)
  - Remove unneeded execution permissions [#&#8203;7802](FreshRSS/FreshRSS#7802)
- Bug fixing
  - Fix redirections when scraping from HTML [#&#8203;7654](FreshRSS/FreshRSS#7654), [#&#8203;7741](FreshRSS/FreshRSS#7741)
  - Fix multiple authentication HTTP headers [#&#8203;7703](FreshRSS/FreshRSS#7703)
  - Fix HTML queries with a single feed [#&#8203;7730](FreshRSS/FreshRSS#7730)
  - WebSub: only perform a redirection when coming from WebSub [#&#8203;7738](FreshRSS/FreshRSS#7738)
  - Include enclosures in entries’ hash [#&#8203;7719](FreshRSS/FreshRSS#7719)
    - Negative side-effect: users of the option to *automatically mark updated articles as unread* will once have some articles with enclosures re-appear as unread
  - Fix cancellation of slider exit UI [#&#8203;7705](FreshRSS/FreshRSS#7705)
  - Honor *disable update* on update page [#&#8203;7733](FreshRSS/FreshRSS#7733)
  - Fix no registration limit setting [#&#8203;7751](FreshRSS/FreshRSS#7751)
  - Fix XML encoding of sharing functions [#&#8203;7822](FreshRSS/FreshRSS#7822)
- SimplePie
  - Fix propagation of HTTP error codes [#&#8203;7670](FreshRSS/FreshRSS#7670)
  - Fix support for XML feeds with HTML entities [#&#8203;7689](FreshRSS/FreshRSS#7689), [simplepie#915](simplepie/simplepie#915)
  - Fix feeds encoded in UTF-16LE [#&#8203;7691](FreshRSS/FreshRSS#7691), [simplepie#916](simplepie/simplepie#916)
  - Various upstream contributions [simplepie#917](simplepie/simplepie#917), [simplepie#924](simplepie/simplepie#924),
    [simplepie#926](simplepie/simplepie#926), [simplepie#932](simplepie/simplepie#932), [simplepie#933](simplepie/simplepie#933)
  - Sync upstream [#&#8203;7706](FreshRSS/FreshRSS#7706), [FreshRSS/simplepie#45](FreshRSS/simplepie#45), [#&#8203;7775](FreshRSS/FreshRSS#7775),
    [FreshRSS/simplepie#50](FreshRSS/simplepie#50), [#&#8203;7824](FreshRSS/FreshRSS#7824), [#&#8203;7825](FreshRSS/FreshRSS#7825),
  - Fix regex *Backtrack limit was exhausted* in `clean_hash()` [#&#8203;7813](FreshRSS/FreshRSS#7813), [FreshRSS/simplepie#48](FreshRSS/simplepie#48)
- Deployment
  - Docker default image (Debian 12 Bookworm) updated to PHP 8.2.29 [#&#8203;7805](FreshRSS/FreshRSS#7805)
  - Docker alternative image updated to Alpine 3.22 with PHP 8.4.11 and Apache 2.4.65 [#&#8203;7740](FreshRSS/FreshRSS#7740), [#&#8203;7740](FreshRSS/FreshRSS#7740),
    [#&#8203;7803](FreshRSS/FreshRSS#7803)
  - Start supporting PHP 8.5+ [#&#8203;7787](FreshRSS/FreshRSS#7787), [#&#8203;7826](FreshRSS/FreshRSS#7826)
    - Docker Alpine dev image `:newest` updated to PHP 8.5-alpha and Apache 2.4.65 [#&#8203;7773](FreshRSS/FreshRSS#7773)
  - Docker: interpolate `FRESHRSS_INSTALL` and `FRESHRSS_USER` variables [#&#8203;7725](FreshRSS/FreshRSS#7725)
  - Docker: Reduce how much data needs to be chown/chmod’ed on container startup [#&#8203;7793](FreshRSS/FreshRSS#7793)
  - Test for database PDO typing support during install (relevant for MySQL / MariaDB with obsolete driver) [#&#8203;7651](FreshRSS/FreshRSS#7651)
- Extensions
  - Add API endpoint for extensions [#&#8203;7576](FreshRSS/FreshRSS#7576)
  - Expose the reading modes for extensions [#&#8203;7668](FreshRSS/FreshRSS#7668), [#&#8203;7688](FreshRSS/FreshRSS#7688)
  - New extension hook `before_login_btn` [#&#8203;7761](FreshRSS/FreshRSS#7761)
- UI
  - Improve *mark as read* request showing popup due to `onbeforeunload` [#&#8203;7554](FreshRSS/FreshRSS#7554)
  - Fix lazy-loading for `<video poster="...">` and `<image>` [#&#8203;7636](FreshRSS/FreshRSS#7636)
  - Avoid styling `<code>` inside of `<pre>` [#&#8203;7797](FreshRSS/FreshRSS#7797)
  - Improve confirmation logic with `data-auto-leave-validation` [#&#8203;7785](FreshRSS/FreshRSS#7785)
  - Update `chart.js` to 4.5.0 [#&#8203;7752](FreshRSS/FreshRSS#7752), [#&#8203;7816](FreshRSS/FreshRSS#7816)
  - Various UI and style improvements: [#&#8203;7616](FreshRSS/FreshRSS#7616), [#&#8203;7811](FreshRSS/FreshRSS#7811)
- I18n
  - Show translation status in README [#&#8203;7715](FreshRSS/FreshRSS#7715)
  - Improve Indonesian [#&#8203;7654](FreshRSS/FreshRSS#7654), [#&#8203;7721](FreshRSS/FreshRSS#7721)
  - Improve Persian [#&#8203;7795](FreshRSS/FreshRSS#7795)
- Misc.
  - Improve PHP code [#&#8203;7642](FreshRSS/FreshRSS#7642), [#&#8203;7665](FreshRSS/FreshRSS#7665), [#&#8203;7761](FreshRSS/FreshRSS#7761),
    [#&#8203;7781](FreshRSS/FreshRSS#7781), [#&#8203;7794](FreshRSS/FreshRSS#7794)
  - Update dev dependencies [#&#8203;7708](FreshRSS/FreshRSS#7708), [#&#8203;7709](FreshRSS/FreshRSS#7709), [#&#8203;7710](FreshRSS/FreshRSS#7710),
    [#&#8203;7711](FreshRSS/FreshRSS#7711), [#&#8203;7776](FreshRSS/FreshRSS#7776), [#&#8203;7777](FreshRSS/FreshRSS#7777)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4zNS4wIiwidXBkYXRlZEluVmVyIjoiNDEuMzUuMCIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOlsiaW1hZ2UiXX0=-->

Reviewed-on: https://gitea.alexlebens.dev/alexlebens/infrastructure/pulls/1253
Co-authored-by: Renovate Bot <[email protected]>
Co-committed-by: Renovate Bot <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants