Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge unified-ui branch and fix some buglets in the process

  • Loading branch information...
commit bd85dba782bbc45b982a6a45842fafbb9e143efb 2 parents 62ebe52 + 09aa004
@optilude optilude authored
Showing with 12,454 additions and 1,459 deletions.
  1. +11 −1 .gitignore
  2. +15 −0 .travis.yml
  3. +5 −911 README.txt
  4. +4 −0 buildout.cfg
  5. +8 −1 docs/HISTORY.txt
  6. +27 −0 docs/TODO.txt
  7. +1 −1  resources/theme/theme1/manifest.cfg
  8. +6 −1 setup.py
  9. +9 −0 src/plone/app/theming/__init__.py
  10. +81 −0 src/plone/app/theming/_roman.py
  11. +36 −0 src/plone/app/theming/browser/configure.zcml
  12. +682 −337 src/plone/app/theming/browser/controlpanel.pt
  13. +192 −30 src/plone/app/theming/browser/controlpanel.py
  14. +11 −0 src/plone/app/theming/browser/help.py
  15. +1,125 −0 src/plone/app/theming/browser/mapper.pt
  16. +307 −0 src/plone/app/theming/browser/mapper.py
  17. +94 −0 src/plone/app/theming/browser/resources/controlpanel.css
  18. BIN  src/plone/app/theming/browser/resources/defaultPreview.png
  19. BIN  src/plone/app/theming/browser/resources/disable.png
  20. BIN  src/plone/app/theming/browser/resources/enable.png
  21. BIN  src/plone/app/theming/browser/resources/full.png
  22. +260 −0 src/plone/app/theming/browser/resources/mapper.css
  23. +441 −0 src/plone/app/theming/browser/resources/mapper.js
  24. BIN  src/plone/app/theming/browser/resources/preview.png
  25. BIN  src/plone/app/theming/browser/resources/refresh.png
  26. BIN  src/plone/app/theming/browser/resources/small.png
  27. BIN  src/plone/app/theming/browser/resources/source.png
  28. +945 −0 src/plone/app/theming/browser/resources/userguide.rst
  29. +16 −0 src/plone/app/theming/browser/theme-error.pt
  30. +14 −0 src/plone/app/theming/configure.zcml
  31. +13 −1 src/plone/app/theming/interfaces.py
  32. +14 −1 src/plone/app/theming/profiles/default/controlpanel.xml
  33. +72 −0 src/plone/app/theming/tests/test_controlpanel.py
  34. +5 −4 src/plone/app/theming/tests/test_transform.py
  35. +31 −8 src/plone/app/theming/tests/test_utils.py
  36. BIN  src/plone/app/theming/tests/zipfiles/manifest_preview.zip
  37. +6 −0 src/plone/app/theming/theme.py
  38. +1,097 −0 src/plone/app/theming/themes/example/assets/ploneui.css
  39. +35 −0 src/plone/app/theming/themes/example/assets/theme.css
  40. +581 −0 src/plone/app/theming/themes/example/bootstrap/css/bootstrap-responsive.css
  41. +4 −0 src/plone/app/theming/themes/example/bootstrap/css/bootstrap-responsive.min.css
  42. +3,496 −0 src/plone/app/theming/themes/example/bootstrap/css/bootstrap.css
  43. +632 −0 src/plone/app/theming/themes/example/bootstrap/css/bootstrap.min.css
  44. BIN  src/plone/app/theming/themes/example/bootstrap/img/glyphicons-halflings-white.png
  45. BIN  src/plone/app/theming/themes/example/bootstrap/img/glyphicons-halflings.png
  46. +1,720 −0 src/plone/app/theming/themes/example/bootstrap/js/bootstrap.js
  47. +1 −0  src/plone/app/theming/themes/example/bootstrap/js/bootstrap.min.js
  48. +4 −0 src/plone/app/theming/themes/example/manifest.cfg
  49. BIN  src/plone/app/theming/themes/example/preview.png
  50. +58 −0 src/plone/app/theming/themes/example/rules.xml
  51. +76 −0 src/plone/app/theming/themes/example/theme.html
  52. +11 −0 src/plone/app/theming/themes/template/index.html
  53. +3 −0  src/plone/app/theming/themes/template/manifest.cfg
  54. +23 −0 src/plone/app/theming/themes/template/rules.xml
  55. +15 −100 src/plone/app/theming/transform.py
  56. +254 −63 src/plone/app/theming/utils.py
  57. +13 −0 travis.cfg
View
12 .gitignore
@@ -1,2 +1,12 @@
*.py?
-src/plone.app.theming.egg-info/
+*.pyc
+.DS_Store
+*.egg-info
+*.graffle
+.installed.cfg
+.mr.developer.cfg
+bin/
+develop-eggs/
+extras/
+parts/
+var/
View
15 .travis.yml
@@ -0,0 +1,15 @@
+language: python
+python:
+ - 2.6
+before_install:
+ - pip install http://effbot.org/downloads/Imaging-1.1.6.tar.gz
+install:
+ - python bootstrap.py
+ - bin/buildout -c travis.cfg -q
+script:
+ - bin/test -s diazo
+ - bin/test -s plone.app.theming
+ - bin/test -s plone.app.themingplugins
+ - bin/test -s plone.resource
+ - bin/test -s plone.resourceeditor
+ - bin/test -s plone.subrequest
View
916 README.txt
@@ -3,915 +3,9 @@ Introduction
============
This package offers a simple way to develop and deploy Plone themes using
-the `Diazo`_ theming engine. If you are not familiar with Diazo,
-check out the `Diazo documentation <http://diazo.org>`_.
+the Diazo theming engine. If you are not familiar with Diazo, check out the
+`Diazo documentation <http://diazo.org>`_.
-.. contents:: Contents
-
-Installation
-============
-
-``plone.app.theming`` works with Plone 4.1 or later.
-
-To install ``plone.app.theming`` into your Plone instance, locate the file
-``buildout.cfg`` in the root of your Plone instance directory on the file
-system, and open it in a text editor. Locate the section that looks like
-this::
-
- # extends = http://dist.plone.org/release/4.1/versions.cfg
- extends = versions.cfg
- versions = versions
-
-It may also have a URL in the "extends" section, similar to the commented-out
-first line, depending on whether you pull the Plone configuration from the
-network or locally.
-
-To add ``plone.app.theming`` to our setup, we need some slightly different
-versions of a couple of the packages, so we extend the base config with a
-version list from the good-py service, so change this part of the
-configuration so it looks like this::
-
- extends =
- versions.cfg
- http://good-py.appspot.com/release/plone.app.theming/1.0b1
- versions = versions
-
-Note that the last part of the URL above is the Diazo version number. There
-may be a newer version by the time you read this, so check out the `overview
-page <http://good-py.appspot.com/release/plone.app.theming>`_ for the known
-good set.
-
-What happens here is that the dependency list for ``plone.app.theming``
-specifies some new versions for you via the good-py URL. This way, you don't
-have to worry about getting the right versions, Buildout will handle it for
-you.
-
-Next step is to add the actual ``plone.app.theming`` add-on to the "eggs"
-section of ``buildout.cfg``. Look for the section that looks like this::
-
- eggs =
- Plone
-
-This section might have additional lines if you have other add-ons already
-installed. Just add the ``plone.app.theming`` on a separate line, like this::
-
- eggs =
- Plone
- plone.app.theming
-
-(Note that there is no need to add a ZCML slug as ``plone.app.theming`` uses
-``z3c.autoinclude`` to configure itself automatically.)
-
-Once you have added these lines to your configuration file, it's time to run
-buildout, so the system can add and set up ``plone.app.theming`` for you. Go
-to the command line, and from the root of your Plone instance (same directory
-as buildout.cfg is located in), run buildout like this::
-
- $ bin/buildout
-
-You will see output similar to this::
-
- Getting distribution for 'plone.app.theming==1.0b1'.
- Got plone.app.theming 1.0b1.
- ...
-
-If everything went according to plan, you now have ``plone.app.theming``
-installed in your Zope instance.
-
-Next, start up Zope, e.g with::
-
- $ bin/instance fg
-
-Then go to the "Add-ons" control panel in Plone as an administrator, and
-install the "Diazo theme support" product. You should then notice a new
-"Diazo theme" control panel in Plone's site setup.
-
-Usage
-=====
-
-In the "Diazo Theme" control panel, you can turn the theming engine on or
-off, and select from a list of pre-registered themes (more on how to
-register your own themes shortly).
-
-You can also upload a theme packaged as a ZIP archive from the control panel,
-under the "Import" tab. See below for more information about how to create
-a valid theme archive.
-
-Alternatively, you can configure a theme manually, under the "Advanced" tab.
-The options here are:
-
-Rules
- URL referencing the Diazo rules file. This file in turn references your
- theme. The URL may be a filesystem or remote URL (in which case you want
- to enable "read network access" - see below). It can also be an absolute
- path, starting with a ``/``, in which case it will be resolved relative
- to the Plone site root, or a special ``python://`` URL - see below.
-
- The most common type of URL will be a relative path using the
- ``++theme++`` traversal namespace. See below.
-
-Absolute prefix
- If given, any relative URL in an ``<img />``, ``<link />``, ``<style />``
- or ``<script />`` in the theme HTML file will be prefixed by this URL
- snippet when the theme is compiled. This makes it easier to develop theme
- HTML/CSS on the file system using relative paths that still work on any
- URL on the server.
-
-Read network
- By default, Diazo will not attempt to resolve external URLs referenced in
- the control panel or in the rules file, as this can have a performance
- impact. If you need to access external URLs, enable the "read network"
- setting.
-
-Unthemed host names
- You can list hostnames here that will never be themed. By default, this
- list contains ``127.0.0.1``, which means that if you access your Plone
- site using that IP address (as opposed to ``localhost`` or some other
- domain name), you will see an unthemed site. This is useful for theme
- development, or scenarios where you want your content authors to be able
- to access a "plain" Plone site.
-
-Parameter expressions
- Some themes will use parameters in their rules files. Available parameters
- can be set up here, using TALES expressions. Each parameter should be
- entered on its own line, in the form ``<parameter name> = <expression>``.
- More on expressions below.
-
-Packaging themes
-----------------
-
-There are several ways to package and distribute themes:
-
-ZIP file format
-~~~~~~~~~~~~~~~
-
-A theme packaged for import as a ZIP archive must adhere to the following
-rules:
-
- * The ZIP file must contain a single top level directory. This will be
- used as the theme id. Only one theme with a given id may exist in any
- given Plone site, though you are given the option to replace an existing
- theme on import if you upload an archive with a theme that already exists.
- * Inside this top level directory, there should be a ``rules.xml`` file with
- the Diazo rules. Any other resources, such as the theme HTML file or
- static resources, will normally also live in this directory or any
- subdirectories you wish to create inside it.
- * Optionally, you can add a ``manifest.cfg`` with a theme title and
- description for the theme. If you want to use a different absolute path
- prefix or rules file, you can also specify this in ``manifest.cfg``. See
- the next section for an example.
-
-The easiest way to create a compliant ZIP file is usually to start with a
-standalone theme built as a static web page in a top level directory,
-referencing its resources (images, stylesheets, JavaScript files, etc) using
-relative URLs. Then, place a ``rules.xml`` file in this same top level
-directory, containing the relevant Diazo directives. Finally, create a ZIP
-archive of the top level directory using the compression features built into
-your operating system or a program such as 7Zip for Windows.
-
-Themes in resources directories
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-This package integrates with `plone.resource`_ to enable the ``theme``
-resource type. This enables themes to be deployed:
-
- * On the filesystem using the global resource directory (if one is
- configured);
- * In the ZODB inside the ``theme`` directory of the
- ``portal_resources`` tool (perhaps initially imported via a ZIP archive
- as described above); or
- * In Python package that use the ``<plone:static />`` ZCML directive to
- register their own resource directory
-
-Provided they contains a ``rules.xml`` file, themes in such directories will
-appear in the control panel.
-
-For example:
-
- * If you had configured a global resource directory inside your buildout
- root called ``resources``, you could add a directory
- ``resources/theme/mytheme``. If this contained a ``rules.xml`` file,
- it would show up in the theme control panel as a pre-registered,
- installable theme.
- you could configure the rules path in the Diazo control panel to be
- ``/++theme++mytheme/rules.xml``, and the absolute prefix to be
- ``/++theme++mytheme``.
-
- * If you had uploaded your theme to the ZMI inside
- ``portal_resources/theme/mytheme`` and placed a ``rules.xml`` file here,
- you could again configure the rules path in the Diazo control panel to be
- ``/++theme++mytheme/rules.xml``, and the absolute prefix to be
- ``/++theme++mytheme``.
-
- * If you had a filesystem package ``my.theme`` you could create a
- subdirectory of this package called ``static/`` containing the
- ``rules.xml`` file then add the following to the ``configure.zcml``
- file in the package root::
-
- <configure
- xmlns:plone="http://namespaces.plone.org/plone"
- xmlns="http://namespaces.zope.org/zope">
-
- ...
-
- <plone:static directory="static" type="theme" />
-
- </configure>
-
- With this, you could configure the Diazo control panel to use the rules
- path ``/++theme++my.theme/rules.xml`` and the absolute prefix
- ``/++theme++my.theme``. The theme name here is taken from the package
- name where ``configure.zcml`` is found. To specify an alternative name,
- use the ``name`` attribute to the ``<plone:static />`` directive.
-
- See the worked example below for a more detailed example.
-
-When themes are deployed in this way, they become available in the control
-panel, provided the resource directory contains a ``rules.xml`` file.
-
-If there is a ``manifest.cfg`` file inside the top level resource directory,
-this may contain a manifest giving information about the theme. This file
-may look like this::
-
- [theme]
- title = My theme
- description = A test theme
-
-As shown here, the manifest file can be used to provide a more user friendly
-title and a longer description for the theme, for use in the control panel.
-Only the ``[theme]`` header is required - all other keys are optional.
-
-You can also set::
-
- rules = myrules.xml
-
-to use a different rule file name than ``rules.xml``, and::
-
- prefix = /some/prefix
-
-to change the absolute path prefix (see above).
-
-Note that when you set ``rules`` and ``prefix``, these are absolute URLs or
-file paths. To reference the theme directory you can use the following
-format::
-
- rules = /++theme++my.theme/myrules.xml
-
-The default is to use ``/++theme++<theme name>/rules.xml`` for the rules and
-``/++theme++<theme name>`` as the absolute path prefix, which is probably
-the right approach for most self-contained themes.
-
-Resources in Python packages
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-When specifying rules or referenced resources (such as the theme), you can use
-a special ``python://`` URI scheme to specify a path relative to the
-installation of a Python package distribution, as installed using
-Distribute/setuptools (e.g. a standard Plone package installed via buildout).
-
-For example, if your package is called ``my.theme`` and it contains a
-directory ``static``, you could reference the file ``rules.xml`` in that
-file as::
-
- ``python://my.theme/static/rules.xml``
-
-This will be resolved to an absolute ``file://`` URL by ``plone.app.theming``.
-
-**Note:** In most cases, it will be easier to use the ``<plone:static />``
-directive as described above.
-
-Theme parameters
-----------------
-
-It is possible to pass arbitrary parameters to your theme, which can be
-referenced as variables in XPath expressions.
-
-For example, you could have a parameter ``mode`` that could be set to the
-string ``live`` or ``test``. In your rules, you could do something like this
-to insert a warning when you are on the test server::
-
- <before css:theme-children="body" if="$mode = 'test'">
- <span class="warning">Warning: This is the test server</span>
- </before>
-
-You could even use the parameter value directly, e.g.::
-
- <before css:theme-children="body">
- <span class="info">This is the <xsl:value-of select="$mode" /> server</span>
- </before>
-
-See the `Diazo documentation`_ for more details about rules that support
-``if`` parameters and inline HTML and XSL.
-
-The following parameters are always available when using
-``plone.app.theming``:
-
-``scheme``
- The scheme portion of the inbound URL, usually ``http`` or ``https``.
-``host``
- The hostname in the inbound URL.
-``path``
- The path segment of the inbound URL. This will not include any virtual
- hosting tokens, i.e. it is the path the end user sees.
-``base``
- The Zope base url (the ``BASE1`` request variable).
-
-You can add additional parameters through the control panel, using TALES
-expressions. Parameters are listed on the *Advanced* tab, one per line, in
-the form ``<name> = <expression>``.
-
-For example, if you want to avoid theming any pages that are loaded by Plone's
-overlays, you can make use of the ``ajax_load`` request parameter that they
-set. Your rules file might include::
-
- <notheme if="$ajax_load" />
-
-To add this parameter as well as the ``mode`` parameter outlined earlier, you
-could add the following in the control panel::
-
- ajax_load = python: 'ajax_load' in request.form
- mode = string: test
-
-The right hand side is a TALES expression. It *must* evaluate to a string,
-integer, float, boolean or ``None``: lists, dicts and objects are not
-supported. ``python:``, ``string:`` and path expressions work as they do
-in page templates.
-
-The following variables are available:
-
- ``context``
- The context of the current request, usually a content object.
- ``request``
- The current request.
- ``portal``
- The portal root object.
- ``context_state``
- The ``@@plone_context_state`` view, from which you can look up additional
- values such as the context's URL or default view.
- ``portal_state``
- The ``@@plone_portal_state`` view, form which you can look up additional
- values such as the navigation root URL or whether or not the current
- user is logged in.
-
-See ``plone.app.layout`` for details about the ``@@plone_context_state`` and
-``@@plone_portal_state`` views.
-
-Theme parameters are really integral to a theme, and will therefore be set
-based on a theme's manifest when a theme is imported from a Zip file or
-enabled from a resource directory. This is done using the
-``[theme:parameters]`` section in the manifest file. For example::
-
- [theme]
- title = My theme
- description = A test theme
-
- [theme:parameters]
- ajax_load = python: 'ajax_load' in request.form
- mode = string: test
-
-Temporarily disabling the theme
--------------------------------
-
-Note that when Zope is in development mode (e.g. running in the foreground
-in a console with ``bin/instance fg``), the theme will be re-compiled on each
-request. In non-development mode, it is compiled once when first accessed, and
-then only re-compiled the control panel values are changed.
-
-Also, in development mode, it is possible to temporarily disable the theme
-by appending a query string parameter ``diazo.off=1``. For example::
-
- http://localhost:8080/Plone/some-page?diazo.off=1
-
-The parameter is ignored in non-development mode.
-
-Disabling the theme for a particular view, script or template
--------------------------------------------------------------
-
-To disable theming for a particular view, script or template set the
-``X-Theme-Disabled`` header. ::
-
- request.response.setHeader('X-Theme-Disabled', 'True')
-
-Or directly from a template::
-
- tal:define="dummy python:request.response.setHeader('X-Theme-Disabled', 'True')"
-
-Static files and CSS
---------------------
-
-Typically, the theme will reference static resources such as images or
-stylesheets. It is usually a good idea to keep all of these in a single,
-top-level directory to minimise the risk of clashes with Plone content paths.
-
-If you are using Zope/Plone standalone, you will need to make your static
-resources available through Zope, or serve them from a separate (sub-)domain.
-Here, you have a few options:
-
- * Create the static resources as ``File`` content objects through Plone.
- * Create the resources inside the ``portal_skins/custom`` folder in the ZMI.
- * Install the resources through a filesystem product.
-
-The latter is most the appropriate option if you are distributing your theme
-as a Python package. In this case, you can register a static resource
-directory in ZCML as outlined above::
-
- <configure
- xmlns="http://namespaces.zope.org/zope"
- xmlns:plone="http://namespaces.plone.org/plone">
-
- ...
-
- <plone:static
- directory="static"
- type="theme"
- />
-
- ...
-
- </configure>
-
-The ``static`` directory should be in the same directory as the
-``configure.zcml`` file. You can now put your theme, rules and static
-resources here.
-
-If you make sure that your theme uses only relative URLs to reference any
-stylesheets, JavaScript files, or images that it needs (including those
-referenced from stylesheets), you should now be able to view your static
-theme by going to a URL like::
-
- http://localhost:8080/Plone/++theme++my.theme/theme.html
-
-You can now set the "Absolute prefix" configuration option to be
-'/++theme++my.theme'. ``plone.app.theming`` will then turn relative URLs
-into appropriate absolute URLs with this prefix.
-
-If you have put Apache, nginx or IIS in front of Zope, you may want to serve
-the static resources from the web server directly instead.
-
-Using portal_css to manage your CSS
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-Plone's "resource registries", including the ``portal_css`` tool, can be used
-to manage CSS stylesheets. This offers several advantages over simply linking
-to your stylesheets in the template, such as:
-
-* Detailed control over the ordering of stylesheets
-* Merging of stylesheets to reduce the number of downloads required to render
- your page
-* On-the-fly stylesheet compression (e.g. whitespace removal)
-* The ability to include or exclude a stylesheet based on an expression
-
-It is usually desirable (and sometimes completely necessary) to leave the
-theme file untouched, but you can still use ``portal_css`` to manage your
-stylesheets. The trick is to drop the theme's styles and then include all
-styles from Plone. For example, you could add the following rules::
-
- <drop theme="/html/head/link" />
- <drop theme="/html/head/style" />
-
- <!-- Pull in Plone CSS -->
- <after theme-children="/html/head" content="/html/head/link | /html/head/style" />
-
-The use of an "or" expression for the content in the ``after />`` rule means
-that the precise ordering is maintained.
-
-For an example of how to register stylesheets upon product installation using
-GenericSetup, see below. In short - use the ``cssregistry.xml`` import step
-in your GenericSetup profile directory.
-
-There is one important caveat, however. Your stylesheet may include relative
-URL references of the following form:
-
- background-image: url(../images/bg.jpg);
-
-If your stylesheet lives in a resource directory (e.g. it is registered in
-``portal_css`` with the id ``++theme++my.theme/css/styles.css``), this
-will work fine so long as the registry (and Zope) is in debug mode. The
-relative URL will be resolved by the browser to
-``++theme++my.theme/images/bg.jpg``.
-
-However, you may find that the relative URL breaks when the registry is put
-into production mode. This is because resource merging also changes the URL
-of the stylesheet to be something like::
-
- /plone-site/portal_css/Suburst+Theme/merged-cachekey-1234.css
-
-To correct for this, you must set the ``applyPrefix`` flag to ``true`` when
-installing your CSS resource using ``cssregistry.xml``. There is a
-corresponding flag in the ``portal_css`` user interface.
-
-Controlling Plone's default CSS
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-It is sometimes useful to show some of Plone's CSS in the styled site. You
-can achieve this by using an Diazo ``after />`` rule or similar to copy the
-CSS from Plone's generated ``<head />`` into the theme. You can use the
-portal_css tool to turn off the style sheets you do not want.
-
-However, if you also want the site to be usable in non-themed mode (e.g. on a
-separate URL), you may want to have a larger set of styles enabled when Diazo
-is not used. To make this easier, you can use the following expressions as
-conditions in the portal_css tool (and ``portal_javascripts``,
-``portal_kss``), in portal_actions, in page templates, and other places that
-use TAL expression syntax::
-
- request/HTTP_X_THEME_ENABLED | nothing
-
-This expression will return True if Diazo is currently enabled, in which case
-an HTTP header "X-Theme-Enabled" will be set.
-
-If you later deploy the theme to a fronting web server such as nginx, you can
-set the same request header there to get the same effect, even if
-``plone.app.theming`` is uninstalled.
-
-Use::
-
- not: request/HTTP_X_THEME_ENABLED | nothing
-
-to 'hide' a style sheet from the themed site.
-
-GenericSetup syntax for enabling a theme
-----------------------------------------
-
-To enable the theme upon installation of a GenericSetup extension profile,
-you can use the ``theme.xml`` import step.
-
-Place a file like this in the profile directory – usually ``profiles/default``
-inside a package that registers a GenericSetup extension profile::
-
- <theme>
- <name>my.theme</name>
- <enabled>true</enabled>
- </theme>
-
-The ``<name />`` element is used to give the name of the theme to enable. The
-``<enabled />`` element is used to enable or disable theming, and may contain
-either ``true`` or ``false``. Both are optional.
-
-Note that this is an import step only. The actual state is stored in the
-``portal_registry`` tool provided by ``plone.app.registry``. Upon export (and
-in a base profile), it can be found in the profile in ``registry.xml``.
-
-A worked example
-=================
-
-There are many ways to set up an Diazo theme. For example, you could upload
-the theme and rules as content in Plone use absolute paths to configure them.
-You could also serve them from a separate static web server, or even load
-them from the filesystem.
-
-To create a deployable theme, however, it is often best to create a simple
-Python package. This also provides a natural home for theme-related
-customisations such as template overrides.
-
-Although a detailed tutorial is beyond the scope of this help file, a brief,
-worked example is shown below.
-
-1. Create a package and install it in your buildout::
-
- $ cd src
- $ paster create -t plone my.theme
-
-See `the buildout manual`_ for details
-
-If you have a recent ``ZopeSkel`` installed, this should work. Pick ``easy``
-mode. Answer "yes" when asked if you want to register a profile.
-
-Then edit ``buildout.cfg`` to add your new package (``my.theme`` above) to the
-``develop`` and ``eggs`` lists.
-
-2. Edit ``setup.py`` inside the newly created package
-
-The ``install_requires`` list should be::
-
- install_requires=[
- 'setuptools',
- 'plone.app.theming',
- ],
-
-Re-run buildout::
-
- $ bin/buildout
-
-3. Edit ``configure.zcml`` inside the newly created package.
-
-Add a resource directory inside the ``<configure />`` tag. Note that you may
-need to add the ``browser`` namespace, as shown.
-
- <configure
- xmlns="http://namespaces.zope.org/zope"
- xmlns:browser="http://namespaces.zope.org/browser"
- xmlns:i18n="http://namespaces.zope.org/i18n"
- xmlns:genericsetup="http://namespaces.zope.org/genericsetup"
- xmlns:plone="http://namespaces.plone.org/plone"
- i18n_domain="my.theme">
-
- <genericsetup:registerProfile
- name="default"
- title="My theme"
- directory="profiles/default"
- description="Installs the my.theme package"
- provides="Products.GenericSetup.interfaces.EXTENSION"
- />
-
- <plone:static
- type="theme"
- directory="static"
- />
-
- </configure>
-
-Here, we have used the package name, ``my.theme``, for the resource directory
-name. Adjust as appropriate.
-
-4. Add a ``static`` directory next to ``configure.zcml``.
-
-5. Put your theme and rules files into this directory.
-
-For example, you may have a ``theme.html`` that references images in a
-sub-directory ``images/`` and stylesheets in a sub-directory ``css/``. Place
-this file and the two directories inside the newly created ``static``
-directory.
-
-Make sure the theme uses relative URLs (e.g. ``<img src="images/foo.jpg" />``)
-to reference its resources. This means you can open theme up from the
-filesystem and view it in its splendour.
-
-Also place a ``rules.xml`` file there. See the `Diazo`_ documentation for
-details about its syntax. You can start with some very simple rules if
-you just want to test::
-
- <?xml version="1.0" encoding="UTF-8"?>
- <rules
- xmlns="http://namespaces.plone.org/diazo"
- xmlns:css="http://namespaces.plone.org/diazo/css"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
- <!-- The default theme, used for standard Plone web pages -->
- <theme href="theme.html" css:if-content="#visual-portal-wrapper" />
-
- <!-- Rules applying to a standard Plone web page -->
- <rules css:if-content="#visual-portal-wrapper">
-
- <!-- Add meta tags -->
- <drop theme="/html/head/meta" />
- <after content="/html/head/meta" theme-children="/html/head" />
-
- <!-- Copy style, script and link tags in the order they appear in the content -->
- <after
- content="/html/head/style | /html/head/script | /html/head/link"
- theme-children="/html/head"
- />
-
- <drop theme="/html/head/style" />
- <drop theme="/html/head/script" />
- <drop theme="/html/head/link" />
-
- <!-- Copy over the id/class attributes on the body tag.
- This is important for per-section styling -->
- <merge attributes="class" css:content="body" css:theme="body" />
- <copy attributes="id dir" css:content="body" css:theme="body" />
-
- <!-- Logo (link target) -->
- <copy attributes="href" css:content='#portal-logo' css:theme="#logo" />
-
- <!-- Site actions -->
- <replace css:content="#portal-siteactions li" css:theme-children="#actions" />
-
- <!-- Global navigation -->
- <replace css:content='#portal-globalnav li' css:theme-children='#global-navigation' />
-
- <!-- Breadcrumbs -->
- <replace css:content-children='#portal-breadcrumbs' css:theme-children='#breadcrumbs' />
-
- <!-- Document Content -->
- <replace css:content-children="#content" css:theme-children="#document-content" />
- <before css:content="#edit-bar" css:theme="#document-content" />
- <before css:content=".portalMessage" css:theme="#document-content" />
-
- <!-- Columns -->
- <replace css:content-children="#portal-column-one > *" css:theme-children="#column-one" />
- <replace css:content-children="#portal-column-two > *" css:theme-children="#column-two" />
-
- </rules>
-
- </rules>
-
-In this example, we have referenced the theme HTML file relative to the
-directory where the ``rules.xml`` resides. We make this theme conditional
-on the ``#visual-portal-wrapper`` element being present in the content (i.e.
-the web page generated by Plone). This ensures we do not apply the theme to
-things like pop-ups or special pages.
-
-We apply the same condition to the rules. The first few rules are probably
-useful in most Plone themes. The remainder of the rules are examples that
-may or may not apply, pulling in the logo, breadcrumbs, site actions,
-document content, and left/right hand side columns.
-
-See below for some more useful rules.
-
-Finally, put a ``manifest.cfg`` file alongside ``rules.xml`` in the
-``static`` directory, containing::
-
- [theme]
- title = My theme
- description = A demo theme from the plone.app.theming README
-
-6. Create the installation profile
-
-The generated code above for the ``<genericsetup:registerProfile />`` tag
-contains a reference to a directory ``profiles/default``. You may need to
-create this next to ``configure.zcml`` if it doesn't exist already, i.e.
-create a new directory ``profiles`` and inside it another directory
-``default``.
-
-In this directory, add a file called ``metadata.xml`` containing::
-
- <metadata>
- <version>1</version>
- <dependencies>
- <dependency>profile-plone.app.theming:default</dependency>
- </dependencies>
- </metadata>
-
-This will install plone.app.theming into Plone when my.theme is installed via
-the add-on control panel later.
-
-Also create a file called ``theme.xml``, with the following contents::
-
- <theme>
- <name>my.theme</name>
- <enabled>true</enabled>
- </theme>
-
-Replace ``my.theme`` with your own package name.
-
-This file configures the settings behind the Diazo control panel.
-
-Also, add a ``cssregistry.xml`` in the ``profiles/default`` directory to
-configure the ``portal_css`` tool::
-
- <?xml version="1.0"?>
- <object name="portal_css">
-
- <!-- Set conditions on stylesheets we don't want to pull in -->
- <stylesheet
- expression="not:request/HTTP_X_THEME_ENABLED | nothing"
- id="public.css"
- />
-
- <!-- Add new stylesheets -->
- <!-- Note: applyPrefix is not available in Plone < 4.0b3 -->
-
- <stylesheet title="" authenticated="False" cacheable="True"
- compression="safe" conditionalcomment="" cookable="True" enabled="on"
- expression="request/HTTP_X_THEME_ENABLED | nothing"
- id="++theme++my.theme/css/styles.css" media="" rel="stylesheet"
- rendering="link"
- applyPrefix="True"
- />
-
- </object>
-
-This shows how to set a condition on an existing stylesheet, as well as
-registering a brand new one. We've set ``applyPrefix`` to True here, as
-explained above.
-
-7. Test
-
-Start up Zope and go to your Plone site. Your new package should show as
-installable in the add-on product control panel. When installed, it should
-install ``plone.app.theming`` as a dependency and pre-configure it to use your
-theme and rule set. By default, the theme is not enabled, so you will need to
-go to the control panel to switch it on.
-
-You can now compare your untouched theme, the unstyled Plone site, and the
-themed site by using the following URLs:
-
-* ``http://localhost:8080`` (or whatever you have configured as the styled
- domain) for a styled Plone. If you used the sample rule above, this will
- look almost exactly like your theme, but with the ``<title />`` tag
- (normally shown in the title bar of your web browser) taken from Plone.
-* ``http://localhost:8080?diazo.off=1`` (presuming this is the port where
- Plone is running) for an unstyled Plone.
-* ``http://localhost:8080/++theme++my.theme/theme.html`` for the pristine
- theme. This is served as a static resource, almost as if it is being
- opened on the filesystem.
-
-Common rules
-============
-
-To copy the page title::
-
- <replace css:theme="title" css:content="title" />
-
-To copy the ``<base />`` tag (necessary for Plone's links to work)::
-
- <replace css:theme="base" css:content="base" />
-
-If there is no ``<base />`` tag in the theme, you can do:
-
- <before css:theme-children="head" css:content="base" />
-
-To drop all styles and JavaScript resources from the theme and copy them
-from Plone's ``portal_css`` tool instead::
-
- <!-- Drop styles in the head - these are added back by including them from Plone -->
- <drop theme="/html/head/link" />
- <drop theme="/html/head/style" />
-
- <!-- Pull in Plone CSS -->
- <after theme-children="/html/head" content="/html/head/link | /html/head/style" />
-
-To copy Plone's JavaScript resources::
-
- <!-- Pull in Plone CSS -->
- <after theme-children="/html/head" content="/html/head/script" />
-
-To copy the class of the ``<body />`` tag (necessary for certain Plone
-JavaScript functions and styles to work properly)::
-
- <!-- Body -->
- <merge attributes="class" css:theme="body" css:content="body" />
-
-Other tips
-==========
-
-* Firebug is an excellent tool for inspecting the theme and content when
- building rules. It even has an XPath extractor.
-* Read up on XPath. It's not as complex as it looks and very powerful.
-* Run Zope in debug mode whilst developing so that you don't need to restart
- to see changes to theme, rules or, resources.
-
-Migrating from collective.xdv
-=============================
-
-``plone.app.theme`` has evolved from the ``collective.xdv`` package.
-Similarly, Diazo is an evolution of ``xdv``.
-
-Migrating XDV rules to Diazo rules
-----------------------------------
-
-The Diazo ``rules.xml`` syntax is very similar to the XDV one, and your XDV
-rules should continue to work unchanged once the namespace is updated. Where
-in XDV you would have::
-
- <rules
- xmlns="http://namespaces.plone.org/xdv"
- xmlns:css="http://namespaces.plone.org/xdv+css"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
- ...
-
- </rules>
-
-you should now use::
-
- <rules
- xmlns="http://namespaces.plone.org/diazo"
- xmlns:css="http://namespaces.plone.org/diazo/css"
- xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
-
- ...
-
- </rules>
-
-In addition, some rules have been changed to simplify the rule set:
-
-* ``<copy />`` should only be used for copying attributes. For the use case
- that ``<copy />`` used to cover, use ``<replace />`` with ``theme-children``
- instead.
-* ``<prepend />`` has similarly been replaced by ``<before />`` with
- ``theme-children``.
-* ``<append />`` has similarly been replaced by ``<after />`` with
- ``theme-children``.
-
-Please see the `Diazo`_ documentation for more details about the available
-rules, including new rules only available in Diazo.
-
-Plone integration changes
--------------------------
-
-If you have installed a theme using ``collective.xdv``, and you wish to
-migrate to ``plone.app.theming``, you should use the following steps.
-
-1. Start up your Plone site, go to the ``portal_quickinstaller`` tool in
- the ZMI and uninstall the XDV theme integration package.
-
-2. Stop your Plone site, and remove ``collective.xdv`` from your buildout,
- by removing any references in ``buildout.cfg`` (or a file it extends),
- and any references in an ``install_requires`` line in a ``setup.py`` file
- you control.
-
-3. Install ``plone.app.theming`` as described above, adjusting your theme
- package as required.
-
-You will notice that ``plone.app.theming`` exposes fewer options than
-``collective.xdv``. This is mainly because the relevant features have moved
-into ``Diazo`` itself and can be configured in the ``rules.xml`` file.
-
-.. _Diazo: http://diazo.org
-.. _Plone: http://plone.org
-.. _plone.resource: http://pypi.python.org/pypi/plone.resource
-.. _the buildout manual: http://plone.org/documentation/manual/developer-manual/managing-projects-with-buildout
-.. _z3c.jbot: http://pypi.python.org/pypi/z3c.jbot
+This version of ``plone.app.theming`` ships with Plone version 4.3 or later.
+It comes with a user guide, reproduced below, avaialble through the theming
+control panel.
View
4 buildout.cfg
@@ -18,6 +18,8 @@ versions = versions
sources-dir = extras
auto-checkout =
plone.app.themingplugins
+ plone.resource
+ plone.resourceeditor
[versions]
plone.app.theming =
@@ -42,6 +44,7 @@ plone.subrequest = git ${remotes:plone}/plone.subrequest.git
plone.transformchain = git ${remotes:plone}/plone.transformchain.git
repoze.xmliter = git ${remotes:repoze}/repoze.xmliter.git
lxml = git ${remotes:lxml}/lxml.git
+plone.resourceeditor = git ${remotes:plone}/plone.resourceeditor.git
plone.app.themingplugins = git ${remotes:plone}/plone.app.themingplugins.git
[instance]
@@ -67,6 +70,7 @@ eggs =
plone.app.theming [test]
plone.app.themingplugins [test]
plone.resource [test]
+ plone.resourceeditor [test]
plone.subrequest [test]
repoze.xmliter
defaults = ['--auto-color', '--auto-progress']
View
9 docs/HISTORY.txt
@@ -1,9 +1,16 @@
Changelog
=========
-1.0.1 (unreleased)
+1.1a1 (unreleased)
------------------
+- Replace the stock "Themes" control panel with a renamed "Theming" control
+ panel, which incorporates the former's settings under its "Advanced" tab.
+ [optilude]
+
+- Add a full in-Plone theme authoring environment
+ [optilude, vangheem]
+
- Update IBeforeTraverseEvent import to zope.traversing.
[hannosch]
View
27 docs/TODO.txt
@@ -0,0 +1,27 @@
+plone.app.theming to-do
+=======================
+
+General
+-------
+
+[ ] Improve test coverage
+ [ ] Create
+ [ ] Copy
+ [ ] Delete
+ [ ] Enable
+ [ ] Disable
+ [ ] Advanced save
+
+Mapper
+------
+
+
+Future
+------
+
+[ ] Let preview show better error if theme not found
+[ ] Make preview show current path from content?
+[ ] Instead of hiding file manager for read-only themes, show with read-only
+ editor?
+[ ] Working copy editing
+[ ] Table-based visual rules list viewer/editor instead of source (unless rules source too complex)
View
2  resources/theme/theme1/manifest.cfg
@@ -1,5 +1,5 @@
[theme]
-title = Test theme
+title = Test theme - available in p.a.theming test buildout only!
doctype = <!DOCTYPE html>
[theme:parameters]
View
7 setup.py
@@ -1,12 +1,13 @@
from setuptools import setup, find_packages
import os
-version = '1.0.1.dev0'
+version = '1.1a1'
setup(name='plone.app.theming',
version=version,
description="Integrates the Diazo theming engine with Plone",
long_description=open("README.txt").read() + "\n\n" +
+ open(os.path.join("src", "plone", "app", "theming", "browser", "resources", "userguide.rst")).read() + "\n\n" +
open(os.path.join("docs", "HISTORY.txt")).read(),
# Get more strings from http://www.python.org/pypi?%3Aaction=list_classifiers
classifiers=[
@@ -27,15 +28,19 @@
install_requires=[
'setuptools',
'diazo',
+ 'docutils',
+ 'roman',
'lxml>=2.2.4',
'plone.app.registry>=1.0a2',
'plone.subrequest',
'plone.transformchain',
'plone.resource>=1.0b5',
+ 'plone.resourceeditor',
'repoze.xmliter>=0.3',
'five.globalrequest',
'Products.CMFPlone',
'zope.traversing',
+ 'plone.app.controlpanel',
],
extras_require={
'test': ['plone.app.testing'],
View
9 src/plone/app/theming/__init__.py
@@ -4,3 +4,12 @@
except ImportError: # pragma: no cover
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
+
+# Some systems have a broken/missing ``roman`` module; monkey patch one in
+
+try:
+ import roman
+except ImportError:
+ from plone.app.theming import _roman
+ import sys
+ sys.modules['roman'] = _roman
View
81 src/plone/app/theming/_roman.py
@@ -0,0 +1,81 @@
+"""Convert to and from Roman numerals"""
+
+__author__ = "Mark Pilgrim (f8dy@diveintopython.org)"
+__version__ = "1.4"
+__date__ = "8 August 2001"
+__copyright__ = """Copyright (c) 2001 Mark Pilgrim
+
+This program is part of "Dive Into Python", a free Python tutorial for
+experienced programmers. Visit http://diveintopython.org/ for the
+latest version.
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the Python 2.1.1 license, available at
+http://www.python.org/2.1.1/license.html
+"""
+
+import re
+
+#Define exceptions
+class RomanError(Exception): pass
+class OutOfRangeError(RomanError): pass
+class NotIntegerError(RomanError): pass
+class InvalidRomanNumeralError(RomanError): pass
+
+#Define digit mapping
+romanNumeralMap = (('M', 1000),
+ ('CM', 900),
+ ('D', 500),
+ ('CD', 400),
+ ('C', 100),
+ ('XC', 90),
+ ('L', 50),
+ ('XL', 40),
+ ('X', 10),
+ ('IX', 9),
+ ('V', 5),
+ ('IV', 4),
+ ('I', 1))
+
+def toRoman(n):
+ """convert integer to Roman numeral"""
+ if not (0 < n < 5000):
+ raise OutOfRangeError, "number out of range (must be 1..4999)"
+ if int(n) <> n:
+ raise NotIntegerError, "decimals can not be converted"
+
+ result = ""
+ for numeral, integer in romanNumeralMap:
+ while n >= integer:
+ result += numeral
+ n -= integer
+ return result
+
+#Define pattern to detect valid Roman numerals
+romanNumeralPattern = re.compile("""
+ ^ # beginning of string
+ M{0,4} # thousands - 0 to 4 M's
+ (CM|CD|D?C{0,3}) # hundreds - 900 (CM), 400 (CD), 0-300 (0 to 3 C's),
+ # or 500-800 (D, followed by 0 to 3 C's)
+ (XC|XL|L?X{0,3}) # tens - 90 (XC), 40 (XL), 0-30 (0 to 3 X's),
+ # or 50-80 (L, followed by 0 to 3 X's)
+ (IX|IV|V?I{0,3}) # ones - 9 (IX), 4 (IV), 0-3 (0 to 3 I's),
+ # or 5-8 (V, followed by 0 to 3 I's)
+ $ # end of string
+ """ ,re.VERBOSE)
+
+def fromRoman(s):
+ """convert Roman numeral to integer"""
+ if not s:
+ raise InvalidRomanNumeralError, 'Input can not be blank'
+ if not romanNumeralPattern.search(s):
+ raise InvalidRomanNumeralError, 'Invalid Roman numeral: %s' % s
+
+ result = 0
+ index = 0
+ for numeral, integer in romanNumeralMap:
+ while s[index:index+len(numeral)] == numeral:
+ result += integer
+ index += len(numeral)
+ return result
+
View
36 src/plone/app/theming/browser/configure.zcml
@@ -9,6 +9,11 @@
image="icon.gif"
/>
+ <browser:resourceDirectory
+ name="plone.app.theming"
+ directory="resources"
+ />
+
<browser:page
name="theming-controlpanel"
for="Products.CMFPlone.interfaces.IPloneSiteRoot"
@@ -17,4 +22,35 @@
permission="cmf.ManagePortal"
/>
+ <browser:page
+ name="theming-controlpanel-help"
+ for="Products.CMFPlone.interfaces.IPloneSiteRoot"
+ class=".help.Help"
+ permission="zope2.View"
+ />
+
+ <browser:page
+ name="theming-controlpanel-mapper"
+ for="plone.resource.interfaces.IResourceDirectory"
+ class=".mapper.ThemeMapper"
+ template="mapper.pt"
+ permission="cmf.ManagePortal"
+ />
+
+ <browser:page
+ name="theming-controlpanel-mapper-getframe"
+ for="plone.resource.interfaces.IResourceDirectory"
+ class=".mapper.ThemeMapper"
+ attribute="getFrame"
+ permission="cmf.ManagePortal"
+ />
+
+ <browser:page
+ name="theming-controlpanel-mapper-save"
+ for="plone.resource.interfaces.IResourceDirectory"
+ class=".mapper.ThemeMapper"
+ attribute="save"
+ permission="cmf.ManagePortal"
+ />
+
</configure>
View
1,019 src/plone/app/theming/browser/controlpanel.pt
@@ -6,9 +6,134 @@
metal:use-macro="context/prefs_main_template/macros/master"
i18n:domain="plone">
+<metal:block fill-slot="top_slot">
+
+ <tal:defines tal:define="dummy python:request.set('disable_border',1);
+ disable_column_one python:request.set('disable_plone.leftcolumn',0);
+ disable_column_two python:request.set('disable_plone.rightcolumn',1);"/>
+
+ <link
+ rel="stylesheet"
+ type="text/css"
+ tal:attributes="href string:${context/portal_url}/++resource++plone.app.theming/controlpanel.css"
+ />
+
+<script type="text/javascript" charset="utf-8" tal:content="string:var OPEN_OVERLAY='${view/overlay}';;"></script>
+<script type="text/javascript" charset="utf-8">
+
+ jQuery(function($) {
+
+ $().ready(function() {
+
+ $('.previewImageContainer').click(function() {
+ window.open($(this).attr("href"), "preview");
+ return false;
+ });
+
+ // move to top so overlays work
+ $(".overlay").appendTo("body");
+
+ // Help overlay
+ $("#helpButtonForm").prepOverlay({
+ subtype: 'iframe'
+ });
+
+ // Create/copy overlay
+ $("#overlay-new-theme").overlay();
+ $("#overlayTitleNewTheme").show();
+ $("#overlayTitleCopyTheme").hide();
+
+ $("#createButton").click(function() {
+ $("#baseOn").val('template');
+ $("#overlayTitleNewTheme").show();
+ $("#overlayTitleCopyTheme").hide();
+ $("#overlay-new-theme").data('overlay').load();
+
+
+ $("#overlay-new-theme .field.error").removeClass('error');
+ $("#overlay-new-theme .errorMessage").remove();
+
+ return false;
+ });
+
+ $(".copyButton").click(function() {
+ $("#baseOn").val($(this).parents(".themeEntry").attr('data-theme'));
+ $("#overlayTitleNewTheme").hide();
+ $("#overlayTitleCopyTheme span").html($(this).parents(".themeEntry").attr('data-theme-title'));
+ $("#overlayTitleCopyTheme").show();
+ $("#overlay-new-theme").data('overlay').load();
+
+ $("#overlay-new-theme .field.error").removeClass('error');
+ $("#overlay-new-theme .errorMessage").remove();
+
+ return false;
+ });
+
+ $("#overlay-new-theme input[name=form.button.Cancel]").click(function() {
+ $("#overlay-new-theme").data('overlay').close();
+ return false;
+ });
+
+ // Delete confirm overlay
+ $("#overlay-delete-confirm").overlay();
+
+ $(".deleteLink").click(function() {
+ $("#deleteConfirmTheme").val($(this).parents(".themeEntry").attr('data-theme'));
+ $("#overlayTitleDeleteConfirm span").html($(this).parents(".themeEntry").attr('data-theme-title'));
+ $("#overlay-delete-confirm").data('overlay').load();
+ return false;
+ });
+
+ $("#overlay-delete-confirm input[name=form.button.Cancel]").click(function() {
+ $("#overlay-delete-confirm").data('overlay').close();
+ return false;
+ });
+
+ // Upload overlay
+ $("#overlay-upload").overlay();
+
+ $("#uploadButton").click(function() {
+
+ $("#overlay-upload .field.error").removeClass('error');
+ $("#overlay-upload .errorMessage").remove();
+
+ $("#overlay-upload").data('overlay').load();
+ return false;
+ });
+
+ $("#overlay-upload input[name=form.button.Cancel]").click(function() {
+ $("#overlay-upload").data('overlay').close();
+ return false;
+ });
+
+ // Open overlay if there was an error
+ if(OPEN_OVERLAY) {
+
+ if(OPEN_OVERLAY == 'new-theme') {
+ var baseOn = $("#baseOn").val();
+ if(baseOn != 'template') { // operation was a copy
+ $("#overlayTitleNewTheme").hide();
+ $("#overlayTitleCopyTheme span").html($("#themeEntry-" + baseOn).attr('data-theme-title'));
+ $("#overlayTitleCopyTheme").show();
+ }
+ }
+
+ var triggeredOverlay = $("#overlay-" + OPEN_OVERLAY).data('overlay');
+ if(triggeredOverlay) triggeredOverlay.load();
+ }
+
+ });
+
+});
+
+</script>
+
+
+</metal:block>
+
<body>
-<div metal:fill-slot="prefs_configlet_main">
+<div metal:fill-slot="prefs_configlet_main" id="themeControlPanel">
<h1 class="documentFirstHeading"
i18n:translate="heading_theme_settings">Theme settings</h1>
@@ -20,445 +145,665 @@
Up to Site Setup
</a>
- <p i18n:translate="description_theme_settings">
- Use this control panel to enable a Diazo theme. You can either
- select a pre-registered theme, or configure a theme directly by
- specifying a rules file.
- </p>
-
<dl class="portalMessage info">
- <dt>Info</dt>
+ <dt i18n:translate="">Note</dt>
<dd i18n:translate="description_notheme_controlpanel">
Please note that this control panel page will never be themed.
</dd>
</dl>
<dl class="enableFormTabbing">
- <dt id="fieldsetlegend-basic">Basic settings</dt>
+ <dt id="fieldsetlegend-basic" i18n:translate="">Themes</dt>
<dd id="fieldset-basic">
<p i18n:translate="description_basic_settings">
- To enable a theme registered with Plone, choose it from the
- list below and make sure <em>Enable theme</em> is selected.
- It is also possible to use themes that are not pre-registered
- with Plone. Use the <em>Advanced</em> tab to configure a
- theme manually.
+ Use the buttons to create or upload a new Diazo theme,
+ or select an existing theme from a the list below.
</p>
+ <div class="formControls">
+ <button
+ id="createButton"
+ class="standalone"
+ i18n:translate="">New theme</button>
+
+ <button
+ id="uploadButton"
+ class="standalone"
+ i18n:translate="">Upload Zip file</button>
+
+ <form id="helpButtonForm" method="get" tal:attributes="action string:${portal_url}/@@theming-controlpanel-help">
+ <button
+ class="standalone"
+ i18n:translate="">Help</button>
+ </form>
+
+ </div>
+
+ <div id="themesList">
+
+ <div class="themeEntry"
+ tal:repeat="theme view/themeList"
+ tal:attributes="class python:theme['selected'] and 'themeEntry activeThemeEntry' or 'themeEntry';
+ id string:themeEntry-${theme/name};
+ data-theme theme/name;
+ data-theme-title theme/title;">
+
+ <div clas="themeEntryDetail">
+
+ <span class="themeEntryTitle">
+ <span tal:replace="theme/title">Title</span>
+ <span
+ tal:condition="theme/selected"
+ class="themeActive"
+ i18n:translate="">(active)</span>
+ </span>
+
+ <div class="themeEntryWrapper">
+
+ <a class="previewImageContainer"
+ title="Click to view a live preview. Forms will be disabled in the preview."
+ i18n:translate="title [tooltip_theme_preview]"
+ tal:attributes="href string:${context/portal_url}/++theme++${theme/name}/@@theming-controlpanel-mapper-getframe?path=/&amp;theme=apply&amp;forms=disable&amp;links=replace&amp;title=Preview:+${theme/title}"
+ target="_new"
+ href="#">
+ <img
+ tal:attributes="src theme/preview"
+ />
+ </a>
+
+ <div class="themeDescription" tal:content="theme/description" />
+
+ <div class="themeEntryControls">
+
+ <form method="post" tal:attributes="action request/URL">
+ <input tal:replace="structure context/@@authenticator/authenticator" />
+ <input type="hidden" name="themeName" tal:attributes="value theme/name" />
+ <button
+ tal:condition="not:theme/selected"
+ i18n:translate=""
+ type="submit"
+ name="form.button.Enable">Activate</button>
+ <button
+ tal:condition="theme/selected"
+ i18n:translate=""
+ type="submit"
+ name="form.button.Disable">Deactivate</button>
+ </form>
+
+ <button class="copyButton" i18n:translate="">Copy</button>
+
+ <form method="get" target="_blank" tal:attributes="action string:${context/absolute_url}/++theme++${theme/name}/@@download-zip">
+ <button i18n:translate="">Download</button>
+ </form>
+
+ <form method="get" tal:attributes="action string:${context/portal_url}/++theme++${theme/name}/@@theming-controlpanel-mapper">
+ <button tal:condition="theme/editable" i18n:translate="">Modify theme</button>
+ <button tal:condition="not:theme/editable" i18n:translate="">Inspect theme</button>
+ </form>
+
+ <a href="#" class="deleteLink"
+ tal:condition="theme/editable"
+ i18n:translate="">Delete</a>
+
+ </div>
+
+ </div>
+
+ </div>
+ </div>
+
+ <div class="visualClear"><!-- --></div>
+
+ </div>
+
+ </dd>
+
+ <dt id="fieldsetlegend-advanced" i18n:translate="">Advanced settings</dt>
+ <dd id="fieldset-advanced">
+
<form
- name="basic"
+ name="advanced"
method="post"
class="enableUnloadProtection"
tal:attributes="action request/URL"
tal:define="errors view/errors">
- <div
- class="field"
- tal:define="selected python:request.get('enabled', view.settings.enabled)">
-
- <input type="hidden" value="" name="enabled:boolean:default" />
- <input type="checkbox" value="1" name="enabled:boolean" id="enabled"
- tal:attributes="checked python:'checked' if selected else None"
- />
- <label for="enabled" i18n:translate="label_enabled">Enable theme</label>
- <div class="formHelp" i18n:translate="help_enabled">
- If this option is disabled, no theme will be applied.
- </div>
+ <fieldset>
+ <legend i18n:translate="">Theme details</legend>
- </div>
+ <p i18n:translate="description_advanced">
+ Use the fields below to configure the Diazo theme
+ manually. Usually, these settings are applied by
+ enabling a theme from the <strong>Themes</strong>
+ tab.
+ </p>
- <div
- class="field"
- tal:define="selected python:request.get('selectedTheme', view.selectedTheme)">
+ <div
+ class="field"
+ tal:define="selected python:request.get('themeEnabled', view.settings.enabled)">
- <label for="selectedTheme" i18n:translate="label_selected_theme">Select a theme</label>
- <div class="formHelp" i18n:translate="help_selected_theme">
- Select a theme from the list below to apply this theme.
- </div>
-
- <select size="1" id="selectedTheme" name="selectedTheme">
- <option
- value=""
- i18n:translate="label_please_select_theme">Please select</option>
- <option
- value="_other_"
- tal:condition="python:not selected and view.settings.rules is not None"
- selected="selected"
- i18n:translate="label_other">Other (see advanced tab)</option>
- <option
- tal:repeat="theme view/availableThemes"
- tal:content="string:${theme/title} (${theme/__name__})"
- tal:attributes="value theme/__name__;
- title theme/description;
- selected python:theme.__name__ == selected and 'selected' or None"
+ <input type="hidden" value="" name="themeEnabled:boolean:default" />
+ <input type="checkbox" value="1" name="themeEnabled:boolean" id="themeEnabled"
+ tal:attributes="checked python:'themeEnabled' if selected else None"
/>
- </select>
+ <label for="themeEnabled" i18n:translate="label_theme_enabled">Theme enabled</label>
+ <div class="formHelp" i18n:translate="help_theme_enabled">
+ If enabled the currently configured Diazo theme (if any)
+ will be applied.
+ </div>
- </div>
+ </div>
- <div class="formControls">
- <input
- type="submit"
- name="form.button.BasicSave"
- class="context"
- value="Save"
- i18n:attributes="value" />
-
- <input
- type="submit"
- name="form.button.Cancel"
- class="context"
- value="Cancel"
- i18n:attributes="value" />
- </div>
+ <div
+ tal:define="error errors/rules | nothing;
+ rules python:request.get('rules', view.settings.rules)"
+ tal:attributes="class python:'field error' if error else 'field'">
- <input tal:replace="structure context/@@authenticator/authenticator" />
+ <label for="rules" i18n:translate="label_rules">Rules file</label>
+ <div class="formHelp" i18n:translate="help_rules">
+ Enter a path or URL for the theme rules file.
+ </div>
- </form>
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
- </dd>
+ <input
+ name="rules"
+ id="rules"
+ type="text"
+ size="50"
+ tal:attributes="value rules"
+ />
- <dt id="fieldsetlegend-advanced">Advanced settings</dt>
- <dd id="fieldset-advanced">
+ </div>
- <p i18n:translate="description_advanced">
- Use the fields below to configure the Diazo rules file and
- absolute path prefix, or to enable reading a theme from a
- remote server.
- </p>
+ <div
+ tal:define="error errors/absolutePrefix | nothing;
+ absolutePrefix python:request.get('absolutePrefix', view.settings.absolutePrefix)"
+ tal:attributes="class python:'field error' if error else 'field'">
- <form
- name="advanced"
- method="post"
- class="enableUnloadProtection"
- tal:attributes="action request/URL"
- tal:define="errors view/errors">
+ <label for="absolutePrefix" i18n:translate="label_absolute_prefix">Absolute path prefix</label>
+ <div class="formHelp" i18n:translate="help_absolute_prefix">
+ If your theme uses relative paths for images, stylesheets
+ or other resources, you can enter a prefix here to make
+ sure these resources will work regardless of which page
+ Plone is rendering.
+ </div>
+
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
- <div
- tal:define="error errors/rules | nothing;
- rules python:request.get('rules', view.settings.rules)"
- tal:attributes="class python:'field error' if error else 'field'">
+ <input
+ name="absolutePrefix"
+ id="absolutePrefix"
+ type="text"
+ size="50"
+ tal:attributes="value absolutePrefix"
+ />
- <label for="rules" i18n:translate="label_rules">Rules file</label>
- <div class="formHelp" i18n:translate="help_rules">
- Enter a path or URL for the theme rules file.
</div>
- <div tal:content="error" tal:condition="error" />
+ <div
+ tal:define="error errors/doctype | nothing;
+ doctype python:request.get('doctype', view.settings.doctype)"
+ tal:attributes="class python:'field error' if error else 'field'">
- <input
- name="rules"
- id="rules"
- type="text"
- size="50"
- tal:attributes="value rules"
- />
+ <label for="doctype" i18n:translate="label_doctype">Doctype</label>
+ <div class="formHelp" i18n:translate="help_doctype">
+ You can specify a Doctype string which will be set on
+ the output, for example "<!DOCTYPE html>". If left
+ blank the default XHTML 1.0 transistional Doctype or
+ that set in the Diazo theme is used.
+ </div>
- </div>
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
+
+ <input
+ name="doctype"
+ id="doctype"
+ type="text"
+ size="50"
+ tal:attributes="value doctype"
+ />
- <div
- tal:define="error errors/absolutePrefix | nothing;
- absolutePrefix python:request.get('absolutePrefix', view.settings.absolutePrefix)"
- tal:attributes="class python:'field error' if error else 'field'">
-
- <label for="absolutePrefix" i18n:translate="label_absolute_prefix">Absolute path prefix</label>
- <div class="formHelp" i18n:translate="help_absolute_prefix">
- If your theme uses relative paths for images, stylesheets
- or other resources, you can enter a prefix here to make
- sure these resources will work regardless of which page
- Plone is rendering.
</div>
- <div tal:content="error" tal:condition="error" />
+ <div
+ class="field"
+ tal:define="selected python:request.get('readNetwork', view.settings.readNetwork)">
- <input
- name="absolutePrefix"
- id="absolutePrefix"
- type="text"
- size="50"
- tal:attributes="value absolutePrefix"
- />
+ <input type="hidden" value="" name="readNetwork:boolean:default" />
+ <input type="checkbox" value="1" name="readNetwork:boolean" id="readNetwork"
+ tal:attributes="checked python:'readNetwork' if selected else None"
+ />
+ <label for="readNetwork" i18n:translate="label_read_network">Read network</label>
+ <div class="formHelp" i18n:translate="help_read_network">
+ Allow rules and themes to be read from remote servers.
+ </div>
- </div>
+ </div>
- <div
- tal:define="error errors/doctype | nothing;
- doctype python:request.get('doctype', view.settings.doctype)"
- tal:attributes="class python:'field error' if error else 'field'">
+ <div
+ tal:define="error errors/hostnameBlacklist | nothing;
+ hostnameBlacklist view/settings/hostnameBlacklist | python:[];
+ hostnameBlacklist python:request.get('hostnameBlacklist', hostnameBlacklist)"
+ tal:attributes="class python:'field error' if error else 'field'">
+
+ <label for="hostnameBlacklist" i18n:translate="label_hostname_blacklist">Unthemed host names</label>
+ <div class="formHelp" i18n:translate="help_hostname_blacklist">
+ If there are hostnames that you do not want to be
+ themed, you can list them here, one per line. This is
+ useful during theme development, so that you can
+ compare the themed and unthemed sites. In some cases,
+ you may also want to provided an unthemed host alias
+ for content administrators to be able to use 'plain'
+ Plone.
+ </div>
+
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
+
+ <textarea
+ name="hostnameBlacklist:lines"
+ id="hostnameBlacklist"
+ rows="5"
+ cols="50"
+ tal:content="python:'\n'.join(hostnameBlacklist)"
+ ></textarea>
- <label for="doctype" i18n:translate="label_doctype">Doctype</label>
- <div class="formHelp" i18n:translate="help_doctype">
- A text string which will be written before the first "html" tag on
- all served pages. If left blank, "&lt;!DOCTYPE html&gt;" (i.e. HTML5),
- or the doctype specified by the enabled Diazo theme, will be used.
</div>
- <div tal:content="error" tal:condition="error" />
+ <div
+ tal:define="error errors/parameterExpressions | nothing;
+ parameterExpressions python:view.settings.parameterExpressions or {};
+ parameterExpressions python:['%s = %s' % (k,v) for k,v in parameterExpressions.items()];
+ parameterExpressions python:request.get('parameterExpressions', parameterExpressions)"
+ tal:attributes="class python:'field error' if error else 'field'">
+
+ <label for="parameterExpressions" i18n:translate="label_parameter_expressions">Parameter expressions</label>
+ <div class="formHelp" i18n:translate="help_parameter_expressions">
+ You can define parameters that will be passed
+ to the compiled theme here. In your rules file, you can
+ refer to a parameter by <code>$name</code>. Parameters
+ are defined using TALES expressions, which should
+ evaluate to a string, a number, a boolean or None.
+ Available variables are <code>context</code>,
+ <code>request</code>, <code>portal</code>,
+ <code>portal_state</code>, and
+ <code>context_state</code>. Define one variable
+ per line, in the format <code>name = expression</code>.
+ </div>
+
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
+
+ <textarea
+ name="parameterExpressions:lines"
+ id="parameterExpressions"
+ rows="8"
+ cols="50"
+ tal:content="python:'\n'.join(parameterExpressions)"
+ ></textarea>
+ </div>
- <input
- name="doctype"
- id="doctype"
- type="text"
- size="50"
- tal:attributes="value doctype"
- />
+ </fieldset>
+ <fieldset>
+ <legend i18n:translate="">Theme base</legend>
+
+ <p i18n:translate="description_advanced_base">
+ The settings below control the presentation of the
+ <em>content</em> produced by Plone before a Diazo theme
+ is applied. Note that these settings will have an effect
+ even if no Diazo theme is currently enabled.
+ </p>
+
+ <div
+ class="field"
+ tal:define="selected python:request.get('themeBase', view.skinsSettings.theme)">
+
+ <label for="themeBase" i18n:translate="label_theme_base">Theme base</label>
+
+ <div class="formHelp" i18n:translate="help_theme_base">
+ The theme base defines a collection of templates and other
+ resources that makes up the raw content to which a theme is
+ applied. Most Diazo themes will assume the default theme base,
+ so only change this if you know what you are doing.
+ </div>
+
+ <select size="1" name="themeBase" id="themeBase">
+ <option
+ tal:repeat="skin view/skinsVocabulary"
+ tal:attributes="value skin/value;
+ selected python:skin.value == selected and 'selected' or None"
+ tal:content="skin/title"
+ />
+ </select>
- </div>
+ </div>
+
+ <div
+ class="field"
+ tal:define="selected python:request.get('markSpecialLinks', view.skinsSettings.mark_special_links)">
+
+ <input type="hidden" value="" name="markSpecialLinks:boolean:default" />
+ <input type="checkbox" value="1" name="markSpecialLinks:boolean" id="markSpecialLinks"
+ tal:attributes="checked python:'markSpecialLinks' if selected else None"
+ />
+ <label for="markSpecialLinks" i18n:translate="label_mark_special_links">Mark special links</label>
+ <div class="formHelp" i18n:translate="help_mark_special_links">
+ If enabled all external links will be marked with link type specific icons.
+ </div>
- <div
- class="field"
- tal:define="selected python:request.get('readNetwork', view.settings.readNetwork)">
-
- <input type="hidden" value="" name="readNetwork:boolean:default" />
- <input type="checkbox" value="1" name="readNetwork:boolean" id="readNetwork"
- tal:attributes="checked python:'readNetwork' if selected else None"
- />
- <label for="readNetwork" i18n:translate="label_read_network">Read network</label>
- <div class="formHelp" i18n:translate="help_read_network">
- Allow rules and themes to be read from remote servers.
</div>
- </div>
+ <div
+ class="field"
+ tal:define="selected python:request.get('extLinksOpenInNewWindow', view.skinsSettings.ext_links_open_new_window)">
+
+ <input type="hidden" value="" name="extLinksOpenInNewWindow:boolean:default" />
+ <input type="checkbox" value="1" name="extLinksOpenInNewWindow:boolean" id="extLinksOpenInNewWindow"
+ tal:attributes="checked python:'extLinksOpenInNewWindow' if selected else None"
+ />
+ <label for="extLinksOpenInNewWindow" i18n:translate="label_ext_links_open_new_window">External links open in new window</label>
+ <div class="formHelp" i18n:translate="help_ext_links_open_new_window">
+ If enabled all external links in the content region open in a new window.
+ </div>
- <div
- tal:define="error errors/hostnameBlacklist | nothing;
- hostnameBlacklist view/settings/hostnameBlacklist | python:[];
- hostnameBlacklist python:request.get('hostnameBlacklist', hostnameBlacklist)"
- tal:attributes="class python:'field error' if error else 'field'">
-
- <label for="hostnameBlacklist" i18n:translate="label_hostname_blacklist">Unthemed host names</label>
- <div class="formHelp" i18n:translate="help_hostname_blacklist">
- If there are hostnames that you do not want to be
- themed, you can list them here, one per line. This is
- useful during theme development, so that you can
- compare the themed and unthemed sites. In some cases,
- you may also want to provide an unthemed host alias
- for content administrators to be able to use 'plain'
- Plone.
</div>
- <div tal:content="error" tal:condition="error" />
+ <div
+ class="field"
+ tal:define="selected python:request.get('usePopups', view.skinsSettings.use_popups)">
+
+ <input type="hidden" value="" name="usePopups:boolean:default" />
+ <input type="checkbox" value="1" name="usePopups:boolean" id="usePopups"
+ tal:attributes="checked python:'usePopups' if selected else None"
+ />
+ <label for="usePopups" i18n:translate="label_use_popups">Use popup overlays for simple forms</label>
+ <div class="formHelp" i18n:translate="help_use_popups">
+ If enabled popup overlays will be used for simple forms like login, contact and delete confirmation.
+ </div>
- <textarea
- name="hostnameBlacklist:lines"
- id="hostnameBlacklist"
- rows="5"
- cols="50"
- tal:content="python:'\n'.join(hostnameBlacklist)"
- ></textarea>
+ </div>
- </div>
+ <div
+ class="field radio"
+ tal:define="selected python:request.get('iconVisibility', view.skinsSettings.icon_visibility)">
+
+ <label i18n:translate="label_icon_visibility">Show content type icons </label>
+ <div class="formHelp" i18n:translate="help_icon_visibility">
+ If disabled the content icons in folder listings and portlets won't be visible.
+ </div>
+
+ <div>
+ <input type="radio" name="iconVisibility" id="iconVisibility_enabled" value="enabled"
+ tal:attributes="checked python:selected == 'enabled' and 'selected' or None" />
+ <label class="radioLabel" for="iconVisibility_enabled" i18n:translate="">Always shown icons</label>
+ </div>
+
+ <div>
+ <input type="radio" name="iconVisibility" id="iconVisibility_authenticated" value="authenticated"
+ tal:attributes="checked python:selected == 'authenticated' and 'selected' or None" />
+ <label class="radioLabel" for="iconVisibility_authenticated" i18n:translate="">Only for users who are logged in</label>
+ </div>
+
+ <div>
+ <input type="radio" name="iconVisibility" id="iconVisibility_disabled" value="disabled"
+ tal:attributes="checked python:selected == 'disabled' and 'selected' or None" />
+ <label class="radioLabel" for="iconVisibility_disabled" i18n:translate="">Never show icons</label>
+ </div>
- <div
- tal:define="error errors/parameterExpressions | nothing;
- parameterExpressions python:view.settings.parameterExpressions or {};
- parameterExpressions python:['%s = %s' % (k,v) for k,v in parameterExpressions.items()];
- parameterExpressions python:request.get('parameterExpressions', parameterExpressions)"
- tal:attributes="class python:'field error' if error else 'field'">
-
- <label for="parameterExpressions" i18n:translate="label_parameter_expressions">Parameter expressions</label>
- <div class="formHelp" i18n:translate="help_parameter_expressions">
- You can define parameters that will be passed
- to the compiled theme here. In your rules file, you can
- refer to a parameter by <code>$name</code>. Parameters
- are defined using TALES expressions, which should
- evaluate to a string, a number, a boolean or None.
- Available variables are <code>context</code>,
- <code>request</code>, <code>portal</code>,
- <code>portal_state</code>, and
- <code>context_state</code>. Define one variable
- per line, in the format <code>name = expression</code>.
</div>
- <div tal:content="error" tal:condition="error" />
- <textarea
- name="parameterExpressions:lines"
- id="parameterExpressions"
- rows="8"
- cols="50"
- tal:content="python:'\n'.join(parameterExpressions)"
- ></textarea>
- </div>
+ </fieldset>
- <div class="formControls">
- <input
- type="submit"
- name="form.button.AdvancedSave"
- class="context"
- value="Save"
- i18n:attributes="value" />
-
- <input
- type="submit"
- name="form.button.Cancel"
- class="context"
- value="Cancel"
- i18n:attributes="value" />
- </div>
+ <div class="formControls">
+ <input
+ type="submit"
+ name="form.button.AdvancedSave"
+ class="context"
+ value="Save"
+ i18n:attributes="value" />
- <input tal:replace="structure context/@@authenticator/authenticator" />
+ <input
+ type="submit"
+ name="form.button.Cancel"
+ class="context"
+ value="Cancel"
+ i18n:attributes="value" />
+ </div>
- </form>
+ <input tal:replace="structure context/@@authenticator/authenticator" />
- </dd>
- <dt id="fieldsetlegend-import">Import theme</dt>
- <dd id="fieldset-import">
- <p i18n:translate="description_import">
- Use the form below to upload a Zip file containing a theme.
- </p>
+ </form>
- <form
- name="import"
- method="post"
- enctype="multipart/form-data"
- class="enableUnloadProtection"
- tal:attributes="action request/URL"
- tal:define="errors view/errors">
+ </dd>
- <div
- class="field"
- tal:define="error errors/themeArchive | nothing"
- tal:attributes="class python:'field error' if error else 'field'">
+ </dl>
- <label for="themeArchive" i18n:translate="label_theme_archive">Theme archive</label>
+ <!-- Delete confirmation overlay -->
+ <div id="overlay-delete-confirm" class="overlay overlay-ajax">
+ <div class="close"><span i18n:translate="">Close</span></div>
+ <div class="pb-ajax">
+ <div>
+ <h1 id="overlayTitleDeleteConfirm" class="documentFirstHeading" i18n:translate="theming_controlpanel_delete_confirm">
+ Are you sure you want to delete <span i18n:name="theme_name"></span>
+ </h1>
+
+ <p class="documentDescription" i18n:translate="theming_controlpanel_delete_confirm_description">
+ This operation cannot be undone. Note that filesystem themes
+ cannot be deleted from within Plone.
+ </p>
- <div class="formHelp" i18n:translate="help_theme_archive">
- Select a file to upload. This must be a Zip file with
- a single top level directory, which will be used as
- the theme identifier. This directory must contain a
- <code>rules.xml</code> file or a
- <code>manifest.cfg</code> file indicating an
- alternative Diazo rules file.
+ <form name="delete" method="post" tal:attributes="action request/URL">
+ <input tal:replace="structure context/@@authenticator/authenticator" />
+ <input type="hidden" name="themes:list" id="deleteConfirmTheme" value="" />
+ <div class="formControls">
+ <input
+ type="submit"
+ name="form.button.DeleteSelected"
+ class="destructive"
+ value="Delete"
+ i18n:attributes="value"
+ />
+ <input
+ type="submit"
+ class="standalone allowMultiSubmit"
+ type="submit"
+ name="form.button.Cancel"
+ value="Cancel"
+ i18n:attributes="value"
+ />
</div>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <!-- New/copy overlay -->
+ <div id="overlay-new-theme" class="overlay overlay-ajax">
+ <div class="close">
+ <span i18n:translate="">Close</span>
+ </div>
+ <div class="pb-ajax">
+ <div>
+ <h1 id="overlayTitleNewTheme" class="documentFirstHeading" i18n:translate="theming_controlpanel_new_theme">New theme</h1>
+ <h1 id="overlayTitleCopyTheme" class="documentFirstHeading" i18n:translate="theming_controlpanel_copy_theme">Create copy of <span i18n:name="theme_name"></span></h1>
+
+ <p class="documentDescription" i18n:translate="theming_controlpanel_new_theme_description">
+ Please enter the details of your new theme
+ </p>
- <div tal:content="error" tal:condition="error" />
+ <form name="create" method="post" tal:attributes="action request/URL" tal:define="errors view/errors">
- <input
- type="file"
- name="themeArchive"
- id="themeArchive"
- />
+ <div
+ tal:define="error errors/title | nothing"
+ tal:attributes="class python:'field error' if error else 'field'">
- </div>
+ <label for="title" i18n:translate="label_new_theme_title">Title</label>
+ <div class="formHelp" i18n:translate="help_new_theme_title">
+ Enter a short, descriptive title for your theme
+ </div>
- <div
- class="field"
- tal:define="selected python:request.get('enableNewTheme', True)">
- <input type="hidden" value="" name="enableNewTheme:boolean:default" />
- <input type="checkbox" value="1" name="enableNewTheme:boolean" id="enableNewTheme"
- tal:attributes="checked python:'enableNewTheme' if selected else None"
- />
- <label for="enableNewTheme" i18n:translate="label_enable_new_theme">Immediately enable new theme</label>
- <div class="formHelp" i18n:translate="help_enable_new_theme">
- Select this option to enable the newly uploaded theme
- immediately.
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
+
+ <input
+ type="text"
+ name="title"
+ id="title"
+ tal:attributes="value request/title | nothing"
+ />
</div>
- </div>
- <div
- class="field"
- tal:define="selected python:request.get('replaceExisting', False)">
- <input type="hidden" value="" name="replaceExisting:boolean:default" />
- <input type="checkbox" value="" name="replaceExisting:boolean" id="replaceExisting"
- tal:attributes="checked python:'replaceExisting' if selected else None"
- />
- <label for="replaceExisting" i18n:translate="label_replace_existing">Replace existing theme</label>
- <div class="formHelp" i18n:translate="help_replace_existing">
- Select this option to replace any existing theme that
- may have been uploaded previously.
+ <div class="field">
+ <label for="description" i18n:translate="label_new_theme_description">Description</label>
+ <div class="formHelp" i18n:translate="help_new_theme_description">
+ You may also provide a longer description for your theme.
+ </div>
+ <textarea
+ name="description"
+ id="description"
+ tal:content="request/description | nothing"></textarea>
</div>
- </div>
- <div class="formControls">
- <input
- type="submit"
- name="form.button.Import"
- class="context"
- value="Import"
- i18n:attributes="value" />
-
- <input
- type="submit"
- name="form.button.Cancel"
- class="context"
- value="Cancel"
- i18n:attributes="value" />
- </div>
+ <input type="hidden" name="baseOn" id="baseOn" tal:attributes="value request/baseOn | string:template" />
- <input tal:replace="structure context/@@authenticator/authenticator" />
+ <div
+ class="field"
+ tal:define="selected python:request.get('enableImmediately', False)">
+ <input type="hidden" value="" name="enableImmediately:boolean:default" />
+ <input type="checkbox" value="1" name="enableImmediately:boolean" id="enableImmediately"
+ tal:attributes="checked python:'enableImmediately' if selected else None"
+ />
+ <label for="enableImmediately" i18n:translate="label_enable_immediately">Immediately enable new theme</label>
+ <div class="formHelp" i18n:translate="help_enable_immediately">
+ Select this option to enable the newly created theme
+ immediately.
+ </div>
+ </div>
- </form>
+ <div class="formControls">
+ <input
+ type="submit"
+ name="form.button.CreateTheme"
+ class="standalone"
+ value="Create"
+ i18n:attributes="value"
+ />
+ <input
+ type="submit"
+ name="form.button.Cancel"
+ class="standalone allowMultiSubmit"
+ value="Cancel"
+ i18n:attributes="value"
+ />
+ </div>
- </dd>
+ <input tal:replace="structure context/@@authenticator/authenticator" />
- <tal:block condition="view/zodbThemes">
- <dt id="fieldsetlegend-import">Manage themes</dt>
- <dd id="fieldset-import">
+ </form>
- <p i18n:translate="description_manage">
- Use the form below to delete themes that have previously been
- uploaded. Click on a theme name to download it as a Zip
- archive.
+ </div>
+ </div>
+ </div>
+
+ <!-- Upload overlay -->
+ <div id="overlay-upload" class="overlay overlay-ajax">
+ <div class="close">
+ <span i18n:translate="">Close</span>
+ </div>
+ <div class="pb-ajax">
+ <div>
+ <h1 class="documentFirstHeading" i18n:translate="theming_controlpanel_upload">Upload theme</h1>
+
+ <p class="documentDescription" i18n:translate="description_import">
+ You can import a Zip file containing an existing theme.
+ This should contain a single top level directory, which will be used as
+ the theme identifier. If no Diazo <code>rules.xml</code> or
+ <code>manifest.cfg</code> file is found in this directory, a
+ default <code>rules.xml</code> file will be created.
</p>
<form
- name="manage"
+ name="import"
method="post"
+ enctype="multipart/form-data"
class="enableUnloadProtection"
tal:attributes="action request/URL"
tal:define="errors view/errors">
- <table class="listing">
- <thead>
- <tr>
- <th />
- <th i18n:translate="heading_theme_title">Title (id)</th>
- <th i18n:translate="heading_theme_description">Description</th>
- </tr>
- </thead>
- <tbody>
- <tr tal:repeat="theme view/zodbThemes">
- <td>
- <input
- type="checkbox"
- name="themes:list"
- tal:attributes="value theme/__name__"
- />
- </td>
- <td>
- <a target="_new"
- tal:attributes="href string:${context/absolute_url}/++theme++${theme/__name__}/@@download-zip"
- tal:content="string:${theme/title} (${theme/__name__})"
- />
- </td>
- <td tal:content="theme/description" />
- </tr>
- </tbody>
- </table>
+ <div
+ class="field"
+ tal:define="error errors/themeArchive | nothing"
+ tal:attributes="class python:'field error' if error else 'field'">
+
+ <div class="formHelp" i18n:translate="help_theme_archive">
+ Select a file to upload.
+ </div>
+
+ <div class="errorMessage" tal:content="error" tal:condition="error" />
+
+ <input
+ type="file"
+ name="themeArchive"
+ id="themeArchive"
+ />
+
+ </div>
+
+ <div
+ class="field"
+ tal:define="selected python:request.get('enableNewTheme', False)">
+ <input type="hidden" value="" name="enableNewTheme:boolean:default" />
+ <input type="checkbox" value="1" name="enableNewTheme:boolean" id="enableNewTheme"
+ tal:attributes="checked python:'enableNewTheme' if selected else None"
+ />
+ <label for="enableNewTheme" i18n:translate="label_enable_new_theme">Immediately enable new theme</label>
+ <div class="formHelp" i18n:translate="help_enable_new_theme">
+ Select this option to enable the newly uploaded theme
+ immediately.
+ </div>
+ </div>
+
+ <div
+ class="field"
+ tal:define="selected python:request.get('replaceExisting', False)">
+ <input type="hidden" value="" name="replaceExisting:boolean:default" />
+ <input type="checkbox" value="1" name="replaceExisting:boolean" id="replaceExisting"
+ tal:attributes="checked python:'replaceExisting' if selected else None"
+ />
+ <label for="replaceExisting" i18n:translate="label_replace_existing">Replace existing theme</label>
+ <div class="formHelp" i18n:translate="help_replace_existing">
+ Select this option to replace any existing theme that
+ may have been uploaded previously.
+ </div>
+ </div>
<div class="formControls">
<input
type="submit"
- name="form.button.DeleteSelected"
- class="destructive"
- value="Delete"
- i18n:attributes="value"
- />
+ name="form.button.Import"
+ class="context"
+ value="Import"
+ i18n:attributes="value" />
+
+ <input
+ type="submit"
+ name="form.button.Cancel"
+ class="context allowMultiSubmit"
+ value="Cancel"
+ i18n:attributes="value" />
</div>
<input tal:replace="structure context/@@authenticator/authenticator" />
</form>
- </dd>
- </tal:block>
-
- </dl>
+ </div>
+ </div>
+ </div>
</div>
View
222 src/plone/app/theming/browser/controlpanel.py
@@ -3,25 +3,33 @@
from zope.component import getUtility
from zope.component import getMultiAdapter
+from zope.schema.interfaces import IVocabularyFactory
from zope.publisher.browser import BrowserView
from plone.resource.utils import queryResourceDirectory
-
from plone.registry.interfaces import IRegistry
+from plone.memoize.instance import memoize
+
from plone.app.theming.interfaces import _
from plone.app.theming.interfaces import IThemeSettings
from plone.app.theming.interfaces import THEME_RESOURCE_NAME
+from plone.app.theming.interfaces import RULE_FILENAME
+from plone.app.theming.interfaces import DEFAULT_THEME_FILENAME
+from plone.app.theming.interfaces import TEMPLATE_THEME