fix(class): allow class names with mixed case
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
This commit is contained in:
parent
329a6e00dc
commit
a8b57256c8
|
@ -23,7 +23,12 @@ import {DomElementBinder, Event, HostAction} from './element_binder';
|
||||||
|
|
||||||
import * as api from '../../api';
|
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 {
|
export class ProtoViewBuilder {
|
||||||
variableBindings: Map<string, string> = new Map();
|
variableBindings: Map<string, string> = new Map();
|
||||||
|
@ -366,7 +371,8 @@ function createElementPropertyBinding(ast: ASTWithSource, propertyNameInTemplate
|
||||||
} else if (parts[0] == ATTRIBUTE_PREFIX) {
|
} else if (parts[0] == ATTRIBUTE_PREFIX) {
|
||||||
return new api.ElementPropertyBinding(api.PropertyBindingType.ATTRIBUTE, ast, parts[1]);
|
return new api.ElementPropertyBinding(api.PropertyBindingType.ATTRIBUTE, ast, parts[1]);
|
||||||
} else if (parts[0] == CLASS_PREFIX) {
|
} 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) {
|
} else if (parts[0] == STYLE_PREFIX) {
|
||||||
var unit = parts.length > 2 ? parts[2] : null;
|
var unit = parts.length > 2 ? parts[2] : null;
|
||||||
return new api.ElementPropertyBinding(api.PropertyBindingType.STYLE, ast, parts[1], unit);
|
return new api.ElementPropertyBinding(api.PropertyBindingType.STYLE, ast, parts[1], unit);
|
||||||
|
|
|
@ -42,11 +42,10 @@ export class DomView {
|
||||||
|
|
||||||
setElementClass(elementIndex: number, className: string, isAdd: boolean) {
|
setElementClass(elementIndex: number, className: string, isAdd: boolean) {
|
||||||
var element = this.boundElements[elementIndex];
|
var element = this.boundElements[elementIndex];
|
||||||
var dashCasedClassName = camelCaseToDashCase(className);
|
|
||||||
if (isAdd) {
|
if (isAdd) {
|
||||||
DOM.addClass(element, dashCasedClassName);
|
DOM.addClass(element, className);
|
||||||
} else {
|
} else {
|
||||||
DOM.removeClass(element, dashCasedClassName);
|
DOM.removeClass(element, className);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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',
|
it('should add and remove classes based on changes in object literal values',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
||||||
var template = '<div [class]="{foo: condition, bar: !condition}"></div>';
|
var template = '<div [class]="{foo: condition, bar: !condition}"></div>';
|
||||||
|
@ -141,14 +157,14 @@ export function main() {
|
||||||
|
|
||||||
it('should add classes specified in a list literal',
|
it('should add classes specified in a list literal',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
expect(rootTC.componentViewChildren[0].nativeElement.className)
|
expect(rootTC.componentViewChildren[0].nativeElement.className)
|
||||||
.toEqual('ng-binding foo bar');
|
.toEqual('ng-binding foo bar foo-bar fooBar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
@ -212,14 +228,14 @@ export function main() {
|
||||||
|
|
||||||
it('should add classes specified in a string literal',
|
it('should add classes specified in a string literal',
|
||||||
inject([TestComponentBuilder, AsyncTestCompleter], (tcb: TestComponentBuilder, async) => {
|
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)
|
tcb.overrideTemplate(TestComponent, template)
|
||||||
.createAsync(TestComponent)
|
.createAsync(TestComponent)
|
||||||
.then((rootTC) => {
|
.then((rootTC) => {
|
||||||
rootTC.detectChanges();
|
rootTC.detectChanges();
|
||||||
expect(rootTC.componentViewChildren[0].nativeElement.className)
|
expect(rootTC.componentViewChildren[0].nativeElement.className)
|
||||||
.toEqual('ng-binding foo bar');
|
.toEqual('ng-binding foo bar foo-bar fooBar');
|
||||||
|
|
||||||
async.done();
|
async.done();
|
||||||
});
|
});
|
||||||
|
|
|
@ -100,11 +100,15 @@ export function main() {
|
||||||
expect(DOM.hasClass(el, 'active')).toEqual(false);
|
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, 'veryActive', true);
|
||||||
|
view.setElementClass(0, 'very-active', true);
|
||||||
|
expect(DOM.hasClass(el, 'veryActive')).toEqual(true);
|
||||||
expect(DOM.hasClass(el, 'very-active')).toEqual(true);
|
expect(DOM.hasClass(el, 'very-active')).toEqual(true);
|
||||||
|
|
||||||
view.setElementClass(0, 'veryActive', false);
|
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);
|
expect(DOM.hasClass(el, 'very-active')).toEqual(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue