Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

feat(ngMock.$componentController): not increase extra bytes in angular.min.js #13732

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions docs/app/src/examples.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,26 @@ angular.module('examples', [])


.factory('openPlunkr', ['formPostData', '$http', '$q', function(formPostData, $http, $q) {
return function(exampleFolder, clickEvent) {

var COPYRIGHT = 'Copyright ' + (new Date()).getFullYear() + ' Google Inc. All Rights Reserved.\n'
+ 'Use of this source code is governed by an MIT-style license that\n'
+ 'can be found in the LICENSE file at http://angular.io/license';
var COPYRIGHT_JS_CSS = '\n\n/*\n' + COPYRIGHT + '\n*/';
var COPYRIGHT_HTML = '\n\n<!-- \n' + COPYRIGHT + '\n-->';
function getCopyright(filename) {
switch (filename.substr(filename.lastIndexOf('.'))) {
case '.html':
return COPYRIGHT_HTML;
case '.js':
case '.css':
return COPYRIGHT_JS_CSS;
case '.md':
return COPYRIGHT;
}
return '';
}

return function(exampleFolder, clickEvent) {

var exampleName = 'AngularJS Example';
var newWindow = clickEvent.ctrlKey || clickEvent.metaKey;
Expand Down Expand Up @@ -67,7 +86,7 @@ angular.module('examples', [])
var postData = {};

angular.forEach(files, function(file) {
postData['files[' + file.name + ']'] = file.content;
postData['files[' + file.name + ']'] = file.content + getCopyright(file.name);
});

postData['tags[0]'] = "angularjs";
Expand Down
12 changes: 8 additions & 4 deletions src/ng/animateCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,14 @@ var $CoreAnimateCssProvider = function() {
this.$get = ['$$rAF', '$q', '$$AnimateRunner', function($$rAF, $q, $$AnimateRunner) {

return function(element, initialOptions) {
// we always make a copy of the options since
// there should never be any side effects on
// the input data when running `$animateCss`.
var options = copy(initialOptions);
// all of the animation functions should create
// a copy of the options data, however, if a
// parent service has already created a copy then
// we should stick to using that
var options = initialOptions || {};
if (!options.$$prepared) {
options = copy(options);
}

// there is no point in applying the styles since
// there is no animation that goes on at all in
Expand Down
4 changes: 3 additions & 1 deletion src/ng/compile.js
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,8 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {
* See also {@link ng.$compileProvider#directive $compileProvider.directive()}.
*/
this.component = function registerComponent(name, options) {
var controller = options.controller || function() {};

function factory($injector) {
function makeInjectable(fn) {
if (isFunction(fn) || isArray(fn)) {
Expand All @@ -1065,7 +1067,7 @@ function $CompileProvider($provide, $$sanitizeUriProvider) {

var template = (!options.template && !options.templateUrl ? '' : options.template);
return {
controller: options.controller || function() {},
controller: controller,
controllerAs: identifierForController(options.controller) || options.controllerAs || '$ctrl',
template: makeInjectable(template),
templateUrl: makeInjectable(options.templateUrl),
Expand Down
2 changes: 1 addition & 1 deletion src/ng/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
var $controllerMinErr = minErr('$controller');


var CNTRL_REG = /^(\S+)(\s+as\s+(\w+))?$/;
var CNTRL_REG = /^(\S+)(\s+as\s+([\w$]+))?$/;
function identifierForController(controller, ident) {
if (ident && isString(ident)) return ident;
if (isString(controller)) {
Expand Down
14 changes: 8 additions & 6 deletions src/ngAnimate/animateCss.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,10 +447,14 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
}

return function init(element, initialOptions) {
// we always make a copy of the options since
// there should never be any side effects on
// the input data when running `$animateCss`.
var options = copy(initialOptions);
// all of the animation functions should create
// a copy of the options data, however, if a
// parent service has already created a copy then
// we should stick to using that
var options = initialOptions || {};
if (!options.$$prepared) {
options = prepareAnimationOptions(copy(options));
}

var restoreStyles = {};
var node = getDomNode(element);
Expand All @@ -460,8 +464,6 @@ var $AnimateCssProvider = ['$animateProvider', function($animateProvider) {
return closeAndReturnNoopAnimator();
}

options = prepareAnimationOptions(options);

var temporaryStyles = [];
var classes = element.attr('class');
var styles = packageStyles(options);
Expand Down
51 changes: 49 additions & 2 deletions src/ngMock/angular-mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -797,7 +797,10 @@ angular.mock.animate = angular.module('ngAnimateMock', ['ng'])

var animateJsConstructor = function() {
var animator = $delegate.apply($delegate, arguments);
runners.push(animator);
// If no javascript animation is found, animator is undefined
if (animator) {
runners.push(animator);
}
return animator;
};

Expand Down Expand Up @@ -2161,6 +2164,49 @@ angular.mock.$ControllerDecorator = ['$delegate', function($delegate) {
};
}];

/**
* @ngdoc service
* @name $componentController
* @description
* A service that can be used to create instances of component controllers.
* <div class="alert alert-info">
* Be aware that the controller will be instantiated and attached to the scope as specified in
* the component definition object. That means that you must always provide a `$scope` object
* in the `locals` param.
* </div>
* @param {string} componentName the name of the component whose controller we want to instantiate
* @param {Object} locals Injection locals for Controller.
* @param {Object=} bindings Properties to add to the controller before invoking the constructor. This is used
* to simulate the `bindToController` feature and simplify certain kinds of tests.
* @param {string=} ident Override the property name to use when attaching the controller to the scope.
* @return {Object} Instance of requested controller.
*/
angular.mock.$ComponentControllerProvider = ['$compileProvider', function($compileProvider) {
return {
$get: ['$controller','$injector', function($controller,$injector) {
return function $componentController(componentName, locals, bindings, ident) {
// get all directives associated to the component name
var directives = $injector.get(componentName + 'Directive');
// look for those directives that are components
var candidateDirectives = directives.filter(function(directiveInfo) {
// components have controller, controllerAs and restrict:'E' compatible
return directiveInfo.controller && directiveInfo.controllerAs && directiveInfo.restrict.indexOf('E') >= 0;
});
// check if valid directives found
if (candidateDirectives.length === 0) {
throw new Error('No component found');
}
if (candidateDirectives.length > 1) {
throw new Error('Too many components found');
}
// get the info of the component
var directiveInfo = candidateDirectives[0];
return $controller(directiveInfo.controller, locals, bindings, ident || directiveInfo.controllerAs);
};
}]
};
}];


/**
* @ngdoc module
Expand All @@ -2184,7 +2230,8 @@ angular.module('ngMock', ['ng']).provider({
$log: angular.mock.$LogProvider,
$interval: angular.mock.$IntervalProvider,
$httpBackend: angular.mock.$HttpBackendProvider,
$rootElement: angular.mock.$RootElementProvider
$rootElement: angular.mock.$RootElementProvider,
$componentController: angular.mock.$ComponentControllerProvider
}).config(['$provide', function($provide) {
$provide.decorator('$timeout', angular.mock.$TimeoutDecorator);
$provide.decorator('$$rAF', angular.mock.$RAFDecorator);
Expand Down
15 changes: 13 additions & 2 deletions test/helpers/privateMocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ function browserSupportsCssAnimations() {
return true;
}

function createMockStyleSheet(doc, wind) {
function createMockStyleSheet(doc, prefix) {
doc = doc ? doc[0] : document;
wind = wind || window;

var node = doc.createElement('style');
var head = doc.getElementsByTagName('head')[0];
Expand All @@ -63,6 +62,18 @@ function createMockStyleSheet(doc, wind) {
}
},

addPossiblyPrefixedRule: function(selector, styles) {
if (prefix) {
var prefixedStyles = styles.split(/\s*;\s*/g).map(function(style) {
return !style ? '' : prefix + style;
}).join('; ');

this.addRule(selector, prefixedStyles);
}

this.addRule(selector, styles);
},

destroy: function() {
head.removeChild(node);
}
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/privateMocksSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ describe('private mocks', function() {

var doc = $document[0];
var count = doc.styleSheets.length;
var stylesheet = createMockStyleSheet($document, $window);
var stylesheet = createMockStyleSheet($document);
var elm;
runs(function() {
expect(doc.styleSheets.length).toBe(count + 1);
Expand Down
22 changes: 22 additions & 0 deletions test/ng/animateCssSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,28 @@ describe("$animateCss", function() {
expect(copiedOptions).toEqual(initialOptions);
}));

it("should not create a copy of the provided options if they have already been prepared earlier",
inject(function($animateCss, $$rAF) {

var options = {
from: { height: '50px' },
to: { width: '50px' },
addClass: 'one',
removeClass: 'two'
};

options.$$prepared = true;
var runner = $animateCss(element, options).start();
runner.end();

$$rAF.flush();

expect(options.addClass).toBeFalsy();
expect(options.removeClass).toBeFalsy();
expect(options.to).toBeFalsy();
expect(options.from).toBeFalsy();
}));

it("should apply the provided [from] CSS to the element", inject(function($animateCss) {
$animateCss(element, { from: { height: '50px' }}).start();
expect(element.css('height')).toBe('50px');
Expand Down
27 changes: 16 additions & 11 deletions test/ng/compileSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ describe('$compile', function() {


describe('svg namespace transcludes', function() {
var ua = window.navigator.userAgent;
var isEdge = /Edge/.test(ua);

// this method assumes some sort of sized SVG element is being inspected.
function assertIsValidSvgCircle(elem) {
expect(isUnknownElement(elem)).toBe(false);
Expand Down Expand Up @@ -300,17 +303,19 @@ describe('$compile', function() {
}));

// NOTE: This test may be redundant.
it('should handle custom svg containers that transclude to foreignObject' +
' that transclude to custom svg containers that transclude to custom elements', inject(function() {
element = jqLite('<div><svg-container>' +
'<my-foreign-object><svg-container><svg-circle></svg-circle></svg-container></my-foreign-object>' +
'</svg-container></div>');
$compile(element.contents())($rootScope);
document.body.appendChild(element[0]);

var circle = element.find('circle');
assertIsValidSvgCircle(circle[0]);
}));
if (!isEdge) {
it('should handle custom svg containers that transclude to foreignObject' +
' that transclude to custom svg containers that transclude to custom elements', inject(function() {
element = jqLite('<div><svg-container>' +
'<my-foreign-object><svg-container><svg-circle></svg-circle></svg-container></my-foreign-object>' +
'</svg-container></div>');
$compile(element.contents())($rootScope);
document.body.appendChild(element[0]);

var circle = element.find('circle');
assertIsValidSvgCircle(circle[0]);
}));
}
}

it('should handle directives with templates that manually add the transclude further down', inject(function() {
Expand Down
11 changes: 11 additions & 0 deletions test/ng/controllerSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -209,5 +209,16 @@ describe('$controller', function() {
"Badly formed controller string 'ctrl as'. " +
"Must match `__name__ as __id__` or `__name__`.");
});


it('should allow identifiers containing `$`', function() {
var scope = {};

$controllerProvider.register('FooCtrl', function() { this.mark = 'foo'; });

var foo = $controller('FooCtrl as $foo', {$scope: scope});
expect(scope.$foo).toBe(foo);
expect(scope.$foo.mark).toBe('foo');
});
});
});
2 changes: 1 addition & 1 deletion test/ng/directive/inputSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1196,7 +1196,7 @@ describe('input', function() {

it('should validate if max is empty', function() {
$rootScope.maxVal = undefined;
$rootScope.value = new Date(9999, 11, 31, 23, 59, 59);
$rootScope.value = new Date(3000, 11, 31, 23, 59, 59);
$rootScope.$digest();

expect($rootScope.form.alias.$error.max).toBeFalsy();
Expand Down
4 changes: 2 additions & 2 deletions test/ng/directive/ngRepeatSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -1491,11 +1491,11 @@ describe('ngRepeat animations', function() {
}));

it('should not change the position of the block that is being animated away via a leave animation',
inject(function($compile, $rootScope, $animate, $document, $window, $sniffer, $timeout) {
inject(function($compile, $rootScope, $animate, $document, $sniffer, $timeout) {
if (!$sniffer.transitions) return;

var item;
var ss = createMockStyleSheet($document, $window);
var ss = createMockStyleSheet($document);

try {

Expand Down
4 changes: 3 additions & 1 deletion test/ng/snifferSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,9 @@ describe('$sniffer', function() {
inject(function($sniffer, $window) {
var expectedPrefix;
var ua = $window.navigator.userAgent.toLowerCase();
if (/chrome/i.test(ua) || /safari/i.test(ua) || /webkit/i.test(ua)) {
if (/edge/i.test(ua)) {
expectedPrefix = 'Ms';
} else if (/chrome/i.test(ua) || /safari/i.test(ua) || /webkit/i.test(ua)) {
expectedPrefix = 'Webkit';
} else if (/firefox/i.test(ua)) {
expectedPrefix = 'Moz';
Expand Down
4 changes: 2 additions & 2 deletions test/ngAnimate/animateCssDriverSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,11 @@ describe("ngAnimate $$animateCssDriver", function() {

element = jqLite('<div></div>');

return function($$animateCssDriver, $document, $window) {
return function($$animateCssDriver, $document) {
driver = function(details, cb) {
return $$animateCssDriver(details, cb || noop);
};
ss = createMockStyleSheet($document, $window);
ss = createMockStyleSheet($document);
};
}));

Expand Down
Loading