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