parent
cdb1e82216
commit
3395624cb3
|
@ -1,4 +1,4 @@
|
||||||
import {isBlank, isPresent} from 'facade/src/lang';
|
import {isBlank, isPresent, BaseException} from 'facade/src/lang';
|
||||||
import {DOM, TemplateElement} from 'facade/src/dom';
|
import {DOM, TemplateElement} from 'facade/src/dom';
|
||||||
import {MapWrapper, ListWrapper} from 'facade/src/collection';
|
import {MapWrapper, ListWrapper} from 'facade/src/collection';
|
||||||
|
|
||||||
|
@ -7,6 +7,9 @@ import {Parser} from 'change_detection/change_detection';
|
||||||
import {CompileStep} from './compile_step';
|
import {CompileStep} from './compile_step';
|
||||||
import {CompileElement} from './compile_element';
|
import {CompileElement} from './compile_element';
|
||||||
import {CompileControl} from './compile_control';
|
import {CompileControl} from './compile_control';
|
||||||
|
import {StringWrapper} from 'facade/src/lang';
|
||||||
|
|
||||||
|
import {$BANG} from 'change_detection/src/parser/lexer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Splits views at `<template>` elements or elements with `template` attribute:
|
* Splits views at `<template>` elements or elements with `template` attribute:
|
||||||
|
@ -51,8 +54,26 @@ export class ViewSplitter extends CompileStep {
|
||||||
control.addChild(viewRoot);
|
control.addChild(viewRoot);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var templateBindings = MapWrapper.get(current.attrs(), 'template');
|
var attrs = current.attrs();
|
||||||
if (isPresent(templateBindings)) {
|
var templateBindings = MapWrapper.get(attrs, 'template');
|
||||||
|
var hasTemplateBinding = isPresent(templateBindings);
|
||||||
|
|
||||||
|
// look for template shortcuts such as !if="condition" and treat them as template="if condition"
|
||||||
|
MapWrapper.forEach(attrs, (attrValue, attrName) => {
|
||||||
|
if (StringWrapper.charCodeAt(attrName, 0) == $BANG) {
|
||||||
|
var key = StringWrapper.substring(attrName, 1); // remove the bang
|
||||||
|
if (hasTemplateBinding) {
|
||||||
|
// 2nd template binding detected
|
||||||
|
throw new BaseException(`Only one template directive per element is allowed: ` +
|
||||||
|
`${templateBindings} and ${key} cannot be used simultaneously!`);
|
||||||
|
} else {
|
||||||
|
templateBindings = (attrValue.length == 0) ? key : key + ' ' + attrValue;
|
||||||
|
hasTemplateBinding = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (hasTemplateBinding) {
|
||||||
var newParent = new CompileElement(DOM.createTemplate(''));
|
var newParent = new CompileElement(DOM.createTemplate(''));
|
||||||
current.isViewRoot = true;
|
current.isViewRoot = true;
|
||||||
this._parseTemplateBindings(templateBindings, newParent);
|
this._parseTemplateBindings(templateBindings, newParent);
|
||||||
|
|
|
@ -100,5 +100,78 @@ export function main() {
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('elements with !directive_name attribute', () => {
|
||||||
|
|
||||||
|
it('should replace the element with an empty <template> element', () => {
|
||||||
|
var rootElement = el('<div><span !if></span></div>');
|
||||||
|
var originalChild = rootElement.childNodes[0];
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
expect(results[0].element).toBe(rootElement);
|
||||||
|
expect(DOM.getOuterHTML(results[0].element)).toEqual('<div><template if=""></template></div>');
|
||||||
|
expect(DOM.getOuterHTML(results[2].element)).toEqual('<span !if=""></span>')
|
||||||
|
expect(results[2].element).toBe(originalChild);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should mark the element as viewRoot', () => {
|
||||||
|
var rootElement = el('<div><div !foo="bar"></div></div>');
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
expect(results[2].isViewRoot).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should work with top-level template node', () => {
|
||||||
|
var rootElement = DOM.createTemplate('<div !foo>x</div>');
|
||||||
|
var originalChild = rootElement.content.childNodes[0];
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
|
||||||
|
expect(results[0].element).toBe(rootElement);
|
||||||
|
expect(results[0].isViewRoot).toBe(true);
|
||||||
|
expect(results[2].isViewRoot).toBe(true);
|
||||||
|
expect(DOM.getOuterHTML(results[0].element)).toEqual('<template><template foo=""></template></template>');
|
||||||
|
expect(results[2].element).toBe(originalChild);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add property bindings from the template attribute', () => {
|
||||||
|
var rootElement = el('<div><div !prop="expr"></div></div>');
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
expect(MapWrapper.get(results[1].propertyBindings, 'prop').source).toEqual('expr');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add variable mappings from the template attribute', () => {
|
||||||
|
var rootElement = el('<div><div !foreach="var varName=mapName"></div></div>');
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
expect(results[1].variableBindings).toEqual(MapWrapper.createFromStringMap({'mapName': 'varName'}));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add entries without value as attribute to the element', () => {
|
||||||
|
var rootElement = el('<div><div !varname></div></div>');
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
expect(results[1].attrs()).toEqual(MapWrapper.createFromStringMap({'varname': ''}));
|
||||||
|
expect(results[1].propertyBindings).toBe(null);
|
||||||
|
expect(results[1].variableBindings).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should iterate properly after a template dom modification', () => {
|
||||||
|
var rootElement = el('<div><div !foo></div><after></after></div>');
|
||||||
|
var results = createPipeline().process(rootElement);
|
||||||
|
// 1 root + 2 initial + 1 generated template elements
|
||||||
|
expect(results.length).toEqual(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow multiple template directives on the same element', () => {
|
||||||
|
expect( () => {
|
||||||
|
var rootElement = el('<div><div !foo !bar="blah"></div></div>');
|
||||||
|
createPipeline().process(rootElement);
|
||||||
|
}).toThrowError('Only one template directive per element is allowed: foo and bar cannot be used simultaneously!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not allow template and bang directives on the same element', () => {
|
||||||
|
expect( () => {
|
||||||
|
var rootElement = el('<div><div !foo template="blah"></div></div>');
|
||||||
|
createPipeline().process(rootElement);
|
||||||
|
}).toThrowError('Only one template directive per element is allowed: blah and foo cannot be used simultaneously!');
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,6 +61,10 @@ class StringWrapper {
|
||||||
static String replaceAll(String s, RegExp from, String replace) {
|
static String replaceAll(String s, RegExp from, String replace) {
|
||||||
return s.replaceAll(from, replace);
|
return s.replaceAll(from, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static String substring(String s, int start, [int end]) {
|
||||||
|
return s.substring(start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StringJoiner {
|
class StringJoiner {
|
||||||
|
|
|
@ -67,6 +67,10 @@ export class StringWrapper {
|
||||||
static replaceAll(s:string, from:RegExp, replace:string):string {
|
static replaceAll(s:string, from:RegExp, replace:string):string {
|
||||||
return s.replace(from.multiple, replace);
|
return s.replace(from.multiple, replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static substring(s:string, start:int, end:int = undefined) {
|
||||||
|
return s.substring(start, end);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StringJoiner {
|
export class StringJoiner {
|
||||||
|
|
Loading…
Reference in New Issue