Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Navigation, history and referenceability in GUIs

7 views
Skip to first unread message
Message has been deleted

Lars Rune Nøstdal

unread,
Jun 2, 2008, 7:52:49 AM6/2/08
to
Lars Rune Nøstdal wrote:
> Hello,
> I'm seeking some advice here. This is not something I've thought out
> well so I don't understand the question I'm asking or the answer I'm
> expecting to be honest ..
>
> I'm working on a widget based AJAX/COMET framework(#1), and in some
> cases the ability to link to interesting parts (and/or states?) of an
> application is needed(#2).
>
> Forget about the normal "web problems"(#3), and think of this in similar
> terms as normal GUI frameworks like GTK+ or QT, but one that needs an
> address bar in certain cases.

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/

vanekl

unread,
Jun 2, 2008, 2:42:53 PM6/2/08
to
On Jun 2, 10:45 am, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
> Hello,
> I'm seeking some advice here. This is not something I've thought out well so I don't understand the question I'm asking or the answer I'm expecting to be honest ..
>
> I'm working on a widget based AJAX/COMET framework(#1), and in some cases the ability to link to interesting parts (and/or states?) of an application is needed(#2).
>
> Forget about the normal "web problems"(#3), and think of this in similar terms as normal GUI frameworks like GTK+ or QT, but one that needs an address bar in certain cases. But, I haven't seen this in frameworks like QT and GTK+ before so I'm not sure how to go about it still.
>
> For example; a simple application with a single toggle-button widget in it. It has two states, T and NIL, and this state should be "transferred" to the address bar if the application-programmer wants this to happen. I guess the question is; how would a high-level nice API for doing or requesting something like this look like? Here is this simple application _without_ address bar support:
>
>   (defapp history-app ()
>     ((toggle-button (mk-toggle-button (mk-span "Toggle me")))))
>
>   (defmethod main ((app history-app))
>     (with-slots (toggle-button) app
>       (add toggle-button (root-widget-of app))))
>
> The toggle-button widget has a on-state-change slot I can "hook into". I suppose I could use that .. somehow .. but I'm thinking I'll run into problems later by doing this in a naive way.
>
> . I've been stuck on this for a couple of hours now. Maybe others (other GUI frameworks?) have done something similar already in a smart way that will scale to more complicated widgets and scenarios later? I'm thinking search results in a table widget with pagination etc. .. the most ideal solution, API or way to express this that you can imagine or have seen - totally disregarding any problems with regards to actually implementing it .. x)
>
> #1:http://groups.google.com/group/symbolicweb
>
> #2: ..and it seems the old guys with money always click the "back" button.
>
> #3: The reason for this is that I've already solved the lower-level problem of this and can code and think of web-applications as if they where normal GUI applications. I'm really looking for the most ideal way of expressing this in higher level terms.
>
> --
> Lars Rune Nøstdalhttp://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

Lars Rune Nøstdal

unread,
Jun 2, 2008, 3:40:42 PM6/2/08
to

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)

vanekl

unread,
Jun 2, 2008, 4:42:57 PM6/2/08
to
On Jun 2, 7:40 pm, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
> vanekl wrote:
> > On Jun 2, 10:45 am, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
> >> Hello,
> >> I'm seeking some advice here. This is not something I've thought out well so I don't understand the question I'm asking or the answer I'm expecting to be honest ..
>
> >> I'm working on a widget based AJAX/COMET framework(#1), and in some cases the ability to link to interesting parts (and/or states?) of an application is needed(#2).
>
> >> Forget about the normal "web problems"(#3), and think of this in similar terms as normal GUI frameworks like GTK+ or QT, but one that needs an address bar in certain cases. But, I haven't seen this in frameworks like QT and GTK+ before so I'm not sure how to go about it still.
>
> >> For example; a simple application with a single toggle-button widget in it. It has two states, T and NIL, and this state should be "transferred" to the address bar if the application-programmer wants this to happen. I guess the question is; how would a high-level nice API for doing or requesting something like this look like? Here is this simple application _without_ address bar support:
>
> >>   (defapp history-app ()
> >>     ((toggle-button (mk-toggle-button (mk-span "Toggle me")))))
>
> >>   (defmethod main ((app history-app))
> >>     (with-slots (toggle-button) app
> >>       (add toggle-button (root-widget-of app))))
>
> >> The toggle-button widget has a on-state-change slot I can "hook into". I suppose I could use that .. somehow .. but I'm thinking I'll run into problems later by doing this in a naive way.
>
> >> . I've been stuck on this for a couple of hours now. Maybe others (other GUI frameworks?) have done something similar already in a smart way that will scale to more complicated widgets and scenarios later? I'm thinking search results in a table widget with pagination etc. .. the most ideal solution, API or way to express this that you can imagine or have seen - totally disregarding any problems with regards to actually implementing it .. x)
>
> >> #1:http://groups.google.com/group/symbolicweb
>
> >> #2: ..and it seems the old guys with money always click the "back" button.
>
> >> #3: The reason for this is that I've already solved the lower-level problem of this and can code and think of web-applications as if they where normal GUI applications. I'm really looking for the most ideal way of expressing this in higher level terms.
>
> >> --
> >> Lars Rune Nøstdalhttp://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...

>
> > 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)
>
> --
> Lars Rune Nøstdalhttp://nostdal.org/

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

vanekl

unread,
Jun 2, 2008, 6:03:24 PM6/2/08
to
On Jun 2, 8:42 pm, vanekl <va...@acd.net> wrote:
> 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.

Lars Rune Nøstdal

unread,
Jun 2, 2008, 7:52:17 PM6/2/08
to

..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

Message has been deleted
Message has been deleted
Message has been deleted

vanekl

unread,
Jun 3, 2008, 10:24:04 PM6/3/08
to
On Jun 4, 12:50 am, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
> Ok,
> So things looks like this at the moment:
>
>   (defapp history-app (empty-page-app)

>     ((toggle-button (mk-toggle-button (mk-span "Toggle me")
>                                       :id "some-toggle-button"
>                                       :urlized-p t))))

>
>   (defmethod main ((app history-app))
>     (with-slots (toggle-button) app
>       (add toggle-button (root-widget-of app))))
>
> ..the only thing new here is the :URLIZED-P (couldn't think of a better name) thingy. As I click the toggle-button the URL changes (without a page update) since URLIZED-P is T:
>
>  http://localhost:6001/history-app#some-toggle-button=nil
>  http://localhost:6001/history-app#some-toggle-button=t
>
> ..as soon as I do (setf (urlized-p-of toggle-button) nil) it is removed from the URL (without a page update), and (toggle-button) state is only kept in a server side session again:
>
>  http://localhost:6001/history-app
>
> This was added to the TOGGLE-BUTTON class:
>
>   (defmethod uri-value<-serialize-state ((toggle-button toggle-button))
>     (if (state-of toggle-button)
>         "t"
>         "nil"))
>
> ..just like that. Key is widget ID slot, and value is the result of calling that method vs. the widget.
>
> Got to start on the reverse now; manipulation of URL (either it being pasted or changed via back-button or whatever) causes manipulation of widget state and a redraw of the changed widgets.
>
> ... this is great ... :)

>
> --
> Lars Rune Nøstdalhttp://nostdal.org/

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/

Lars Rune Nøstdal

unread,
Jun 4, 2008, 6:22:19 AM6/4/08
to
vanekl wrote:
> On Jun 4, 12:50 am, Lars Rune Nøstdal <larsnost...@gmail.com> wrote:
>> Ok,
>> So things looks like this at the moment:
>>
>> (defapp history-app (empty-page-app)
>> ((toggle-button (mk-toggle-button (mk-span "Toggle me")
>> :id "some-toggle-button"
>> :urlized-p t))))
>>
>> (defmethod main ((app history-app))
>> (with-slots (toggle-button) app
>> (add toggle-button (root-widget-of app))))
>>
>> ..the only thing new here is the :URLIZED-P (couldn't think of a better name) thingy. As I click the toggle-button the URL changes (without a page update) since URLIZED-P is T:
>>
>> http://localhost:6001/history-app#some-toggle-button=nil
>> http://localhost:6001/history-app#some-toggle-button=t
>>
>> ..as soon as I do (setf (urlized-p-of toggle-button) nil) it is removed from the URL (without a page update), and (toggle-button) state is only kept in a server side session again:
>>
>> http://localhost:6001/history-app
>>
>> This was added to the TOGGLE-BUTTON class:
>>
>> (defmethod uri-value<-serialize-state ((toggle-button toggle-button))
>> (if (state-of toggle-button)
>> "t"
>> "nil"))
>>
>> ..just like that. Key is widget ID slot, and value is the result of calling that method vs. the widget.
>>
>> Got to start on the reverse now; manipulation of URL (either it being pasted or changed via back-button or whatever) causes manipulation of widget state and a redraw of the changed widgets.
>>
>> ... this is great ... :)
>>
>
> 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.

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 ..

Lars Rune Nøstdal

unread,
Jun 5, 2008, 3:22:21 PM6/5/08
to
Lars Rune Nøstdal wrote:
> vanekl wrote:

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)

Message has been deleted

vanekl

unread,
Jun 5, 2008, 5:10:27 PM6/5/08
to
woops, let's try that again.

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.

Lars Rune Nøstdal

unread,
Jun 5, 2008, 8:12:35 PM6/5/08
to
>vanekl wrote:
>
> 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. :)

Lars Rune Nøstdal

unread,
Jun 5, 2008, 8:18:25 PM6/5/08
to

..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.

Lars Rune Nøstdal

unread,
Jun 5, 2008, 8:37:13 PM6/5/08
to
Lars Rune Nøstdal wrote:

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)

vanekl

unread,
Jun 5, 2008, 8:43:55 PM6/5/08
to

Thanks. I'll play around with this and see if it things feel snappier.
-lv

0 new messages