| Age | Commit message (Collapse) | Author |
|
|
|
|
|
|
|
diff_against compared title/abstract/body under whatever I18n.locale
happened to be ambient, with no concept of 'diff this translation
specifically' -- so a change confined to one locale was invisible to
Diff Head vs. Draft regardless of which locale you were looking at
when you clicked it, exactly the 'yields nothing' complaint from
earlier this session.
Page#diff_against gains a locale: keyword, additive only -- nil
preserves the exact original ambient-locale behavior every existing
caller and test already depends on; passing a locale switches to
reading each side's actual PageTranslation row directly, same
fallback-free reasoning as Page#translation_summary. Page#locale_diff_summary
reports one entry per locale present on either side, so an added or
removed translation counts as a change even where content matches
everywhere it exists on both.
RevisionsController#diff now resolves a real locale before diffing --
defaulting to whichever locale actually changed, falling back to the
default locale only when nothing did -- and the view carries that
locale through every existing control (view toggle, layer-pair
buttons, the revision-select form) so it and the view/layer-pair axis
stay independently selectable rather than resetting each other.
|
|
superseded/currently_public used published_at presence as a proxy
for page-row relevance, but published_at is carried forward onto
every new draft descended from previously-published content
(Page#clone_attributes_from, Node#save_draft!) -- so it read true
for any draft on an already-published node, whether or not that
specific draft had ever gone live itself. Compare draft_id/head_id
identity directly instead; no timestamp involved. A stale
(superseded) link now redirects to the live public page rather than
an admin URL an anonymous holder can't reach anyway.
|
|
The shared TinyMCE setup initializes cccms.setup_autosave() on any
page with a textarea.with_editor, unconditionally starting a
7-second interval that submits to the form's data-autosave-url --
which the translation edit form never set, so the interval PUT the
current page URL itself and 404'd on a nonexistent route.
Fixed by actually giving it something to talk to, rather than
suppressing it: a real autosave endpoint, and update now goes
through Node#autosave!/#save_draft! -- the same pipeline the
primary editor uses, fixed earlier this session for exactly this
kind of cross-locale carryover. This was the autosave-buffer parity
already flagged as due after the proof of concept; the shared JS
just forced the timing.
|
|
Replaces the old locale-switch-and-edit-the-same-screen workflow,
which conflated presentation locale with content locale and let an
editor silently drift into editing the wrong language with no
persistent signal that anything had changed. Non-default-locale
content now has its own explicit routes and screens, never sharing
a route param with the ambient chrome locale.
- PageTranslationsController: index/show/edit/update/destroy,
scoped to Page.non_default_locales; update handles first-time
creation too, so there's no separate new/create step.
- Reads go through the actual PageTranslation row
(Page#translation_summary), never through the Globalize
fallback-bearing accessor -- fallback is correct for public
rendering but wrong for editing, where a missing translation
needs to look empty, not borrowed from another locale.
- Translations ride on the page's own draft/head cycle; no
independent publish state.
- nodes#show gains a Translations section (per-locale Lock+Edit /
Create+Lock, Destroy, a link into the read-only Compare view) and
a locale indicator on its own default-locale content; nodes#edit,
nodes#update, and nodes#autosave are pinned to the default locale
via Globalize.with_locale regardless of the ambient route locale.
- nodes#show no longer double-loads the node or calls wipe_draft!
on every view (see previous commit for why that's now safe).
- .preview_link_row is renamed .aligned_action_row now that it has
a second real consumer.
|
|
Replaces nodes#edit's old Images section -- a hidden panel dumping
every image asset in the system unfiltered (#image_browser) plus a
raw drag-and-drop box (#image_box) -- with a small search-and-click
picker built on the endpoint from the last two commits. Attaching
posts immediately and appends the new thumbnail via a cloned
<template> -- icons only render correctly through the Rails helper
server-side, so the template holds real, pre-rendered markup for JS
to clone rather than duplicating raw SVG in a JS string. Reordering is
jQuery UI sortable on the small attached list only, with a dedicated
drag handle rather than the whole thumbnail.
Two bugs caught while click-testing, fixed here rather than shipped
and patched after: the search panel never closed after attaching an
image, since the success handler re-triggered focus to keep it open
for attaching several in a row -- which meant it just re-populated
itself forever instead of signaling "done." Fixed to close explicitly;
a click-outside-closes handler was added alongside it, matching the
affordance the top-bar search already has.
A real, independent, pre-existing data bug surfaced during the same
testing: Node#autosave!'s first-time-creation branch never carried
related assets forward from whatever page was previously current --
attach an image, let autosave fire once, and it silently landed on a
fresh, assetless Page row. Long-dormant, not introduced by this work,
just finally exercised by something that made it visible. Fixed inside
the `unless self.autosave` guard specifically -- running this on every
call, not just creation, would overwrite anything attached directly to
an existing autosave in between, a worse bug than the one being fixed.
nodes#show gains a read-only Images section, rendered only when a page
actually has attached images, so an attachment can be confirmed
present without entering the edit/lock cycle -- useful on its own, and
specifically useful the next time an asset bug needs investigating.
Its thumbnail CSS is shared with the edit view's picker via a class
(.thumbnail_list) rather than duplicated under a second name.
|
|
initSearchPicker's input handler has always short-circuited on an empty
term -- correct for every existing picker, none of which want results
appearing before anything's typed. The asset picker does want exactly
that (show the last few uploaded images without requiring a search
first), so this adds an opt-in loadOnFocus option instead of changing
the shared default: it fires once when the input gains focus with no
term yet, reusing the same request/render path a real search uses
rather than a separate code path. The AJAX call itself was pulled out
into a named runSearch function so both triggers could share it without
duplicating the success/render logic.
RelatedAssetsController#search now treats a blank term as "show the
most recently created, unattached images" (limit 5) rather than
returning nothing, matching the new client behavior. A real search
term still returns up to 10 name-matched results, unchanged.
|
|
Backend for the asset-picker rebuild -- replaces the plan to dump
every image asset in the system into a hidden, unfiltered browse
panel on every node edit (the actual current behavior, confirmed by
reading nodes/edit.html.erb directly) with a small, name-scoped search
endpoint plus create/destroy/update for attach, detach, and reorder.
No schema change needed -- RelatedAsset already had everything this
requires (asset_id, page_id, an acts_as_list position). search excludes
assets already attached to the page, keeping results meaningfully small
given hundreds of assets total but only a handful per node in practice.
create is find_or_create_by! rather than a bare create!, guarding
against the same asset being attached twice from two separate search
results. update leans on acts_as_list's own insert_at rather than
custom position-shifting logic.
Node#editable_page (autosave || draft || head) is extracted since this
is now its third call site with identical logic -- deliberately not
touching nodes#show, which resolves draft || head without autosave on
purpose, a different and correct semantic for "current committed
state" versus "what's actively being edited."
|
|
Replaces the old admin#index wizard -- accreted over years, never
designed as a whole -- with the dashboard settled on this session:
a three-icon nav (dashboard/search/log out, no locale selector), a
nodes-first search bar, four task signposts, and two symmetric
widgets (drafts/autosaves, recent changes) with a quiet housekeeping
row beneath them.
Node.recently_changed now filters and orders by the head page's own
updated_at instead of the node's blanket timestamp, so a lock/unlock
cycle with no actual publish no longer surfaces here, and the
original publisher is no longer misattributed to someone else's
housekeeping action. This also restores the "published" qualifier on
each entry, which the query previously couldn't guarantee was true.
@mynodes and its dedicated "My Work" table are retired along with the
old wizard -- "Continue my work" is a link to the existing, already-
correct NodesController#mine instead of a second, duplicate query.
Its one dedicated test (dedup across multiple revisions by the same
user) is ported to nodes_controller_test.rb, since mine already
carries the same .distinct protection the old query did; it just had
no test of its own until now.
|
|
AdminController#dashboard_search returns tags and nodes as separate,
labeled groups (via ActsAsTaggableOn::Tag.named_like and
Node.editor_search) rather than the flat per-node list every existing
picker returns. initSearchPicker gains a renderResults callback option
that, when given, replaces the default per-node rendering entirely --
lets the dashboard render its two labeled groups without a second,
parallel picker implementation.
resultsHeaderHtml (the "Press Enter to see all results" hint) is now
threaded through as a third argument to renderResults, so a picker with
custom rendering can still show it -- previously only the default
per-node branch ever did.
Tags link straight to the existing /admin/nodes/tags/:tag view rather
than becoming an in-place filter chip.
|
|
Node.drafts_and_autosaves and Node.recently_changed replace inline
query logic in NodesController#drafts/#recent -- pure refactor, no
behavior change for either action. The real reason: the dashboard's
upcoming abridged widgets need the exact same queries the full pages
already use, just limited and (for drafts) sorted with the current
user's own locked nodes first. Better to share one method than let a
widget and a full page quietly drift onto two versions of "what counts
as a current draft."
current_user_id: is an explicit, optional argument rather than a
separate method -- ordering by lock ownership only applies when a user
is given; omitted entirely, it's pure recency, exactly today's
behavior. Needed Arel.sql wrapping a sanitized CASE expression before
.order would accept it -- sanitize_sql_array only vouches for the
values inside the string, a separate Rails safety check still refuses
any string shaped like more than a plain column reference unless it's
explicitly marked as already-vetted.
|
|
menu_items/parent_search/move_to_search/event_search each duplicated
their own debounce-free AJAX call and result rendering. Replaced with
one shared initSearchPicker, taking each picker's distinctive
behavior (parent_search's live path preview, event_search's title
hint) as a callback rather than a whole reimplementation. Adds a real
debounce with an out-of-order-response guard -- none of the four had
either before. admin_search (the Alt+F top-bar search) now shares the
same function via its own url/isActive/header options, gaining the
same guard and fixing an inconsistency of its own (it previously
always slid its panel open, even on zero results).
Each picker's results container gets its own id instead of sharing
was ever supposed to be on screen at once, an assumption with no
actual enforcement behind it. Styling moved from an id-pair
(#menu_search_results, #search_results) to a shared .search_results
class so a future picker never needs this file touched again.
menu_search and the admin top-bar search now call Node.editor_search
instead of the public, head-only Node.search -- both are admin-only,
authenticated views, and had no reason to inherit the public search's
"can't find a draft" limitation. The always-ignored :per_page => 1000
on the latter is gone too; Node.search's second argument was never
read by the method at all.
Also removed a stale #metadata a { text-transform: lowercase } rule,
found while verifying the above -- written for the pre-subnav-removal
expand-toggle, which no longer exists; it had been silently
lowercasing nodes#edit's own, unrelated #metadata div (including
move_to_search's results) by id coincidence ever since. #main_navigation
and #overview_toggle intentionally left capitalized rather than
special-cased -- both belong to the nav bar already slated to shrink
to three icons, not worth polishing on the way out.
|
|
Extracted from admin#index's inline table into NodesController#sitemap.
Nested <details>/<summary> per branch, one linear pass over the
existing flat [node, level] list (no added queries) -- each node's own
descendant count computed the same way, via a small stack rather than
re-walking the tree per node. Branches under updates/, club/erfas,
club/chaostreffs, and disclosure start collapsed by default
(CccConventions::SITEMAP_COLLAPSED_PATHS); any branch currently
collapsed, whether by that default or because someone just closed it,
is highlighted via a plain :not([open]) selector -- no state tracked
outside the DOM itself.
Dropped the update?-post exclusion this view used to rely on -- no
longer needed now that updates/ collapses instead of being filtered
out, so its real children (previously silently absent) now show up
correctly. admin#index's own, separate @sitemap query is unchanged;
that view has no collapse mechanism to compensate and wasn't part of
this.
|
|
Four NodesController actions -- drafts, recent, mine, chapters --
each building its own base scope, sharing one private method
(index_matching) for search narrowing and pagination. Wizard rewrite
to link into these instead of rendering its own tables is a separate,
later step.
Node.editor_search backs the shared "q" narrowing: an ILIKE substring
match against title/abstract on whichever of head or draft is
present, splitting the term on whitespace and requiring every word to
match somewhere independently, not as one phrase, since real words can
end up separated by markup in the underlying HTML. Deliberately
separate from Node.search, the public content search, which stays
tsvector-based and head-only.
chapters generalizes into /admin/nodes/tags/:tags for an arbitrary
tag list (OR'd, not AND'd), sharing the controller action but
rendering its own template rather than branching inside one view.
|
|
@mynodes used the bare @current_user ivar instead of the current_user
method (works today only because login_required already forces that
memoization; every other query and controller in this app uses the
method), and .uniq, which is plain Enumerable#uniq here, not
Relation#distinct -- it materializes every joined row into an Array
before deduplicating, rather than deduplicating in SQL.
@mypages had the same ivar pattern, no .order/.limit unlike every
sibling query in this action, and -- confirmed via a full grep -- is
referenced nowhere else in the codebase. Removed rather than bounded;
nothing was ever rendering it.
|
|
|
|
Node#resolve_page_reference and #available_layer_pairs let
Page#diff_against compare named layers (head/draft/autosave), not
just numbered revisions -- autosave was never part of Node#pages, so
this was the missing piece.
Wired into nodes#show's Status section, nodes#edit right after an
autosave gets resurrected ("What changed?"), and the admin wizard's
current-drafts table, which now also lists autosave-only nodes it
previously never showed.
revisions#diff hides the numbered-revision picker when comparing
named layers (it can't represent them), shows a plain label instead,
and offers buttons to switch between whichever other pairs make
sense for the node's current state. Destroying the topmost layer is
available directly from the diff view, reusing the existing revert!
path.
"Discard changes" is renamed "Discard Autosave" everywhere it
appears, to match "Destroy Draft".
|
|
Revisions#diff now computes an inline or side-by-side word diff
server-side (Page#diff_against, lib/html_word_diff.rb) instead of
shipping raw/escaped content to the browser for a 2008-era vendored
JS differ to mangle. View mode is picked via a `view` param, settable
either on the diff page itself or directly from the revisions#index
sticky bar next to "Diff revisions".
Also fixes a pre-existing bug in RevisionsController#diff's single-
revision branch, which set params[:start]/params[:end] instead of
params[:start_revision]/params[:end_revision].
|
|
|
|
|
|
Editors' TinyMCE output can contain unclosed void elements like <br>,
which is valid HTML5 but invalid XML -- three different places assumed
the stricter rule and broke or silently misbehaved on the looser one.
The Atom feed's <content type="xhtml"> block required real, well-formed
XML structure but was handed a raw, unescaped body string; switched to
type="html" with CGI.escapeHTML, matching how title/summary already
handle the same content. rewrite_links_in_body used libxml's strict XML
parser to rewrite internal links to be locale-prefixed, which raised on
exactly this class of malformed markup -- silently, since the whole
method was wrapped in rescue; nil, meaning the link rewrite (not the
save) quietly failed with no error anywhere. Replaced with Nokogiri's
lenient HTML parser, which repairs malformed void elements rather than
rejecting them; also drops the bare rescue now that the actual failure
mode it was guarding against shouldn't occur, and fixes two adjacent
bugs found while in this method: a typo'd /sytem/uploads/ regex that
could never match, and a missing https:// exclusion alongside the
existing http:// one.
Also addresses stale flash messaging surfaced while testing the above:
update's save confirmation was being clobbered by edit's own "locked
and ready" notice on the very next request, since nothing distinguished
a fresh lock acquisition from a redirect back after saving. The save
confirmation now names the next step (publish from Status) and flags a
stale translation if one exists, using Page#outdated_translations?,
already present but previously unused by any controller.
|
|
Remove dead pages#index and occurrences resource; fix menu_items#new
menu_items#new called menu_item_params, which requires a submitted
menu_item key that can never be present on a fresh GET -- new only
ever needs a blank record to render against.
pages#index and the entire occurrences resource were unmodified Rails
scaffold generator output, unlinked from any nav and unreachable except
by direct URL. pages#index had no controller action at all (@pages was
never assigned); occurrences#index queried every row with no scoping or
pagination and its layout referenced a scaffold.css asset that no
longer exists in the pipeline. Neither is a real editorial surface --
occurrences are auto-generated from an event's RRULE and were never
meant to be browsed as a flat list. Removed rather than repaired.
pages#preview and pages#sort_images remain, now as explicit routes
rather than under a full resources :pages block.
|
|
Retires content_for :subnavigation on nodes#show entirely -- Preview
was fully redundant with Links' own preview URLs in every state, and
Edit is now a permanent, always-rendered action inside the new Status
section rather than a link floating at the top, consistent with the
"action lives next to the info" pattern People already established
for Unlock. Status surfaces head/draft/autosave plainly and gates
Edit/Publish/Destroy/Discard on lock ownership specifically, not mere
lock presence -- @node.locked? alone would have blocked the lock
owner's own session, caught by the click-test and fixed here rather
than shipped.
nodes#edit's action bar is rebuilt to sit outside form_for (both
button_to calls render their own nested form, invalid HTML the
browser was silently stripping) with Save wired back in via
form="..." rather than needing to live inside the form tag at all.
Also brings the locked-and-ready-to-edit flash message, and the
visual polish from this session's click-test: consistent button
heights across the bordered and pill-shaped variants sharing a row,
spacing between Status's data and its actions, and error_messages
styling reusing the destructive-red vocabulary already established
elsewhere.
|
|
revert! requires the lock to already be held, correct for nodes#edit
where the editor holds it throughout -- but both exclusive-case
buttons on nodes#show fire from a node that starts out unlocked,
which raised LockedByAnotherUser incorrectly. lock_for_editing! first
makes both call sites safe: a harmless re-stamp when already the
owner, a real but momentary acquisition otherwise, released again by
revert! itself once nothing is left to protect.
|
|
A blank title failed presence and length validation simultaneously,
showing two redundant messages for one problem; length now skips
whenever slug is already blank, matching presence's own skip
condition. Separately, create's failure path never computed
@selected_kind/@parent_id/@parent_name the way new does, so
re-rendering after a validation error silently lost which kind and
parent had been chosen -- for the auto-tagging/auto-templating kinds,
that meant a corrected resubmission could silently produce a plain
generic node instead. required on the title field closes the common
case without a round trip; the server-side fix remains the actual
guarantee, since required is trivially bypassed.
|
|
revert! discards exactly the topmost non-empty layer -- autosave if
present, else draft -- and reveals whatever's beneath it, releasing the
lock only once nothing is left to protect. Guards against destroying a
brand-new, never-published node's only draft, which would violate the
(head | draft) invariant every other method here assumes holds; the
view's Destroy/Discard button is gated the same way.
nodes#edit now calls lock_for_editing! instead of find_or_create_draft,
and always displays autosave || draft || head, resurrecting an
abandoned session's unsaved content by default with an explicit flash
explaining what's shown and how to get back to the last saved version.
The view drops content_for :subnavigation entirely: Show becomes
"Unlock + Back", Preview stays a plain link, metadata's own <details>
already replaced the old toggle, and Publish moves off this page for
good, per the earlier decision to manage the publish lifecycle
entirely from nodes#show. Save Draft and Save + Unlock + Exit appear
both above and below the form, given the body field alone runs 600px
on desktop.
|
|
Route Save and autosave through the new Node methods
update now promotes the current autosave into the draft via
save_draft! rather than writing submitted params directly; autosave
gets its own PUT member route so PATCH update can mean "deliberate
save" specifically, matching every other custom action on this
resource. Both now require the lock to already be held rather than
acquiring it themselves, which is a deliberate narrowing: through the
real UI this is always true, since neither can fire before edit has
loaded. Two existing tests called update directly with no prior
edit, which the old code tolerated by acquiring the lock as a side
effect; updated to call edit first instead of loosening the
guarantee back open.
NodesController#edit itself is unchanged and still calls the old
find_or_create_draft, so drafts are still created eagerly on entering
edit for now -- switching that over is the next step, not this one.
|
|
parent_match Procs on CccConventions::NODE_KINDS, matched against
unique_path, decide which "add child" kinds show on a given node. Fixes
nodes#new not honoring a pre-selected kind (radio group and parent-field
visibility both defaulted to "generic" unconditionally).
|
|
Root-caused this session: appending a child to any node never widened
that parent's own rgt boundary, on the pinned revision (Gemfile tracked
main directly, chasing a too-conservative gemspec constraint - not, as
first assumed, a deliberate pin to avoid a known bug). Reproduced
cleanly on a single ordinary create with no concurrency and no bulk
operation involved, confirmed via the gem's own SetValidator, then
confirmed as the root cause of nodes_controller_test.rb's 3 long-standing
"pre-existing" failures - not three separate mysteries, one bug.
admin_controller's sitemap needed its own real conversion, not just a
drop-in: awesome_nested_set's lft column implicitly provided correct
depth-first tree order for free, which the old code combined with a
separate class-level each_with_level iterator. Both replaced by one
method, self_and_descendants_ordered_with_level, computing an ordered
[node, level] list in a single query-then-walk pass - checked against
the actual view template first (admin/index.html.erb) rather than
assumed, since it relies on list order alone to render correct visual
nesting.
lft/rgt/depth columns intentionally left in schema, unused - dropping
them is a separate, deliberately deferred migration once this is proven
running for a while, not bundled with the behavior change.
|
|
A token's page could stop being node.head_id (superseded by a newer
draft) while still being published_at.present? - the old check only
compared against the current head, so a superseded page fell through
to direct rendering instead of redirecting, serving a stale frozen
snapshot indefinitely instead of the current live content.
Also handles scheduled publishing correctly: a page can be head_id but
not yet public? (published_at in the future) - that case must still
render directly, not redirect into a 404 on the not-yet-live public
URL.
|
|
Lets editors share a draft with people outside the admin system, via a
random per-page token rather than an enumerable id - /preview/<token>.
shared_previews#show is intentionally unauthenticated. Redirects to the
real public URL once the page is published. Surfaced on nodes#show
(Admin Preview + Public Preview, next to Public Link) as generate/revoke
buttons.
|
|
|
|
lib/ccc_conventions.rb: NODE_KINDS registry replaces the kind-specific
branches previously scattered across nodes_controller#create (tags),
unique_path-position check). Each kind declares its parent lookup
(a Proc - Update's "update"/"press_release" continue to genuinely
find-or-create their year-folder via Update.find_or_create_parent;
erfa/chaostreff use a plain find_by_unique_name!, since their parent
nodes are fixed and a missing one should fail loudly, not be silently
created), its tags, and (new) its default template.
Node gains a default_template_name column (migration, with backfill
for existing update-tree nodes via node.update? - reusing that method
rather than re-deriving its unique_path check in raw SQL). Page#set_template
now inherits from node.default_template_name, falling back to the old
update?-based check only when the column is blank, and only fills in
template_name when nothing's already been explicitly chosen - a
deliberate change from the previous behavior, which unconditionally
overwrote template_name on every save regardless of manual selection.
Node#update? itself is unchanged and still used as-is by
admin_controller's sitemap filtering - a genuinely different, still
valid use of that check.
"generic" stays special-cased in the controller, parametrized by
params[:parent_id] at request time - doesn't fit "kind implies a fixed
lookup" and isn't in the registry.
nodes#new's four hardcoded radio buttons and nodes_controller's
kind-specific case/when branches are both replaced by iterating/looking
up this one registry - adding a new kind now means one new hash entry,
not four scattered edits.
|
|
layouts/admin.html.erb's top-bar search results div shared id
"search_results" with nodes#new/nodes#edit's parent-search widget -
since the layout renders on every admin page, whichever widget's JS
ran last silently won the shared ID, putting top-bar results into the
parent-search box on affected pages. Renamed to "menu_search_results"
and updated admin_search.js to match.
Also modernizes admin_search.js's event bindings from keyup/keydown/
keypress/paste/cut + .attr("value") to input + .val() throughout
(menu_items, parent_search, move_to_search) - the multi-event binding
was working around old IE compatibility that .val() + "input" already
handles correctly. parent_search's result rendering now matches
menu_search's convention (real <p>/<a> markup with a .result_path
span) instead of a bare <a> in a throwaway wrapper div, so the same
CSS rule now correctly applies to both.
menu_search's JSON response gains node_path per result, matching what
admin_search's own results already provide - not yet consumed by
parent_search/move_to_search, which still render click-to-select links
rather than navigable ones (correct for their purpose - selecting a
value, not leaving the page).
Known remaining gap, not fixed here: menu_items, parent_search, and
move_to_search still all target the literal id "search_results"
between themselves. No live collision today since none of the three
currently share a page, but it's the same fragility as the bug above -
tracked alongside the existing menu_items/parent_search/move_to_search
consolidation backlog item rather than treated as resolved.
|
|
Defined only in ApplicationHelper, which Rails auto-mixes into views
but not controllers - so events#create and events#update, which call
it directly, have been broken since introduction. Likely unexercised
until now because every existing event was created via
node.events.create! in the seed script, never through a real POST.
Moved to ApplicationController as a protected method + helper_method
declaration, so both controllers and views can call it (form_error_
messages stays in ApplicationHelper - it's genuinely view-only,
content_tag isn't available in a controller either). Logic unchanged,
caught by the new EventsController tests in the previous commit.
|
|
nodes#show's events table now renders unconditionally (previously
hidden entirely for a zero-event node) and gains an "add event" link.
The suggested tag_list is derived from the page's own category tags
via NodesHelper::DEFAULT_EVENT_TAG_BY_PAGE_TAG (erfa-detail/
chaostreff-detail -> open-day) rather than hardcoded, and degrades to
a blank field for any node whose tags don't match - deliberately
universal, not chapter-specific, since Updates have historically
carried event dates the same way.
events#new surfaces *why* the tag was pre-filled via flash.now (not
flash - this is a same-request render, not a redirect), using an
explicit auto_tag_source param passed alongside tag_list rather than
having the controller re-derive the reason from node_id.
No destroy link added to nodes#show's events list - deliberate, per
existing subnav-semantics convention (destructive actions live on the
resource's own views). Covered directly by test.
Adds real coverage for EventsController, previously 100% commented-out
scaffold, plus unit tests for the new tag-mapping helper and the
weekday-abbreviation helpers from the prior commit.
|
|
- events_controller: wire return_to through show and new actions;
create respects return_to with fallback to node/event path;
new pre-populates node_id and tag_list from params
- events/edit: remove custom_rrule checkbox; node link removed from
subnav (use show for node navigation); destroy button added
- events/new: remove custom_rrule checkbox; add return_to hidden
field and back link; tag_list field added
- events/show: fix back link via safe_return_to; add node link to
subnav; add destroy button; remove custom_rrule display; show
humanized rrule below raw string
- events/index: destructive class on destroy button; node_id column
replaced with node link; show/edit links carry return_to
- nodes/show: add show/edit links to event entries with return_to
|
|
- event_params now permits title, description, is_primary
- event_information helper lists all node.events, not just the first
- Occurrence.generate handles nil node (standalone events)
- Page.aggregate order_by title uses correlated subquery to avoid
GROUP BY conflict with tag-filter path; order_direction whitelisted
to ASC/DESC to prevent SQL injection
- Events link added to admin menu bar
- events/index shows title, is_primary; drops latitude/longitude columns
|
|
|
|
|
|
|
|
- Widen overlay (300px -> min(520px, 90vw)), centre instead of
hardcoded left:400px, so it scales from mobile to desktop
- Split title and unique_name into separate JSON fields and DOM
elements; two-line result layout (bold title, small grey
monospace path) instead of "Title (path)" wrapping awkwardly
- Add small margin between title and path line
- Fix event handler stacking: keyup/escape/outside-click handlers
were being rebound on every display_toggle call. Moved all
bindings to initialize(), display_toggle() now only shows/hides
- Switch search input from keyup to input event, catching paste
and cut via mouse which keyup misses
- Add Escape key and outside-click to dismiss the overlay
- Stop clearing search box and results on close; reopening now
preserves prior search, matching standard search UI behaviour
- Link search results to node_path instead of edit_node_path,
since opening edit auto-locks the node
- Add "press Enter to see all results" hint in dropdown
- Disable browser autocomplete on search input
|
|
- Admin search broke when routing-filter was removed: hardcoded /admin/search
and /admin/menu_search URLs in admin_search.js no longer matched the
locale-scoped routes. Fix by emitting locale-aware URLs from the layout
as JS variables.
- Also fixes form submission (POST -> GET, missing = on form_tag), jQuery
.attr("value") -> .val() for typeahead input reading, and template name
for Rails 8 compatibility.
- Adds a visible "search" link to the admin menu so editors can discover
the feature without knowing the Alt+F shortcut. Search results now show
node path alongside title and link directly to the edit view.
Named route admin_menu_search added to routes.rb.
|
|
- rss#tag_updates action: filters Page.heads by tag name, default
locale, 20 items, same caching as updates feed
- tag_updates.xml.builder: Atom feed with CGI.escapeHTML on title
and summary, consistent with updates.xml.builder
- tags/show.html.erb: add subscription link above article list
- routes: two routes per existing pattern (format-less + .:format
constrained to /xml/)
|
|
- nodes_controller: permit staged_slug and staged_parent_id in node
params; these were silently dropped since strong parameters migration,
breaking the two-phase slug/parent change workflow
- file_attachment: add SVG support; vector files are copied to all style
directories without rasterisation, preserving scalability in the browser
- assets index/show: constrain image display with max-width/max-height
via admin.css td img rule; fixes oversized SVG thumbnails while leaving
raster variants unaffected
|
|
- Bump Rails to 8.1.3 (Ruby unchanged at 3.2.11, new gemset rails8-upgrade)
- config.load_defaults 8.1; merge app:update diffs for all environment files
- Remove routing-filter 0.7.0; replace with native scope '(:locale)' in
routes.rb and default_url_options in ApplicationController
- Delete config/initializers/routing_filter_rails71_patch.rb
- Replace vendored TinyMCE 3.x (~200 files) with tinymce-rails ~> 8.3;
migrate admin_interface.js from jQuery .tinymce()/advanced theme to
tinymce.init(); add config/tinymce.yml; note: TinyMCE 7+ is GPL
- rails-i18n ~> 8.0 added explicitly (previously indirect dependency)
- awesome_nested_set, acts-as-taggable-on pinned to git main/master
(gemspec activerecord < 8.1 ceiling; no functional incompatibility;
repin to version once upstream releases updated gemspecs)
- globalize ~> 7.0, libxml-ruby ~> 5.0, nokogiri ~> 1.18, pg ~> 1.5
- sass-rails, coffee-rails, uglifier moved from :assets group to main
(Sprockets 4 convention; :assets group no longer meaningful)
- Node: head, draft, lock_owner marked belongs_to optional: true
- Page: node, user, editor marked belongs_to optional: true
- Static assets in public/images/ and public/javascripts/ referenced via
plain HTML tags; Rails 8 load_defaults raises on pipeline helpers for
undeclared assets
- sessions_controller_test.rb: remove stale require and dead rescue_action
- users_controller_test.rb: assert button[type=submit] not input[type=submit]
(Rails 8 button_to renders <button> not <input>)
- test_helper.rb: node.reload after children.create! (awesome_nested_set
3.9.0 does not refresh parent in memory after callback)
- 129 runs, 339 assertions, 3 failures, 0 errors — identical baseline to 7.2
|
|
|
|
- routing-filter 0.6.3 -> 0.7.0 (Rails 6.1 compatibility)
- RSS named routes rss_xml/rss_rdf added
- RouteWithParams workarounds: will_paginate_patch, content_path shim, safe_path helper
- Paperclip removed, replaced with FileAttachment concern (preserves URL scheme)
- Assets resource moved to /admin/assets (Sprockets middleware conflict)
- ApplicationRecord base class added, all models migrated
- Strong parameters added to Assets, Occurrences, Events, MenuItems controllers
- update_attributes -> update throughout
- render :nothing -> head :ok/:not_found throughout
- language_selector rewritten (removes :overwrite_params)
- Environment files updated for Rails 6.1 (eager_load, public_file_server, ActionMailer)
- Arel::Visitors::DepthFirst and Integer/Float duration patches removed from test_helper
- AssetsController tests added (10 tests covering upload, variants, destroy, auth)
- ImageMagick geometry: 460x250! for headline crop (not # which is invalid in IM6)
129 runs, 311 assertions, 5 failures (all pre-existing), 0 errors
|