================================
Developer level changes in Silva
================================

From 1.5 to 1.6
===============

ZCML for extension registration
-------------------------------

Silva extensions and content types are now registered through ZCML
instead of in __init__.py. For the time being, __init__.py based
registration will continue to work, but the ZCML approach makes things
much easier.  For details read doc/extension.txt.

The ZCML directives normally work without you having to specify your
own "manage_add" factory anymore - this is automatically
generated. Some facilities exist however to support this for backwards
compatibility.

For details on the options available for the ZCML directives, read
zcml/interfaces.py. These schemas describe the options to the
directives.

The Silva core as well as Silva Document now use ZCML to register
themselves and their content types. You can read the configure.zcml
file in these products for example code.

no more 'title' argument for versions
-------------------------------------

The base classes in Version, namely Version and CatalogedVersion, have
been changed so they do not expect a 'title' argument anymore; the
only argument needed is an 'id'. This means that if you subclass from
Version or CatalogedVersion you will probably need to change your
constructor so it doesn't pass a title anymore to the superclass.

This change has been made because the 'title' argument to the version
has not been in use for a long time.

Kupu
----

When switching to Kupu 1.4 (currently unreleased) we decided to make some
changes in the way Silva uses it: instead of having a 'silva' directory inside
the Kupu package containing Silva-speficic Kupu code, there's now a 'kupu'
directory in the Silva core package. This should make it easier to release
Silva seperately from Kupu, since most of the required changes for Silva can
be done in Silva itself, so hopefully a lot of times a change in Silva's Kupu
will only require a Silva release, not a Kupu one.

This means that changes on Silva tools and template should now be done inside
that new directory, and also that creating the 'kupumacros.html' file should
be done from there: calling 'make' in Silva/kupu will result in what used to
require calling 'make silvamacros' in kupu/silva.

An additional change made is that the FileSystemSite directories that used to
be called 'kupu' and 'kupu_silva' (residing in the Silva root) are now called
'service_kupu' and 'service_kupu_silva'. This will break existing Silva 
extensions that implement a custom Kupu edit view. Make sure to update any
URLs pointing to those objects in your extensions.

removed activation API
----------------------

Silva contained an old set of APIs dealing with activation and
deactivation of content. This was not in use anymore in the Silva UI
for a long time, but the APIs still existed. These have been cleaned
up. It's possible your code still uses these APIs. Here's a list of
the methods that disappeared and what to do to adjust your code.

is_active()
~~~~~~~~~~~

If this is a check in an `if` clause, remove this from the
expression. If is the the only check in an `if` clause, remove the
`if` part and let the main block always be executed (dedent it).

can_deactivate()
~~~~~~~~~~~~~~~~

If you use this in an `if` clause, remove this from the expression. If
it is the only check in the `if` clause, remove the `if` part and let
the main block always be executed (dedent it).

can_approve()
~~~~~~~~~~~~~

If you use this in an `if` clause, remove this from the expression. If
it is the only check in the `if` clause, remove the `if` part and let
the main block always be executed (dedent it).

get_nonactive_publishables()
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The notion of non-active publishables is gone, so if you were using it
you probably can remove its use from the codebase entirely (the list
would always be empty).

activate(), deactivate()
~~~~~~~~~~~~~~~~~~~~~~~~      

This method disappeared. It wasn't possible to deactive from the user
interface before, and now it stopped being possible from code.

From 1.4 to 1.5
===============

Five
----

Zope 2.8 includes a significant portion of Zope 3, and includes Five. Silva
does need a later version of Five than included with Zope 2.8 however,
namely Five 1.2, which can be easily installed as a product and which
ships with the Five tarball.

Zope 3 interfaces
-----------------

Silva now uses Zope 3 interfaces throughout, instead of Zope 2 interfaces.

If you use interfaces in your own code, import the `Interface` base class like
this::

  from zope.interface import Interface

Instead of using `__implements__`, state that your class implements
interfaces using the `implements` class annotation::

  from zope.interface import implements

  ...
 
  class Foo:
      implements(IFoo)

You can check whether an instance provides an interface (i.e. whether
its class implements an interface or the interface directly provides
an interface) using `providedBy` (in Zope 2 this used to be 
'isImplementedBy')::

  IFoo.providedBy(instance)

In the rare case you want to check whether a *class* implements an
interface (i.e. whether its instances will provide that interface), you
use `implementedBy` (this used to be `isImplementedByInstancesOf` in
Zope 2)::

  IFoo.implementedBy(some_class)

Five-based i18n
---------------

Silva now uses Zope 3 based i18n infrastructure, and
PlacelessTranslationService is not in use anymore.

All the translations of a product (such as `Silva`, `SilvaDocument`,
etc) are now in a directory, i18n which is registered in that
product's `configure.zcml` with the following simple directive::

    <!-- i18n -->
  <i18n:registerTranslations directory="i18n" />

The i18n directory has the following structure::

* a `.pot` file, such as `silva.pot`

* an `__init__.py` file.

* for each language, a subdirectory, such as `de`.

This language subdirectory follows a standard pattern derives from the
standard `gettext` tool. It contains a single subdirectory called
`LC_MESSAGES`. This directory contains a `.po` file and a `.mo` file,
such as `silva.mo` and `silva.po`.

The `.mo` file is a compiled version of the `.po` file. Zope only
consults the `.mo` files when looking for translations, so be sure to
update the `.mo` file whenever you change the `.po` file. You can do
this (on linux) with the standard `msgfmt` tool, with a command like
this::

  msgfmt silva.po -o silva.mo

Zope 3 will likely evolve ways to make the generation of `.mo` files
more automatic in the future and Silva will follow.

Translating in Python code
--------------------------

Normally your i18n-ed code will just mark up page templates with
i18n:translate, or return a message id (_('Something') to the page
template. The page template will then take care of looking up
translation and doing any interpolation.

Sometimes you want to explicitly force translation (and interpolation)
from Python code, for instance when your Python code is generating a
snippet of HTML. Before Silva 1.5, this was done by calling
`unicode()` on the message id. This doesn't work anymore, and has
been replaced by something more explicit. Instead, you do the following::

  from zope.i18n import translate

which is also legal in Python scripts. And then in your code::

  text = translate(msg_id)

This forces translation and interpolation to happen directly,
returning the translated string. Whenever you see interpolation
characters such as ${foo} in the Silva UI, you know you probably have
a missing `translate()` call in there; replace the `unicode()` call
with a `translate()` call.

Zope 3 adapters
---------------

Quite a few adapters in the `adapters` directory have been converted
to use Zope 3 patterns. That is, Silva looks them up by interface now
in the standard Zope 3 pattern. They also get registered through ZCML.

Here's an example of some ZCML registrations::

  <adapter
    for="Products.Silva.interfaces.IGhost"
    provides=".interfaces.IIndexable"
    factory=".indexable.GhostIndexableAdapter"
    />
  
  <adapter
    for="Products.Silva.interfaces.IContainer"
    provides=".interfaces.IIndexable"
    factory=".indexable.ContainerIndexableAdapter"
    />
  
  <adapter
    for="Products.Silva.interfaces.ISilvaObject"
    provides=".interfaces.IIndexable"
    factory=".indexable.IndexableAdapter"
    />

And here's how you look it up in Python code::

  indexable = IIndexable(my_content_object)

You can then call methods on 'indexable'; to see which methods exist
you can consult `adapters/interfaces.py`.

From 1.3 to 1.4
===============

* For running the unit tests, ZopeTestCase 0.9.8 is now required.

From 1.2 to 1.3
===============

* Metadata sets can have a 'category' property. This property can be used
  to define special purpose metadata sets. This is used now for the
  tab_settings SMI screen and the tab_metadata.

* The minimal_role and category properties are exported and imported
  to/from the XML metadata set definitions.

* setValuesFromRequest now uses Formulator to validate user input. This
  solves the infamous 'checkbox' problem.

* MetadataTool.setMetadataValues() has been removed.

From 1.1 to 1.2
===============

* the 'action_paste' and 'action_paste_to_ghost' methods on Folder have
  a new signature, instead of returning a list of messages it now returns
  (message_type, messages) where message_type can be 'feedback' and 'error'
  and messages is the list that used to be returned.

* tab_edit for VersionedContent views has changed to make use of a new
  macro, ``macro_tab_edit/macros/editor``, instead of
  ``macro_index/macros/master`` directly. ``macro_tab_edit`` does use
  ``macro_index`` indirectly.

  A default tab_edit is supplied in VersionedContent
  views. SilvaDocument however overrides this with its own tab_edit.
  You can also do in your own product.

  The following slots are available in ``macro_tab_edit/macros/editor``:

    * editor_css - add in editor-specific CSS stylesheets.

    * editor_refresher - a slot to put in special refreshing code for
      editors that are sensitive to Zope session timeouts, such as the
      forms editor.

    * editor_selection - add extra fields above the main editor content area
      to allow the user to switch editors, such as between kupu and the
      forms editor.

    * editor_content - the main editor content area, showing for instance
      the forms editor or kupu.

* The public view directory layout changed due to some change in the way
  we register views. For some functionality on the VersionManagementAdapter,
  we needed to get a rendered version, which wasn't allowed the way the views
  were previously set up (fetching the version happened in the render scripts,
  each script would render a specific version).

  Changes:

    * instead of registering a 'public' view for VersionedContent
      objects, they are now registered for Version objects.

    * instead of 2 scripts 'render_view' and 'render_preview' only
      'render' is called for both view and preview, if you want to
      make a distinction between the two, you can register a new
      view_type called 'preview' to another subdirectory and place a
      'render' script in that, the general pattern is that if you want
      to use only 1 script you place it directly in the
      'public/<meta_type>' directory, if you want to have seperate
      scripts for view and preview, create a 'view' and 'preview'
      directory in that dir ('public/<meta_type>/view' and
      'public/<meta_type>/preview')

    * the 'model' variable in the render script does not point to the
      VersionedContent object anymore, but instead it refers to the
      Version object (of course it still refers to the object itself
      in case the object is not of a versioned type)

From 1.0 to 1.1
===============

* The previously deprecated method 'archive_file_import' on Folder.py and
  the ImportArchive module have been removed. Code that depended on this
  should be rewritten to use the archivefileimport adapter.

* XSLT support for document renderers. While this shouldn't break
  existing code, it opens up new possibilities for extension
  writers. You can register your own XSLT templates with Silva that
  handle content rendering. Read doc/xslt_renderers_howto.txt for more   
  information

* new parser in forms-based editor. The existing parser for bold,
  italic and the like in the forms based editor has been scrapped and
  replaced with a parser that uses a simple HTML subset. The new
  parser should be more predictable for authors and a lot
  faster. Developers who have written their own widgets-based editors
  may need to modify code. If you already use the Silva-1.0
  infrastructure for finding the parser, the changes should be minimal
  and be limited to the UI, however. The Silva-1.0 pattern is::

    supp = context.editorsupport.getMixedContentSupport(model, node)
    supp.parse(text)

* new method on Folder objects, get_public_tree_all().  Returns a list
  of all published content objects (including containers) below this
  object (not including this object itself), including non-transparent
  containers like publications.
