WebFlash-0.1a9/ 0000755 0000765 0000024 00000000000 11157175137 012622 5 ustar alberto staff WebFlash-0.1a9/MANIFEST.in 0000644 0000765 0000024 00000000040 11134224300 014330 0 ustar alberto staff recursive-include webflash *.js
WebFlash-0.1a9/PKG-INFO 0000644 0000765 0000024 00000001115 11157175137 013715 0 ustar alberto staff Metadata-Version: 1.0
Name: WebFlash
Version: 0.1a9
Summary: Portable flash messages for WSGI apps
Home-page: http://python-rum.org/wiki/WebFlash
Author: Alberto Valverde Gonzalez
Author-email: alberto@python-rum.org
License: MIT
Description: UNKNOWN
Keywords: wsgi flash webob
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
WebFlash-0.1a9/setup.cfg 0000644 0000765 0000024 00000000261 11157175137 014442 0 ustar alberto staff [egg_info]
tag_build =
tag_date = 0
tag_svn_revision = 0
[nosetests]
cover-package = webflash
with-coverage = false
with-doctest = true
[aliases]
release = egg_info -RDb ""
WebFlash-0.1a9/setup.py 0000644 0000765 0000024 00000002017 11157175012 014324 0 ustar alberto staff from setuptools import setup, find_packages
import sys, os
version = '0.1a9'
install_requires=[]
if sys.version_info[:2] < (2,6):
install_requires.append("simplejson")
setup(
name='WebFlash',
version=version,
description="Portable flash messages for WSGI apps",
long_description="",
keywords='wsgi flash webob',
author='Alberto Valverde Gonzalez',
author_email='alberto@python-rum.org',
url='http://python-rum.org/wiki/WebFlash',
license='MIT',
packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
include_package_data=True,
install_requires=install_requires,
tests_require=["WebTest", "nose"],
test_suite="nose.collector",
zip_safe=False,
classifiers = [
'Development Status :: 4 - Beta',
'Environment :: Web Environment',
'Topic :: Software Development :: Libraries :: Python Modules',
'Intended Audience :: Developers',
'Operating System :: OS Independent',
'Programming Language :: Python',
],
)
WebFlash-0.1a9/webflash/ 0000755 0000765 0000024 00000000000 11157175137 014415 5 ustar alberto staff WebFlash-0.1a9/webflash/__init__.py 0000644 0000765 0000024 00000017360 11157174774 016543 0 ustar alberto staff import os
from urllib import quote, unquote
from logging import getLogger
try:
import json
except ImportError:
# Python < 2.6
import simplejson as json
__all__ = ["Flash"]
IS_DEBUG = 'WEBFLASH_DEBUG' in os.environ
log = getLogger(__name__)
class Flash(object):
"""
A flash message creator.
*Parameters (all optional):*
`cookie_name`
The name of the cookie that will be used as transport
`default_status`
The CSS class that will be added to the flash container when it
is not passed explicitly when calling the Flash instance.
`get_response`
A callable that will provide the response object of the framework
if no explicit response is passed when calling the Flash instance.
`js_path`
Shall you want to override the JS code that will display the flash
message then pass the path to where the file lives. Note that this
is a path within the file-system, not a URL
`debug`
Should the JS code be provided in an uncompressed form (provided that
js_path has not been overriden) and reloaded every time a page is
rendered?
Flash needs a Reponse object with a `set_cookie` method, like WebOb's
:class:`webob.Response`. We'll mock one for demonstration purposes::
>>> class MyResponse(object):
... def set_cookie(self, name, value):
... pass
The :class:`Flash` object could be instantiated once for the lifetime
of an application and be kept at module scope (or a request-local object
if the framework provides one). A :meth:`get_response` callable is useful
in this case if the framework provides a global response to avoid passing
the response object around on every call to the :class:`Flash` instance::
>>> flash = Flash(get_response=lambda: MyResponse())
Displaying the flash message is done by calling the Flash instance from
your controller/view code::
>>> flash("All your data has been erased and your identity destroyed")
>>> flash("Stuff broke", status="error")
To insert the JavaScript code needed for Flash to work you need to insert
the result of the :meth:`render` method on every page you might want to
display flash messages (normally all of them, so you might want to include
the call in a base template)::
>>> _ = flash.render("flash-container")
"""
template = '
'\
''\
'
'
static_template = ''
_js_code = None
def __init__(self, cookie_name="webflash", default_status="ok",
get_response=None, get_request=None, js_path=None,
debug=IS_DEBUG):
self.default_status = default_status
self.get_response = get_response or (lambda: None)
self.get_request = get_request or (lambda: None)
self.cookie_name = cookie_name
self.js_path = js_path or _get_js_path(debug)
if not debug:
# Preload js_code so we don't need to read the file on every request
self.js_code = open(self.js_path).read()
def _get_js_code(self):
return self._js_code or open(self.js_path).read()
def _set_js_code(self, value):
self._js_code = value
js_code = property(_get_js_code, _set_js_code)
def __call__(self, message, status=None, response=None, request=None,
**extra_payload):
response = response or self.get_response()
if response is None:
raise ValueError(
"Must provide a response object or configure a callable that "
"provides one"
)
payload = self.prepare_payload(
message = message,
status = status or self.default_status,
**extra_payload
)
request = request or self.get_request()
if request is not None:
# Save the payload in environ too in case JavaScript is not being
# used and the message is being displayed in the same request.
request.environ['webflash.payload'] = payload
log.debug("Setting payload in environ %d", id(request.environ))
log.debug("Setting payload in cookie")
response.set_cookie(self.cookie_name, payload)
def prepare_payload(self, **data):
return quote(json.dumps(data))
def js_call(self, container_id):
return 'webflash(%(options)s).render();' % {
'options': json.dumps({
'id': container_id,
'name': self.cookie_name
})
}
def render(self, container_id, use_js=True, request=None, response=None):
if use_js:
return self._render_js_version(container_id)
else:
return self._render_static_version(container_id, request, response)
def _render_static_version(self, container_id, request, response):
payload = self.pop_payload(request, response)
if not payload:
return ''
payload['message'] = html_escape(payload.get('message',''))
payload['container_id'] = container_id
return self.static_template % payload
def _render_js_version(self, container_id):
return self.template % {
'container_id': container_id,
'js_code': self.js_code,
'js_call': self.js_call(container_id)
}
def pop_payload(self, request=None, response=None):
"""
Fetches and decodes the flash payload from the request and sets the
required Set-Cookie header in the response so the browser deletes the
flash cookie.
This method is intended to manage the flash payload without using
JavaScript and requires webob compatible request/response
objects.
"""
# First try fetching it from the request
request = request or self.get_request()
response = response or self.get_response()
if request is None or response is None:
raise ValueError("Need to provide a request and reponse objects")
payload = request.environ.get('webflash.payload', {})
if not payload:
payload = request.str_cookies.get(self.cookie_name, {})
if payload:
log.debug("Got payload from cookie")
else:
log.debug("Got payload for environ %d, %r",
id(request.environ), payload)
if payload:
payload = json.loads(unquote(payload))
if 'webflash.deleted_cookie' not in request.environ:
log.debug("Deleting flash payload")
response.delete_cookie(self.cookie_name)
request.environ['webflash.delete_cookie'] = True
return payload or {}
html_escape_table = {
"&": "&",
'"': """,
"'": "'",
">": ">",
"<": "<",
}
# From http://wiki.python.org/moin/EscapingHtml
def html_escape(text):
"""Produce entities within text."""
L=[]
for c in text:
L.append(html_escape_table.get(c,c))
return "".join(L)
def _get_js_path(debug):
filename = debug and 'webflash.js' or 'webflash.min.js'
try:
import pkg_resources
return pkg_resources.resource_filename('webflash', filename)
except ImportError:
# Be compatible with pkg_resources haters
return os.path.abspath(
os.path.join(os.path.dirname(__file__), filename)
)
WebFlash-0.1a9/webflash/webflash.js 0000644 0000765 0000024 00000021300 11134621326 016531 0 ustar alberto staff /* webflash.js *
* Copyright (c) 2009 Alberto Valverde González
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* USAGE:
* var wf = webflash(options);
*
* Available options:
* id -> The id of the DOM node that acts as a container of
* the flash message. This element must exist in the DOM.
* Will default to "webflash" if missing from hash.
*
* name -> The name of the cookie that carries the payload.
* Will default to "webflash" if missing from hash.
*
* on_display -> (optional) Callback to execute after the flash message
* has been displayed. It is called with the payload
* and the container DOM node as first and second
* arguments.
* If this option is a string it is expected to be the
* name of a function attached to the window object
* create_node -> (optional) A function that should return the DOM node
* that will be appended to the container.
* If this option is a string it is expected to be the
* name of a function attached to the window object
*
* Available methods:
*
* wf.render() -> Renders the flash message stored in the flash cookie.
* This function must be called before the window has
* finisihed loading.
* If the cookie was not set by the server this is a noop.
*
* wf.payload() -> Returns an object with the payload stored in the cookie
* If no cookie was set returns null.
*
* Payload structure:
*
* The payload is expected to be an escaped JSON string which deserializes
* into an object with the following keys:
*
* message (string) -> The text to insert into the container. By default this
* text will be apended as a text node so HTML will be
* escaped. Initialize webflash with a custom
* 'create_node' function to override this.
* status (string) -> If present this will be the class of the div that
* holds the flash message inside the container.
* delay (int) -> If present, the flash container will be hidden after
* this amount of milliseconds.
*
* Extra arguments may be passed in th payload and interpreted by a custom
* create_node or on_display function.
*
*/
if (!window.webflash) {
webflash = (function() {
var doc = document; // Alias to aid name-mangling
var allCookies = doc.cookie;
var cookie_name = null;
var flash_shown = false;
var container_id = null;
var isIE = /msie|MSIE/.test(navigator.userAgent);
// This function creates the node that will hold the flash message inside
// the flash container. It can be overrided with the options.create_node
// option passed to webflash()
var create_node = function (payload) {
return doc.createTextNode(payload.message);
}
var on_display = function(payload, node) {};
var lookup_method = function(name_or_func, _default) {
var ret = _default;
if (typeof(name_or_func) == "string") {
ret = window[name_or_func];
} else if (name_or_func) {
ret = name_or_func;
}
return ret
}
var get_payload = function() {
var pos = allCookies.indexOf(cookie_name + '=');
if (pos<0) {
return null;
}
var start = pos + cookie_name.length + 1;
var end = allCookies.indexOf(';', start);
if (end == -1) {
end = allCookies.length;
}
var cookie = allCookies.substring(start, end);
// remove cookie
doc.cookie = cookie_name + '=; expires=Fri, 02-Jan-1970 00:00:00 GMT; path=/';
return webflash.lj(unescape(cookie));
}
var display_flash = function() {
if (flash_shown) return;
flash_shown = true;
var payload = get_payload();
if (payload !== null) {
var container = doc.getElementById(container_id);
var flash_div = doc.createElement('div');
if (payload.status) {
flash_div.setAttribute(isIE?'className':'class', payload.status);
}
var messageNode = create_node(payload);
flash_div.appendChild(messageNode);
container.style.display = 'block';
if (payload.delay) {
setTimeout(function() {
container.style.display = 'none';
}, payload.delay);
}
container.appendChild(flash_div);
on_display(payload, container);
}
}
// Adds a display_flash for when the DOM is ready. It also adds a
// callback for the window "onload" event since the domready event does
// not always work.
// This code is heavily inspired by jquery's ready() function.
var attachLoadEvent = function() {
if (!isIE) {
// DOM 2 Event model
var domloaded = "DOMContentLoaded";
doc.addEventListener(domloaded, function() {
doc.removeEventListener(domloaded, arguments.callee, false);
display_flash();
}, false);
// A fallback to window.onload that will always work
window.addEventListener("load", display_flash, false);
} else if (isIE) {
// IE event model
var domloaded = "onreadystatechange";
// ensure firing before onload,
// maybe late but safe also for iframes
doc.attachEvent(domloaded, function() {
doc.detachEvent(domloaded, arguments.callee);
display_flash();
});
// If IE and not an iframe
// continually check to see if the document is ready
if (doc.documentElement.doScroll && !frameElement ) (function(){
if (flash_shown) return;
try {
// If IE is used, use the trick by Diego Perini
// http://javascript.nwbox.com/IEContentLoaded/
doc.documentElement.doScroll("left");
} catch( error ) {
setTimeout( arguments.callee, 0 );
return;
}
display_flash()
})();
// A fallback to window.onload that will always work
window.attachEvent("load", display_flash);
}
}
return function(opts) {
cookie_name = opts.name || "webflash";
container_id = opts.id || "webflash";
on_display = lookup_method(opts.on_display, on_display);
create_node = lookup_method(opts.create_node, create_node);
return {
payload: get_payload,
render: attachLoadEvent
}
}
})();
// This function needs to live outside the anonymous function's closure for
// YUICompressor to be able to mangle the private symbols because it uses
// eval
webflash.lj = function(s) {
// Loads a JSON string
var r;
eval("r="+s);
return r;
};
};
WebFlash-0.1a9/webflash/webflash.min.js 0000644 0000765 0000024 00000003012 11134621536 017316 0 ustar alberto staff if(!window.webflash){webflash=(function(){var j=document;var k=j.cookie;var f=null;var e=false;var g=null;var c=/msie|MSIE/.test(navigator.userAgent);var a=function(m){return j.createTextNode(m.message)};var l=function(n,m){};var b=function(o,m){var n=m;if(typeof(o)=="string"){n=window[o]}else{if(o){n=o}}return n};var h=function(){var p=k.indexOf(f+"=");if(p<0){return null}var o=p+f.length+1;var m=k.indexOf(";",o);if(m==-1){m=k.length}var n=k.substring(o,m);j.cookie=f+"=; expires=Fri, 02-Jan-1970 00:00:00 GMT; path=/";return webflash.lj(unescape(n))};var i=function(){if(e){return}e=true;var p=h();if(p!==null){var m=j.getElementById(g);var n=j.createElement("div");if(p.status){n.setAttribute(c?"className":"class",p.status)}var o=a(p);n.appendChild(o);m.style.display="block";if(p.delay){setTimeout(function(){m.style.display="none"},p.delay)}m.appendChild(n);l(p,m)}};var d=function(){if(!c){var m="DOMContentLoaded";j.addEventListener(m,function(){j.removeEventListener(m,arguments.callee,false);i()},false);window.addEventListener("load",i,false)}else{if(c){var m="onreadystatechange";j.attachEvent(m,function(){j.detachEvent(m,arguments.callee);i()});if(j.documentElement.doScroll&&!frameElement){(function(){if(e){return}try{j.documentElement.doScroll("left")}catch(n){setTimeout(arguments.callee,0);return}i()})()}window.attachEvent("load",i)}}};return function(m){f=m.name||"webflash";g=m.id||"webflash";l=b(m.on_display,l);a=b(m.create_node,a);return{payload:h,render:d}}})();webflash.lj=function(s){var r;eval("r="+s);return r}}; WebFlash-0.1a9/WebFlash.egg-info/ 0000755 0000765 0000024 00000000000 11157175137 016007 5 ustar alberto staff WebFlash-0.1a9/WebFlash.egg-info/dependency_links.txt 0000644 0000765 0000024 00000000001 11157175137 022055 0 ustar alberto staff
WebFlash-0.1a9/WebFlash.egg-info/not-zip-safe 0000644 0000765 0000024 00000000001 11134156407 020227 0 ustar alberto staff
WebFlash-0.1a9/WebFlash.egg-info/PKG-INFO 0000644 0000765 0000024 00000001115 11157175137 017102 0 ustar alberto staff Metadata-Version: 1.0
Name: WebFlash
Version: 0.1a9
Summary: Portable flash messages for WSGI apps
Home-page: http://python-rum.org/wiki/WebFlash
Author: Alberto Valverde Gonzalez
Author-email: alberto@python-rum.org
License: MIT
Description: UNKNOWN
Keywords: wsgi flash webob
Platform: UNKNOWN
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Web Environment
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
WebFlash-0.1a9/WebFlash.egg-info/requires.txt 0000644 0000765 0000024 00000000012 11157175137 020400 0 ustar alberto staff simplejson WebFlash-0.1a9/WebFlash.egg-info/SOURCES.txt 0000644 0000765 0000024 00000000437 11157175137 017677 0 ustar alberto staff MANIFEST.in
setup.cfg
setup.py
WebFlash.egg-info/PKG-INFO
WebFlash.egg-info/SOURCES.txt
WebFlash.egg-info/dependency_links.txt
WebFlash.egg-info/not-zip-safe
WebFlash.egg-info/requires.txt
WebFlash.egg-info/top_level.txt
webflash/__init__.py
webflash/webflash.js
webflash/webflash.min.js WebFlash-0.1a9/WebFlash.egg-info/top_level.txt 0000644 0000765 0000024 00000000011 11157175137 020531 0 ustar alberto staff webflash