So for awhile now, I have really ponder on how to cache only certain CTool modals display. For instance, I have wanted to create a CTools Modal for zooming in on images and I would like it to respond right away. So when I click it, I don't want to wait for an AJAX request, I want it now.
Same thing for login forms, when I click sign in, I would really like the form to be displayed right away. Modern websites accomplish this by putting the form in the markup and just hiding it until button click.
This patch, accomplishes these goals without using the markup. It does a fetch when Drupal.attachBehaviors is run and creates a cache in the browser. (Drupal.CTools.Modal.Cache).
So the response moves really fast on any a.ctools-use-modal-cache.
For whatever reason the following code failed on the .ajax request
/**
* Click() function for modals that can be cached.
*/
Drupal.CTools.Modal.clickAjaxCacheLink = function () {
var position = $(this).attr('rel');
if (position.length != 0 && Drupal.CTools.Modal.Cache[position]) {
Drupal.CTools.Modal.show();
Drupal.CTools.AJAX.respond(Drupal.CTools.Modal.Cache[position]);
return false;
}
else {
// HERE WE FAIL WITH UNDEFINED ERROR
Drupal.CTools.Modal.clickAjaxLink.apply(this)
}
};
Not sure as to why, so I just copied that function into the else (see patch).
Comment | File | Size | Author |
---|---|---|---|
#14 | ctools_686052-14.patch | 4.24 KB | Scott Reynolds |
#10 | ctools_686052-10.patch | 4.05 KB | Scott Reynolds |
#6 | ctools_686052-6.patch | 3.89 KB | Scott Reynolds |
#5 | ctools_686052-4.patch | 3.9 KB | Scott Reynolds |
#3 | ctools_686052-3.patch | 3.5 KB | Scott Reynolds |
Comments
Comment #1
merlinofchaos CreditAttribution: merlinofchaos commentedI! Love! This!
I would like to see this a little more generic. It seems like this could be used in all kinds of places that aren't the modal. For example, let's say I'm using the AJAX framework to write an image browser, where I show X images and have left and right buttons that use AJAX to fetch the next.
It seems like it would be very simple to warm the cache with the commands array, but only execute it when the button is actually clicked. It would be nearly the same code, I think and so could possibly be genericized?
It could have a massive, positive performance impact on many tools...for no cost to developers whatsoever.
Comment #2
Scott Reynolds CreditAttribution: Scott Reynolds commentedThis time, tested patch with more then one ctools-use-modal-cache link and realized a minor error with the .each.
Comment #3
Scott Reynolds CreditAttribution: Scott Reynolds commentedok so here is the generalization for any ctools command. I have used it and tested it with both modal and non modal commands. I have to tell ya, its sexy.....
Comment #4
Scott Reynolds CreditAttribution: Scott Reynolds commentedBeen think aobut it some more. Perhaps we create a jquery event ('ctools-cached'). Then in warm cache, it fetches the result and fires off that event.
This then allows the click functions to do
That way we don't hit the server twice for the same link (one when its trying to cache, and the other when its not cached yet but user clicked).
Comment #5
Scott Reynolds CreditAttribution: Scott Reynolds commentedOk so followed up on my last comment. What the real point of that change is to prevent a user from clicking a cachable link before the result has been cached. Thus creating TWO hits on the url, one for the cache warming and one for the user click.
This patch addresses that point, when a user clicks and its ctools-fetching, it binds to the ctools-cache-warm event to render the display. Thus waiting for the cache result to return.
Comment #6
Scott Reynolds CreditAttribution: Scott Reynolds commentedtiny code style change (4 spaces instead of 2 on one of the lines.)
Comment #7
m3avrck CreditAttribution: m3avrck commentedThis is looking great! However, if you have 3 links on the page that all goto a login form, you will fire off 3 of the same AJAX requests:
http://img.skitch.com/20100119-ku8xd4nfcsnwpm277u3r1ukicf.jpg
I think a way around it would be a static cache within warmCache():
What would make this even killer was if it was smart enough to run a single AJAX request even if the destination was different, and then be smart enough to fix the response with the correct destination.
Comment #8
m3avrck CreditAttribution: m3avrck commentedSorry this should be updated to use an object cache, not an array cache. But same psuedo-code still applies.
Comment #9
Scott Reynolds CreditAttribution: Scott Reynolds commentedI agree, instead of an Array() we use an Object(). and then we can do .commandCache[url] = data.
then we have to manage a set of links, triggering ctools-warm-cache on all of them that match as well as setting ctools-fetching on all the ones that do match but didn't init the ajax call.
Some management that can go in there, that while, complicated is totally doable and desirable.
Comment #10
Scott Reynolds CreditAttribution: Scott Reynolds commentedSo this next installment :-D, achieves the following.
For three links that goto user/login/nojs?destination=user, it does exactly one request to that url and this is done via cache warming. If the user clicks the link before the cache is warm, it still waits until the cache is warm, displaying only the loading modal for instance.
It achieves m3avrck's goals, minus the destination part. And thats only because, the get parameters could really determine a different response not just another additional ctools command. Take pagers for example, a ?page=2 will return completely different markup then ?page=4. It would be undesirable to try and determine that at the javascript layer.
But for links like that where you know that on your site user/login/nojs?destination=X, you could write your own behavior for those links and have it the cache warming only once for them. Just requires some creativity.
Small note about my coding style for variables, I use $STRING to represent jQuery objects. if you object to that, then I can rework that. Its just a small short hand I use and I find it helpful.
Comment #11
m3avrck CreditAttribution: m3avrck commentedDoes:
var $objects = $('a[href=' + old_url + ']')
need to refind the same link? Won't this actually just be$this
instead of an expensive selector?Also, in the $.ajax, can you try adding cache: true? IIRC, jQuery doesn't cache JSON by default. In this case, I would imagine it could be cached locally in browser, so subsequent hits are even faster.
Comment #12
Scott Reynolds CreditAttribution: Scott Reynolds commentedIts not finding the same link. Its finding all links like it (hence plural). So it finds all user/login/nojs?destination=user, and that includes $this, but its also is every other link.
ahh you sure? looking at http://api.jquery.com/jQuery.ajax/, it says "Default true, false for dataType 'script' and 'jsonp'". Now I think that site is for jquery 1.4, so maybe its changed?
Comment #13
m3avrck CreditAttribution: m3avrck commentedOk maybe add a comment that is finding duplicates? Forgot about that :)
You would need to check the cache headers from AJAX response.
For clarity, it might be better to explicitly state cache: true
Comment #14
Scott Reynolds CreditAttribution: Scott Reynolds commentedOk I agree with m3avrck that we should add a comment about 'duplicates'. If he couldn't understand what that line was doing and he had explicitly asked for that then clearly it need some comments
added
I think that makes it clear.
Comment #15
merlinofchaos CreditAttribution: merlinofchaos commentedOk, I went ahead and committed this. I rearranged the binding slightly so that it's safe to use ctools-use-ajax and ctools-use-ajax-cache together (previously you would've gotten ugly errors). You still don't really want to do this, but it won't cause errors now, I think.
The use of this should be documented along with the ajax documentation. Though there's a bigger project there too, which is that we may want to go look up all the nice documentation that got written for core when this went into D7, and backport it into CTools documentation (with a comparison of what's different in D7 which may help people in their porting).
Comment #16
merlinofchaos CreditAttribution: merlinofchaos commentedOh one other thing. We probably want to port the cache warming part to D7, but that's going to basically be its own thing since most of the AJAX stuff is in core in D7.
Comment #17
merlinofchaos CreditAttribution: merlinofchaos commentedComment #18
japerryClosing this issue as outdated as Drupal 6 ctools is not supported. If this issue is relevant for Drupal 7, feel free to re-open and mark for Drupal 7 (or 8)