Table of Contents
Objective: To understand how to customize the web user interface for a new document type and understand the relationship between the larger Nuxeo EP server UI and the UI of a particular document type.
I was taught that the way of progress was neither swift nor easy. Marie Curie, Polish/French Physicist, twice winner of the Nobel Prize (1867-1934)
If you have any comments, questions, or general-purpose harassment you would like give us about this book, then please use the comment form at the bottom of each page! We promise that we will try to incorporate any feedback you give (minus the profanity, of course), will respond to your questions, and credit you appropriately in section 4 below.
As in the last lesson, we have a prepared a skeleton for you to start from for this lesson. This skeleton contains all the code from the last lesson so we can improve the look of our new document type. To retrieve, unpack and build an eclipse project, use a set of commands like this:
[~] $ cd /nuxeo/workspace/ [/nuxeo/workspace] $ svn export http://svn.nuxeo.org/nuxeo/sandbox/iansmith/book/lesson-basic-ui/ [/nuxeo/workspace] $ cd lesson-basic-ui [/nuxeo/workspace/lesson-basic-ui] $ mvn eclipse:eclipse
Note that we are using the same eclipse workspace as in the previous
    lesson, /nuxeo/workspace, and that we have created
    another project for Eclipse to use, this time called
    lesson-basic-ui. Also as before, you will need to
    import the project into your eclipse workspace and then verify in eclipse
    that your source code path is free of Maven-generated excess; you should
    have only src/main/java and
    src/test/java in your source code path.
We will start updating the user interface by adding the ability to
    actually use the fields we so carefully added in the previous lesson. To
    do this, we are going to use another extension point,
    layout, in the WebLayoutManager component.
    The following content should be placed in a file called
    layout-contrib.xml in the
    OSGI-INF directory.
<component name="org.nuxeo.book.component.layout">
  <extension target="org.nuxeo.ecm.platform.forms.layout.WebLayoutManager"
    point="layouts">
    
    <templates>
        <template mode="any">/layouts/layout_default_template.xhtml</template>
    </templates>
    <layout name="upcoming">
      <rows>
        <row>
          <widget>upcoming_when</widget>
        </row>
        <row>
          <widget>upcoming_who</widget>
        </row>
        <row>
          <widget>upcoming_howmuch</widget>
        </row>
      </rows>
      <widget name="upcoming_when" type="datetime">
        <labels>
          <label mode="any">When?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:occursOn</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
      <widget name="upcoming_who" type="text">
        <labels>
          <label mode="any">Who?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:presenter</field>
        </fields>
      </widget>
      <widget name="upcoming_howmuch" type="text">
        <labels>
          <label mode="any">How much to get in?</label>
        </labels>
        <translated>false</translated>
        <fields>
          <field>up:admissionPrice</field>
        </fields>
        <properties widgetMode="edit">
          <property name="required">true</property>
        </properties>
      </widget>
    </layout>
  </extension>
</component> This is a much more substantive
    contribution than the prior ones have been. This contribution can be
    broken into three parts: the top section, surrounded by the
    templates tag, the middle section inside the rows
    tag, that defines where the items are laid out on the
    screen, and the bottom part, inside each of the three widget tags, which
    defines what is going to be laid out. We are going to
    defer discussing the first part of the contribution until a later time in
    this lesson.
The middle section defines three rows, each one with a widget in it.
    You can place all the widgets in one row if you want to see what happens;
    we just felt this was the most appropriate for our data. (If you want to
    use two rows and make things line up, this <widget/> can
    be used as a spacer.) The values in the middle section's widget nodes,
    such as upcoming_who, must match up with existing
    widget definitions (defined elsewhere in Nuxeo) or those in the remainder
    of the file. In our case, all three widgets we are using are defined in
    the lower section. We have prefixed our widgets with the the schema name
    of the of the data they display because we want to be sure that these are
    unique. It is possible to share widget definitions between layouts by
    using the same widget names, so it is advised that you take steps to make
    your widget names unique if you want to be sure.
The latter section of this contribution defines our three new widget
    types, one for each field in our upcoming schema. Roughly, a
    widget definition in this file tells Nuxeo's web interface what type of
    objects you want on screen. So, looking at the
    upcoming_when widget definition you can see that the
    "type" is an object capable of displaying the date and time: this will
    result in a calendar plus a spot to enter the time of day. Similarly,
    upcoming_who widget uses an object capable of entering
    text. Strangely, the upcoming_howmuch widget does too!
    This is because the widget type describes only what
    visual form the user will see on the screen; it is unrelated to the type
    of data in the schema. You should notice that each widget says what fields
    of the schema data in corresponds to, one widget for each field in this
    example. The definition of upcoming_howmuch says that
    it will use a text object on screen, yet the schema definition
    (upcoming.xsd) says that the field
    up:admissionPrice is a floating point number! The nuxeo
    server will take care of doing most of these transformations from the
    display representation to the stored representation for you without any
    help. You can also add your own, as we will see in a future lesson.
Each widget definition above declares a label and some text. This is
    the text that will be shown to the user just beside the value of the field
    in the schema. Just after the label definition, we have set
    <translated>false</translated> because we want the
    text used literally. In the next lesson, you will see how to change a
    layout definition to work correctly in multiple languages.
The definitions of the first and last widgets,
    upcoming_when and upcoming_howmuch
    have a properties section. There a number of properties that
    can be set on a widget, but we will limit ourselves to just discussing two
    key issues. Obviously, the first and third widget (which work out to the
    fields occursOn and admissionPrice
    on the schema) are required to be present... but under
    what circumstances? The attribute widgetName and
    its value, edit, indicate that these fields are
    required in when the document's meta-data can be changed, such as when you
    create a document or when you modify the meta-data via the web UI's
     tab. Similarly the label tag has
    the attribute mode which is also referring to which
    state the widget is currently in; all our labels above use the mode
    any to indicate we always want the same text displayed.
    One could, for example, set the label to be "Please Enter a Date" for mode
    edit and "Date" for mode view. The
    full list of widget modes is edit,
    view, any (to indicate both edit and
    view), and hidden. The last of these is to allow a
    widget to be defined, but not displayed.
After adding this new contribution, do not forget to update your
    manifest file. Further, this new extension means that we will now need
    another bundle to be required so we can have access to the
    WebLayoutManager. Here is the updated
    MANIFEST.MF.
Manifest-Version: 1.0 Bundle-ManifestVersion: 1 Bundle-Name: lesson4 project Bundle-SymbolicName: org.nuxeo.book.upcoming;singleton:=true Bundle-Version: 0.0.1 Bundle-Vendor: YOU! Nuxeo-Require: org.nuxeo.ecm.core, org.nuxeo.ecm.core.schema, org.nuxeo.ecm.webapp.core Nuxeo-Component: OSGI-INF/schema-contrib.xml, OSGI-INF/doctype-contrib.xml, OSGI-INF/layout-contrib.xml, OSGI-INF/ui-contrib.xml
Again, the ordering of contributions is tricky in
      Nuxeo-Component because there is a dependency between
      the layout contribution and the UI contribution so our new layout
      contribution must come first.
We now need to inform Nuxeo that our document type,
    Upcoming, wants to use the layout we have constructed (sadly,
    also customarily called "upcoming") as part of its display. This is done
    by replacing the previous list of layouts with the
    upcoming layout; this controls which layout or layouts
    is used to display or edit the meta-data of the document type
    Upcoming. Below is a snippet from the
    ui-contrib.xml file showing the change:
    <type id="Upcoming" coretype="Upcoming">
      <label>Upcoming Event</label>
      <icon>/icons/upcoming.png</icon>
      <default-view>view_documents</default-view>
      <layouts mode="any">
        <layout>upcoming</layout>
      </layouts>
    </type>
    The result of all this work can be seen in this screen capture of creating a new upcoming document:

The last when and how much fields have a red asterisk because they are required. Clicking on the grey button to the right of "When" opens a calendar widget.
If you have forgotten, you should build your now updated version
      of lesson-simple-ui with mvn clean install in the
      lesson-basic-ui directory. When it completes
      successfully, you will find the file
      lesson-basic-ui.0.0.1.jar in the
      target subdirectory. You should make sure your
      Nuxeo server is not running, then copy this jar file into the
      plugins subdirectory inside the
      nuxeo.ear subdirectory of your server, this would
      be
      /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear
      if you have been following our instructions . Restart your server and
      try logging in and creating a new Upcoming document!
In general, it is bad to have your Nuxeo system have multiple different definitions for a single document type or schema while you are doing development. When this happens, you are likely to experience strange results from using the system. This also happens when you end up with multiple layout or ui contributions to the same point, but it is easier to see what is happening and realize you are running the older version of the code!
If you have not configured any database system into your nuxeo installation-and we haven't covered that yet!-you will probably want to use commands like this to destroy the databases maintained by Nuxeo like this:
[~] $ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/data [/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/data] $ rm -rf h2/nuxeo.* hypersonic/* derby/*
Do not do this if you have content in your database you want to keep! This will also revert your Administrator password back its default setting of "Administrator". Where is administrator password stored? Does it really reset?
However, during normal software development you will find that a common sequence is to kill the running server, make some changes to your source code in Eclipse, rebuild your jar file, copy the jar file into the plugins directory, destroy the old databases, destroy the old logs, and restart the server. To make this easier, one of the authors uses multiple tabs in a shell window like this:

This makes it a bit easier to complete any of the steps listed since hitting the up arrow once or twice in any tab gets the desired effect.
Above we suggested that it is a good idea to clear the old logs
    (/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/logs)
    before any run. We suggest this because we have found it useful to turn
    the logging up to the maximum (DEBUG level, as shown in
    a previous lesson) and then use grep to find the lines of interest in the
    logs. Here is any example from the log tab above:
[~] $ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/log [/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/log] $ cat *.log | grep -i upcoming 2009-01-25 21:17:12,807 INFO [org.nuxeo.runtime.jboss.deployment.preprocessor.DeploymentPreprocessor] Running custom installation for fragment: org.nuxeo.book.upcoming 2009-01-25 21:17:47,785 INFO [org.nuxeo.osgi.BundleRegistry] Registering resolved bundle: org.nuxeo.book.upcoming
This is easy way to find errors that may have occurred as the system was booting or as your bundle was being loaded.
Giving the Upcoming document its own icon is easy-and visually pleasing so the Upcoming object lines up when showing the list of document types that can be created. You can use any image you want so long as it is in any image format that a web browser understands such as jpeg, gif, or png. If you want to your icon to line up with others, use a 16 pixel by 16 pixel icon.
Start by creating a new subdirectory of
    src/main/resources in your Eclipse project called
    nuxeo.war. This will be a peer of the
    OSGI-INF directory both in Eclipse and in the final
    bundle file. Inside nuxeo.war create a subdirectory
    icons. Place your graphics file in this directory and
    then change the start of your ui-contrib.xml file to
    point to it with an icon tag like your existing
    label tag. Here is a snippet from the improved
    ui-contrib.xml:
    <type id="Upcoming" coretype="Upcoming">
      <label>Upcoming Event</label>
      <icon>/icons/upcoming.png</icon>
      <default-view>view_documents</default-view>
    The icon path should start with a '/' character.
In the prior lesson we noted that the deployment fragment can be used to help "deploy" resources that are part of your program into the Nuxeo EP server. Now you have a need for this functionality, since you are going to end up with your icon file inside your bundle file. Here is the updated deployment-fragment.xml that copies all the contents of the nuxeo.war part of your project into Nuxeo server.
<fragment>
  <extension target="application#MODULE">
    <module>
      <java>${bundle.fileName}</java>
    </module>
  </extension>
  <install>
    <!-- Unzip the contents of our nuxeo.war into the server -->
    <unzip from="${bundle.fileName}" to="/">
      <include>nuxeo.war/**</include>
    </unzip>
  </install>
</fragment>The notation nuxeo.war/** means to include
          all the files in the directory nuxeo.war in
          your bundle and recursively copy the contents of all subdirectories.
          Nuxeo deployment fragments use the same notation for included and
          excluded files as the Ant and Maven build tools, if you are familiar
          with those.
After running through the steps of section 2.1 again, when you create a new document via the web interface to Nuxeo you should see a set of document types like this, but with your chosen image:
If you studied the deployment fragment above carefully, you would
    have noticed that target of the unzip operation is the directory
    /, yet if you look in your filesystem root you will
    not find your icons directory! The
    / above is relative to the
    nuxeo.war directory inside the
    nuxeo.ear portion of your server. Here is a snippet
    from that directory:
[~] $ cd /nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/ [/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war] $ ls create_document.xhtml members_management.xhtml create_domain.xhtml META-INF create_file.xhtml nuxeo_error.jsp [... many more lines elided...]
The nuxeo.war
    directory contains all the web resources for the Nuxeo server. One of the
    many subdirectories of nuxeo.war is
    icons, where the system icons are held. Thus, our
    deployment fragment puts our upcoming icon in among all the other icons
    and this is normal practice for plugin developers:
[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war] $ cd icons/ [/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/icons] $ ls u* unchecked.gif unknown.png upcoming.png user.gif user_go.png
Returning to our discussion of the layout contribution above in
    section 2 (layout-contrib.xml) it may now be more
    clear why we waited to explain the top section of the file. The layout
    contribution tells Nuxeo to use a template (again, starting with
    /)
    /layouts/layout_default_template.xhtml and it should
    not be a surprise where this file is actually located:
[/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war] $ cd layouts [/nuxeo/tools/NuxeoEP5/NuxeoServer/server/default/deploy/nuxeo.ear/nuxeo.war/layouts] $ ls layout_default_template.xhtml
A crucial idea of the Nuxeo system, we reiterate, is that Nuxeo's
    ECM functionality is provided by bundles that are "just like yours" and
    there are no special, hidden mechanisms exploited by the Nuxeo "system" as
    you see it through the web interface. As an example, the Note document
    type you can create via the web UI, uses exactly the
    same extension points and xml configuration that we have walked through
    for building the Upcoming document type (although Note exploits a bit more
    of the functionality!). As you can see from the
    nuxeo.war directory, you can even re-purpose the web
    resources that are used to implement the Nuxeo ECM functionality.
If you would like to practice more with the concepts in this lesson, here are some suggested exercises.
Using chapter 8 of the Nuxeo Developer's Documentation
        (http://doc.nuxeo.org/5.2/books/nuxeo-book/html/) change
        the ui for Upcoming documents:
Use a non-editable label to display the date and time for
            the field occursOn when the user cannot edit
            the data. The user interface should continue to use the calendar
            widget in situations where the user can change the value of the
            field. It is ok if the display in non-editable situations only
            shows the date of the event, not the date and time.
Solving this without duplication of code (a big no-no!) requires
        the use of an additional extension point in your
        layout-contrib.xml.
If you create a document of type Upcoming now, you will notice that it is displayed with your icon but with a rather ugly title:

This is because the title is not being set when you create a document (dublincore:title), so Nuxeo defaults to chosing a title which is a unique identifier for the document. Correct this by adding back in the support for the layout type heading.