-
Notifications
You must be signed in to change notification settings - Fork 4
Traversing the maze of HTML rendering
There's a few layers of magic that takes place to ultimately render the DOM of the MinCCY application, as the user sees it.
First, the embedded Tomcat + Spring MVC gets a request for
GET /
which in controllers/ViewController.java
maps to the view called "index"
@RequestMapping("/")
String index() {
return "index";
}
Spring MVC goes off and looks for things that'll satisfy the view called "index". A feature of Spring Boot it that is has wired in Freemarker template support and it knows to look in the classpath under templates
, which originates from src/main/resources/templates
in the source structure.
So far the only model attribute (variables that feed into the view, the Freemarker template in this case) I inject is the new, optional deploymentPoweredBy
@ModelAttribute("deploymentPoweredBy")
public MccySettings.DeploymentPoweredBy deploymentPoweredBy() {
return mccySettings.getDeploymentPoweredBy();
}
but as another case the "login" view injects the CSRF token
@RequestMapping("/login")
ModelAndView loginPage(HttpServletRequest request, HttpServletResponse response, Model model) {
response.addHeader("x-login", "true");
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
.getName());
final ModelAndView modelAndView = new ModelAndView()
.addObject("csrf", csrf);
modelAndView.setViewName("login");
return modelAndView;
}
that becomes a hidden input
in the login form:
<input type="hidden" name="${csrf.parameterName}" value="${csrf.token}" />
where ${csrf.parameterName}
is a Freemarker variable reference that dips into the model attribute csrf
supplied by the Java code above.
Back to the templates, both the rendered "index" and "login" views are basically a mashup of the common pieces (Javascript/CSS references, etc) under templates/ftl-bits
The next major layer, is the DOM-level switch-out driven by the ng-view placeholder in the rendered "index":
<div class="col-md-10">
<div class="row" ng-view>
</div>
</div>
In js/routes.js
I have declared the mapping of routes to views+controllers (an Angular controlle, not the Spring MVC controller shown above in Java land):
.config(function ($routeProvider) {
$routeProvider
.when('/view', {
templateUrl: 'views/view-containers.html',
controller: 'ViewContainersCtrl'
})
.when('/new-server', {
templateUrl: 'views/create-container.html',
controller: 'NewContainerCtrl'
})
// ...and more
.otherwise('/view')
})
Towards the end of this crazy maze, is the use of ng-include directives like
<div ng-repeat="c in containers" class="panel panel-default" ng-include="'ng-bits/current-container.html'">
</div>
from views/view-containers.html
One last twist in the DOM snippets inclusion maze is a custom Angular directive here and there, like the mods managements makes use of the following from js/mods.js
.directive('mccyModPanel', function(){
//... controller stuff
return {
templateUrl: 'ng-bits/mod-panel.html',
restrict: 'A',
scope: {
mod: '=mccyModPanel',
showDelete: '=mccyModPanelShowDelete'
},
controller: controller
}
})
where that templateUrl
is specifying an HTML snippet to use as the directive template. To keep myself sane, my convention is to put both ng-include
and templateUrl
target snippets under static/ng-bits
...hence the vague term "bits".