Display Paradigms

Pre-release documentation

For version 1.0 of Mechanics I want to solve three main areas that are currently lacking: Versioning, Rendering and Performance. Versioning is part-way there (meaning: a complete history of relationships is maintained in the content database alongside your content version history). Rendering is about to undergo some drastic changes to vastly improve HTML output, and what I am doing here is documenting these changes prior to developing them in order to help with the development process. Performance is a big issue, especially when large numbers of relationships are being rendered on the same page; it is hoped that the Rendering changes will vastly help this by a) reducing the number of shapes and nested levels being rendered, b) reduce the number of "alternates" (override template names) by allowing better Match clauses in Placement.info, this should result in less disk scanning for templates, c) reduce redundant copies of templates (something I've found happening a lot in my own website to get everything displaying how I want it) and d) actually reduce the number of database queries required in certain rendering scenarios, because it seems currently we have a lot of queries that can get executed for data that doesn't even render, and some "leaky" situations which allow the database to be accessed inefficiently.

It is expected that these changes might break some existing templates and overrides. This should be minimised and it'll be easy to adapt to the new system - things should be vastly easier to customise in Placement, rather than the old approach which has a cargo cultish system of manipulating arbitrary display types and using "magic" override names to alter specific parts of the template. Actually, I doubt very few people other than myself even understand how to fully customise the rendering of multiple different types of relationships and the rendering of the items in those relationships!

The new system has the broad name of "Paradigms" - this term has been used for most of the life of Mechanics but only in relation to the Editor display. There, paradigms control the behaviour of certain parts of the editor - e.g. do we have a drop-down or a checkbox list? This system was a little underused; the idea was to eventually have new paradigms like "ContentPicker" (this is happening in a new project called "Lens", being developed in parallel to 1.0). This particular usage of "Paradigm" will be retracted since such UI decisions will be made automatically; therefore Paradigms in the context of an editor will mean just as clear shifts of behaviour as within normal display. In fact, I want to blur the lines between display/editor as much as possible, with a view towards enabling editor functionality in the front-end.

The new Paradigms are happening on a separate branch called "paradigms". This work should be completed over the next week or two.

Problems with current rendering

Firstly, to clarify the need for a better method. If you've looked at the HTML output of content items with relationships, you'll be more than aware of the mess that is generated. Here is an abstract overview of a typical rendering; this content item has two types of relationship; one of the relationships has a single item (an image) and the other has two items (related pages). Each node in this tree represent at least one HTML element (at the moment this is unfortunately necessary, because Shape Tracing gets horribly confused if there isn't at least one HTML element to attach to in each shape!)
  • Content Item "Page"
    • Zone (Header)
      • RoutePart / TitlePart
    • Zone (Content)
      • BodyPart
      • Socket "PageToImage" (shape)
        • Title (h2)
        • Zone (Connectors)
          • Connector (shape)
            • Zone (RightItem)
              • Content Item "PageToImage" (connector item)
                • Zone (Content)
                  • Content Item "Image" (in Placement this is aliased as Parts_Connector)
                    • Zone (Content)
                      • MediaPart (finally renders the image!)
      • Socket "PageToRelated" (shape)
        • Title (h2)
        • Zone (Connectors)
          • Connector (shape)
            • Zone (RightItem)
              • Content Item "PageToRelated" (connector item)
                • Zone (Content)
                  • Content Item "Page"
                    • Zone (Header)
                      • RoutePart/TitlePart
                    • Zone (Content)
                      • BodyPart (Summary)
          • Connector (shape)
            • Zone (RightItem)
              • Content Item "PageToRelated" (connector item)
                • Zone (Content)
                  • Content Item "Page"
                    • Zone (Header)
                      • RoutePart/TitlePart
                    • Zone (Content)
                      • BodyPart (Summary)

Hopefully it's clear what a mess this is! Just to display a thumbnail and two related pages we have a huge tree of HTML where, respectively, a div and an unordered list would suffice. Looking at a mass of HTML like this it can be a bit difficult to even figure out the best way to style things (although there are plenty of classes composed along the way from the different content type names that you can use). It's even inconsistent with its own terminology; the "RightItem" zone actually contains the connector item, which then itself renders the real right-hand item (that is a legacy from an earlier version where things were arranged slightly differently).

For some Science Project modules I've used hacks and overrides to simplify the output. You might notice that the Cartography menu renders a neat set of nested ul's, even though it runs through the same rendering system - it was actually quite difficult to reduce the templates down to such a simple case, and it's all very hackish involving multiple template overrides and some complex Placement entries. This results in the menu being surprisingly slow to render, because so many content items have to be traversed through, and each one runs through a full render pipeline, even if most shapes end up unused. I cache the menu output as the page is been rendered to mitigate this. Now, for that particular case it is probably better to just read the connection hierarchies from the database and pass that into Orchard's built-in navigation system which will render quickly; but even though I might still do this, I want a solution that will easily allow that kind of rendering whilst preserving performance (and more importantly, not breaking Shape Tracing, which is a problem with that menu right now).

To explain things a bit further and show why so much chaff is generated I'll summarise how relationships are rendered:
  • The parent (left) item is rendered
  • All drivers are executed
  • When the SocketsPartDriver executes, it creates a shape for each type of connection from that item (the "Socket" shape)
  • That shape is rendered using a model and the Origami module, so we have pluggable drivers and placement that can compose even these non-content shapes
  • The Socket shape has zones; usually the only one used is "Connectors", but the other zones are there if we wanted for instance to add filters on this type of connection, and the other zones are used during Editor rendering, to position the UI elements above and below the list of content
  • Into the Connectors zone we push a "Connector" shape for each actual connector item; this is rendered with Origami using another model
  • Connectors also have zones, this is again so we could use Placement to position things like Edit/Delete/Move buttons
  • Usually the only relevant zone is RightItem - into here we render the connector Content Item - back in the hands of Orchard's ContentManager for this rendering
  • Now we have another Content Item rendering (along with all its zones, drivers, etc.). Connector items don't usually have a lot of parts, the important one is ConnectorPart - when that executes it renders another Content Item, this one is the actual right-hand item that is being connected
  • So the final content item renders; usually that's all we wanted to see, and usually it wants to display in Summary (or even an even more compact DisplayType, such as Link)

Why does it all have to be so complicated?

The reasons I designed things this way are explained elsewhere; but to summarise, doing things like this gives us the maximum possible flexibility. We can have data stored on the connector item that is only relevant in the relationship but still needs rendering when the relationships are displayed. (Example: on a social networking site, when you have a "friend", you can define data across that relationship such as whether they're friend/family/coworker/etc.; this data shouldn't be stored on their profile, nor on yours - it's part of the relationship).

In setting up the rendering system and the templates, I provided the maximum number of HTML regions you could possibly need to be able to meaningfully partition the data. In the Editor display, all of these zones and levels are being utilised and for good reason. The original thinking was that by cleverly overriding templates you could always reduce this down to just the minimum that you needed.

Unfortunately, that didn't work out so well, primarily because of the problem with Shape Tracing that I alluded to, but also because it just ends up being so crazily complicated understanding all the different templates involved, the many permutations of alternate override names, different named zones at different levels, etc. As I've been setting up a few different sites and scenarios using this system, I've frequently found myself getting horribly confused, so I know it must be really tough for anything else trying to use this!

The Solution: Paradigms

The basic idea behind Paradigms is that, instead of rendering passing through that very same system each time, we instead have a set of pluggable, programmable behaviours that oversee how the rendering is composed. This means that you can switch a whole socket to a set of templates simple enough for a specific application; and then override just the bits you need to change in those templates. Shape Tracing should be the primary tool to check for template names to override; so I don't want to force the user to create nodeless templates to get the markup they want, well, because then Shape Tracing stops working.

An additional thing to note is that multiple paradigms can be applied in any context

Out of the box I'll provide a number of useful named Paradigms to cover most scenarios:

Paradigm Description Templates
Expanded The current status quo - renders all zones, and the connector and right item, in an expanded tree.
Collapsed Very similar, but it renders both Connector item and Right item in the same zones of the same shape (you can use Placement to control which parts display from the connector or the right item
Flattened Left item, Connector and Right item all render in the same shape - the original (top-level) content shape. This is most useful for attached images, it will be as if the MediaPart was attached to the item itself.
Count Displays a simple record count of the number of connectors Socket.Count.cshtml
Links Displays a comma-separated list of links Socket.Links.cshtml
List Displays an (un)ordered list of items Socket.List.cshtml


Last edited Nov 14, 2011 at 3:29 PM by randompete, version 1

Comments

No comments yet.