Enabling strict di mode

Using strict DI mode will improve angular's performance when injecting
dependencies in injectable functions because it doesn't have to
dynamically discover a function's dependencies.

It is suggested by Angular official web site to use strict dependency
injection mode in production for get better performance:
https://docs.angularjs.org/guide/di#using-strict-dependency-injection

This patch fixes all the places where explicit di is not applied, and
then enables strict-di mode in production.

This is prioritized as CRITICAL for Horizon Mitaka release:
https://etherpad.openstack.org/p/mitaka-horizon-priorities

Change-Id: I1c0e01d7ac9aec03d961f14ff7297bc98c513637
Implements: blueprint angular-performance-strict-di
This commit is contained in:
Shaoquan Chen 2015-11-17 00:10:44 -08:00
parent 23ee8bedd7
commit 67beea4138
5 changed files with 141 additions and 120 deletions

View File

@ -27,71 +27,75 @@
* this directive is the hook to make it more dynamic.
* Only visible if websso is enabled.
*/
.directive('hzLoginFinder', function($timeout) {
return {
restrict: 'A',
controller: 'hzLoginController',
link: function(scope, element, attrs, ctrl) {
.directive('hzLoginFinder', hzLoginFinder);
/**
* Test code does not have access to document,
* so we are restricted to search through the element
*/
var authType = element.find('#id_auth_type');
var userInput = element.find("#id_username").parents('.form-group');
var passwordInput = element.find("#id_password").parents('.form-group');
var domainInput = element.find('#id_domain').parents('form-group');
var regionInput = element.find('#id_region').parents('form-group');
hzLoginFinder.$inject = ['$timeout'];
/**
* `helpText` exists outside of element,
* so we have to traverse one node up
*/
var helpText = element.parent().find('.help_text');
helpText.hide();
function hzLoginFinder($timeout) {
return {
restrict: 'A',
controller: 'hzLoginController',
link: function(scope, element, attrs, ctrl) {
// Update the visuals when user selects item from dropdown
function onChange() {
$timeout(function() {
/**
* Test code does not have access to document,
* so we are restricted to search through the element
*/
var authType = element.find('#id_auth_type');
var userInput = element.find("#id_username").parents('.form-group');
var passwordInput = element.find("#id_password").parents('.form-group');
var domainInput = element.find('#id_domain').parents('form-group');
var regionInput = element.find('#id_region').parents('form-group');
/**
* If auth_type is 'credential', show the username and password fields,
* and domain and region if applicable
*/
ctrl.auth_type = authType.val();
switch (ctrl.auth_type) {
case 'credentials':
userInput.show();
passwordInput.show();
domainInput.show();
regionInput.show();
break;
default:
userInput.hide();
passwordInput.hide();
domainInput.hide();
regionInput.hide();
}
}); // end of timeout
} // end of onChange
/**
* `helpText` exists outside of element,
* so we have to traverse one node up
*/
var helpText = element.parent().find('.help_text');
helpText.hide();
// If authType field exists then websso was enabled
if (authType.length > 0) {
// Update the visuals when user selects item from dropdown
function onChange() {
$timeout(function() {
/**
* Programmatically insert help text after dropdown.
* This is the only way to do it since template is generated server side,
* via form_fields
* If auth_type is 'credential', show the username and password fields,
* and domain and region if applicable
*/
authType.after(helpText);
helpText.show();
ctrl.auth_type = authType.val();
switch (ctrl.auth_type) {
case 'credentials':
userInput.show();
passwordInput.show();
domainInput.show();
regionInput.show();
break;
default:
userInput.hide();
passwordInput.hide();
domainInput.hide();
regionInput.hide();
}
}); // end of timeout
} // end of onChange
// Trigger the onChange on first load so that initial choice is auto-selected
onChange();
authType.change(onChange);
}
} // end of link
}; // end of return
}); // end of directive
// If authType field exists then websso was enabled
if (authType.length > 0) {
/**
* Programmatically insert help text after dropdown.
* This is the only way to do it since template is generated server side,
* via form_fields
*/
authType.after(helpText);
helpText.show();
// Trigger the onChange on first load so that initial choice is auto-selected
onChange();
authType.change(onChange);
}
} // end of link
}; // end of return
} // end of directive
})();

View File

@ -37,6 +37,8 @@
// this can happen when session expires
$httpProvider.interceptors.push(redirect);
redirect.$inject = ['$q'];
function redirect($q) {
return {
responseError: function (error) {

View File

@ -84,6 +84,9 @@
* For multiple input / multiple promise resolution:
*
*/
hzPromiseToggleTemplate.$inject = ['$q', '$parse'];
function hzPromiseToggleTemplate($q, $parse) {
var directive = {
name: null,

View File

@ -19,77 +19,89 @@ limitations under the License.
'use strict';
angular.module('serialConsoleApp', [])
.constant('protocols', ['binary', 'base64'])
.constant('states', [gettext('Connecting'), gettext('Open'), gettext('Closing'), gettext('Closed')])
.constant('protocols', [
'binary',
'base64'
])
.constant('states', [
gettext('Connecting'),
gettext('Open'),
gettext('Closing'),
gettext('Closed')
])
/**
* @ngdoc directive
* @ngname serialConsole
*
* @description
* The serial-console element creates a terminal based on the widely-used term.js.
* The "connection" attribute is input to a WebSocket object, which connects
* to a server. In Horizon, this directive is used to connect to nova-serialproxy,
* opening a serial console to any instance. Each key the user types is transmitted
* to the instance, and each character the instance reponds with is displayed.
*/
.directive('serialConsole', function(protocols, states) {
return {
scope: true,
template: '<div id="terminalNode"></div><br>{{statusMessage()}}',
restrict: 'E',
link: function postLink(scope, element, attrs) {
* @ngdoc directive
* @ngname serialConsole
*
* @description
* The serial-console element creates a terminal based on the widely-used term.js.
* The "connection" attribute is input to a WebSocket object, which connects
* to a server. In Horizon, this directive is used to connect to nova-serialproxy,
* opening a serial console to any instance. Each key the user types is transmitted
* to the instance, and each character the instance reponds with is displayed.
*/
.directive('serialConsole', serialConsole);
var connection = scope.$eval(attrs.connection);
var term = new Terminal();
var socket = new WebSocket(connection, protocols);
serialConsole.$inject = ['protocols', 'states'];
socket.onerror = function() {
scope.$apply(scope.status);
};
socket.onopen = function() {
scope.$apply(scope.status);
// initialize by "hitting enter"
socket.send(String.fromCharCode(13));
};
socket.onclose = function() {
scope.$apply(scope.status);
};
function serialConsole(protocols, states) {
return {
scope: true,
template: '<div id="terminalNode"></div><br>{{statusMessage()}}',
restrict: 'E',
link: function postLink(scope, element, attrs) {
// turn the angular jQlite element into a raw DOM element so we can
// attach the Terminal to it
var termElement = angular.element(element)[0];
term.open(termElement.ownerDocument.getElementById('terminalNode'));
var connection = scope.$eval(attrs.connection);
var term = new Terminal();
var socket = new WebSocket(connection, protocols);
term.on('data', function(data) {
socket.send(data);
});
socket.onerror = function() {
scope.$apply(scope.status);
};
socket.onopen = function() {
scope.$apply(scope.status);
// initialize by "hitting enter"
socket.send(String.fromCharCode(13));
};
socket.onclose = function() {
scope.$apply(scope.status);
};
socket.onmessage = function(e) {
if (e.data instanceof Blob) {
var f = new FileReader();
f.onload = function() {
term.write(f.result);
};
f.readAsText(e.data);
} else {
term.write(e.data);
}
};
// turn the angular jQlite element into a raw DOM element so we can
// attach the Terminal to it
var termElement = angular.element(element)[0];
term.open(termElement.ownerDocument.getElementById('terminalNode'));
scope.status = function() {
return states[socket.readyState];
};
term.on('data', function(data) {
socket.send(data);
});
scope.statusMessage = function() {
return interpolate(gettext('Status: %s'), [scope.status()]);
};
socket.onmessage = function(e) {
if (e.data instanceof Blob) {
var f = new FileReader();
f.onload = function() {
term.write(f.result);
};
f.readAsText(e.data);
} else {
term.write(e.data);
}
};
scope.$on('$destroy', function() {
socket.close();
});
scope.status = function() {
return states[socket.readyState];
};
scope.statusMessage = function() {
return interpolate(gettext('Status: %s'), [scope.status()]);
};
scope.$on('$destroy', function() {
socket.close();
});
}
};
}
}
};
});
}());

View File

@ -17,7 +17,7 @@
{% include "horizon/_custom_head_js.html" %}
{% block ng_route_base %} {% endblock %}
</head>
<body id="{% block body_id %}{% endblock %}" ng-app='horizon.app'>
<body id="{% block body_id %}{% endblock %}" ng-app='horizon.app' ng-strict-di>
<noscript>
<div class="javascript_disabled_alert">
{% trans "This application requires JavaScript to be enabled in your web browser." %}