Renderer consistency | |
---|---|
Project state | Specification |
Tracker issue | https://tracker.moodle.org/browse/MDL-45829 |
Discussion | https://moodle.org/mod/forum/discuss.php?d=261202 |
Assignee | Damyon, Sam |
Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the talk.
This page documents the proposed core elements, variations of them, what we expect they will contain, and the core_renderer block.
The user action
An action in this sense is a collection of data that all pertains to one action that can be taken by the user. The action, once populated with data can be rendered as is required for the job it is going to fulfil, usually with some relation to the frontend framework in use. In this way the action could be a link, or a button; it could even be interpreted into a more complex structure.
An action has the following properties:
- content [string]
- text content for the link or button.
- url [moodle_url]
- the url for the action to take when the user interacts with this action.
- description
- a description of the action. Typically used within a title or alt attribute.
- active
- True if this is the action the user is current performing.
- enabled
- True if the action is possible, false if it is not possible and should be shown as disabled.
- dimmed
- True if the action should be shown as dimmed, usually used to the action is hidden to other users.
- method
- The preferred method of submitting this action, typically GET but can be set to POST.
It is also possible to add JavaScript actions (component_action objects) to an action. These attach a JS listener to the action that gets executed when the user interacts with the action. Attached JavaScript actions get initialised when the properties for the action are retrieved so any events must be attached BEFORE the action is rendered, and all renderers must ensure they use the get_attributes() call.
Grids
We need to come up with some way to include grids in core, it is desirable to keep it framework agnostic so perhaps a grid object that allows for items to be added and a "width" specified when that occurs. The width would be either a fixed number or a percentage. Steps of 12 seems pretty common.
Design requirements
The following concepts need to be accounted for in core, or decisions made on how we choose to support these and where.
Clearfix
We have this in core already, bootstrap has it, pretty much every front end framework has it. Clearfix is more of a design decision, should only be used when require, and only ever applied by a renderer. This gets special mention as being important, support is already 100%.
Floats
Pull left, pull right etc. These are a design decisions and should be implemented by the renderer. Bootstrap caters for these and as such they will be easily catered for in bootstrapbase, however work may be required to get them operational in base.
Discarded ideas
The following things are ideas that came up during discussions on what elements are, and what elements we want in core that have being discarded.
Core atoms, molecules, and organisms
Action {atom}
See the section above about #The user action
Actions are special atoms the represent an action the user can make. They can be rendered by a theme as a link, a button or I suppose anything else. There should be a default for when it is not specified and the renderer in change of producing the current thing can decide whether to use the default and just call render or if it requires something specific render_link or render_button as required.
Block {atom}
Unique to Moodle. This represents a block on the page, and is displayed within a #Block region. It accepts two arguments, the first is a block_contents object instance, and the second is the region name the block instance is being shown within.
At present a block is rendered using the core_render::block method. Internally this calls several renderer methods to produce the different parts of a block.
- core_renderer::block_header - Produces a header
- core_renderer::block_controls - Produces controls to display within the header.
- core_renderer::block_content - Produces the actual content of the block.
- core_renderer::block_controls - Used to check if block controls were rendered. PUKE!!!
- core_renderer::block_footer - Produces a footer that actually resides within the content.
- core_renderer::block_annotation - Produces an annotation, used VERY rarely.
Current structure
The following is the output when called for a navigation block with a bit of extra added to show how a footer is displayed and an annotation.
<a href="#sb-1" class="skip-block">Skip Navigation</a>
Block region {molecule}
Unique to Moodle, the block region is a contain for all of the blocks in one location. We currently have two methods that produce a block region within Moodle, the first is core_renderer::blocks_for_region which adds no surrounding content. The preferred method core_renderer::blocks adds some embedded information to a common structure.
Current structure
The following is the structure of the core_renderer::blocks() method.
public function blocks($region, $classes = array(), $tag = 'aside');
The following is the html output is $region was pre and the default tag and classes were used.
<aside id="block-region-pre" class="block-region" data-blockregion="pre" data-droptarget="1">
</aside>
Thoughts on this
The blocks method is a convenience method and serves an important purpose. However it should not take classes and tag as arguments.
These should certainly only settable within the renderer itself, and if themes wish to change this without wrapping the call they should override the renderer.
Both the data attributes relate to servicing JavaScript functionality. Perhaps they should be moved to a component_action or somehow else integrated with JS rather than with the renderer directly.
Internally it is calling blocks for region, however this should change it should request a array of blocks, convert the array to #Block elements and call render on each.
Proposed HTML structure
Much like the current structure but with the data attributes coming through a JS mechanism.
<aside id="block-region-pre" class="block-region">
</aside>
Breadcrumb {molecule}
Currently called the navbar within Moodle, controlled by the navbar class located in lib/navigationlib.php and rendered by core_renderer::navbar().
Internally it calls moodle_page->navbar->get_items() to get an array containing navigation node items to display in the navigation bar.
It produces a bit of surrounding structure before calling render on each item.
Current structure
The following shows the structure for two items in the navigation bar presently within Moodle.
Page path
<nav class="breadcrumb-nav">
</nav>
Notice the excessive amount of markup to make the separator accessible.
Markup in various frontend frameworks
Design considerations
- The currently active page should be marked with a class.
- The current item should probably not be a link MDL-46037
- wia-aria breadcrumb role
- The divider perhaps could come through CSS with these changes to avoid markup necessary to make it accessible (in combination with the above).
Implementation thoughts
- Owns an array of [#Action {atoms}]
Buttons {atom}
This will be both an element and a representation of a [#Action {atom}].
Obviously buttons can serve different purposes and roles so have several easily reachable customisations is probably a wise idea.
Current structure None, presently you produce a button when you need it so there are several throughout Moodle.
Markup in various frontend frameworks
Bootstrap 2.3.2 and Bootstrap 3
<button type="button" class="btn btn-default">Default</button>
<a href="#" class="btn btn-default btn-lg active" role="button">Link</a>
<input class="btn btn-default" type="button" value="Input">
Customisations available through Bootstrap:
- Purposes: default, primary, success, info, warning, danger, link
- Sizes: large, default, small, extra-small
- Block level (wider)
- States: Active, disabled.
Zurb foundation
<a href="#" class="button">Default Button</a>
Customisations available through Zurb Foundation:
- Purposes: default, secondary, success, alert
- Sizes: large, default, small, tiny
- Corner style: radius, round
- Expanded (wider)
- States: disabled
Calendar {organism}
A simple idea really, apparently not already covered by the frontend frameworks being referenced during the creation of the doc. The display of the calendar is fixed, but it can contain content for each day shown.
The calendar should have several views, perhaps these are separate organisms, perhaps not.
- Compact month
- Month
- Week
- Day
Each day could:
- Contain an action with an icon for events, and link to the fullday display.
- Have an associated action to load and display the events in a tooltip.
Collapsible region {molecule}
We use these in several places within Moodle. I could not find a reference to this concept in any of the frontend frameworks I looked at. The concept is simple - you have a heading and an icon with content. By default the content is hidden, when the user clicks the heading and/or the icon the content is revealed.
As noted we do this in several places within Moodle, it would be good to have a single way of displaying this idea of a collapsible region.
Design thoughts
- It should support an optional collapse/expand all trigger action.
- We want to be able to use it both inside and outside of forms.
- It should be usable in situations like the combo list frontpage component as well.
- Will obviously have a JS component as without JS it would not work.
Confirmation {molecule}
A simple concept used regularly in Moodle to confirm a users intention to perform an actions. Most commonly seeing when deleting content. The structure is relatively basic in Moodle at present.
- A message
- A forwards button
- A back button
Current structure
The method core_renderer::confirm does the rendering at present. Its signature is as follows:
public function confirm($message, $continue, $cancel);
The output it produces is like:
The message goes here
Continue
Choice
Not sure about this one quite yet. A description with 2 or more actions allowing the user to select the next step. Think of it like when editing a module you get: Cancel, Save and return to course, Save and display
Divider
Think horizontal rule.
Dropdowns
- From button
- From link
- From icon
Forms {organism}
This is an advanced organism and would be quite a bit of work to create in Moodle as we'd need to translate from QuickForms to elements for rendering. It would be worthwhile doing this however, and would be a good way of quickly showing our new work.
Frontend framework structures
All of those are quite in-depth and offer a range of configurations. We should carefully consider these when analysing our work here.
Headings {atom}
Currently handled by core_renderer::heading.
- h1 - h6
- Optional icon
- Optional help icon
Current structure
The render method is currently:
public function heading($text, $level = 2, $classes = null, $id = null);
The output generated by this is, assuming we use the default level, classes, and id.
I am a heading
Whats worth noting is that the render method should not accept level and classes as arguments. These should only be set by the render method and should not be directly influenced.
Image {atom}
There are really two types of images to focus on here, or really two ways to display an image to focus on here.
- Standard images
- Thumbnail images
Each of these would share some common properties:
- Image
- Description (alt/title)
- Size
- Action (making it a link) - This would actually make it a molecule, we would have to consider this and either have a new element, drop the ability to wrap in an action, or simply ignore this inconsistency.
Image - Icon {element}
This covers the display of an icon. Should be a separate element from image as really they should be treated individually. Within Moodle there are a few classifications of icons to consider:
- Standard icons
- Help icon (popup, tooltip)
- Loading icon (really regular icon but worth showing separately as its only seen when required)
Image - Profile picture {molecule}
We already have a user_picture component within Moodle. It can be found in lib/outputcomponents.php.
It has two render methods, core_renderer::user_picture and core_renderer::render_user_picture.
Current structure
The following is the output structure for the user picture:
<a href="#" id="userpicture_randomid">
<img src="#" alt="Picture of Joe" title="Picture of Joe" class="userpicture" width="[35, 100, XX]" height="[35, 100, XX]" />
</a>
What you'll notice about this is that the link has no attributes marking it as a user picture link.
The PHP code for the user_picture object itself is really quite in depth and complex. The component serves the user profile fields required to render a user picture. This is good in the scope of the component but would be bad within the scope of an element.
Don't you wish we had a proper user object!
Links
Lists
- Ordered list
- Unordered list
- Presentation list (currently our unlist)
Logo
Menu
- Orientation (Horizontal, Vertical)
- Nesting
Navigation is a collection of actions.
Notification {atom}
- Info
- Success
- Warning
- Danger
Menu
Action group
Formerly navbar, can't be called that because the render method would conflict.
Tabs
Page header {molecule}
Currently being produced by core_renderer::page_heading this is simply a header for the page, by default the only h1 element on the page.
Current structure
The render method has the following signature:
public function page_heading($tag = 'h1');
The output from the above method is:
The page heading (from moodle_page::heading)
The core_renderer method should not allow the tag to be set. The page heading should always be H1. If its not an H1 then page header should not be used.
Frontend framework examples
Heading
Tagline
<a class="btn btn-primary btn-large">
Learn more
</a>
Example page header Subtext for header
Foundation doesn't appear to have a page header component.
Design thoughts
- In Moodle all page headings are set as a single string, we won't be changing this.
- Usually just a plain string sometimes an icon is used, and sometimes a help icon is used.
Progress bars {molecule}
A pretty simple concept, we already have a couple of ways of producing progress bars within Moodle.
Markup in various frontend frameworks
The following options are offered by Bootstrap 2.3.2:
- Striped
- Striped + Animated
- Stacked (multiple bars forming a single)
- Colours: default (blue), info (light blue), success (green), warning (orange), danger (red)
The following options are offered by Bootstrap 3:
- Striped
- Striped + Animated
- Stacked (multiple bars forming a single)
- Colours: default (blue), info (light blue), success (green), warning (orange), danger (red)
The following options are offered by Zurb foundation:
- Width
- Colours: default (blue), secondary (grey), success (green), alert (red)
- Corner style: default (square), radius (slight rounding), round
Search
- Text input + button.
- Optional collapsible region with more content.
Timer
Tree
User badge
User content
Think of this like the forum post. We need a common structure in which to display content entered by the user along with information on the user. The users name, picture, date perhaps, title, content, footer (attachments, badges, what ever). It could be applied to things like forum posts, calendar events etc.
At present we have no abstraction for this.
Existing renderables and what they will become
Existing renderable | Description | Future renderable | Convenience method (if different) |
---|---|---|---|
action_menu | UI component for a drop down edit menu | menu | |
action_menu_link | UI component for a menu item in an action menu | action | |
action_menu_filler | UI component for a filler menu item in an action menu | action | |
action_menu_link_primary | UI component for a primary menu item in an action menu | action | |
action_menu_link_secondary | UI component for a secondary menu item in an action menu | action | |
action_link | Link with alt text, and an icon | action | |
single_button | A form with a single button | button (action with post method) | |
confirm | A form with a message and cancel/confirm buttons | confirmation | |
single_select | A form with a single drop down list that submits on change | ||
url_select | A navigation element consisting of a single drop down list of urls that navigates on change | ||
doc_link | A link to the Moodle docs | ||
pix_icon | A small icon | icon | |
emoticon_icon | A small emoticon | ||
heading_with_help | A page heading with a link to help docs | heading | |
help_icon | A help icon that opens a help popup when clicked | icon_help | |
help_icon_scale | A help icon that opens a help popup when clicked | ||
user_picture | A user profile picture which links to their profile | ||
container | A block level element used to surround something. Can have a class to allow specific targeting with CSS. | ||
error_text | An error to show to the user. | ||
notification | A message for the user | ||
continue_button | A message and a button to continue to the next page | ||
paging_bar | A list of next previous and specific page links | ||
skip_link_to | A link to a section on the page | ||
skip_link_target | A target for a matching skip_link_to call | ||
heading | A page heading | heading | |
box | A page section with a border | ||
rarrow | A right arrow | ||
larrow | A left arrow | ||
tabtree | A list of tabs | menu | |
tabobject | A single tab panel | action |