fix(view): pass standard Underscore templateSettings on every compile#404
Merged
Merged
Conversation
Problem: every Underscore template in this portlet (event list, event
detail, role-param row) currently renders its raw source into the
portlet body instead of being interpolated. The events column shows
literal `<% if (_(days).size() === 0) { %>...<%= day.displayName %>...`
text where the actual events should appear.
Why: uPortal's respondr.xsl global init (in uPortal core,
respondr.xsl ~line 274) calls `up._ = _.noConflict()` and then
overwrites the shared `up._.templateSettings` with Mustache-style
delimiters:
interpolate: /{{=(.+?)}}/g
evaluate: /{{(.+?)}}/g
escape: /{{-([\s\S]+?)}}/g
scripts.jsp aliases that same instance via `${n}._ = up._`, so every
`_.template(...)` call in this portlet inherits the Mustache
delimiters. The portlet's templates use the standard `<% %>` /
`<%= %>` sigils, which no longer match anything in the regex, and
Underscore returns the source unchanged.
Goal: have the portlet's templates compile against the delimiters
they were authored for, without mutating the shared `up._` (which
would break other portlets — Marketplace, etc. — that already rely
on the Mustache override).
Changes:
- scripts.jsp: define a per-portlet-namespace
`${n}.upcalTemplateSettings` object holding the standard sigils.
The regex literals must be emitted as `${"<%"}...${"%>"}` so JSP's
own scriptlet parser doesn't swallow them — same trick the view
JSPs already use to write the literal sigils into the rendered
HTML templates.
- calendarWideView.jsp, calendarNarrowView.jsp,
editCalendarDefinition.jsp: pass `${n}.upcalTemplateSettings` as
the second argument to every `_.template(...)` call so the
per-call settings shadow the global Mustache defaults without
touching them.
Notes: Underscore 1.8.3's `_.template(text, settings)` does
`_.defaults({}, settings, _.templateSettings)`, so the explicit
settings win cleanly. Verified end-to-end with Playwright in
uPortal-start: a regression guard
(`tests/ux/portlets/calendar.spec.ts › event list renders without
leaking Underscore template sigils`) goes from failing to passing
once this change is deployed.
bjagg
added a commit
to bjagg/uPortal-start
that referenced
this pull request
May 5, 2026
Problem: this branch has been carrying tests and overlay seeds that depend on three companion fixes published over the last few days (uPortal Bootstrap dedupe, CalendarPortlet template-sigil leak, NotificationPortlet jjwt runtime classpath). Until those landed on Maven Central, CI couldn't go green here even though every spec passed locally against the locally-built SNAPSHOTs. Goal: consume the published GA versions so PR uPortal-Project#692 lights up green and is ready to merge. Changes: - uPortalVersion 5.17.4 → 5.17.5 (picks up uPortal-Project/uPortal#2980 — Bootstrap 5 include de-dup in the respondr skin, fixes silently-broken Options menus / favorites / rate-portlet across the dashboard) - calendarPortletVersion 2.7.2 → 2.7.3 (picks up uPortal-Project/CalendarPortlet#404 — Underscore template settings override per call, fixes the events column rendering raw template source instead of event entries) - notificationPortletVersion 4.8.3 → 4.8.4 (picks up uPortal-Project/NotificationPortlet#695 — pin jjwt-impl + jjwt-jackson at runtime, fixes /api/v2 silently 403'ing and the notification web components rendering empty) Notes: locally redeployed the three webapps from Maven Central artifacts and ran the Playwright suite three times in a row — 117/117 each pass — to confirm the published versions match what we were testing against the SNAPSHOTs.
6 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Every Underscore template in CalendarPortlet (event list, event detail, admin role-param row) currently renders its raw source into the portlet body instead of being interpolated. The events column shows literal text like:
…where the actual events should appear. Screenshot before:
Root cause
uPortal's
respondr.xsl(uPortal-webapp/src/main/resources/layout/theme/respondr/respondr.xsl, ~line 274) does:scripts.jspaliases that same instance via${n}._ = up._, so every_.template(...)call in this portlet inherits the Mustache delimiters at runtime. The portlet's templates use the standard<% %>/<%= %>sigils, which no longer match anything in the (Mustache) regex. Underscore returns the source unchanged, the rendered HTML is the template, and the user sees the raw Underscore syntax in the events column.The Mustache override in uPortal is intentional and shipping: Marketplace and other portlets rely on it. Mutating
up._.templateSettingsback from this portlet would break those.Fix
Set a per-portlet-namespace
${n}.upcalTemplateSettingsobject once inscripts.jspand pass it to every_.template(...)call as the second argument. Underscore 1.8.3's_.template(text, settings)does_.defaults({}, settings, _.templateSettings), so the explicit settings win without touching the shared global.The regex literals in
scripts.jspare emitted via the${\"<%\"}...${\"%>\"}EL trick — the same trick the view JSPs already use to write literal Underscore sigils into rendered HTML templates — so JSP's own scriptlet parser doesn't swallow the regex while compiling the page.Files changed
scripts.jsp— define${n}.upcalTemplateSettings.calendarWideView.jsp— pass settings to both_.template(...)calls (event list, event detail).calendarNarrowView.jsp— same two calls.editCalendarDefinition.jsp— pass settings to the role-param row template (the JSP that errored at the screenshot below isn't this one, but the fix is uniform).Verification
uPortal-start Playwright spec
tests/ux/portlets/calendar.spec.tsgets a new regression guard: "event list renders without leaking Underscore template sigils". Asserts the.upcal-event-listdoes not contain the substring<%. Fails before this PR, passes after redeployingCalendarPortlet.Visual confirmation: the events column now shows the expected "No events" alert (or the populated day list) instead of raw template text.
Notes
<% %>regex literals through the same EL escape (${\"<%\"}/${\"%>\"}) precisely because JSP cannot tolerate raw<%in the source. I made the same mistake mid-fix and got JspException immediately, which is how I traced the EL-escape pattern back intoscripts.jsp.calendar.js(upcal.tplSettings) so the JSPs would pull it from the compiled JS bundle. Decided against —scripts.jspalready runs per-portlet-instance and namespaces under${n}, which keeps the override scoped without leaking into other portlets that load this WAR.