Message-ID: <1837235317.3784.1485855328248.JavaMail.confluence@ip-10-127-227-164> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_3783_311964086.1485855328248" ------=_Part_3783_311964086.1485855328248 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
Each route defines a View to render when the route is matched. As explai= ned in the Platf= ormUI technical introduction, this kind of view is called a Mai= n View. Like any view, it can have an arbitrary number of sub-view= s.
Good practice: keep the views small and do not hesitate= to create sub-views. This eases the maintenance and allows you to reuse th= e small sub-views in different context.
A View is responsible for generating the User Interface and handling the= user input (click, keyboard, drag and drop, etc.). In its lifecycle, a vie= w first receives a set of parameters, then it is rendered and added to DOM.=
PlatformUI reuses the YUI View=
system. Y.View
is designed to be a very simple component.=
PlatformUI extends this concept to have views with more features like temp=
lates or asynchronous behavior.
As for the plugin in the previous step, the first thing to do is to decl=
are a new module in the extension bundle yui.yml
file:
ezconf-listview: requires: ['ez-view'] path: %extending_platformui.public_dir%/js/views/ezconf-listview.js=20
Our basic view will extend the PlatformUI basic view which is available =
in the ez-view
module. As a result, ez-view
has t=
o be added in the module requirements.
Then we have to create the corresponding module file. In this file, we'l=
l create a new View component by extending Y.eZ.View
provided =
by ez-view
.
YUI.add('ezconf-listview', function (Y) { Y.namespace('eZConf'); Y.eZConf.ListView =3D Y.Base.create('ezconfListView', Y.eZ.View, [], { initializer: function () { console.log("Hey, I'm the list view"); }, render: function () { // this.get('container') is an auto generated <div> // here, it's not yet in the DOM of the page and it will be add= ed // after the execution of render(). this.get('container').setContent( "Hey, I'm the listView and I was rendered it seems" ); this.get('container').setStyles({ background: '#fff', fontSize: '200%', }); return this; }, }); });=20
This code creates the Y.eZConf.ListView
by extending =
Y.eZ.View
. The newly created view component has a custom rende=
r
method. As its name suggests, this method is called when the view =
needs to be rendered. For now, we are directly manipulating the DOM. =
this.get('container')
in a View allows you to retrieve the container=
DOM node, it's actually a Y.Node instance that is autom=
atically created and added to the page when the View is needed in the appli=
cation.
A View is responsible for handling only what happens in its own containe= r. While it's technically possible, it is a very bad practice for a View to= handle anything that is outside its own container.
At this point, if you open/refresh PlatformUI in your browser, nothing w= ill have really changed, because the newly added View is not used anywhere = yet.
Now that we have a View, it's time to change the route configuration add=
ed in the previous step so that our custom route uses it. To do that, we'll=
have to change the application plugin to register the new view as a main v=
iew in the application and then to define the custom route with that view. =
Since we want to use the new view in the plugin, the ezconf-listview<=
/code> module becomes a dependency of the plugin module. The plugin module =
declaration becomes:
ezconf-listapplugin: requires: ['ez-pluginregistry', 'plugin', 'base', 'ezconf-listview'] # = we've added 'ezconf-listview' dependencyOf: ['ez-platformuiapp'] path: %extending_platformui.public_dir%/js/apps/plugins/ezconf-listappp= lugin.js=20
Then in the plugin, Y.eZConf.ListView
becomes available; we=
can register it as a potential main view and change the route to use it:=
p>
YUI.add('ezconf-listapplugin', function (Y) { Y.namespace('eZConf.Plugin'); Y.eZConf.Plugin.ListAppPlugin =3D Y.Base.create('ezconfListAppPlugin', = Y.Plugin.Base, [], { initializer: function () { var app =3D this.get('host'); // the plugged object is called h= ost console.log("Hey, I'm a plugin for PlatformUI App!"); console.log("And I'm plugged in ", app); console.log('Registering the ezconfListView in the app'); app.views.ezconfListView =3D { type: Y.eZConf.ListView, }; console.log("Let's add a route"); app.route({ name: "eZConfList", path: "/ezconf/list", view: "ezconfListView", // because we registered the view i= n app.views.ezconfListView sideViews: {'navigationHub': true, 'discoveryBar': false}, callbacks: ['open', 'checkUser', 'handleSideViews', 'handle= MainView'], }); }, }, { NS: 'ezconfTypeApp' // don't forget that }); Y.eZ.PluginRegistry.registerPlugin( Y.eZConf.Plugin.ListAppPlugin, ['platformuiApp'] ); });=20
After doing that, /ez#/ezconf/list
should no longer display=
the dashboard, but you should see the message generated by Y.eZConf.=
ListView
.
Manipulating the DOM in a view render method is fine for small changes b= ut not very handy as soon as you want to generate a more complex UI. It's a= lso a great way to separate pure UI/markup code from the actual view logic.=
In PlatformUI, most views are using a template to generate their own mar= kup, those templates are interpreted by the Handlebars= .js template engine embed into YUI.
The templates are made available in the application by defining them as =
modules in yui.yml
. The template modules are a bit special tho=
ugh. To be recognized as a template and correctly handled by the applicatio=
n, a template module has a type
property that should be set to=
template
. Also, to get everything ready automatically, the module name should follow a naming convention. The module name shoul=
d consist of the lowercase View internal name (the first Y.Base.=
create
parameter) where the template is supposed to be used followed=
by the suffix -ez-template
. In our case, the internal name of=
Y.eZConf.ListView
is ezconfListView
, so if we wa=
nt to use a template in this view, the module for this template should be <=
code>ezconflistview-ez-template. The template module must also be ad=
ded as a dependency of the view module using it (ezconf-listview in this case). As a result, the modules declaration for the template and=
the view will be:
ezconf-listview: requires: ['ez-templatebasedview', 'ezconflistview-ez-template'] path: %extending_platformui.public_dir%/js/views/ezconf-listview.js ezconflistview-ez-template: # internal view name + '-ez-template' suffix type: 'template' # mandatory so that the template is available in JavaS= cript path: %extending_platformui.public_dir%/templates/ezconflistview.hbt=20
In yui.yml
, we also have to change the ezconf-listvie=
w
module to now require ez-
templatebasedview
instead of ez-view
so =
that Y.eZConf.ListView
can inherit from Y.eZ.Templa=
teBasedView
instead of Y.eZ.View.
Once that is in place, the rendering logic can be changed to use=
the template:
YUI.add('ezconf-listview', function (Y) { Y.namespace('eZConf'); Y.eZConf.ListView =3D Y.Base.create('ezconfListView', Y.eZ.TemplateBase= dView, [], { // Y.eZ.TemplateBasedView now! initializer: function () { console.log("Hey, I'm the list view"); }, render: function () { // when extending Y.eZ.TemplateBasedView // this.template is the result of the template // compilation, it's a function. You can pass an object // in parameters and each property will be available in the tem= plate // as a variable named after the property. this.get('container').setHTML( this.template({ "name": "listView" }) ); this.get('container').setStyles({ background: '#fff', fontSize: '200%', }); return this; }, }); });=20
And the last part of the chain is the Handlebars template file itself:= p>
<h1 class=3D"ezconf-list-title">List view</h1> Hey, I'm the {{ name }} and I'm rendered with the template!=20
At this point, /ez#/ezconf/list
should display the Y.eZConf.ListView
rendered with the template.
We've just moved the markup logic from the view component to a template =
file. It is also time to do the same for the CSS styles that are still in t=
he render
method. For that, a CSS file can be created on the d=
isk to replace the inline styles:
.ez-view-ezconflistview { background: #fff; } .ez-view-ezconflistview .ezconf-list-title { margin-top: 0; }=20
By default, a view container element has an auto-generated class built f= rom the internal view name.
Good practice: using that auto-generated class to write= the CSS rule greatly limits the risk of side effects when styling a view.<= /p>
Then this file has to be listed in the extension bundle css.yml configuration file:
system: default: css: files: - %extending_platformui.css_dir%/views/list.css=20
After this is done, a custom view is now used when reaching /ez#/e=
zconf/list
and the UI is now styled with a custom external styleshee=
t.
The resulting code can be seen in the 4_view tag on GitHub, this step result can also be=
viewed as a diff between tags 3_routing
and 4_view
=
a>.
The next step is then to configure the navigation so that user can easily reach the new= page.