Discussion:
[jifty-devel] Server pushed region updates (was Re: Manipulating page regions from actions)
Sterling Hanenkamp
2008-08-25 03:01:44 UTC
Permalink
Attached you find a patch that modifies the webservices/xml template and
jifty.js to include a feature for updating parts of the web site not
requested by the client, i.e., server pushed updates.

It works like this. An action or dispatcher on the server could decide to
update other regions other than those requested by the "fragments" part of a
webservices request. The webservices request might not even include a
fragments request. It works like this:

(1) The action or dispatcher before rule (or something else called before
the on rules start) calls Jifty->web->request->add_fragment() and adds a
custom fragment request. As the code currently works, an action might do
this, but that response would be ignored by the client.

(2) When add_fragment() is called, an additional parameter named "metadata"
is passed a hashref of options. These options are a subset of the options
normally passed to an event handler added to a hyperlink() or other form
element. For example, a request might be something like:

Jifty->web->request->add_fragment(
name => 'journal_list-new_comment_entry-status',
path => '/status_message',
arguments => { message => 'Add a comment to a task.' },
metadata => {
region => 'journal_list-new_comment_entry-status',
mode => 'Replace',
},
);

(3) This will cause the dispatcher to invoke "/status_message" when handling
the response. This will be added to the webservices/xml response with an
additional <metadata> section added. The metadata section is parsed and read
by Jifty.update() to take the place of the fragment information normally
used to determine where and how to update the page.

One interesting thing I changed was the allowance for an "element" attribute
to be included to update multiple elements on the page with a single
fragment. This is both powerful and dangerous since you might replace lots
of things unintentionally if your selector is too inclusive.

I'm not sure the actual implementation I've included is idea, but it is
along the lines of what I was thinking when I posted my last message.

Another implementation I thought of during the process is somehow providing
hooks that could be run to do really fancy customized updates based upon the
same principle. The way I thought of implementing that would be to include
class attributes on the <fragment>s returned that could be matched by hooks
which are then setup in a Behaviour-esque manner. When such a fragment is
returned, the matching hook or hooks would be called and giving the fragment
as a data structure to be dealt with in whatever manner suits the
application.

As a side note, Jifty.update() does includes a little more than just the web
services call and the handling of the fragments and action results that I
expected. It also includes some code for client-side templating (very cool)
and single page app stuff that seems like it belongs elsewhere to be invoked
only when those things are used by the application, but that's just my
opinion. Seems like Jifty.update() ought to be more easily moddable though
since it is such a central feature of Jifty. If it were, these things might
be easily extracted off into specialized hooks of some kind.

Cheers,
Sterling

On Sat, Aug 16, 2008 at 9:41 PM, Sterling Hanenkamp
Maybe there's a way to do this, but I have found myself recently wanting to
be able to manipulate page regions on the basis of an action's result.
For example, I have an action that does a bunch of magic based upon the
input. I have a page that shows a list of timers. These timers each belong
to an entry, which groups a set of timers together. Each entry has a list of
tasks associated with it that is displayed in a sidebar of each timer for
that entry.
My magic action may have one of the following 5 manipulations that could
1. *Create a task.* If the action creates a new task, it will need to
insert the task into zero or more lists (zero or more page regions depending
on how many timers are currently being displayed on the page).
2. *Comment on a task.* In this case, we don't need to refresh
anything. All regions should remain unchanged.
3. *Comment on a timer.* I'd need to insert the new comment at the top
of the comments list (a region) on the top-most timer.
4. *Restart an entry.* I'd need to insert a new timer (complete with a
list of comments and tasks) at the top of the timers list.
5. *Start a new entry.* This is exactly the same as (4), it just
happens to represent a new, never before seen entry.
I can do this pretty easily by just refreshing the whole page, but I'd
rather not. The page can get pretty long by the end of a day and the point
of using ajax is so that I don't have to refresh the whole page.
# on create a task
$self->result->update_page({
region => 'entry_list-entry_14-task_list',
prepend => '/journal/task',
arguments => {
task_id => 103,
format => 'journal',
},
});
# on comment on a task.... nothing
# on comment on a timer
$self->result->update_page({
region => 'entry_list-entry_14-comment_list',
prepend => '/journal/view_comment',
arguments => { comment_id => 7813 },
});
# on restart an entry
$self->result->update_page({
region => 'entry_list',
prepend => '/journal/view_timer',
arguments => { timer_id => 155 },
});
# on start a new entry
# same as above
Essentially, I'd like to change the onclick actions in the response from
the action itself rather than having to foreknow them during at click time.
The other solution I've come up with (and quite possibly the one I use for
now) is to include 5 different buttons that each do these things. Then,
present the button that does the right thing as soon as we have enough input
to make that judgment. I do that to some extent now by having an extra ajax
request that changes the name of the button to something that hints at
what's going on (1=Taskinate, 2=Comment, 3=Post, 4=Restart, 5=Start), but
there are a couple places where I'm going to have to handle that delicately
to make sure it DWIMs.
I'm open to doing this anyway that works reasonably well and will to commit
smallish sized patches to help at thsi time, but I don't have much time to
spare at the moment for anything moderate to largish.
Any suggestions?
Cheers,
Sterling
Jesse Vincent
2008-08-25 13:00:54 UTC
Permalink
Sterling,

My cranky-architect comments are that the name "metadata" isn't really
very evocative and that without docs or tests, the patch isn't likely
to be used by many people and is likely to get broken the first time
someone tries to clean up one of these codepaths.

In general, though, I'm a fan. I know that we've had code that does
something along these lines before, though I don't recall the exact
mechanism. Similarly, alex has been doing a lot of work on the pubsub
stuff and I know it's possible for the server to build up and stream a
queue of fragment updates for the client side. It'd be cool if there
were more unity between these mechanisms.

-j
Sterling Hanenkamp
2008-08-25 14:02:01 UTC
Permalink
Post by Jesse Vincent
Sterling,
My cranky-architect comments are that the name "metadata" isn't really
very evocative and that without docs or tests, the patch isn't likely
to be used by many people and is likely to get broken the first time
someone tries to clean up one of these codepaths.
Agreed. Which is why I essentially said not to use the patch in the
comments. It's more a proof of concept than a useful hunk of code at this
point. However, if there was a mechanism for injecting some information into
the returned response that could be reacted to, I think that would be swell.
Currently, I'd have to implement such a thing on my own.

I'm going to see if I can come up with something that's more flexible and
less likely to bring out the cranky-architect. After looking through
jifty.js in detail, it looks like Jifty.update() and related functions
really ought to be refactored as a Jifty.Update class (probably with a
better name than that) with parts that could be used separately and would be
more extensible. I could see Ajax and PubSub being extensions of some base
with the potential of the application further extending them and then
setting:

framework:
javascript:
ajax_update_class: MyApp.AjaxUpdate
pubsub_update_class: MyApp.PubSubUpdate

to make all the event handler code use a custom class instead. Just thinking
out loud...

Cheers,
Sterling
Post by Jesse Vincent
In general, though, I'm a fan. I know that we've had code that does
something along these lines before, though I don't recall the exact
mechanism. Similarly, alex has been doing a lot of work on the pubsub
stuff and I know it's possible for the server to build up and stream a
queue of fragment updates for the client side. It'd be cool if there
were more unity between these mechanisms.
-j
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
Jesse Vincent
2008-08-25 15:23:36 UTC
Permalink
Post by Jesse Vincent
Sterling,
My cranky-architect comments are that the name "metadata" isn't really
very evocative and that without docs or tests, the patch isn't likely
to be used by many people and is likely to get broken the first time
someone tries to clean up one of these codepaths.
Agreed. Which is why I essentially said not to use the patch in the
comments. It's more a proof of concept than a useful hunk of code at
this point. However, if there was a mechanism for injecting some
information into the returned response that could be reacted to, I
think that would be swell. Currently, I'd have to implement such a
thing on my own.
I'm going to see if I can come up with something that's more
flexible and less likely to bring out the cranky-architect. After
looking through jifty.js in detail, it looks like Jifty.update() and
related functions really ought to be refactored as a Jifty.Update
class (probably with a better name than that) with parts that could
be used separately and would be more extensible. I could see Ajax
and PubSub being extensions of some base with the potential of the
That all sounds pretty reasonable.

-j
Post by Jesse Vincent
ajax_update_class: MyApp.AjaxUpdate
pubsub_update_class: MyApp.PubSubUpdate
to make all the event handler code use a custom class instead. Just
thinking out loud...
Cheers,
Sterling
In general, though, I'm a fan. I know that we've had code that does
something along these lines before, though I don't recall the exact
mechanism. Similarly, alex has been doing a lot of work on the pubsub
stuff and I know it's possible for the server to build up and stream a
queue of fragment updates for the client side. It'd be cool if there
were more unity between these mechanisms.
-j
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
_______________________________________________
jifty-devel mailing list
http://lists.jifty.org/cgi-bin/mailman/listinfo/jifty-devel
Loading...