0

I am making a sort of tabbed interface for a Tiddlywiki, and I am wondering how to get this code to fire every time a tiddler is opened or closed. Tiddlywiki is an HTML notebook type of thing that runs in the browser, and a tiddler is a div in #tiddlerDisplay. There can be, and usually are, more than one in it at a time.

The divs I want to list are contained in #tiddlerDisplay, and the list itself is jQuery("#mainMenu > #singleTiddlerList").

config.macros.singleTiddler.update = function(){
    jQuery("#mainMenu > #singleTiddlerList").empty();
    jQuery("#tiddlerDisplay > div").each(function(i,e){
        jQuery("#mainMenu > #singleTiddlerList").append(jQuery(
            createTiddlyButton(document.createElement("li"),jQuery(e).attr("tiddler"),"",config.macros.singleTiddler.clickHandler)
        ).parent());
    });
};

Update: I can't just add a custom event, unless I can do it from outside the current code (such as something that fires on document load).

Arlen Beiler
  • 15,336
  • 34
  • 92
  • 135

2 Answers2

0

First create two custom events for your append/clearing of divs. Have them bind in the document you use the code posted above.

jQuery(document).bind('div-removed',function(e){ 
  // code stuff to do for removal 
  jQuery("#mainMenu > #singleTiddlerList").empty(); // required
  // other stuff here
});
jQuery(document).bind('div-appended',function(e){ 
 // code stuff to do on append 
        jQuery("#tiddlerDisplay > div").each(function(i,e){
            jQuery("#mainMenu > #singleTiddlerList").append(jQuery(
                createTiddlyButton(document.createElement("li"),jQuery(e).attr("tiddler"),"",config.macros.singleTiddler.clickHandler)
            ).parent());
        }); // required
  //other stuff here
});

Then in your code change slightly the execution:

config.macros.singleTiddler.update = function(){
  $(document).trigger("div-removed");
  $(document).trigger("div-appended");  
};

It's definitely not the only way (I think now it can also be done with .promise() but it's a start. update updated to check if this works.

Panagiotis
  • 1,539
  • 1
  • 14
  • 28
  • Will the first trigger only fire when all the divs are removed or whenever a div is removed? – Arlen Beiler Jul 20 '12 at 20:51
  • Wait, I think there is a misunderstanding here. The tiddlers are in `#tiddlerDisplay` and the list is in `#singleTiddlerList`. I've updated my question to reflect this. The code I don't want to edit is the code that adds and removes divs from `#tiddlerDisplay`. – Arlen Beiler Jul 20 '12 at 20:55
  • Hmm maybe [this](http://api.jquery.com/delegate/) will help you then. Maybe you need delegation. – Panagiotis Jul 20 '12 at 21:00
  • What event do I assign? Does JavaScript have a function hook feature that can fire an event when a function is called? – Arlen Beiler Jul 20 '12 at 21:09
  • Can you see if the new code works? Actually you break the inner code to two events, that are fired and execute the excess code inside. – Panagiotis Jul 20 '12 at 21:24
  • It says removed is not defined, but that may be an error on my part. However, I don't quite think you understand what I'm trying to do. All I want to do is catch the event that fires (if one does) when a div is added to or removed from the div with ID `#singleTiddlerList`. – Arlen Beiler Jul 20 '12 at 22:07
0

One way is jQuery("#tiddlerDisplay").bind("DOMSubtreeModified", config.macros.singleTiddler.update);, however i think this only works in Chrome (maybe Opera or Safari, not sure), and also appears to be deprecated. Firefox has a duo of events to accomplish the same thing, but i think these are also deprecated.

Another way I found after reading this article and exploring the TiddlyWiki source code is this:

(function( $, oldRem ){
    Story.prototype.displayTiddler = function(){
        var resp = oldRem.apply( this, arguments );
        $("#tiddlerDisplay").trigger("displayTiddler");
        return(resp);
    };
})( jQuery, Story.prototype.displayTiddler );
(function( $, oldRem ){
    Story.prototype.closeTiddler = function(){
        var resp = oldRem.apply( this, arguments );
        $("#tiddlerDisplay").trigger("closeTiddler");
        return(resp);
    };
})( jQuery, Story.prototype.closeTiddler );
jQuery("#tiddlerDisplay").bind("displayTiddler", config.macros.singleTiddler.update);
jQuery("#tiddlerDisplay").bind("closeTiddler", config.macros.singleTiddler.update);

Notice that the event fires after the tiddler opens or closes. Also, as the article states, jQuery can be bugged in the same way, but I don't know about the native DOM methods, and I kind of doubt it. There's supposed to be an event for it, but regardless, everyone should totally drop them and use jQuery!

Arlen Beiler
  • 15,336
  • 34
  • 92
  • 135
  • 1
    My brain is racing with all the posibilities this opens up! A year ago I was wishing for exactly this. It's amazing how sometimes when you can't figure something out, and you come back to it later, it just kind of falls into place. – Arlen Beiler Jul 20 '12 at 23:27
  • I don't know if this is called an override or not, but this works great for me. I just have to beware of another plugin overriding it. I call this method bugging. – Arlen Beiler Jul 21 '12 at 00:06