I was playing around with the newsfeed notification system
(`ARTICLE_MORE_DETAILS`, `ARTICLE_TOGGLE_FULL`, …) and discovered some
issues with the full article view:
The iframe was loading the CORS proxy URL instead of the actual article
URL, which could cause blank screens depending on the feed. Also, many
news sites block iframes entirely (`X-Frame-Options: DENY`) and the user
got no feedback at all — just an empty page. On top of that, scrolling
used `window.scrollTo()` which moved the entire MagicMirror page instead
of just the article.
This PR cleans that up:
- Use the raw article URL for the iframe (CORS proxy is only needed for
server-side feed fetching)
- Check `X-Frame-Options` / `Content-Security-Policy` headers
server-side before showing the iframe — if the site blocks it, show a
brief "Article cannot be displayed here." message and return to normal
view
- Show the iframe as a fixed full-screen overlay so other modules aren't
affected, scroll via `container.scrollTop`
- Keep the progressive disclosure behavior for `ARTICLE_MORE_DETAILS`
(title → description → iframe → scroll)
- Delete `fullarticle.njk`, replace with `getDom()` override
- Fix `ARTICLE_INFO_RESPONSE` returning proxy URL instead of real URL
- A few smaller fixes (negative scroll, null guard)
- Add `NEWSFEED_ARTICLE_UNAVAILABLE` translation to all 47 language
files
- Add e2e tests for the notification handlers (`ARTICLE_NEXT`,
`ARTICLE_PREVIOUS`, `ARTICLE_INFO_REQUEST`, `ARTICLE_LESS_DETAILS`)
## What this means for users
- The full article view now works reliably across different feeds
- If a news site blocks iframes, the user sees a brief message instead
of a blank screen
- Additional e2e tests make the module more robust and less likely to
break silently in future MagicMirror versions
This migrates the Newsfeed module to use the centralized HTTPFetcher
class (introduced in #4016), following the same pattern as the Calendar
module.
This continues the refactoring effort to centralize HTTP error handling
across all modules.
## Changes
**NewsfeedFetcher:**
- Refactored from function constructor to ES6 class (like the calendar
module in #3959)
- Replaced manual fetch() + timer handling with HTTPFetcher composition
- Uses structured error objects with translation keys
- Inherits smart retry strategies (401/403, 429, 5xx backoff)
- Inherits timeout handling (30s) and AbortController
**node_helper.js:**
- Updated error handler to use `errorInfo.translationKey`
- Simplified property access (`fetcher.url`, `fetcher.items`)
**Cleanup:**
- Removed `js/module_functions.js` (`scheduleTimer` no longer needed)
- Removed `#module_functions` import from package.json
## Related
Part of the HTTPFetcher migration effort started in #4016.
Next candidate: Weather module (client-side → server-side migration).
Since the project's inception, I've missed a clear separation between
default and third-party modules.
This increases complexity within the project (exclude `modules`, but not
`modules/default`), but the mixed use is particularly problematic in
Docker setups.
Therefore, with this pull request, I'm moving the default modules to a
different directory.
~~I've chosen `default/modules`, but I'm not bothered about it;
`defaultmodules` or something similar would work just as well.~~
Changed to `defaultmodules`.
Let me know if there's a majority in favor of this change.