Skip to content

Commit

Permalink
fix(class): allow class names with mixed case
Browse files Browse the repository at this point in the history
Fixes #3001

BREAKING CHANGE:

View renderer used to take normalized CSS class names (ex. fooBar for foo-bar).
With this change a rendered implementation gets a calss name as specified in a
template, without any transformations / normalization. This change only affects
custom view renderers that should be updated accordingly.

Closes #3264
  • Loading branch information
pkozlowski-opensource committed Jul 27, 2015
1 parent 329a6e0 commit a8b5725
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 10 deletions.
10 changes: 8 additions & 2 deletions modules/angular2/src/render/dom/view/proto_view_builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ import {DomElementBinder, Event, HostAction} from './element_binder';

import * as api from '../../api';

import {NG_BINDING_CLASS, EVENT_TARGET_SEPARATOR, queryBoundTextNodeIndices} from '../util';
import {
NG_BINDING_CLASS,
EVENT_TARGET_SEPARATOR,
queryBoundTextNodeIndices,
camelCaseToDashCase
} from '../util';

export class ProtoViewBuilder {
variableBindings: Map<string, string> = new Map();
Expand Down Expand Up @@ -366,7 +371,8 @@ function createElementPropertyBinding(ast: ASTWithSource, propertyNameInTemplate
} else if (parts[0] == ATTRIBUTE_PREFIX) {
return new api.ElementPropertyBinding(api.PropertyBindingType.ATTRIBUTE, ast, parts[1]);
} else if (parts[0] == CLASS_PREFIX) {
return new api.ElementPropertyBinding(api.PropertyBindingType.CLASS, ast, parts[1]);
return new api.ElementPropertyBinding(api.PropertyBindingType.CLASS, ast,
camelCaseToDashCase(parts[1]));
} else if (parts[0] == STYLE_PREFIX) {
var unit = parts.length > 2 ? parts[2] : null;
return new api.ElementPropertyBinding(api.PropertyBindingType.STYLE, ast, parts[1], unit);
Expand Down
5 changes: 2 additions & 3 deletions modules/angular2/src/render/dom/view/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,10 @@ export class DomView {

setElementClass(elementIndex: number, className: string, isAdd: boolean) {
var element = this.boundElements[elementIndex];
var dashCasedClassName = camelCaseToDashCase(className);
if (isAdd) {
DOM.addClass(element, dashCasedClassName);
DOM.addClass(element, className);
} else {
DOM.removeClass(element, dashCasedClassName);
DOM.removeClass(element, className);
}
}

Expand Down
24 changes: 20 additions & 4 deletions modules/angular2/test/directives/class_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,22 @@ export function main() {
});
}));


it('should add classes specified in an object literal without change in class names',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [class]="{'foo-bar': true, 'fooBar': true}"></div>`;

tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((rootTC) => {
rootTC.detectChanges();
expect(rootTC.componentViewChildren[0].nativeElement.className)
.toEqual('ng-binding foo-bar fooBar');

async.done();
});
}));

it('should add and remove classes based on changes in object literal values',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = '<div [class]="{foo: condition, bar: !condition}"></div>';
Expand Down Expand Up @@ -141,14 +157,14 @@ export function main() {

it('should add classes specified in a list literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [class]="['foo', 'bar']"></div>`;
var template = `<div [class]="['foo', 'bar', 'foo-bar', 'fooBar']"></div>`;

tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((rootTC) => {
rootTC.detectChanges();
expect(rootTC.componentViewChildren[0].nativeElement.className)
.toEqual('ng-binding foo bar');
.toEqual('ng-binding foo bar foo-bar fooBar');

async.done();
});
Expand Down Expand Up @@ -212,14 +228,14 @@ export function main() {

it('should add classes specified in a string literal',
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
var template = `<div [class]="'foo bar'"></div>`;
var template = `<div [class]="'foo bar foo-bar fooBar'"></div>`;

tcb.overrideTemplate(TestComponent, template)
.createAsync(TestComponent)
.then((rootTC) => {
rootTC.detectChanges();
expect(rootTC.componentViewChildren[0].nativeElement.className)
.toEqual('ng-binding foo bar');
.toEqual('ng-binding foo bar foo-bar fooBar');

async.done();
});
Expand Down
6 changes: 5 additions & 1 deletion modules/angular2/test/render/dom/view/view_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,15 @@ export function main() {
expect(DOM.hasClass(el, 'active')).toEqual(false);
});

it('should de-normalize class names', () => {
it('should not de-normalize class names', () => {
view.setElementClass(0, 'veryActive', true);
view.setElementClass(0, 'very-active', true);
expect(DOM.hasClass(el, 'veryActive')).toEqual(true);
expect(DOM.hasClass(el, 'very-active')).toEqual(true);

view.setElementClass(0, 'veryActive', false);
view.setElementClass(0, 'very-active', false);
expect(DOM.hasClass(el, 'veryActive')).toEqual(false);
expect(DOM.hasClass(el, 'very-active')).toEqual(false);
});
});
Expand Down

0 comments on commit a8b5725

Please sign in to comment.