mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add a basic sky-element custom element
After this CL, you can use <sky-element> to describe custom elements. The current iteration is very basic and is hardcoded to "example", but its a start. This CL renames the |init| function to |_init| to prevent importers from calling it directly. Also, we now pass the <script> element to |_init| to give some context. R=ojan@chromium.org, eseidel@chromium.org Review URL: https://codereview.chromium.org/950493003
This commit is contained in:
parent
58bfcf3a8f
commit
16db84fde1
@ -115,8 +115,11 @@ void HTMLScriptRunner::executeLibrary(RefPtr<AbstractModule> module,
|
||||
// or script failures, etc.
|
||||
Microtask::performCheckpoint();
|
||||
|
||||
if (LocalFrame* frame = contextFrame(m_element.get()))
|
||||
frame->dart().ExecuteLibraryInModule(module.get(), library->dart_value());
|
||||
if (LocalFrame* frame = contextFrame(m_element.get())) {
|
||||
frame->dart().ExecuteLibraryInModule(module.get(),
|
||||
library->dart_value(),
|
||||
m_element.get());
|
||||
}
|
||||
|
||||
advanceTo(StateCompleted);
|
||||
// We may be deleted at this point.
|
||||
|
||||
@ -16,6 +16,7 @@
|
||||
#include "sky/engine/core/app/Module.h"
|
||||
#include "sky/engine/core/dom/Element.h"
|
||||
#include "sky/engine/core/frame/LocalFrame.h"
|
||||
#include "sky/engine/core/html/HTMLScriptElement.h"
|
||||
#include "sky/engine/core/html/imports/HTMLImport.h"
|
||||
#include "sky/engine/core/html/imports/HTMLImportChild.h"
|
||||
#include "sky/engine/core/loader/FrameLoaderClient.h"
|
||||
@ -29,6 +30,7 @@
|
||||
#include "sky/engine/tonic/dart_gc_controller.h"
|
||||
#include "sky/engine/tonic/dart_isolate_scope.h"
|
||||
#include "sky/engine/tonic/dart_state.h"
|
||||
#include "sky/engine/tonic/dart_wrappable.h"
|
||||
#include "sky/engine/wtf/text/TextPosition.h"
|
||||
|
||||
namespace blink {
|
||||
@ -122,7 +124,8 @@ void DartController::LoadScriptInModule(
|
||||
}
|
||||
|
||||
void DartController::ExecuteLibraryInModule(AbstractModule* module,
|
||||
Dart_Handle library) {
|
||||
Dart_Handle library,
|
||||
HTMLScriptElement* script) {
|
||||
ASSERT(library);
|
||||
DCHECK(Dart_CurrentIsolate() == dart_state()->isolate());
|
||||
DartApiScope dart_api_scope;
|
||||
@ -130,16 +133,23 @@ void DartController::ExecuteLibraryInModule(AbstractModule* module,
|
||||
// Don't continue if we failed to load the module.
|
||||
if (LogIfError(Dart_FinalizeLoading(true)))
|
||||
return;
|
||||
const char* name = module->isApplication() ? "main" : "init";
|
||||
const char* name = module->isApplication() ? "main" : "_init";
|
||||
|
||||
// main() is required, but init() is not:
|
||||
// TODO(rmacnak): Dart_LookupFunction won't find re-exports, etc.
|
||||
Dart_Handle entry = Dart_LookupFunction(library, ToDart(name));
|
||||
if (!Dart_IsFunction(entry) && !module->isApplication())
|
||||
if (module->isApplication()) {
|
||||
LogIfError(Dart_Invoke(library, ToDart(name), 0, nullptr));
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Dart_IsFunction(entry))
|
||||
return;
|
||||
|
||||
Dart_Handle result = Dart_Invoke(library, ToDart(name), 0, nullptr);
|
||||
LogIfError(result);
|
||||
Dart_Handle args[] = {
|
||||
ToDart(script),
|
||||
};
|
||||
LogIfError(Dart_Invoke(library, ToDart(name), arraysize(args), args));
|
||||
}
|
||||
|
||||
static void UnhandledExceptionCallback(Dart_Handle error) {
|
||||
|
||||
@ -16,8 +16,9 @@ namespace blink {
|
||||
class AbstractModule;
|
||||
class BuiltinSky;
|
||||
class DOMDartState;
|
||||
class Document;
|
||||
class DartValue;
|
||||
class Document;
|
||||
class HTMLScriptElement;
|
||||
|
||||
class DartController {
|
||||
public:
|
||||
@ -33,7 +34,9 @@ class DartController {
|
||||
const String& source,
|
||||
const TextPosition& textPosition,
|
||||
const LoadFinishedCallback& load_finished_callback);
|
||||
void ExecuteLibraryInModule(AbstractModule* module, Dart_Handle library);
|
||||
void ExecuteLibraryInModule(AbstractModule* module,
|
||||
Dart_Handle library,
|
||||
HTMLScriptElement* script);
|
||||
|
||||
void ClearForClose();
|
||||
void CreateIsolateFor(Document* document);
|
||||
|
||||
25
examples/example-element/example-element.sky
Normal file
25
examples/example-element/example-element.sky
Normal file
@ -0,0 +1,25 @@
|
||||
<!--
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
-->
|
||||
<import src="/sky/framework/sky-element.sky" />
|
||||
<sky-element>
|
||||
<template>
|
||||
<style>
|
||||
div {
|
||||
height: 50px;
|
||||
width: 50px;
|
||||
background-color: green;
|
||||
}
|
||||
</style>
|
||||
<div>Hi</div>
|
||||
</template>
|
||||
<script>
|
||||
@Tagname('example')
|
||||
class ExampleElement extends SkyElement {
|
||||
}
|
||||
|
||||
_init(script) => register(script, ExampleElement);
|
||||
</script>
|
||||
</sky-element>
|
||||
16
examples/example-element/index.sky
Normal file
16
examples/example-element/index.sky
Normal file
@ -0,0 +1,16 @@
|
||||
<!--
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
-->
|
||||
<sky>
|
||||
<import src="example-element.sky" />
|
||||
<style>
|
||||
example {
|
||||
border: 1px solid blue;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
}
|
||||
</style>
|
||||
<example />
|
||||
</sky>
|
||||
85
framework/sky-element.sky
Normal file
85
framework/sky-element.sky
Normal file
@ -0,0 +1,85 @@
|
||||
<!--
|
||||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
-->
|
||||
<script>
|
||||
import "dart:mirrors";
|
||||
import "dart:sky";
|
||||
|
||||
class _Registration {
|
||||
Element template;
|
||||
_Registration(this.template);
|
||||
}
|
||||
|
||||
final Map<String, _Registration> _registery = new Map<String, _Registration>();
|
||||
|
||||
class Tagname {
|
||||
final String name;
|
||||
const Tagname(this.name);
|
||||
}
|
||||
|
||||
String _getTagName(Type type) {
|
||||
return reflectClass(type).metadata.firstWhere(
|
||||
(i) => i.reflectee is Tagname).reflectee.name;
|
||||
}
|
||||
|
||||
abstract class SkyElement extends Element {
|
||||
// Override these functions to receive lifecycle notifications.
|
||||
void created() {}
|
||||
void attached() {}
|
||||
void detached() {}
|
||||
void attributeChanged(String attrName, String oldValue, String newValue) {}
|
||||
void shadowRootReady() {}
|
||||
|
||||
String get tagName => _getTagName(runtimeType);
|
||||
|
||||
// TODO(abarth): Rather than hard-coding "example" here, we should make the
|
||||
// bindings read the |tagName| property of this object during construction.
|
||||
SkyElement() : super("example") {
|
||||
created();
|
||||
|
||||
// Invoke attributeChanged callback when element is first created too.
|
||||
for (Attr attribute in getAttributes())
|
||||
attributeChangedCallback(attribute.name, null, attribute.value);
|
||||
}
|
||||
|
||||
attachedCallback() {
|
||||
if (shadowRoot == null) {
|
||||
var registration = _registery[tagName];
|
||||
if (registration.template != null) {
|
||||
ShadowRoot shadow = ensureShadowRoot();
|
||||
var tree = registration.template.content.cloneNode(deep:true);
|
||||
shadow.appendChild(tree);
|
||||
shadowRootReady();
|
||||
}
|
||||
}
|
||||
attached();
|
||||
}
|
||||
|
||||
detachedCallback() {
|
||||
detached();
|
||||
}
|
||||
|
||||
attributeChangedCallback(name, oldValue, newValue) {
|
||||
attributeChanged(name, oldValue, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
void register(Element script, Type type) {
|
||||
Element definition = script.parentNode;
|
||||
|
||||
if (definition.tagName != 'sky-element')
|
||||
throw new UnsupportedError('register() calls must be inside a <sky-element>.');
|
||||
|
||||
ClassMirror mirror = reflectClass(type);
|
||||
if (!mirror.isSubclassOf(reflectClass(SkyElement)))
|
||||
throw new UnsupportedError('@Tagname can only be used on descendants of SkyElement');
|
||||
|
||||
String tagName = _getTagName(type);
|
||||
Element template = definition.querySelector('template');
|
||||
|
||||
document.registerElement(tagName, type);
|
||||
_registery[tagName] = new _Registration(template);
|
||||
}
|
||||
</script>
|
||||
@ -2,7 +2,7 @@
|
||||
<script>
|
||||
final String one = 'one';
|
||||
bool oneInit = false;
|
||||
void init() {
|
||||
void _init(_) {
|
||||
oneInit = true;
|
||||
}
|
||||
final conflict = 'one';
|
||||
@ -10,7 +10,7 @@ final conflict = 'one';
|
||||
<script>
|
||||
final String two = 'two';
|
||||
bool twoInit = false;
|
||||
void init() {
|
||||
void _init(_) {
|
||||
twoInit = true;
|
||||
}
|
||||
final conflict = 'two';
|
||||
|
||||
@ -6,7 +6,7 @@ class TestClass extends base.BaseClass {
|
||||
|
||||
bool didInit = false;
|
||||
|
||||
void init() {
|
||||
void _init(_) {
|
||||
didInit = (new TestClass() != null);
|
||||
}
|
||||
</script>
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
import "dart:sky";
|
||||
import "dart:sky.internals" as internals;
|
||||
|
||||
void init() {
|
||||
void _init(_) {
|
||||
window.addEventListener('load', (_) {
|
||||
internals.notifyTestComplete(DomSerializer.serializeNode(document));
|
||||
});
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
import "dart:sky" as sky;
|
||||
import "dart:sky.internals" as internals;
|
||||
|
||||
void init() {
|
||||
void _init(_) {
|
||||
sky.window.addEventListener('load', (_) =>
|
||||
internals.notifyTestComplete(internals.renderTreeAsText()));
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ void handleLoadEvent(event) {
|
||||
internals.notifyTestComplete(internals.contentAsText());
|
||||
}
|
||||
|
||||
void init() {
|
||||
void _init(_) {
|
||||
sky.window.addEventListener('load', handleLoadEvent);
|
||||
}
|
||||
</script>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user