-
Notifications
You must be signed in to change notification settings - Fork 248
Shadowless DOM #936
Shadowless DOM #936
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,24 @@ part of angular.core.dom_internal; | |
|
||
abstract class ComponentFactory { | ||
FactoryFn call(dom.Node node, DirectiveRef ref); | ||
|
||
static _viewFuture(Component component, ViewCache viewCache, DirectiveMap directives) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. return type ? (Future) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
if (component.template != null) { | ||
return new async.Future.value(viewCache.fromHtml(component.template, directives)); | ||
} else if (component.templateUrl != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. else is not required here |
||
return viewCache.fromUrl(component.templateUrl, directives); | ||
} | ||
return null; | ||
} | ||
|
||
static TemplateLoader _setupOnShadowDomAttach(controller, templateLoader, shadowScope) { | ||
if (controller is ShadowRootAware) { | ||
templateLoader.template.then((shadowDom) { | ||
if (!shadowScope.isAttached) return; | ||
(controller as ShadowRootAware).onShadowRoot(shadowDom); | ||
}); | ||
} | ||
} | ||
} | ||
|
||
class ShadowDomComponentFactory implements ComponentFactory { | ||
|
@@ -12,7 +30,6 @@ class ShadowDomComponentFactory implements ComponentFactory { | |
FactoryFn call(dom.Node node, DirectiveRef ref) { | ||
return (Injector injector) { | ||
var component = ref.annotation as Component; | ||
Compiler compiler = injector.get(Compiler); | ||
Scope scope = injector.get(Scope); | ||
ViewCache viewCache = injector.get(ViewCache); | ||
Http http = injector.get(Http); | ||
|
@@ -78,13 +95,7 @@ class _ComponentFactory implements Function { | |
} else { | ||
cssFutures.add(new async.Future.value(null)); | ||
} | ||
var viewFuture; | ||
if (component.template != null) { | ||
viewFuture = new async.Future.value(viewCache.fromHtml( | ||
component.template, directives)); | ||
} else if (component.templateUrl != null) { | ||
viewFuture = viewCache.fromUrl(component.templateUrl, directives); | ||
} | ||
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives); | ||
TemplateLoader templateLoader = new TemplateLoader( | ||
async.Future.wait(cssFutures).then((Iterable<String> cssList) { | ||
if (cssList != null) { | ||
|
@@ -98,19 +109,14 @@ class _ComponentFactory implements Function { | |
if (viewFuture != null) { | ||
return viewFuture.then((ViewFactory viewFactory) { | ||
return (!shadowScope.isAttached) ? | ||
shadowDom : | ||
attachViewToShadowDom(viewFactory); | ||
shadowDom : | ||
attachViewToShadowDom(viewFactory); | ||
}); | ||
} | ||
return shadowDom; | ||
})); | ||
controller = createShadowInjector(injector, templateLoader).get(type); | ||
if (controller is ShadowRootAware) { | ||
templateLoader.template.then((_) { | ||
if (!shadowScope.isAttached) return; | ||
(controller as ShadowRootAware).onShadowRoot(shadowDom); | ||
}); | ||
} | ||
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); | ||
return controller; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
part of angular.core.dom_internal; | ||
|
||
@proxy | ||
class ShadowlessShadowRoot implements dom.ShadowRoot { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ShadowRoot extends DocumentFragment and doesn't add too much more- perhaps just use DocumentFragment instead? Alternatively this may be a good case for a custom element. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is used in onShadowRoot, which needs to be renamed. We'll rework this later. |
||
dom.Element _element; | ||
|
||
ShadowlessShadowRoot(this._element); | ||
|
||
noSuchMethod(Invocation invocation) { | ||
throw new UnimplementedError("Not yet implemented in ShadowlessShadowRoot."); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
part of angular.core.dom_internal; | ||
|
||
@Decorator( | ||
selector: 'content' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 4ws, ")" on the same line - same remarks further below There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. below where? |
||
) | ||
class _Content implements AttachAware, DetachAware { | ||
final _ContentPort _port; | ||
final dom.Element _element; | ||
dom.Comment _beginComment; | ||
_Content(this._port, this._element); | ||
|
||
attach() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. void (for detach also) |
||
if (_port == null) return; | ||
_beginComment = _port.content(_element); | ||
} | ||
|
||
detach() { | ||
if (_port == null) return; | ||
_port.detachContent(_beginComment); | ||
} | ||
} | ||
|
||
class _ContentPort { | ||
dom.Element _element; | ||
var _childNodes = []; | ||
|
||
_ContentPort(this._element); | ||
|
||
pullNodes() { | ||
_element.nodes.forEach((n) => _childNodes.add(n)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would addAll() work here ? |
||
_element.nodes = []; | ||
} | ||
|
||
content(dom.Element elt) { | ||
var hash = elt.hashCode; | ||
var beginComment = new dom.Comment("content $hash"); | ||
|
||
if (!_childNodes.isEmpty) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isNotEmpty |
||
elt.parent.insertBefore(beginComment, elt); | ||
elt.parent.insertAllBefore(_childNodes, elt); | ||
elt.parent.insertBefore(new dom.Comment("end-content $hash"), elt); | ||
_childNodes = []; | ||
} | ||
elt.remove(); | ||
return beginComment; | ||
} | ||
|
||
detachContent(dom.Node _beginComment) { | ||
// Search for endComment and extract everything in between. | ||
// TODO optimize -- there may be a better way of pulling out nodes. | ||
|
||
var endCommentText = "end-${_beginComment.text}"; | ||
|
||
var next; | ||
for (next = _beginComment.nextNode; | ||
next.nodeType != dom.Node.COMMENT_NODE && next.text != endCommentText; | ||
next = _beginComment.nextNode) { | ||
_childNodes.add(next); | ||
next.remove(); | ||
} | ||
assert(next.nodeType == dom.Node.COMMENT_NODE && next.text == endCommentText); | ||
next.remove(); | ||
} | ||
} | ||
|
||
class TranscludingComponentFactory implements ComponentFactory { | ||
final Expando _expando; | ||
|
||
TranscludingComponentFactory(this._expando); | ||
|
||
FactoryFn call(dom.Node node, DirectiveRef ref) { | ||
// CSS is not supported. | ||
assert((ref.annotation as Component).cssUrls == null || | ||
(ref.annotation as Component).cssUrls.isEmpty); | ||
|
||
var element = node as dom.Element; | ||
return (Injector injector) { | ||
var childInjector; | ||
var component = ref.annotation as Component; | ||
Scope scope = injector.get(Scope); | ||
ViewCache viewCache = injector.get(ViewCache); | ||
Http http = injector.get(Http); | ||
TemplateCache templateCache = injector.get(TemplateCache); | ||
DirectiveMap directives = injector.get(DirectiveMap); | ||
NgBaseCss baseCss = injector.get(NgBaseCss); | ||
|
||
var contentPort = new _ContentPort(element); | ||
|
||
// Append the component's template as children | ||
var viewFuture = ComponentFactory._viewFuture(component, viewCache, directives); | ||
|
||
if (viewFuture != null) { | ||
viewFuture = viewFuture.then((ViewFactory viewFactory) { | ||
contentPort.pullNodes(); | ||
element.nodes.addAll(viewFactory(childInjector).nodes); | ||
return element; | ||
}); | ||
} else { | ||
viewFuture = new async.Future.microtask(() => contentPort.pullNodes()); | ||
} | ||
TemplateLoader templateLoader = new TemplateLoader(viewFuture); | ||
|
||
Scope shadowScope = scope.createChild({}); | ||
|
||
var probe; | ||
var childModule = new Module() | ||
..type(ref.type) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. indent |
||
..type(NgElement) | ||
..value(_ContentPort, contentPort) | ||
..value(Scope, shadowScope) | ||
..value(TemplateLoader, templateLoader) | ||
..value(dom.ShadowRoot, new ShadowlessShadowRoot(element)) | ||
..factory(ElementProbe, (_) => probe); | ||
childInjector = injector.createChild([childModule], name: SHADOW_DOM_INJECTOR_NAME); | ||
|
||
var controller = childInjector.get(ref.type); | ||
shadowScope.context[component.publishAs] = controller; | ||
ComponentFactory._setupOnShadowDomAttach(controller, templateLoader, shadowScope); | ||
return controller; | ||
}; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,3 +35,5 @@ class NgTemplate { | |
? (element as dom.TemplateElement).content.innerHtml | ||
: element.innerHtml)); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should you update
_cloneWithNewMap
below ?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch! I wrote a test for this in 0c797cc
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor thing is also to update class level docs "Angular components use shadow-DOM for rendering their templates"