Re-implement flash without sessions

32 views
Skip to first unread message

Alberto Valverde

unread,
Jan 16, 2009, 4:55:49 AM1/16/09
to turbogea...@googlegroups.com, rum-d...@googlegroups.com
Hi,

I'd like to propose (and I'm volunteering to do it) to re-implement TG's
"flash" using the transport mechanism it used before: a POC (plain old
cookie). This would be implemented as a stand-alone egg with no other
dependence apart from webob (perhaps not even webob, a Request/Reponse
object that implements a sub-set of webob's interface could be duck-typed).

The main reason is selfish: I'd like to use this in Rum and would like
it to inter-operate in the best possible way with TG. Sharing the same
code would be ideal.

The other reasons (which are more important ;) are that:

1) Flash messages are easier (possible) for a rich client ui to read
since JS can read the cookie directly.
2) Flash messages can be displayed by JS code in non-dynamic pages
without needing to put them in the template. This makes pages easier to
cache.
3) Apps can be session-less

All these advantages are explained much better than here in this post:
http://blog.ianbicking.org/2008/12/17/javascript-status-message-display/

I'm probably going to implement it for Rum anyway but if TG is
interested I can take it into account from the beginning and make sure
it integrates well.

Alberto

P.S. Cross posting to rum-discuss since this also involves Rum but it is
already being discussed in a ticket there
(http://python-rum.org/ticket/62), please reply only to turbogears-trunk.

Michael Brickenstein

unread,
Jan 16, 2009, 6:29:14 AM1/16/09
to TurboGears Trunk
Hi!

> 2) Flash messages can be displayed by JS code in non-dynamic pages
> without needing to put them in the template. This makes pages easier to
> cache.

In other words: Flashing breaks caching ... And all advertised
scalability is lost.

As stated in the blog another problem are "logged in messages".

Michael

Mark Ramm

unread,
Jan 16, 2009, 10:58:45 AM1/16/09
to rum-d...@googlegroups.com, turbogea...@googlegroups.com
I think this is a good idea. It adds a little bit of complexity to
the template side of things, but we can use a widget in the
master.html to do the flash message via javascript so things can just
work out of the box.

If it's done right away, it can go into tg 2.0, if it takes a bit I'd
support a switch from the current flash implementation to this in
2.1.

I wonder if it could be put into webhelpers rather than into a seprate
library, since its a generally useful pattern....
--
Mark Ramm-Christensen
email: mark at compoundthinking dot com
blog: www.compoundthinking.com/blog

Alberto Valverde

unread,
Jan 16, 2009, 12:03:22 PM1/16/09
to turbogea...@googlegroups.com
Mark Ramm wrote:
> I think this is a good idea. It adds a little bit of complexity to
> the template side of things, but we can use a widget in the
> master.html to do the flash message via javascript so things can just
> work out of the box.
>

Template wise, I hope it will turn out to be a js include and js call
away, something like:

<script src="...."></script>
<script type="text/javascript">
(new Flash({some options or none for sane
defaults})).render(some_id_or_dom_node)
</script>

As a helper, the JS call could be generated with python with something like
${flash(dom_node_id, **options)}

The API to generate messages from the controllers would be something like:

flash("mesage", status="info", webob_request_like, webob_response_like)

Of course, TG could wrap this call and partially apply both response and
request from the SOPs, resulting in the familiar:

flash("message", status="foo")


> If it's done right away, it can go into tg 2.0, if it takes a bit I'd
> support a switch from the current flash implementation to this in
> 2.1.
>

Right away like.. this weekend? (arrg I hate deadlines ;)


> I wonder if it could be put into webhelpers rather than into a seprate
> library, since its a generally useful pattern....
>

Hmm, I'm not using webhelpers in Rum so I'd rather not introduce a new
dependency. I prefer to have it at a standalone egg (not even depending
on TW, which would make it easier to implement). Besides that, it will
need some JS support code and AFAIK webhelpers is moving away from
bundling js in their package.

Alberto

Jorge Vargas

unread,
Jan 16, 2009, 5:08:50 PM1/16/09
to rum-d...@googlegroups.com, turbogea...@googlegroups.com
On Fri, Jan 16, 2009 at 9:58 AM, Mark Ramm <mark.mch...@gmail.com> wrote:
>
> I think this is a good idea. It adds a little bit of complexity to
> the template side of things, but we can use a widget in the
> master.html to do the flash message via javascript so things can just
> work out of the box.
>
> If it's done right away, it can go into tg 2.0, if it takes a bit I'd
> support a switch from the current flash implementation to this in
> 2.1.
>
> I wonder if it could be put into webhelpers rather than into a seprate
> library, since its a generally useful pattern....
>
am I the only one concern by the fact that this will require JS on ALL
TG2 apps to be enable?

How about make it a "second implementation" in a configurable way? so
you could either use the session or js thing, kind of like how beaker
swaps backends?

Alberto Valverde

unread,
Jan 16, 2009, 7:40:42 PM1/16/09
to turbogea...@googlegroups.com
Jorge Vargas wrote:
> On Fri, Jan 16, 2009 at 9:58 AM, Mark Ramm <mark.mch...@gmail.com> wrote:
>
>> I think this is a good idea. It adds a little bit of complexity to
>> the template side of things, but we can use a widget in the
>> master.html to do the flash message via javascript so things can just
>> work out of the box.
>>
>> If it's done right away, it can go into tg 2.0, if it takes a bit I'd
>> support a switch from the current flash implementation to this in
>> 2.1.
>>
>> I wonder if it could be put into webhelpers rather than into a seprate
>> library, since its a generally useful pattern....
>>
>>
> am I the only one concern by the fact that this will require JS on ALL
> TG2 apps to be enable?
I think that nowadays all *webapps* (as opposed to *webpages*) require
JavaScript anyway. Flash is mostly used in the former so I think that
the advantages (cacheability, making servers state-less (or avoid having
to sign marshalled sessions in cookie)) fairly outweight the minor
disadvantages that requiring JS imposes.

>
> How about make it a "second implementation" in a configurable way? so
> you could either use the session or js thing, kind of like how beaker
> swaps backends?
That is easier said than done ;). Anyway, the interface I've implemented
[1] can be extended to support fetching the cookie from the request
(please keep it a simple cookie so no sessions are needed) so... I'd
happily accept a patch to add a ServerFlash subclass to add that
functionality. But please: don't add new dependencies (currently only
the stdlib is required if python 2.6 is used + a response object that
has a set_cookie(name, value) method (eg: webob's)) and keep it portable
across any WSGI framework.

Alberto

[1] http://hg.python-rum.org/WebFlash

Michael Brickenstein

unread,
Jan 17, 2009, 5:16:07 AM1/17/09
to TurboGears Trunk
Besides cacheability, I think its important to have a flash mechanism,
which is
easily adaptable by app kinds of wsgi apps: classical web app, rich
client application,
applications with session and without session.
Glueing applications together using WSGI and having different flashing
mechanisms is just cruel to end users:
When leaving the boundary from app A to B, the message is kept,
and displayed half an hour later, when the user is again in
application B.

Michael

On 17 Jan., 01:40, Alberto Valverde <albe...@toscat.net> wrote:
> Jorge Vargas wrote:

Alberto Valverde

unread,
Jan 17, 2009, 2:42:43 PM1/17/09
to turbogea...@googlegroups.com

I've finally integrated WebFlash (that's the name of the library I've
release implementing this) into TG2 at:
http://trac.turbogears.org/changeset/6112

Some notes:

* Released at PyPI, should be added to TG2's private index
(http://pypi.python.org/pypi/WebFlash/)
* Due to popular demand, I've added support for flash without JS.
* The transport mechanism has changed to be a plain old cookie instead
of the session. This enables users to display the message more easily
from JS code and allows the use of TG2 without sessions.
* Code is unit-tested (both the JS part and the python part) and documented.
* The JS part has been tested to work under under IE6, IE7, Safari,
mobile Safari (aka: iphone), Chrome, Opera and Firefox 3)
* All of TG2's unit-tests pass without any modification. So, in theory,
no backwatds incompatible change has been introduced

Instructions:

To enable JS-only flash (recommended, but YMMV) you need to change your
master template:

Change:

<div id="${tg.flash_status}" py:if="tg.flash" class="flash"
py:content="tg.flash">
</div>

To:

${flash.render_genshi("some_id")}
<div id="some_id" />


That's all, the 1318 of minified JS code to support that will be inlined
in a <script> tag. If you don't want this code inlined you should:
a) Add a controller method that serves the file whose path is stored
at flash.js_path and add a <script> link to it.
b) Add this somewhere in your <head>: <script type="text/javascript"
content="XML(flash.js_call('some_id'))" />
b) Tweak the CSS since the DOM structure the JS version generates is
slightly different.


If someone wants to cook a widget or something for this or add a config
option so TG can use one or the other or something the community will
appreciate it (hint, Jorge, hint ;)

One more thing: I'd finally like to change the DOM structure and CSS of
the quickstart template to match the structure generated by the JS
version. Mainly so both versions can be used interchangeably and because
the current one sucks ;) Why? Because:

1) The class of the message should be conveyed in a... class attribute.
The current implementation makes impossible to refer to the *unique* div
that holds the flash in a reliable way from JS code. The id should
remain static, the class should vary with the kind of message (not the
other way around)

2) If the flash message is wrapped in a div inside the "flash" div then
one can implement floating centered messages easily.

To make it easy to visualize, the dom structure that the js code
generates is like this:

<div id="some_id_of_your_liking">
<div class="status_code">Message</div>
</div>

So the CSS style this could be something like:

#some_id_of_your_liking {
display: none; /* Recommended so a conditional can be avoided, the
JS code will make it visible */
...
}

#some_id_of_your_liking .ok { ....}
#some_id_of_your_liking .warn { ....}
#some_id_of_your_liking .error { ....}

Please strip the status_X prefix from the status code names, it is
redundant to say:

flash("lalalala", status="status_ok")
much nicer (IMHO) and less typing (mathematically provable):
flash("lalala", status="ok")

If no one object I'll implement these *slightly* breaking changes (for
existing users) tomorrow. Note that the default will still be non-js
flash messages, I'm just proposing to change the dom structure and CSS
to keep both in sync so it is easy to change between them.

Enjoy,
Alberto

Mark Ramm

unread,
Jan 17, 2009, 3:42:01 PM1/17/09
to turbogea...@googlegroups.com
I have no objection to that, and I'll do the release prep this weekend
and a beta early next week, so this will be another great feature to
plug in our next beta.

Jorge Vargas

unread,
Jan 18, 2009, 10:31:08 AM1/18/09
to turbogea...@googlegroups.com
That's really nice thank you.
Ok I will :) But I can't promise I could get some time before b3, it
seems we are going to have b4 so I don't see this as a problem (nor a
blocker), of course for this to work what you say below has to be
implemented, which I'm +1

Alberto Valverde

unread,
Jan 18, 2009, 1:12:45 PM1/18/09
to turbogea...@googlegroups.com
Jorge Vargas wrote:
>> If someone wants to cook a widget or something for this or add a config
>> option so TG can use one or the other or something the community will
>> appreciate it (hint, Jorge, hint ;)
>>
>>
> Ok I will :) But I can't promise I could get some time before b3, it
> seems we are going to have b4 so I don't see this as a problem (nor a
> blocker), of course for this to work what you say below has to be
> implemented, which I'm +1
>

Nevermind, I already implemented a helper :) read below...

Done in:

http://trac.turbogears.org/changeset/6114
http://trac.turbogears.org/changeset/6115
http://trac.turbogears.org/changeset/6116
http://trac.turbogears.org/changeset/6117


The quickstart template has been updated to the new DOM structure and
existing apps should continue working but show deprecation warnings.

How to upgraded your existsing apps (the following instructions could be
copy and pasted somewhere in the CHANGELOG)

1) The flash message is now rendered like this (in a genshi template)

<py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
<div py:if="flash" py:content="XML(flash)" />
</py:with>

Note that the tg.flash_obj.render() method returns a string so we need
to use the XML wrapper (not the HTML!) so genshi doesn't escape the html
entities. The conditional is so XML doesn't barf when there's no flash
(and we're not using JS) since render() will return an empty string.

To enable JS flash messages and be able to cache your pages just pass
use_js=True to the render() method

1.5) Using the helper in string based templates is easier, just do:

${tg.flash_obj.render('flash', use_js=False)}

2) Upgrade the your CSS to the new DOM structure, which is:

<div ="$flash_id">
<div class="$status">$message</div>
</div>

The one in the quickstart template looks like:

#flash {
font-size:120%;
font-weight:bolder;
margin:0pt auto 0.5em;
width:680px;
}
#flash div {
padding:5px 15px 15px 55px;
}
#flash .ok {
background:#EEEEFF url(../images/ok.png) no-repeat scroll left center;
border:1px solid #CCCCEE;
}
#flash .warning {
background:#FF9999 url(../images/error.png) no-repeat scroll left center;
border:1px solid #FF3333;
}
#flash .alert {
background:#FFFF99 url(../images/info.png) no-repeat scroll left center;
border:1px solid #FFFF00;
}

3) Change your code so the status string you pass to flash() does not
contain the "status_" prefix, eg:

status_ok -> ok
status_warning -> warning
status_alert -> alert

This step might not be needed if you use custom status codes

The tg.flash and tg.flash_status variables in the template have been
deprecated, the equivalents are tg.flash_obj.status and
tg.flash_obj.message. Note that any access to these will remove the
cookie so do not access them if using JS to render the messages.

Enjoy,
Alberto

percious

unread,
Feb 1, 2009, 12:48:10 PM2/1/09
to TurboGears Trunk
I'm upgrading an existing TG2 site and having problems. I put what
you described in my master template but get the following error:
http://beta.pylonshq.com/tracebacks/30c47ca627f51fffe2a56298936fd4db

Is there something I'm missing?

cheers.
-chris


On Jan 18, 11:12 am, Alberto Valverde <albe...@toscat.net> wrote:
> Jorge Vargas wrote:
> >> If someone wants to cook a widget or something for this or add a config
> >> option so TG can use one or the other or something the community will
> >> appreciate it (hint, Jorge, hint ;)
>
> > Ok I will :) But I can't promise I could get some time before b3, it
> > seems we are going to have b4 so I don't see this as a problem (nor a
> > blocker), of course for this to work what you say below has to be
> > implemented, which I'm +1
>
> Nevermind, I already implemented a helper :) read below...
>
>
>
>
>
> >> One more thing: I'd finally like to change the DOM structure and CSS of
> >> the quickstart template to match the structure generated by the JS
> >> version. Mainly so both versions can be used interchangeably and because
> >> the current one sucks ;)  Why? Because:
>
> >> 1) The class of  the message should be conveyed in a... class attribute.
> >> The current implementation makes impossible to refer to the *unique* div
> >> that holds theflashin a reliable way from JS code. The id should
> >> remain static, the class should vary with the kind of message (not the
> >> other way around)
>
> >> 2) If theflashmessage is wrapped in a div inside the "flash" div then
> >> one can implement floating centered messages easily.
>
> >> To make it easy to visualize, the dom structure that the js code
> >> generates is like this:
>
> >> <div id="some_id_of_your_liking">
> >>    <div class="status_code">Message</div>
> >> </div>
>
> >> So the CSS style this could be something like:
>
> >> #some_id_of_your_liking {
> >>    display: none;  /* Recommended so a conditional can be avoided, the
> >> JS code will make it visible */
> >>    ...
> >> }
>
> >> #some_id_of_your_liking .ok { ....}
> >> #some_id_of_your_liking .warn { ....}
> >> #some_id_of_your_liking .error { ....}
>
> >> Please strip the status_X prefix from the status code names, it is
> >> redundant to say:
>
> >>flash("lalalala", status="status_ok")
> >> much nicer (IMHO) and less typing (mathematically provable):
> >>flash("lalala", status="ok")
>
> >> If no one object I'll implement these *slightly* breaking changes (for
> >> existing users) tomorrow. Note that the default will still be non-js
> >>flashmessages, I'm just proposing to change the dom structure and CSS
> >> to keep both in sync so it is easy to change between them.
>
> Done in:
>
> http://trac.turbogears.org/changeset/6114http://trac.turbogears.org/changeset/6115http://trac.turbogears.org/changeset/6116http://trac.turbogears.org/changeset/6117
>
> The quickstart template has been updated to the new DOM structure and
> existing apps should continue working but show deprecation warnings.
>
> How to upgraded your existsing apps (the following instructions could be
> copy and pasted somewhere in the CHANGELOG)
>
> 1) Theflashmessage is now rendered like this (in a genshi template)
>
> <py:with vars="flash=tg.flash_obj.render('flash', use_js=False)">
>     <div py:if="flash" py:content="XML(flash)" />
> </py:with>
>
> Note that the tg.flash_obj.render() method returns a string so we need
> to use the XML wrapper (not the HTML!) so genshi doesn't escape the html
> entities. The conditional is so XML doesn't barf when there's noflash
> (and we're not using JS) since render() will return an empty string.
>
> To enable JSflashmessages and be able to cache your pages just pass
> use_js=True to the render() method
>
> 1.5) Using the helper in string based templates is easier, just do:
>
> ${tg.flash_obj.render('flash', use_js=False)}
>
> 2) Upgrade the your CSS to the new DOM structure, which is:
>
> <div ="$flash_id">
>     <div class="$status">$message</div>
> </div>
>
> The one in the quickstart template looks like:
>
> #flash{
> font-size:120%;
> font-weight:bolder;
> margin:0pt auto 0.5em;
> width:680px;}
>
> #flashdiv {
> padding:5px 15px 15px 55px;}
>
> #flash.ok {
> background:#EEEEFF url(../images/ok.png) no-repeat scroll left center;
> border:1px solid #CCCCEE;}
>
> #flash.warning {
> background:#FF9999 url(../images/error.png) no-repeat scroll left center;
> border:1px solid #FF3333;}
>
> #flash.alert {
> background:#FFFF99 url(../images/info.png) no-repeat scroll left center;
> border:1px solid #FFFF00;
>
> }
>
> 3) Change your code so the status string you pass toflash() does not
> contain the "status_" prefix, eg:
>
> status_ok -> ok
> status_warning -> warning
> status_alert -> alert
>
> This step might not be needed if you use custom status codes
>
> The tg.flashand tg.flash_status variables in the template have been

percious

unread,
Feb 1, 2009, 12:54:19 PM2/1/09
to TurboGears Trunk
I figured it out, i was missing the py:with part.

BTW for mako templates, you are going to want:
%if tg.flash_obj:
${tg.flash_obj.render('flash', use_js=False) | n}
%endif
<div id="tg_flash" />

cheers.
-chris
> >http://trac.turbogears.org/changeset/6114http://trac.turbogears.org/c...
Reply all
Reply to author
Forward
0 new messages