So think of this like if an ADDRESS-BAR widget existed. Any manipulation of it (on the server) is mirrored in real time on the client (without the page there refreshing). Remember; typical web problems like this are solved already.
But the general problem still remains. One have several widgets with states, and an ADDRESS-BAR widget instance -- and these widgets communicate something(?) with this ADDRESS-BAR widget instance.
*sigh* Maybe I should "just do it"; start with a TOGGLE-BUTTON widget, sync it with the ADDRESS-BAR widget instance and see where it leads me. I'll probably paint myself into a corner 3 or 4 times as there doesn't seem to be too many (any at all?) well-known solutions for this.
--
Lars Rune Nøstdal
http://nostdal.org/
This is one way how an ajax app handles "old guys with money (who)
always click the 'back' button":
http://nettuts.com/javascript-ajax/how-to-load-in-and-animate-content-with-jquery/#comments
They use the jquery History plugin (search the comments for
"history").
HTH
yeah, i was thinking of something like that for the client end of things ..
.. puzzled about how to express this on the server end of things though .. i think some serialize-state-to-uri method is needed for widgets, and some way for the user to add widgets to a list of widgets that is to have their states serialized and synced with the client side uri .....orsomething
..and, yeah, the other way around too; transferring state from uri to widgets .. that should be interesting x)
you're right, the jquery history plugin doesn't help you much if you
are using a widget architecture.
then you might consider (what I call) the "undo" pattern, whose
'proper' name is the Memento pattern.
http://en.wikipedia.org/wiki/Memento_pattern
In other words, this is just a stack of saved states.
You could annotate the stack with URIs. If somebody hits the back
button, you just pop the saved states and reset the corresponding
widgets. This would be hell on a server if your site is high-traffic,
but I guess you can offload this to perm storage to get it out of main
memory (as you say, serialize it).
The alternative to saved states is saving reciprocal functions. For
every action a widget takes, it places it's reciprocal action in a
stack in session state in case the old, rich man hits the back button.
This is more difficult to do than simply saving state prior to making
any widget changes. I can't think of any distinct advantages to using
this method.
HTH
Thinking about this a little more.
It would be more efficient to use reciprocal functions if state is
large. I guess you would use reciprocal functions if you were writing
a text editor, for example, since it would be too cumbersome to save
the entire document before every edit.
..thanks for the ideas.. i've been doing some thinking too .. this might read as nonsense(#1) but here goes nothing:
What about not maintaining history on the server at all since it's already there at the client?
I mean; this URL is supposed to be able to represent the _current_ state of some interesting widgets so one can share the URL with others so they can view approximately the same thing as I do Right Now (and only that) anyway. History can't be copy/pasted as URLs so what is the point in storing or dealing with this at the server in the first place?
If one have a 3 widget application that does something like:
* add some basic search terms
* add some more advanced search terms
* show search results
..the two first widgets changes their own states and mirrors this in the URL at the same time as they go.
If the user copies the URL and pastes it into another browser it too will have the same effect as the user manipulating the two first widgets. It will change the internal state of the widgets based on the URL. The back-button will at this time be grayed out.
Now, at this point, if the user changes some of the search terms it will change the URL at the same time thus adding client side history and enabling the back-button as we go. If he wants to go back, the client will remember the previous URL and send this data to the server thus updating the internal state of the widgets again and it'll work as if one is navigating through history or time when really one's just changing the current state (single point in time all the times) from a different mechanism than doing it via the UI.
The "location" is also just a state. Location is just a container widget that has a certain child widget(#2) added to it or marked as visible. Which widget that is contained or visible is also just a state that is maintained or mirrored in the URL.
Going to try to rephrase this;
* widget's state is changed through two "channels"
* ..the first channel is a user manipulating regular UI widgets
* ..the second channel is the URL manipulating the same widgets
* ..and manipulation of the first channel changes the URL
A concern now is of course that the URL can't just keep growing. If the user navigates to an entirely different part of the application it should forget about the URL-data that mirrors the old part or section of the applications state. This part is still fuzzy to me (more than other parts) ... x)
#1: but i'm pretty certain it isn't .. i'm just not sure how to express it properly in words or in code yet
#2: or a container widget can really contain many child-widgets .. even other container widgets .. so this is, or can be, a tree really
This is an excellent exercise but I don't think it's going to scale on
all important axes. I like how you made this optional.
Other "state" articles/projects I've recently stumbled upon that you
might find of interest:
http://www.ibm.com/developerworks/web/library/wa-aj-resttip.html?S_TACT=105AGX08&S_CMP=EDU
http://www.ajaxonomy.com/2007/web-design/a-better-ajax-back-button-solution
http://www.ajaxonomy.com/2008/web-design/a-better-ajax-back-button-part2
http://code.google.com/p/reallysimplehistory/
Yeah, only way it _can_ scale is because the user can control what widget's state to "put in the URL" like that.
At least the feature is there now(#1), and the user can fully control it down to pr. widget basis (what and how to serialize to URL) -- so it's up to him to make sure he doesn't overflow the URL I guess.
#1: well, haven't committed a patch yet ..
Ok, done .. early initial patch committed ..
..what now? O_o .. i forgot where i was before i started on this :P .. i still got some more weeks where i can work, almost, full time on this
maybe i should look at what Hans is doing with Hunchentoot or perhaps look at IOLib .. or maybe forget about scalability for a while longer and just add more widgets (which?) .. or something .....?
(tbh. there is so much to do i just keep losing track or overview of where i am and what to do next)
I don't have any specific symbolicweb insights but I can share my
latest thought experiment. Maybe you have some insight or experience.
Webkit seems to be doing the most innovative browser development so
I've been following their blog. I'm trying to get my web work to be a
little more responsive so I found Webkit's write-up insightful:
http://webkit.org/blog/166/optimizing-page-loading-in-web-browser/
This got me thinking, what if you took this one step further. Instead
of trying to load the page all in one shot, why not try loading it
sequentially and from top to bottom? For example, some web pages have
a table of images that are loaded in parallel. The only problem is,
the browser doesn't seem to do a very good job of populating these
types of tables. Sometimes portions of tables that aren't even
displayed are fully loaded before the topmost cells of the window are
loaded, and the parallel requests are (normally) limited to just four
at a time. I've been wondering how much faster the page would /appear/
to load if the table was loaded one cell at a time, starting at the
top left, and sequentially making new requests to load the next cell
as soon as that cell finishes loading. I would think that loading
pages/tables from top to bottom would make the page appear to be more
responsive, even if it took the same amount of time to load in total.
I don't know, just something I'm kicking around. Taking over part of
the browser functionality is a lot of work, but if the experiment
makes the page appear to load noticably faster, it may be worth it.
Cool idea. jQuery has something related to it:
http://www.appelsiini.net/projects/lazyload
http://plugins.jquery.com/project/lazyload
What you describe would look something like this in SW:
(defun load-images-in-sequence (images)
(let ((previous-image (first images)))
(dolist (image (rest images))
(let ((original-src (src-of image)))
(setf (on-load-of previous-image)
(js-code-of (setf (src-of image) original-src)))
previous-image
image)))))
Working with instances of the IMAGE widget here. Pretty decent -- well, it beats doing this in plain JavaScript IMHO. :)
..actually, this will do if I'm not mistaken:
(defun load-images-in-sequence (images)
(let ((previous-image (first images)))
(dolist (image (rest images))
(setf (on-load-of previous-image)
(js-code-of (setf (src-of image) (src-of image)))
previous-image
image))))
..no need for the LET.
No wait, need this ofc.
(defun load-images-in-sequence (images)
(let ((previous-image (first images)))
(dolist (image (rest images))
(setf (on-load-of previous-image)
(js-code-of (setf (src-of image) (src-of image)))
(src-of image)
""
previous-image
image))))
..so it doesn't trigger the initial load that the browser does by itself.
(last try this .. :P)
Thanks. I'll play around with this and see if it things feel snappier.
-lv