Edgewall Software

Opened 6 years ago

Last modified 2 years ago

#10852 new enhancement

Hooks for custom Javascript after expanding/collapsing an element

Reported by: Ethan Jucovy <ethan.jucovy@…> Owned by:
Priority: normal Milestone: next-stable-1.2.x
Component: general Version:
Severity: normal Keywords: javascript
Cc: Ryan J Ollos Branch:
Release Notes:
API Changes:


I need to hook in some Javascript to be executed right after Trac's folding.js causes a section to be expanded or collapsed.

(Specifically, when a section with a textarea is expanded after being initially collapsed, I need to redraw any WYSIWYG editors that might be applied to those textareas.)

Right now it's hard to hook in that Javascript: since enableFolding binds a click event to a trigger element that it may or may not create dynamically, it's not easy to apply another click event to the right element; and also, your click handler then has to inspect the class of the right div to see if it's currently collapsed or expanded. This means you end up with code that's very dependent on the ordering of DOM elements, and on the order in which click events are bound, in ways that seem somewhat brittle and poorly self-documenting, e.g.:

  $(".foldable").enableFolding(false, true);

  // make sure to bind this click event AFTER enableFolding, or else a:first might not exist, and even if it does the click events will be fired in the wrong order
  $(".foldable a:first").click(function() {  // is it always the first anchor?
    var collapsed = $(this.parentNode.parentNode).hasClass("collapsed");  // is it always going to be the grandparent node?
    if( collapsed ) {

Some of these problems would be lessened by applying some more helper classes in the enableFolding function, so that (e.g.) the trigger could always be identified by .foldable a.foldable-trigger and the collapsible div could always be identified by $(".foldable").closest(".collapsible"). Beyond that, though, it would also be useful to trigger a custom jQuery event on the foldable element itself, so that custom Javascript could just hook in to be fired right after the folding event has taken place, and without having to worry about the order of event bindings or whether the triggers have been created in the DOM when the binding is set up.

Attachments (1)

folding-hooks.diff (767 bytes ) - added by Ethan Jucovy <ethan.jucovy@…> 6 years ago.

Download all attachments as: .zip

Change History (7)

by Ethan Jucovy <ethan.jucovy@…>, 6 years ago

Attachment: folding-hooks.diff added

comment:1 by Ethan Jucovy <ethan.jucovy@…>, 6 years ago

The attached patch adds class hooks to the various functional elements, and fires a custom "fold" event on the element that folding was enabled on, passing along a boolean flag indicating whether the container was just folded or unfolded. (Possibly firing two distinct events "fold" and "unfold" would be cleaner, I'm not sure?) This would let me simplify my client code to:

  // this event can be bound at any time, before or after enableFolding(".foldable")
  $(".foldable").bind("fold", function(event, collapsed) {
    if( collapsed ) {
       // do something with the container that was just collapsed, which is now easy to find
       $(this).closest("collapsible") [...]

  $(".foldable").enableFolding(false, true);

comment:2 by Christian Boos, 6 years ago

While adding these extra classes won't hurt, we certainly need to think about JavaScript modularity and extensibility by plugins. Custom events (trac:fold?) would be one possibility, but in the end I think we'll need something like our trac.core.Components mechanism…

comment:3 by Christian Boos, 6 years ago

Keywords: javascript added
Milestone: next-stable-1.0.x

comment:4 by Ethan Jucovy <ethan.jucovy@…>, 6 years ago

I just noticed that adding the extra classes would also make it possible to refactor the styles in trac.css a bit — all the .foldable :link, .foldable :visited rules could be replaced with .foldable-trigger:link, .foldable-trigger:visited. The class foldable itself would then just be used in limited ways (report.css, admin.css) as a styling class, independent of its related Javascript functionality. (And of course as a hook for applying that Javascript functionality on specific Trac pages.)

This would make it much easier to reuse folding.js with elements that don't have class="foldable"; right now the Javascript doesn't require or document that class, and Trac's internal usage implies that you can call $(any_selector).enableFolding(), but the CSS only applies the styles that make it functional (arrows indicating state, rounded box to make it clearly an interactive widget) if the selected elements have class="foldable".

comment:5 by Ryan J Ollos, 4 years ago

Cc: Ryan J Ollos added

comment:6 by Ryan J Ollos, 2 years ago

Milestone: next-stable-1.0.xnext-stable-1.2.x

Moved ticket assigned to next-stable-1.0.x since maintenance of 1.0.x is coming to a close. Please move the ticket back if it's critical to fix on 1.0.x.

Modify Ticket

Change Properties
Set your email in Preferences
as new The ticket will remain with no owner.
The ticket will be disowned.
as The resolution will be set.
The owner will be changed from (none) to anonymous.

Add Comment

E-mail address and name can be saved in the Preferences .
Note: See TracTickets for help on using tickets.