zc.resourcelibrary-1.3.4/0000775000177100020040000000000011706347337016507 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/setup.py0000664000177100020040000000537611706347254020232 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2007 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Setup for zc.resourcelibrary package $Id: setup.py 81038 2007-10-24 14:34:17Z srichter $ """ import os from setuptools import setup, find_packages def read(*rnames): return open(os.path.join(os.path.dirname(__file__), *rnames)).read() setup(name='zc.resourcelibrary', version='1.3.4', author='Zope Foundation and Contributors', author_email='zope-dev@zope.org', description='Post-rendering Resource Inclusion', long_description=( read('README.txt') + '\n\n.. contents::\n\n' + read('src', 'zc', 'resourcelibrary', 'README.txt') + '\n\n' + read('CHANGES.txt') ), keywords = "zope3 resource javascript css inclusion", classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Intended Audience :: Developers', 'License :: OSI Approved :: Zope Public License', 'Programming Language :: Python', 'Natural Language :: English', 'Operating System :: OS Independent', 'Topic :: Internet :: WWW/HTTP', 'Framework :: Zope3'], url='http://pypi.python.org/pypi/zc.resourcelibrary', license='ZPL 2.1', packages=find_packages('src'), package_dir = {'': 'src'}, namespace_packages=['zc'], extras_require=dict( test=['zope.app.testing', 'zope.app.zcmlfiles', 'zope.pagetemplate', 'zope.securitypolicy', 'zope.testbrowser', 'zope.testing', ]), install_requires=['setuptools', 'zope.app.publication', 'zope.browserpage', 'zope.browserresource', 'zope.component', 'zope.configuration', 'zope.interface', 'zope.publisher', 'zope.security', 'zope.tales', 'zope.traversing', ], include_package_data = True, zip_safe = False, ) zc.resourcelibrary-1.3.4/CHANGES.txt0000664000177100020040000001027411706347254020322 0ustar menesismenesis00000000000000======= CHANGES ======= 1.3.4 (2012-01-20) ------------------ - Register adapters with getSiteManager rather than getGlobalSiteManager. This allows registering resource libraries in non-global sites. For detais see: - https://mail.zope.org/pipermail/zope-dev/2010-March/039657.html - http://docs.pylonsproject.org/projects/pyramid_zcml/en/latest/narr.html#using-broken-zcml-directives - Raise NotImplementedError if we find that a second ZCML declaration would change the global library_info dict in a way that may (depending on ZCML ordering) break applications at runtime. These errors were pretty hard to debug. - Remove unneeded test dependencies on ``zope.app.authentication`` and ``zope.app.securitypolicy``. - Remove dependency on ``zope.app.pagetemplate``. 1.3.2 (2010-08-16) ------------------ - Response._addDependencies will only include a ResourceLibrary in the list of dependencies if the ResourceLibrary actually has included resources. This makes directives that simply declare dependencies on other libraries work again. - Add missing depedency on ``zope.app.pagetemplate``, clean up unused imports and whitespace. 1.3.1 (2010-03-24) ------------------ - Resource libraries that are required during a retried request are now correctly registered and injected to the HTML. - Import hooks functionality from zope.component after it was moved there from zope.site. This lifts the dependency on zope.site. - Removed an unused ISite import and thereby, the undeclared dependency on zope.location. 1.3.0 (2009-10-08) ------------------ - Use ``zope.browserresource`` instead of ``zope.app.publisher``, removing a dependency on latter. - Look up the "resources view" via queryMultiAdapter instead of looking into the adapter registry. - Moved the dependency on zope.site to the test dependencies. 1.2.0 (2009-06-04) ------------------ - Use ``zope.site`` instead of ``zope.app.component``. Removes direct dependency on ``zope.app.component``. 1.1.0 (2009-05-05) ------------------ New features: - An attempt to generate resource URLs using the "resources view" (@@) is now made; if unsuccesful, we fall back to the previous method of crafting the URL by hand from the site url. This ensures that the resource library respects the existing plugging points for resource publishing (see ``zope.app.publisher.browser.resources``). - You can now explicitly specify where resource links should be inserted using the special marker comment ''. 1.0.2 (2009-01-27) ------------------ - Remove zope.app.zapi from dependencies, substituting its uses with direct imports. - Use zope-dev at zope.org mailing list address instead of zope3-dev at zope.org as the latter one is retired. - Change "cheeseshop" to "pypi" in the package homepage. 1.0.1 (2008-03-07) ------------------ Bugs fixed: - added the behavior from the standard Zope 3 response to guess that a body that is not HTML without an explicit mimetype should have a 'text/plain' mimetype. This means that, for instance, redirects with a body of '' and no explicit content type will no longer cause an exception in the resourcelibrary response code. 1.0.0 (2008-02-17) ------------------ New features: - You can now provide an alternative "directory-resource" factory. This facilitates implementation of dynamic resources. Bugs fixed: - Updated the functional-testing zcml file to get rid of a deprecation warning. 0.8.2 (2007-12-07) ------------------ - bug fix: when checking content type, take into account that it may be None 0.8.1 (2007-12-05) ------------------ - changed MIME type handling to be more restrictive about whitespace to conform to RfC 2045 0.8 (2007-12-04) ---------------- - fixed the check for HTML and XML content to allow content type parameters 0.6.1 (2007-11-03) ------------------ - Update package meta-data. - Fixed package dependencies. - Merged functional and unit tests. 0.6.0 (2006-09-22) ------------------ ??? 0.5.2 (2006-06-15) ------------------ - Add more package meta-data. 0.5.1 (2006-06-06) ------------------ - Update package code to work with newer versions of other packages. 0.5.0 (2006-04-24) ------------------ - Initial release. zc.resourcelibrary-1.3.4/PKG-INFO0000664000177100020040000005716711706347337017624 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zc.resourcelibrary Version: 1.3.4 Summary: Post-rendering Resource Inclusion Home-page: http://pypi.python.org/pypi/zc.resourcelibrary Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: The resource library is a Zope 3 extension that is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. .. contents:: ================ Resource Library ================ The resource library is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. For instance, if two widgets on a page need the same JavaScript library, the library should be only loaded once, but the widget designers should not have to concern themselves with the presence of other widgets. Imagine that one widget has a copy of a fictional Javascript library. To configure that library as available use ZCML like this: >>> zcml(""" ... ... ... ... ... ... ... ... """) This is exactly equivalent to a resourceDirectory tag, with no additional effect. Loading Files ------------- It is also possible to indicate that one or more Javascript or CSS files should be included (by reference) into the HTML of a page that needs the library. This is the current difference between resourceLibrary and resourceDirectory. >>> zcml(""" ... ... ... ... ... ... ... ... """) If a file is included that the resource library doesn't understand (i.e. it isn't Javascript or CSS), an exception will occur. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError:... ConfigurationError: Resource library doesn't know how to include this file: "included.bad". Usage ----- Components signal their need for a particular resource library (Javascript or otherwise) by using a special TAL expression. (The use of replace is not mandated, the result may be assigned to a dummy variable, or otherwise ignored.) >>> zpt('') We'll be using a testbrowser.Browser to simulate a user viewing web pages. >>> from zope.testbrowser.testing import Browser >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') When a page is requested that does not need any resource libraries, the HTML will be untouched. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_1') >>> browser.contents '......' When a page is requested that uses a component that needs a resource library, the library will be referenced in the rendered page. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_2') A reference to the JavaScript is inserted into the HTML. >>> '/@@/my-lib/included.js' in browser.contents True And the JavaScript is available from the URL referenced. >>> browser.open('/@@/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); } For inclusion of resources the full base url with namespaces is used. >>> browser.open('http://localhost/++skin++Basic/zc.resourcelibrary.test_template_2') >>> print browser.contents 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; } A reference to an unknown library causes an exception. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_3') Traceback (most recent call last): ... RuntimeError: Unknown resource library: "does-not-exist" Library usage may also be signaled programattically. For example, if a page would not otherwise include a resource library... >>> page = ('' ... '' ... 'This is the body.') >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... pass >>> zpt(page, view=View()) '......' ...but we programmatically indicate that a resource library is needed, it will be included. >>> import zc.resourcelibrary >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... zc.resourcelibrary.need('my-lib') >>> '/@@/my-lib/included.js' in zpt(page, view=View()) True Content-type checking --------------------- Resources should be referenced only from HTML and XML content, other content types should not be touched by the resource library: >>> page = ('' ... '' ... '') >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/html') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/xml') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/none') False This also works if the content type contains uppercase characters, as per RfC 2045 on the syntax of MIME type specifications (we can't test uppercase characters in the major type yet since the publisher is not completely up to the RfC on that detail yet): >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/hTMl') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/nOne') False Parameters to the content type can't fool the check either: >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml; charset=utf-8') True >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/none; charset=utf-8') False The content type is, however, assumed to be a strictly valid MIME type specification, implying that it can't contain any whitespace up to the semicolon signalling the start of parameters, if any (we can't test whitespace around the major type as that would already upset the publisher): >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/ xml') False >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml ; charset=utf-8') False The content type may also be None if it was never set, which of course doesn't count as HTML or XML either: >>> from zc.resourcelibrary import publication >>> from StringIO import StringIO >>> request = publication.Request(body_instream=StringIO(''), environ={}) >>> request.response.setResult("This is not HTML text.") >>> '/@@/my-lib/included.js' in request.response.consumeBody() False Dependencies ------------ If a resource library registers a dependency on another library, the dependency must be satisfied or an error will be generated. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ConfigurationExecutionError:...Resource library "dependent-but-unsatisfied" has unsatisfied dependency on "not-here"... When the dependencies are satisfied, the registrations will succeed. >>> zcml(""" ... ... ... ... ... ... ... ... ... ... ... ... """) If one library depends on another and the first library is referenced on a page, the second library will also be included in the rendered HTML. >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_4') >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True Order matters, espacially for js files, so the dependency should appear before the dependent library in the page >>> print browser.contents.strip() ...dependency/2.css...dependent/1.js... It is possible for a resource library to only register a list of dependencies and not specify any resources. When such a library is used in a resource_library statement in a template, only its dependencies are referenced in the final rendered page. >>> zcml(""" ... ... ... ... ... ... """) >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_7') >>> '/@@/my-lib/included.js' in browser.contents True >>> '/@@/my-lib/included.css' in browser.contents True >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True >>> '/@@/only_require' in browser.contents False Error Conditions ---------------- Errors are reported if you do something wrong. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError: ... ConfigurationError: Directory u'...does-not-exist' does not exist Multiple Heads -------------- On occasion the body of an HTML document may contain the text "". In those cases, only the actual head tag should be manipulated. The first occurrence of "" has the script tag inserted... >>> browser.open('http://localhost/zc.resourcelibrary.test_template_5') >>> print browser.contents ... ... Future Work ----------- * We want to be able to specify a single file to add to the resource. * We may want to be able to override a file in the resource with a different file. * Currently only one tag is allowed per-library. If multiple tags are allowed, should they be merged or have distinct prefixes? * Add a test to ensure that files are only included once, and in the proper order ======= CHANGES ======= 1.3.4 (2012-01-20) ------------------ - Register adapters with getSiteManager rather than getGlobalSiteManager. This allows registering resource libraries in non-global sites. For detais see: - https://mail.zope.org/pipermail/zope-dev/2010-March/039657.html - http://docs.pylonsproject.org/projects/pyramid_zcml/en/latest/narr.html#using-broken-zcml-directives - Raise NotImplementedError if we find that a second ZCML declaration would change the global library_info dict in a way that may (depending on ZCML ordering) break applications at runtime. These errors were pretty hard to debug. - Remove unneeded test dependencies on ``zope.app.authentication`` and ``zope.app.securitypolicy``. - Remove dependency on ``zope.app.pagetemplate``. 1.3.2 (2010-08-16) ------------------ - Response._addDependencies will only include a ResourceLibrary in the list of dependencies if the ResourceLibrary actually has included resources. This makes directives that simply declare dependencies on other libraries work again. - Add missing depedency on ``zope.app.pagetemplate``, clean up unused imports and whitespace. 1.3.1 (2010-03-24) ------------------ - Resource libraries that are required during a retried request are now correctly registered and injected to the HTML. - Import hooks functionality from zope.component after it was moved there from zope.site. This lifts the dependency on zope.site. - Removed an unused ISite import and thereby, the undeclared dependency on zope.location. 1.3.0 (2009-10-08) ------------------ - Use ``zope.browserresource`` instead of ``zope.app.publisher``, removing a dependency on latter. - Look up the "resources view" via queryMultiAdapter instead of looking into the adapter registry. - Moved the dependency on zope.site to the test dependencies. 1.2.0 (2009-06-04) ------------------ - Use ``zope.site`` instead of ``zope.app.component``. Removes direct dependency on ``zope.app.component``. 1.1.0 (2009-05-05) ------------------ New features: - An attempt to generate resource URLs using the "resources view" (@@) is now made; if unsuccesful, we fall back to the previous method of crafting the URL by hand from the site url. This ensures that the resource library respects the existing plugging points for resource publishing (see ``zope.app.publisher.browser.resources``). - You can now explicitly specify where resource links should be inserted using the special marker comment ''. 1.0.2 (2009-01-27) ------------------ - Remove zope.app.zapi from dependencies, substituting its uses with direct imports. - Use zope-dev at zope.org mailing list address instead of zope3-dev at zope.org as the latter one is retired. - Change "cheeseshop" to "pypi" in the package homepage. 1.0.1 (2008-03-07) ------------------ Bugs fixed: - added the behavior from the standard Zope 3 response to guess that a body that is not HTML without an explicit mimetype should have a 'text/plain' mimetype. This means that, for instance, redirects with a body of '' and no explicit content type will no longer cause an exception in the resourcelibrary response code. 1.0.0 (2008-02-17) ------------------ New features: - You can now provide an alternative "directory-resource" factory. This facilitates implementation of dynamic resources. Bugs fixed: - Updated the functional-testing zcml file to get rid of a deprecation warning. 0.8.2 (2007-12-07) ------------------ - bug fix: when checking content type, take into account that it may be None 0.8.1 (2007-12-05) ------------------ - changed MIME type handling to be more restrictive about whitespace to conform to RfC 2045 0.8 (2007-12-04) ---------------- - fixed the check for HTML and XML content to allow content type parameters 0.6.1 (2007-11-03) ------------------ - Update package meta-data. - Fixed package dependencies. - Merged functional and unit tests. 0.6.0 (2006-09-22) ------------------ ??? 0.5.2 (2006-06-15) ------------------ - Add more package meta-data. 0.5.1 (2006-06-06) ------------------ - Update package code to work with newer versions of other packages. 0.5.0 (2006-04-24) ------------------ - Initial release. Keywords: zope3 resource javascript css inclusion Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zc.resourcelibrary-1.3.4/bootstrap.py0000664000177100020040000000337011706347254021077 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Bootstrap a buildout-based project Simply run this script in a directory containing a buildout.cfg. The script accepts buildout command-line options, so you can use the -c option to specify an alternate configuration file. $Id: bootstrap.py 110151 2010-03-24 09:31:41Z zagy $ """ import os, shutil, sys, tempfile, urllib2 tmpeggs = tempfile.mkdtemp() ez = {} exec urllib2.urlopen('http://peak.telecommunity.com/dist/ez_setup.py' ).read() in ez ez['use_setuptools'](to_dir=tmpeggs, download_delay=0) import pkg_resources cmd = 'from setuptools.command.easy_install import main; main()' if sys.platform == 'win32': cmd = '"%s"' % cmd # work around spawn lamosity on windows ws = pkg_resources.working_set assert os.spawnle( os.P_WAIT, sys.executable, sys.executable, '-c', cmd, '-mqNxd', tmpeggs, 'zc.buildout', dict(os.environ, PYTHONPATH= ws.find(pkg_resources.Requirement.parse('setuptools')).location ), ) == 0 ws.add_entry(tmpeggs) ws.require('zc.buildout') import zc.buildout.buildout zc.buildout.buildout.main(sys.argv[1:] + ['bootstrap']) shutil.rmtree(tmpeggs) zc.resourcelibrary-1.3.4/COPYRIGHT.txt0000664000177100020040000000004011706347254020610 0ustar menesismenesis00000000000000Zope Foundation and Contributorszc.resourcelibrary-1.3.4/src/0000775000177100020040000000000011706347337017276 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/0000775000177100020040000000000011706347337017712 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/__init__.py0000664000177100020040000000031011706347254022013 0ustar menesismenesis00000000000000# this is a namespace package try: import pkg_resources pkg_resources.declare_namespace(__name__) except ImportError: import pkgutil __path__ = pkgutil.extend_path(__path__, __name__) zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/0000775000177100020040000000000011706347337023126 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/resourcelibrary.py0000664000177100020040000000310611706347254026712 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## from zope.publisher.interfaces import IRequest import zope.security.management import zope.security.interfaces library_info = {} class LibraryInfo(object): def __init__(self): self.included = [] self.required = [] def getRequest(): try: i = zope.security.management.getInteraction() # raises NoInteraction except zope.security.interfaces.NoInteraction: return for p in i.participations: if IRequest.providedBy(p): return p def need(library_name): request = getRequest() # only take note of needed libraries if there is a request, and it is # capable of handling resource librarys if request and hasattr(request, 'resource_libraries'): if not library_name in request.resource_libraries: request.resource_libraries.append(library_name) def getRequired(name): return library_info[name].required def getIncluded(name): return library_info[name].included zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/meta.zcml0000664000177100020040000000105311706347254024740 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/0000775000177100020040000000000011706347337024270 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/duplicate_declarations.zcml0000664000177100020040000000037411706347254031663 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/localsite.txt0000664000177100020040000000144611706347254027013 0ustar menesismenesis00000000000000Like most zope.component declarations, resource libraries are registered against the current, not global site manager: >>> class DummySiteManager: ... def registerAdapter(self, *args, **kw): ... print 'registering our adapter' >>> class DummySite: ... def getSiteManager(self): ... return DummySiteManager() >>> zcml(""" ... ... ... ... ... ... ... ... """, site=DummySite()) registering our adapter Clean Up: >>> import zope.component.hooks >>> zope.component.hooks.setSite(None) zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/duplicate_declarations_overrides.zcml0000664000177100020040000000034011706347254033736 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/0000775000177100020040000000000011706347337025723 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/1.js0000664000177100020040000000000011706347254026405 0ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/2.css0000664000177100020040000000000011706347254026562 0ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/my-lib/0000775000177100020040000000000011706347337027114 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/my-lib/included.kss0000664000177100020040000000005011706347254031416 0ustar menesismenesis00000000000000body:click { action-client: alert; }zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/my-lib/included.css0000664000177100020040000000005511706347254031413 0ustar menesismenesis00000000000000div .border { border: 1px silid black; } zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/my-lib/included.js0000664000177100020040000000006311706347254031236 0ustar menesismenesis00000000000000function be_annoying() { alert('Hi there!'); } zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/example/3.kss0000664000177100020040000000000011706347254026573 0ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_2.pt0000664000177100020040000000015711706347254027731 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/tests.py0000664000177100020040000001040411706347254026001 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: ntests.py 3330 2005-09-09 23:05:34Z jim $ """ from StringIO import StringIO from zc.resourcelibrary import resourcelibrary from zc.resourcelibrary import publication from zc.resourcelibrary import tal from zope.app.testing import functional from zope.configuration import xmlconfig import zope.interface from zope.pagetemplate import pagetemplate import zope.publisher.interfaces.browser import doctest import os import unittest import zope.component.hooks import zope.security.management class TestFactory: zope.interface.implements( zope.publisher.interfaces.browser.IBrowserPublisher) def __init__(self, source, checker, name): self.name = name self.__Security_checker__ = checker def __call__(self, request): return self def __getitem__(self, name): return lambda: "http://localhost/@@/%s/%s" % (self.name, name) def publishTraverse(self, request, name): return getattr(self, name.replace('.', '_')) def foo_js(self): return 'foo = 1;\n' #### testing framework #### def zcml(s, execute=True, clear=(), site=None): zope.component.hooks.setSite(site) for i in clear: del resourcelibrary.library_info[i] from zope.app.appsetup.appsetup import __config_context as context try: xmlconfig.string(s, context, execute=execute) except: context.end() raise class TestPageTemplate(pagetemplate.PageTemplate): def __init__(self, view): self.view = view super(TestPageTemplate, self).__init__() def pt_getContext(self, *args, **kws): context = super(TestPageTemplate, self).pt_getContext(*args, **kws) context['view'] = self.view return context def zpt(s, view=None, content_type=None): request = publication.Request(body_instream=StringIO(''), environ={}) zope.security.management.newInteraction(request) # if no set has been set, try setting it the view context if zope.component.hooks.getSite() is None and hasattr(view, 'context'): zope.component.hooks.setSite(view.context) pt = TestPageTemplate(view) # if the resource library expression hasn't been registered, do so engine = pt.pt_getEngine() type_name = 'resource_library' if type_name not in engine.types: engine.registerType(type_name, tal.ResourceLibraryExpression) pt.write(s) html = pt() zope.security.management.endInteraction() if content_type: request.response.setHeader("Content-Type", content_type) if html: request.response.setResult(html) return request.response.consumeBody() #### tests #### def test_empty_body(): """ If a response body is not html, guess that it is text/plain. This follows the behavior of zope.publication's trunk as of this writing. >>> import zc.resourcelibrary.publication >>> response = zc.resourcelibrary.publication.Response() >>> response.setResult('') >>> response.getHeader('content-type') 'text/plain' """ #### test setup #### ResourceLibraryFunctionalLayer = functional.ZCMLLayer( os.path.join(os.path.split(__file__)[0], 'ftesting.zcml'), __name__, 'ResourceLibraryFunctionalLayer') def test_suite(): suite = functional.FunctionalDocFileSuite( '../README.txt', 'duplicate_declarations.txt', 'localsite.txt', globs={'zcml': zcml, 'zpt': zpt}, optionflags=doctest.NORMALIZE_WHITESPACE | doctest.ELLIPSIS, ) suite.layer = ResourceLibraryFunctionalLayer return unittest.TestSuite(( suite, doctest.DocTestSuite() )) if __name__ == '__main__': unittest.main(defaultTest='test_suite') zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_4.pt0000664000177100020040000000016211706347254027727 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/__init__.py0000664000177100020040000000000211706347254026367 0ustar menesismenesis00000000000000# zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_unit.py0000664000177100020040000000456611706347254026671 0ustar menesismenesis00000000000000import doctest import unittest from zc.resourcelibrary import resourcelibrary from zc.resourcelibrary.resourcelibrary import LibraryInfo def setUp(test): test.old_library_info = resourcelibrary.library_info resourcelibrary.library_info = library_info = {} # Dependencies: # # libE # / # libA libD # \ / # libB / # \/ # libC def lib_info(included=None, required=None): res = LibraryInfo() if included: res.included.append(included) if required: res.required.append(required) return res library_info['libA'] = lib_info('foo.js', 'libB') library_info['libB'] = lib_info('bar.js', 'libC') library_info['libC'] = lib_info('baz.js') library_info['libD'] = lib_info('foo.css', 'libC') library_info['libE'] = lib_info(required='libD') def tearDown(test): resourcelibrary.library_info = test.old_library_info def doctest_dependency_resolution(): """Test Response._addDependencies >>> from zc.resourcelibrary.publication import Response >>> r = Response() The method gets a list of libraries and adds all their dependencies in the proper order >>> r._addDependencies(['libA']) ['libC', 'libB', 'libA'] Here's a tricky corner case that the old algorithm used to get wrong: >>> r._addDependencies(['libA', 'libD']) ['libC', 'libB', 'libA', 'libD'] No library is included more than once >>> r._addDependencies(['libC', 'libA', 'libD', 'libA']) ['libC', 'libB', 'libA', 'libD'] If a library doesn't contain any included resources, only its required libraries will be included in its list of dependencies. >>> r._addDependencies(['libE']) ['libC', 'libD'] Unknown library names cause errors >>> r._addDependencies(['libA', 'libZ']) Traceback (most recent call last): ... RuntimeError: Unknown resource library: "libZ" """ def test_suite(): return unittest.TestSuite( ( doctest.DocTestSuite(setUp=setUp, tearDown=tearDown), doctest.DocTestSuite('zc.resourcelibrary.publication', optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS, ), )) if __name__ == '__main__': unittest.main(defaultTest='test_suite') zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_1.pt0000664000177100020040000000005711706347254027727 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_7.pt0000664000177100020040000000016511706347254027735 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/duplicate_declarations.txt0000664000177100020040000000361711706347254031540 0ustar menesismenesis00000000000000It used to be that this configuration would result in wierd errors later as the global library_info dict would depend on the order declarations appeared in the ZCML. Now it just errors faster: >>> zcml(""" ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError:... NotImplementedError: Can't cope with 2 different registrations of the same library: some-library ([], []) ([], [u'1.js']) This is what getIncluded would have returned if the above had not errored (it is wrong as includeOverrides should have take precedence): >>> from zc.resourcelibrary import getIncluded >>> getIncluded("some-library") # doctest: +SKIP [u'included.js', u'included.css'] However we work if you load up the same ZCML file twice (as the information in library_info is exactly the same): >>> zcml(""" ... ... ... ... ... ... """) >>> zcml(""" ... ... ... ... ... ... """) The correct result from getIncluded is: >>> getIncluded("some-library") [u'1.js'] zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_3.pt0000664000177100020040000000016711706347254027733 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/ftesting.zcml0000664000177100020040000000434211706347254027003 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_6.pt0000664000177100020040000000034011706347254027727 0ustar menesismenesis00000000000000 Marker test zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tests/test_template_5.pt0000664000177100020040000000025011706347254027726 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/configure.zcml0000664000177100020040000000173611706347254026003 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/tal.py0000664000177100020040000000176611706347254024270 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2001, 2002 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """Resource Library Expression Type $Id: tal.py 3268 2005-08-22 23:31:27Z benji $ """ from zope.tales.expressions import StringExpr from zc.resourcelibrary import resourcelibrary class ResourceLibraryExpression(StringExpr): """Resource library expression handler class""" def __call__(self, econtext): resourcelibrary.need(self._expr) return '' zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/README.txt0000664000177100020040000003335411706347254024632 0ustar menesismenesis00000000000000================ Resource Library ================ The resource library is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. For instance, if two widgets on a page need the same JavaScript library, the library should be only loaded once, but the widget designers should not have to concern themselves with the presence of other widgets. Imagine that one widget has a copy of a fictional Javascript library. To configure that library as available use ZCML like this: >>> zcml(""" ... ... ... ... ... ... ... ... """) This is exactly equivalent to a resourceDirectory tag, with no additional effect. Loading Files ------------- It is also possible to indicate that one or more Javascript or CSS files should be included (by reference) into the HTML of a page that needs the library. This is the current difference between resourceLibrary and resourceDirectory. >>> zcml(""" ... ... ... ... ... ... ... ... """) If a file is included that the resource library doesn't understand (i.e. it isn't Javascript or CSS), an exception will occur. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError:... ConfigurationError: Resource library doesn't know how to include this file: "included.bad". Usage ----- Components signal their need for a particular resource library (Javascript or otherwise) by using a special TAL expression. (The use of replace is not mandated, the result may be assigned to a dummy variable, or otherwise ignored.) >>> zpt('') We'll be using a testbrowser.Browser to simulate a user viewing web pages. >>> from zope.testbrowser.testing import Browser >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') When a page is requested that does not need any resource libraries, the HTML will be untouched. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_1') >>> browser.contents '......' When a page is requested that uses a component that needs a resource library, the library will be referenced in the rendered page. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_2') A reference to the JavaScript is inserted into the HTML. >>> '/@@/my-lib/included.js' in browser.contents True And the JavaScript is available from the URL referenced. >>> browser.open('/@@/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); } For inclusion of resources the full base url with namespaces is used. >>> browser.open('http://localhost/++skin++Basic/zc.resourcelibrary.test_template_2') >>> print browser.contents 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; } A reference to an unknown library causes an exception. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_3') Traceback (most recent call last): ... RuntimeError: Unknown resource library: "does-not-exist" Library usage may also be signaled programattically. For example, if a page would not otherwise include a resource library... >>> page = ('' ... '' ... 'This is the body.') >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... pass >>> zpt(page, view=View()) '......' ...but we programmatically indicate that a resource library is needed, it will be included. >>> import zc.resourcelibrary >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... zc.resourcelibrary.need('my-lib') >>> '/@@/my-lib/included.js' in zpt(page, view=View()) True Content-type checking --------------------- Resources should be referenced only from HTML and XML content, other content types should not be touched by the resource library: >>> page = ('' ... '' ... '') >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/html') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/xml') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/none') False This also works if the content type contains uppercase characters, as per RfC 2045 on the syntax of MIME type specifications (we can't test uppercase characters in the major type yet since the publisher is not completely up to the RfC on that detail yet): >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/hTMl') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/nOne') False Parameters to the content type can't fool the check either: >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml; charset=utf-8') True >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/none; charset=utf-8') False The content type is, however, assumed to be a strictly valid MIME type specification, implying that it can't contain any whitespace up to the semicolon signalling the start of parameters, if any (we can't test whitespace around the major type as that would already upset the publisher): >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/ xml') False >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml ; charset=utf-8') False The content type may also be None if it was never set, which of course doesn't count as HTML or XML either: >>> from zc.resourcelibrary import publication >>> from StringIO import StringIO >>> request = publication.Request(body_instream=StringIO(''), environ={}) >>> request.response.setResult("This is not HTML text.") >>> '/@@/my-lib/included.js' in request.response.consumeBody() False Dependencies ------------ If a resource library registers a dependency on another library, the dependency must be satisfied or an error will be generated. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ConfigurationExecutionError:...Resource library "dependent-but-unsatisfied" has unsatisfied dependency on "not-here"... When the dependencies are satisfied, the registrations will succeed. >>> zcml(""" ... ... ... ... ... ... ... ... ... ... ... ... """) If one library depends on another and the first library is referenced on a page, the second library will also be included in the rendered HTML. >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_4') >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True Order matters, espacially for js files, so the dependency should appear before the dependent library in the page >>> print browser.contents.strip() ...dependency/2.css...dependent/1.js... It is possible for a resource library to only register a list of dependencies and not specify any resources. When such a library is used in a resource_library statement in a template, only its dependencies are referenced in the final rendered page. >>> zcml(""" ... ... ... ... ... ... """) >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_7') >>> '/@@/my-lib/included.js' in browser.contents True >>> '/@@/my-lib/included.css' in browser.contents True >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True >>> '/@@/only_require' in browser.contents False Error Conditions ---------------- Errors are reported if you do something wrong. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError: ... ConfigurationError: Directory u'...does-not-exist' does not exist Multiple Heads -------------- On occasion the body of an HTML document may contain the text "". In those cases, only the actual head tag should be manipulated. The first occurrence of "" has the script tag inserted... >>> browser.open('http://localhost/zc.resourcelibrary.test_template_5') >>> print browser.contents ... ... Future Work ----------- * We want to be able to specify a single file to add to the resource. * We may want to be able to override a file in the resource with a different file. * Currently only one tag is allowed per-library. If multiple tags are allowed, should they be merged or have distinct prefixes? * Add a test to ensure that files are only included once, and in the proper order zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/__init__.py0000664000177100020040000000007311706347254025235 0ustar menesismenesis00000000000000from resourcelibrary import getRequired, getIncluded, need zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/publication.py0000664000177100020040000001655511706347254026023 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2004 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## """ $Id: publication.py 4528 2005-12-23 02:45:25Z gary $ """ from zope import interface from zope.app.publication.interfaces import IBrowserRequestFactory from zope.component import queryMultiAdapter, getMultiAdapter from zope.publisher.browser import BrowserRequest, BrowserResponse from zope.publisher.browser import isHTML from zope.publisher.interfaces.browser import IBrowserPublisher from zope.traversing.browser.interfaces import IAbsoluteURL import zc.resourcelibrary import zope.component.hooks class Request(BrowserRequest): interface.classProvides(IBrowserRequestFactory) # __slots__ = ('resource_libraries',) def _createResponse(self): response = Response() self.resource_libraries = response.resource_libraries = [] return response def retry(self): """Returns request object to be used in a retry attempt. In addition to BrowswerRequest's retry() the libraries are copied over to the new request. Otherwise it is not possible to add even new libraries to a retried request. >>> import StringIO >>> request = Request(StringIO.StringIO(), {}) >>> request.resource_libraries = ['foo'] >>> retry_request = request.retry() >>> retry_request is request False >>> request.resource_libraries is retry_request.resource_libraries True The assigned libraries are flushed because a new request will define its own set of required librarires. >>> request.resource_libraries [] """ request = super(Request, self).retry() if hasattr(self, 'resource_libraries'): request.resource_libraries = self.resource_libraries request.resource_libraries[:] = [] return request class Response(BrowserResponse): def retry(self): """ Returns a response object to be used in a retry attempt. >>> response = Response() >>> response >>> response1 = response.retry() The returned object is not the same. >>> response1 is response False If resource_libraries are defined they are assigned to the new response. >>> rl = ['a','b','c'] >>> response.resource_libraries = rl >>> response.retry().resource_libraries is rl True >>> response.retry().retry().resource_libraries is rl True """ response = super(Response, self).retry() if hasattr(self, 'resource_libraries'): response.resource_libraries = self.resource_libraries return response def _implicitResult(self, body): #figure out the content type content_type = self.getHeader('content-type') if content_type is None: if isHTML(body): content_type = 'text/html' else: content_type = 'text/plain' self.setHeader('x-content-type-warning', 'guessed from content') self.setHeader('content-type', content_type) # check the content type disregarding parameters and case if content_type and content_type.split(';', 1)[0].lower() in ( 'text/html', 'text/xml'): # act on HTML and XML content only! resource_libraries = self._addDependencies(self.resource_libraries) html = self._generateIncludes(resource_libraries) if html: # This is a pretty low-rent way of adding things to the head. # We should probably use a real HTML parser instead. marker = body.find('') if marker != -1: body = body[:marker] + html + body[marker+27:] else: body = body.replace('', '\n %s\n' % html, 1) return super(Response, self)._implicitResult(body) def _generateIncludes(self, libraries): # generate the HTML that will be included in the response site = zope.component.hooks.getSite() if site is None: return resources = queryMultiAdapter( (site, self._request), interface.Interface, name='') if not IBrowserPublisher.providedBy(resources): # a setup with no resources factory is supported; in this # case, we manually craft a URL to the resource publisher # (see ``zope.browserresource.resource``). resources = None base = queryMultiAdapter( (site, self._request), IAbsoluteURL, name="resource") if base is None: baseURL = str(getMultiAdapter( (site, self._request), IAbsoluteURL)) else: baseURL = str(base) html = [] for lib in libraries: if resources is not None: library_resources = resources[lib] included = zc.resourcelibrary.getIncluded(lib) for file_name in included: if resources is not None: url = library_resources[file_name]() else: url = "%s/@@/%s/%s" % (baseURL, lib, file_name) if file_name.endswith('.js'): html.append('') elif file_name.endswith('.css'): html.append('') elif file_name.endswith('.kss'): html.append('' % url) else: # shouldn't get here; zcml.py is supposed to check includes raise RuntimeError('Resource library doesn\'t know how to ' 'include this file: "%s"' % file_name) return '\n '.join(html) def _addDependencies(self, resource_libraries): result = [] def add_lib(lib): if lib in result: return # Nothing to do try: required = zc.resourcelibrary.getRequired(lib) except KeyError: raise RuntimeError('Unknown resource library: "%s"' % lib) for other in required: add_lib(other) if zc.resourcelibrary.getIncluded(lib): result.append(lib) for lib in resource_libraries: add_lib(lib) return result zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/zcml.py0000664000177100020040000001244711706347254024453 0ustar menesismenesis00000000000000############################################################################## # # Copyright (c) 2006 Zope Foundation and Contributors. # All Rights Reserved. # # This software is subject to the provisions of the Zope Public License, # Version 2.1 (ZPL). A copy of the ZPL should accompany this distribution. # THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED # WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS # FOR A PARTICULAR PURPOSE. # ############################################################################## import os.path from zope.browserresource.directory import DirectoryResourceFactory from zope.browserresource.metadirectives import IBasicResourceInformation from zope.browserresource.metaconfigure import allowed_names from zope.component import getSiteManager from zope.configuration.exceptions import ConfigurationError from zope.interface import Interface from zope.publisher.interfaces.browser import IBrowserRequest from zope.publisher.interfaces.browser import IDefaultBrowserLayer from zope.security.checker import CheckerPublic, NamesChecker import zope.configuration.fields from zc.resourcelibrary.resourcelibrary import LibraryInfo, library_info class IResourceLibraryDirective(IBasicResourceInformation): """ Defines a resource library """ name = zope.schema.TextLine( title=u"The name of the resource library", description=u"""\ This is the name used to disambiguate resource libraries. No two libraries can be active with the same name.""", required=True, ) require = zope.configuration.fields.Tokens( title=u"Require", description=u"The resource libraries on which this library depends.", required=False, value_type=zope.schema.Text(), ) class IDirectoryDirective(Interface): """ Identifies a directory to be included in a resource library """ source = zope.configuration.fields.Path( title=u"Source", description=u"The directory containing the files to add.", required=True, ) include = zope.configuration.fields.Tokens( title=u"Include", description=u"The files which should be included in HTML pages which " u"reference this resource library.", required=False, value_type=zope.schema.Text(), ) factory = zope.configuration.fields.GlobalObject( title=u"Factory", description=u"Alternate directory-resource factory", required=False, ) def handler(name, dependencies, required, provided, adapter_name, factory, info=''): if dependencies: for dep in dependencies: if dep not in library_info: raise ConfigurationError( 'Resource library "%s" has unsatisfied dependency on "%s".' % (name, dep)) getSiteManager().registerAdapter( factory, required, provided, adapter_name, info) INCLUDABLE_EXTENSIONS = ('.js', '.css', '.kss') class ResourceLibrary(object): def __init__(self, _context, name, require=(), layer=IDefaultBrowserLayer, permission='zope.Public'): self.name = name self.layer = layer if permission == 'zope.Public': permission = CheckerPublic self.checker = NamesChecker(allowed_names, permission) # make note of the library in a global registry self.old_library_info = library_info.get(name) library_info[name] = LibraryInfo() library_info[name].required.extend(require) def directory(self, _context, source, include=(), factory=None): if not os.path.isdir(source): raise ConfigurationError("Directory %r does not exist" % source) for file_name in include: ext = os.path.splitext(file_name)[1] if ext not in INCLUDABLE_EXTENSIONS: raise ConfigurationError( 'Resource library doesn\'t know how to include this ' 'file: "%s".' % file_name) # remember which files should be included in the HTML when this library # is referenced library_info[self.name].included.extend(include) if factory is None: factory = DirectoryResourceFactory factory = factory(source, self.checker, self.name) _context.action( discriminator = ('resource', self.name, IBrowserRequest, self.layer), callable = handler, args = (self.name, library_info[self.name].required, (self.layer,), Interface, self.name, factory, _context.info), ) def __call__(self): if self.old_library_info is None: return curr_li = library_info[self.name] if self.old_library_info.included != curr_li.included or \ self.old_library_info.required != curr_li.required: raise NotImplementedError( "Can't cope with 2 different registrations of the same " "library: %s (%s, %s) (%s, %s)" % (self.name, self.old_library_info.required, self.old_library_info.included, curr_li.required, curr_li.included)) zc.resourcelibrary-1.3.4/src/zc/resourcelibrary/ftesting.zcml0000664000177100020040000000226111706347254025637 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/0000775000177100020040000000000011706347337024617 5ustar menesismenesis00000000000000zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/PKG-INFO0000664000177100020040000005716711706347331025726 0ustar menesismenesis00000000000000Metadata-Version: 1.1 Name: zc.resourcelibrary Version: 1.3.4 Summary: Post-rendering Resource Inclusion Home-page: http://pypi.python.org/pypi/zc.resourcelibrary Author: Zope Foundation and Contributors Author-email: zope-dev@zope.org License: ZPL 2.1 Description: The resource library is a Zope 3 extension that is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. .. contents:: ================ Resource Library ================ The resource library is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. For instance, if two widgets on a page need the same JavaScript library, the library should be only loaded once, but the widget designers should not have to concern themselves with the presence of other widgets. Imagine that one widget has a copy of a fictional Javascript library. To configure that library as available use ZCML like this: >>> zcml(""" ... ... ... ... ... ... ... ... """) This is exactly equivalent to a resourceDirectory tag, with no additional effect. Loading Files ------------- It is also possible to indicate that one or more Javascript or CSS files should be included (by reference) into the HTML of a page that needs the library. This is the current difference between resourceLibrary and resourceDirectory. >>> zcml(""" ... ... ... ... ... ... ... ... """) If a file is included that the resource library doesn't understand (i.e. it isn't Javascript or CSS), an exception will occur. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError:... ConfigurationError: Resource library doesn't know how to include this file: "included.bad". Usage ----- Components signal their need for a particular resource library (Javascript or otherwise) by using a special TAL expression. (The use of replace is not mandated, the result may be assigned to a dummy variable, or otherwise ignored.) >>> zpt('') We'll be using a testbrowser.Browser to simulate a user viewing web pages. >>> from zope.testbrowser.testing import Browser >>> browser = Browser() >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') When a page is requested that does not need any resource libraries, the HTML will be untouched. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_1') >>> browser.contents '......' When a page is requested that uses a component that needs a resource library, the library will be referenced in the rendered page. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_2') A reference to the JavaScript is inserted into the HTML. >>> '/@@/my-lib/included.js' in browser.contents True And the JavaScript is available from the URL referenced. >>> browser.open('/@@/my-lib/included.js') >>> print browser.contents function be_annoying() { alert('Hi there!'); } For inclusion of resources the full base url with namespaces is used. >>> browser.open('http://localhost/++skin++Basic/zc.resourcelibrary.test_template_2') >>> print browser.contents 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; } A reference to an unknown library causes an exception. >>> browser.open('http://localhost/zc.resourcelibrary.test_template_3') Traceback (most recent call last): ... RuntimeError: Unknown resource library: "does-not-exist" Library usage may also be signaled programattically. For example, if a page would not otherwise include a resource library... >>> page = ('' ... '' ... 'This is the body.') >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... pass >>> zpt(page, view=View()) '......' ...but we programmatically indicate that a resource library is needed, it will be included. >>> import zc.resourcelibrary >>> class View(object): ... context = getRootFolder() ... def doSomething(self): ... zc.resourcelibrary.need('my-lib') >>> '/@@/my-lib/included.js' in zpt(page, view=View()) True Content-type checking --------------------- Resources should be referenced only from HTML and XML content, other content types should not be touched by the resource library: >>> page = ('' ... '' ... '') >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/html') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/xml') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/none') False This also works if the content type contains uppercase characters, as per RfC 2045 on the syntax of MIME type specifications (we can't test uppercase characters in the major type yet since the publisher is not completely up to the RfC on that detail yet): >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/hTMl') True >>> '/@@/my-lib/included.js' in zpt(page, content_type='text/nOne') False Parameters to the content type can't fool the check either: >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml; charset=utf-8') True >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/none; charset=utf-8') False The content type is, however, assumed to be a strictly valid MIME type specification, implying that it can't contain any whitespace up to the semicolon signalling the start of parameters, if any (we can't test whitespace around the major type as that would already upset the publisher): >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/ xml') False >>> '/@@/my-lib/included.js' in zpt( ... page, content_type='text/xml ; charset=utf-8') False The content type may also be None if it was never set, which of course doesn't count as HTML or XML either: >>> from zc.resourcelibrary import publication >>> from StringIO import StringIO >>> request = publication.Request(body_instream=StringIO(''), environ={}) >>> request.response.setResult("This is not HTML text.") >>> '/@@/my-lib/included.js' in request.response.consumeBody() False Dependencies ------------ If a resource library registers a dependency on another library, the dependency must be satisfied or an error will be generated. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ConfigurationExecutionError:...Resource library "dependent-but-unsatisfied" has unsatisfied dependency on "not-here"... When the dependencies are satisfied, the registrations will succeed. >>> zcml(""" ... ... ... ... ... ... ... ... ... ... ... ... """) If one library depends on another and the first library is referenced on a page, the second library will also be included in the rendered HTML. >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_4') >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True Order matters, espacially for js files, so the dependency should appear before the dependent library in the page >>> print browser.contents.strip() ...dependency/2.css...dependent/1.js... It is possible for a resource library to only register a list of dependencies and not specify any resources. When such a library is used in a resource_library statement in a template, only its dependencies are referenced in the final rendered page. >>> zcml(""" ... ... ... ... ... ... """) >>> zpt('') >>> browser.open('http://localhost/zc.resourcelibrary.test_template_7') >>> '/@@/my-lib/included.js' in browser.contents True >>> '/@@/my-lib/included.css' in browser.contents True >>> '/@@/dependent/1.js' in browser.contents True >>> '/@@/dependency/2.css' in browser.contents True >>> '/@@/only_require' in browser.contents False Error Conditions ---------------- Errors are reported if you do something wrong. >>> zcml(""" ... ... ... ... ... ... ... ... """) Traceback (most recent call last): ... ZopeXMLConfigurationError: ... ConfigurationError: Directory u'...does-not-exist' does not exist Multiple Heads -------------- On occasion the body of an HTML document may contain the text "". In those cases, only the actual head tag should be manipulated. The first occurrence of "" has the script tag inserted... >>> browser.open('http://localhost/zc.resourcelibrary.test_template_5') >>> print browser.contents ... ... Future Work ----------- * We want to be able to specify a single file to add to the resource. * We may want to be able to override a file in the resource with a different file. * Currently only one tag is allowed per-library. If multiple tags are allowed, should they be merged or have distinct prefixes? * Add a test to ensure that files are only included once, and in the proper order ======= CHANGES ======= 1.3.4 (2012-01-20) ------------------ - Register adapters with getSiteManager rather than getGlobalSiteManager. This allows registering resource libraries in non-global sites. For detais see: - https://mail.zope.org/pipermail/zope-dev/2010-March/039657.html - http://docs.pylonsproject.org/projects/pyramid_zcml/en/latest/narr.html#using-broken-zcml-directives - Raise NotImplementedError if we find that a second ZCML declaration would change the global library_info dict in a way that may (depending on ZCML ordering) break applications at runtime. These errors were pretty hard to debug. - Remove unneeded test dependencies on ``zope.app.authentication`` and ``zope.app.securitypolicy``. - Remove dependency on ``zope.app.pagetemplate``. 1.3.2 (2010-08-16) ------------------ - Response._addDependencies will only include a ResourceLibrary in the list of dependencies if the ResourceLibrary actually has included resources. This makes directives that simply declare dependencies on other libraries work again. - Add missing depedency on ``zope.app.pagetemplate``, clean up unused imports and whitespace. 1.3.1 (2010-03-24) ------------------ - Resource libraries that are required during a retried request are now correctly registered and injected to the HTML. - Import hooks functionality from zope.component after it was moved there from zope.site. This lifts the dependency on zope.site. - Removed an unused ISite import and thereby, the undeclared dependency on zope.location. 1.3.0 (2009-10-08) ------------------ - Use ``zope.browserresource`` instead of ``zope.app.publisher``, removing a dependency on latter. - Look up the "resources view" via queryMultiAdapter instead of looking into the adapter registry. - Moved the dependency on zope.site to the test dependencies. 1.2.0 (2009-06-04) ------------------ - Use ``zope.site`` instead of ``zope.app.component``. Removes direct dependency on ``zope.app.component``. 1.1.0 (2009-05-05) ------------------ New features: - An attempt to generate resource URLs using the "resources view" (@@) is now made; if unsuccesful, we fall back to the previous method of crafting the URL by hand from the site url. This ensures that the resource library respects the existing plugging points for resource publishing (see ``zope.app.publisher.browser.resources``). - You can now explicitly specify where resource links should be inserted using the special marker comment ''. 1.0.2 (2009-01-27) ------------------ - Remove zope.app.zapi from dependencies, substituting its uses with direct imports. - Use zope-dev at zope.org mailing list address instead of zope3-dev at zope.org as the latter one is retired. - Change "cheeseshop" to "pypi" in the package homepage. 1.0.1 (2008-03-07) ------------------ Bugs fixed: - added the behavior from the standard Zope 3 response to guess that a body that is not HTML without an explicit mimetype should have a 'text/plain' mimetype. This means that, for instance, redirects with a body of '' and no explicit content type will no longer cause an exception in the resourcelibrary response code. 1.0.0 (2008-02-17) ------------------ New features: - You can now provide an alternative "directory-resource" factory. This facilitates implementation of dynamic resources. Bugs fixed: - Updated the functional-testing zcml file to get rid of a deprecation warning. 0.8.2 (2007-12-07) ------------------ - bug fix: when checking content type, take into account that it may be None 0.8.1 (2007-12-05) ------------------ - changed MIME type handling to be more restrictive about whitespace to conform to RfC 2045 0.8 (2007-12-04) ---------------- - fixed the check for HTML and XML content to allow content type parameters 0.6.1 (2007-11-03) ------------------ - Update package meta-data. - Fixed package dependencies. - Merged functional and unit tests. 0.6.0 (2006-09-22) ------------------ ??? 0.5.2 (2006-06-15) ------------------ - Add more package meta-data. 0.5.1 (2006-06-06) ------------------ - Update package code to work with newer versions of other packages. 0.5.0 (2006-04-24) ------------------ - Initial release. Keywords: zope3 resource javascript css inclusion Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: Zope Public License Classifier: Programming Language :: Python Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Topic :: Internet :: WWW/HTTP Classifier: Framework :: Zope3 zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/dependency_links.txt0000664000177100020040000000000111706347331030657 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/namespace_packages.txt0000664000177100020040000000000311706347331031135 0ustar menesismenesis00000000000000zc zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/not-zip-safe0000664000177100020040000000000111706347255027044 0ustar menesismenesis00000000000000 zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/top_level.txt0000664000177100020040000000000311706347331027334 0ustar menesismenesis00000000000000zc zc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/requires.txt0000664000177100020040000000043611706347331027214 0ustar menesismenesis00000000000000setuptools zope.app.publication zope.browserpage zope.browserresource zope.component zope.configuration zope.interface zope.publisher zope.security zope.tales zope.traversing [test] zope.app.testing zope.app.zcmlfiles zope.pagetemplate zope.securitypolicy zope.testbrowser zope.testingzc.resourcelibrary-1.3.4/src/zc.resourcelibrary.egg-info/SOURCES.txt0000664000177100020040000000335211706347331026500 0ustar menesismenesis00000000000000CHANGES.txt COPYRIGHT.txt LICENSE.txt README.txt bootstrap.py buildout.cfg setup.py src/zc/__init__.py src/zc.resourcelibrary.egg-info/PKG-INFO src/zc.resourcelibrary.egg-info/SOURCES.txt src/zc.resourcelibrary.egg-info/dependency_links.txt src/zc.resourcelibrary.egg-info/namespace_packages.txt src/zc.resourcelibrary.egg-info/not-zip-safe src/zc.resourcelibrary.egg-info/requires.txt src/zc.resourcelibrary.egg-info/top_level.txt src/zc/resourcelibrary/README.txt src/zc/resourcelibrary/__init__.py src/zc/resourcelibrary/configure.zcml src/zc/resourcelibrary/ftesting.zcml src/zc/resourcelibrary/meta.zcml src/zc/resourcelibrary/publication.py src/zc/resourcelibrary/resourcelibrary.py src/zc/resourcelibrary/tal.py src/zc/resourcelibrary/zcml.py src/zc/resourcelibrary/tests/__init__.py src/zc/resourcelibrary/tests/duplicate_declarations.txt src/zc/resourcelibrary/tests/duplicate_declarations.zcml src/zc/resourcelibrary/tests/duplicate_declarations_overrides.zcml src/zc/resourcelibrary/tests/ftesting.zcml src/zc/resourcelibrary/tests/localsite.txt src/zc/resourcelibrary/tests/test_template_1.pt src/zc/resourcelibrary/tests/test_template_2.pt src/zc/resourcelibrary/tests/test_template_3.pt src/zc/resourcelibrary/tests/test_template_4.pt src/zc/resourcelibrary/tests/test_template_5.pt src/zc/resourcelibrary/tests/test_template_6.pt src/zc/resourcelibrary/tests/test_template_7.pt src/zc/resourcelibrary/tests/test_unit.py src/zc/resourcelibrary/tests/tests.py src/zc/resourcelibrary/tests/example/1.js src/zc/resourcelibrary/tests/example/2.css src/zc/resourcelibrary/tests/example/3.kss src/zc/resourcelibrary/tests/example/my-lib/included.css src/zc/resourcelibrary/tests/example/my-lib/included.js src/zc/resourcelibrary/tests/example/my-lib/included.ksszc.resourcelibrary-1.3.4/buildout.cfg0000664000177100020040000000055111706347254021016 0ustar menesismenesis00000000000000[buildout] extends = http://svn.zope.org/repos/main/zopetoolkit/trunk/ztk.cfg?p=109981 http://svn.zope.org/repos/main/zopetoolkit/trunk/zopeapp.cfg?p=109918 develop = . parts = test pydev [versions] zc.resourcelibrary = [test] recipe = zc.recipe.testrunner eggs = zc.resourcelibrary [test] [pydev] recipe = pb.recipes.pydev eggs = zc.resourcelibrary zc.resourcelibrary-1.3.4/README.txt0000664000177100020040000000025011706347254020200 0ustar menesismenesis00000000000000The resource library is a Zope 3 extension that is designed to make the inclusion of JavaScript, CSS, and other resources easy, cache-friendly, and component-friendly. zc.resourcelibrary-1.3.4/setup.cfg0000664000177100020040000000007311706347337020330 0ustar menesismenesis00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 zc.resourcelibrary-1.3.4/LICENSE.txt0000664000177100020040000000402611706347254020332 0ustar menesismenesis00000000000000Zope Public License (ZPL) Version 2.1 A copyright notice accompanies this license document that identifies the copyright holders. This license has been certified as open source. It has also been designated as GPL compatible by the Free Software Foundation (FSF). Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions in source code must retain the accompanying copyright notice, this list of conditions, and the following disclaimer. 2. Redistributions in binary form must reproduce the accompanying copyright notice, this list of conditions, and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Names of the copyright holders must not be used to endorse or promote products derived from this software without prior written permission from the copyright holders. 4. The right to distribute this software or to use it for any purpose does not give you the right to use Servicemarks (sm) or Trademarks (tm) of the copyright holders. Use of them is covered by separate agreement with the copyright holders. 5. If any files are modified, you must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. Disclaimer THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.