Static resource library support for Grok.
Project description
megrok.resourcelibrary: Resources in Grok
Introduction
Grok already comes equipped with a simple way to expose static file resources, the static directory.
megrok.resourcelibrary allows the more flexible inclusion of static file resources in Grok. It uses the zc.resourcelibrary package to do this.
A resource library is essentially like a directory like the static directory of a package, full of static resources, such as CSS files, javascript files and images. Resources are intended to be used from HTML pages, as additional resources to help display a particular layout or user interface.
How is megrok.resourcelibrary more flexible than Grok’s default static directory?
A resource library can be in a layer.
A resource library can have a non-public permission.
A resource library can more easily be packaged for reuse by other libraries. Resource libraries have unique names under the control of the developer.
A resource library can automatically include some resources (such as javascript or css) in the head section of a web page whenever a particular widget needs it.
A resource library can also depend on other libraries.
Basic example
Let’s see how this all works. First we need to grok this package itself (this is normally done from ZCML):
>>> from grok.testing import grok >>> grok('megrok.resourcelibrary.meta')
Now we can set up a simple resource library:
>>> import grok >>> import megrok.resourcelibrary >>> class SomeLibrary(megrok.resourcelibrary.ResourceLibrary): ... megrok.resourcelibrary.directory('tests/example')
We need to grok this to make it available (in normal use this is done automatically for you):
>>> from grok.testing import grok_component >>> grok_component('SomeLibrary', SomeLibrary) True
The resources in this directory are now published, by default under the class name of the library, lower cased (therefore somelibrary):
>>> from zope.testbrowser.testing import Browser >>> browser = Browser() >>> browser.open('http://localhost/@@/somelibrary/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); }
The default name can be overridden by using the grok.name directive:
>>> class SomeLibrary2(megrok.resourcelibrary.ResourceLibrary): ... grok.name('some-library') ... megrok.resourcelibrary.directory('tests/example') >>> grok_component('SomeLibrary2', SomeLibrary2) True >>> browser.open('http://localhost/@@/some-library/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); }
It’s an error to point to a directory that doesn’t exist:
>>> class WrongDirectory(megrok.resourcelibrary.ResourceLibrary): ... grok.name('wrong-directory') ... megrok.resourcelibrary.directory('tests/doesnt_exist') >>> grok_component('WrongDirectory', WrongDirectory) Traceback (most recent call last): ... GrokError: Directory 'tests/doesnt_exist' is not a valid directory passed to the 'wrong-directory' directive.
Automactic inclusion of resources
We now set up a resource library that automatically includes two resources whenever it is used in a web page, namely included.js and included.css:
>>> class MyLib(megrok.resourcelibrary.ResourceLibrary): ... grok.name('my-lib') ... megrok.resourcelibrary.directory('tests/example/my-lib') ... megrok.resourcelibrary.include('included.js') ... megrok.resourcelibrary.include('included.css') >>> grok_component('MyLib', MyLib) True
This is how you require the library to be loaded in a particular page template:
<tal:block replace="resource_library:my-lib"/>
test_template_2 makes this requirement, so the included Javascript should be included:
>>> browser.open('http://localhost/zc.resourcelibrary.test_template_2') >>> '/@@/my-lib/included.js' in browser.contents True
And the resource is also published:
>>> browser.open('/@@/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); }
A reference to the CSS is also inserted into the HTML:
>>> browser.open('http://localhost/zc.resourcelibrary.test_template_2') >>> '/@@/my-lib/included.css' in browser.contents True
And the CSS is available from the URL referenced:
>>> browser.open('/@@/my-lib/included.css') >>> print browser.contents div .border { border: 1px silid black; }
Programmatically signalling resource requirements
Above we’ve demonstrated the use of the resource_library namespace in ZPT. Library usage can also be signalled programmatically, for instance in a view:
>>> import grok >>> from zope.interface import Interface >>> class View(grok.View): ... grok.context(Interface) ... def render(self): ... MyLib.need() ... return '<html><head></head><body>Example</body></html>' >>> grok_component('View', View) True >>> browser.open('http://localhost/view') >>> '/@@/my-lib/included.js' in browser.contents True
This also works for libraries which don’t have an explicit grok.name:
>>> class MyLib2(megrok.resourcelibrary.ResourceLibrary): ... megrok.resourcelibrary.directory('tests/example/my-lib') ... megrok.resourcelibrary.include('included.js') ... megrok.resourcelibrary.include('included.css') >>> grok_component('MyLib2', MyLib2) True >>> class View2(grok.View): ... grok.context(Interface) ... def render(self): ... MyLib2.need() ... return '<html><head></head><body>Example</body></html>' >>> grok_component('View2', View2) True >>> browser.open('http://localhost/view2') >>> '/@@/mylib2/included.js' in browser.contents True
You can also signal inclusion by library name instead (like is done in page templates):
>>> class View3(grok.View): ... grok.context(Interface) ... def render(self): ... megrok.resourcelibrary.need('my-lib') ... return '<html><head></head><body>Example</body></html>' >>> grok_component('View3', View3) True >>> browser.open('http://localhost/view3') >>> '/@@/my-lib/included.js' in browser.contents True
Making resource libraries depend on other ones
We can make a resource library depend on another one:
>>> class Dependency(megrok.resourcelibrary.ResourceLibrary): ... megrok.resourcelibrary.directory('tests/example') ... megrok.resourcelibrary.include('1.js') >>> grok_component('Dependency', Dependency) True >>> class Dependent(megrok.resourcelibrary.ResourceLibrary): ... megrok.resourcelibrary.directory('tests/example') ... megrok.resourcelibrary.include('2.css') ... megrok.resourcelibrary.depend(Dependency) >>> grok_component('Dependent', Dependent) True
Let’s make a view that needs Dependent:
>>> class DependentView(grok.View): ... grok.context(Interface) ... def render(self): ... Dependent.need() ... return '<html><head></head><body>Example</body></html>' >>> grok_component('DependentView', DependentView) True
The included code of both the original and the dependency will now show up:
>>> browser.open('http://localhost/dependentview') >>> '/@@/dependency/1.js' in browser.contents True >>> '/@@/dependent/2.css' in browser.contents True
Protecting resources
It’s possible to give a resource a permission:
>>> class MyPermission(grok.Permission): ... grok.name("my.permission") >>> grok_component('MyPermission', MyPermission) True >>> class MyLib3(megrok.resourcelibrary.ResourceLibrary): ... megrok.resourcelibrary.directory('tests/example/my-lib') ... grok.require(MyPermission) >>> grok_component('MyLib3', MyLib3) True
XXX This doesn’t work yet, as resources don’t do their own security checks but rely on proxies, which Grok has removed… Need to introduce new resources/factories to do checks by hand.
Changes
0.9.2 (2008-08-08)
Grokker mistakenly relied on (not imported) GrokImportError in failure case. Corrected this to GrokError and added a test for it.
Rename use directive to depend and make it take a class argument instead of a library name.
0.9.1 (2008-08-06)
Turn off zip-safeness.
Actually add a meta.zcml that loads up the grokker!
0.9 (2008-08-06)
Initial public release.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Hashes for megrok.resourcelibrary-0.9.2.tar.gz
Algorithm | Hash digest | |
---|---|---|
SHA256 | 495c1c557eca82dbf5b364da7f9257d38ce72f24655b5bed8207b9d7a3aa7bfb |
|
MD5 | 6a8f3b917b823ef7d87e3bbc4ecc2344 |
|
BLAKE2b-256 | 551fc7c80135d09c88e82e2bdbaec5191046fb2b796229a49f4b103454062445 |