8f7b8a9d87
TBR=jacobr@google.com,alanknight@google.com Review URL: https://codereview.chromium.org/1914643002 .
480 lines
17 KiB
Plaintext
480 lines
17 KiB
Plaintext
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// WARNING: Do not edit - generated code.
|
|
|
|
part of $LIBRARYNAME;
|
|
|
|
$(ANNOTATIONS)$(NATIVESPEC)$(CLASS_MODIFIERS)class $CLASSNAME$EXTENDS$IMPLEMENTS {
|
|
$!MEMBERS
|
|
|
|
$if DART2JS
|
|
@DomName('Document.body')
|
|
BodyElement body;
|
|
$else
|
|
@DomName('Document.body')
|
|
BodyElement get body => _body;
|
|
|
|
@DomName('Document.body')
|
|
set body(BodyElement value) {
|
|
_body = value;
|
|
}
|
|
$endif
|
|
|
|
/// UNSTABLE: Chrome-only - create a Range from the given point.
|
|
@DomName('Document.caretRangeFromPoint')
|
|
@Unstable()
|
|
Range caretRangeFromPoint(int x, int y) {
|
|
return _caretRangeFromPoint(x, y);
|
|
}
|
|
|
|
@DomName('Document.elementFromPoint')
|
|
Element elementFromPoint(int x, int y) {
|
|
return _elementFromPoint(x, y);
|
|
}
|
|
|
|
/**
|
|
* Checks if the getCssCanvasContext API is supported on the current platform.
|
|
*
|
|
* See also:
|
|
*
|
|
* * [getCssCanvasContext]
|
|
*/
|
|
$if DART2JS
|
|
static bool get supportsCssCanvasContext =>
|
|
JS('bool', '!!(document.getCSSCanvasContext)');
|
|
$else
|
|
static bool get supportsCssCanvasContext => true;
|
|
$endif
|
|
|
|
|
|
/**
|
|
* Gets a CanvasRenderingContext which can be used as the CSS background of an
|
|
* element.
|
|
*
|
|
* CSS:
|
|
*
|
|
* background: -webkit-canvas(backgroundCanvas)
|
|
*
|
|
* Generate the canvas:
|
|
*
|
|
* var context = document.getCssCanvasContext('2d', 'backgroundCanvas',
|
|
* 100, 100);
|
|
* context.fillStyle = 'red';
|
|
* context.fillRect(0, 0, 100, 100);
|
|
*
|
|
* See also:
|
|
*
|
|
* * [supportsCssCanvasContext]
|
|
* * [CanvasElement.getContext]
|
|
*/
|
|
@SupportedBrowser(SupportedBrowser.CHROME)
|
|
@SupportedBrowser(SupportedBrowser.SAFARI)
|
|
@Experimental()
|
|
@DomName('Document.getCSSCanvasContext')
|
|
CanvasRenderingContext getCssCanvasContext(String contextId, String name,
|
|
int width, int height) {
|
|
return _getCssCanvasContext(contextId, name, width, height);
|
|
}
|
|
|
|
@DomName('Document.head')
|
|
HeadElement get head => _head;
|
|
|
|
@DomName('Document.lastModified')
|
|
String get lastModified => _lastModified;
|
|
|
|
@DomName('Document.preferredStylesheetSet')
|
|
String get preferredStylesheetSet => _preferredStylesheetSet;
|
|
|
|
@DomName('Document.referrer')
|
|
String get referrer => _referrer;
|
|
|
|
@DomName('Document.selectedStylesheetSet')
|
|
String get selectedStylesheetSet => _selectedStylesheetSet;
|
|
set selectedStylesheetSet(String value) {
|
|
_selectedStylesheetSet = value;
|
|
}
|
|
|
|
@DomName('Document.styleSheets')
|
|
List<StyleSheet> get styleSheets => _styleSheets;
|
|
|
|
@DomName('Document.title')
|
|
String get title => _title;
|
|
|
|
@DomName('Document.title')
|
|
set title(String value) {
|
|
_title = value;
|
|
}
|
|
|
|
/**
|
|
* Returns page to standard layout.
|
|
*
|
|
* Has no effect if the page is not in fullscreen mode.
|
|
*
|
|
* ## Other resources
|
|
*
|
|
* * [Using the fullscreen
|
|
* API](http://docs.webplatform.org/wiki/tutorials/using_the_full-screen_api)
|
|
* from WebPlatform.org.
|
|
* * [Fullscreen specification](http://www.w3.org/TR/fullscreen/) from W3C.
|
|
*/
|
|
@DomName('Document.webkitExitFullscreen')
|
|
@SupportedBrowser(SupportedBrowser.CHROME)
|
|
@SupportedBrowser(SupportedBrowser.SAFARI)
|
|
@Experimental()
|
|
void exitFullscreen() {
|
|
_webkitExitFullscreen();
|
|
}
|
|
|
|
$if DARTIUM
|
|
|
|
/**
|
|
* Internal routine to find the DOM JS class name being extended for custom
|
|
* elements.
|
|
*/
|
|
String _getJSClassName(ClassMirror classMirror) {
|
|
var jsClassName = null;
|
|
var isElement = false;
|
|
|
|
while (classMirror.superclass != null) {
|
|
var fullName = classMirror.superclass.qualifiedName;
|
|
isElement = isElement ||
|
|
(fullName == #dart.dom.html.Element || fullName == #dart.dom.svg.Element);
|
|
|
|
var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
|
|
if (jsClassName == null && domLibrary) {
|
|
// Lookup JS class name (if not found).
|
|
var metadatas = classMirror.metadata;
|
|
for (var metadata in metadatas) {
|
|
var metaDataMirror = metadata.reflectee;
|
|
var metaType = reflectClass(metaDataMirror.runtimeType);
|
|
if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
|
|
(metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
|
|
jsClassName = metadata.reflectee.name;
|
|
}
|
|
}
|
|
}
|
|
|
|
classMirror = classMirror.superclass;
|
|
}
|
|
|
|
// If we're an element then everything is okay.
|
|
return isElement ? jsClassName : null;
|
|
}
|
|
|
|
// Get the first class that's a super of a dart.dom library.
|
|
ClassMirror _getDartHtmlClassName(ClassMirror classMirror) {
|
|
while (classMirror.superclass != null) {
|
|
var fullName = classMirror.superclass.qualifiedName;
|
|
var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
|
|
if (domLibrary) {
|
|
return classMirror.superclass;
|
|
}
|
|
|
|
classMirror = classMirror.superclass;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Get the class that immediately derived from a class in dart:html or
|
|
* dart:svg (has an attribute DomName of either HTML* or SVG*).
|
|
*/
|
|
ClassMirror _getDomSuperClass(ClassMirror classMirror) {
|
|
var isElement = false;
|
|
var foundSuperElement = null;
|
|
|
|
while (classMirror.superclass != null) {
|
|
var fullName = classMirror.superclass.qualifiedName;
|
|
isElement = isElement || (fullName == #dart.dom.html.Element || fullName == #dart.dom.svg.Element);
|
|
|
|
var domLibrary = MirrorSystem.getName(fullName).startsWith('dart.dom.');
|
|
if (domLibrary) {
|
|
if (foundSuperElement == null) {
|
|
foundSuperElement = classMirror.superclass;
|
|
}
|
|
// Lookup JS class (if not found).
|
|
var metadatas = classMirror.metadata;
|
|
for (var metadata in metadatas) {
|
|
var metaDataMirror = metadata.reflectee;
|
|
var metaType = reflectClass(metaDataMirror.runtimeType);
|
|
if (MirrorSystem.getName(metaType.simpleName) == 'DomName' &&
|
|
(metaDataMirror.name.startsWith('HTML') || metaDataMirror.name.startsWith('SVG'))) {
|
|
if (isElement) return foundSuperElement;
|
|
}
|
|
}
|
|
}
|
|
|
|
classMirror = classMirror.superclass;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Does this CustomElement class have:
|
|
*
|
|
* - a created constructor with no arguments?
|
|
* - a created constructor with a super.created() initializer?
|
|
*
|
|
* e.g., MyCustomClass.created() : super.created();
|
|
*/
|
|
bool _hasCreatedConstructor(ClassMirror classToRegister) {
|
|
var htmlClassMirror = _getDomSuperClass(classToRegister);
|
|
|
|
var classMirror = classToRegister;
|
|
while (classMirror != null && classMirror != htmlClassMirror) {
|
|
var createdParametersValid = false;
|
|
var superCreatedCalled = false;
|
|
var className = MirrorSystem.getName(classMirror.simpleName);
|
|
var methodMirror = classMirror.declarations[new Symbol("$className.created")];
|
|
if (methodMirror != null && methodMirror.isConstructor) {
|
|
createdParametersValid = true; // Assume no parameters.
|
|
if (methodMirror.parameters.length != 0) {
|
|
// If any parameters each one must be optional.
|
|
methodMirror.parameters.forEach((parameter) {
|
|
createdParametersValid = createdParametersValid && parameter.isOptional;
|
|
});
|
|
}
|
|
}
|
|
|
|
if (!createdParametersValid) {
|
|
throw new DomException.jsInterop('created constructor must have no parameters');
|
|
}
|
|
|
|
classMirror = classMirror.superclass;
|
|
while (classMirror != classMirror.mixin) {
|
|
// Skip the mixins.
|
|
classMirror = classMirror.superclass;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
$endif
|
|
|
|
@Experimental()
|
|
/**
|
|
* Register a custom subclass of Element to be instantiatable by the DOM.
|
|
*
|
|
* This is necessary to allow the construction of any custom elements.
|
|
*
|
|
* The class being registered must either subclass HtmlElement or SvgElement.
|
|
* If they subclass these directly then they can be used as:
|
|
*
|
|
* class FooElement extends HtmlElement{
|
|
* void created() {
|
|
* print('FooElement created!');
|
|
* }
|
|
* }
|
|
*
|
|
* main() {
|
|
* document.registerElement('x-foo', FooElement);
|
|
* var myFoo = new Element.tag('x-foo');
|
|
* // prints 'FooElement created!' to the console.
|
|
* }
|
|
*
|
|
* The custom element can also be instantiated via HTML using the syntax
|
|
* `<x-foo></x-foo>`
|
|
*
|
|
* Other elements can be subclassed as well:
|
|
*
|
|
* class BarElement extends InputElement{
|
|
* void created() {
|
|
* print('BarElement created!');
|
|
* }
|
|
* }
|
|
*
|
|
* main() {
|
|
* document.registerElement('x-bar', BarElement);
|
|
* var myBar = new Element.tag('input', 'x-bar');
|
|
* // prints 'BarElement created!' to the console.
|
|
* }
|
|
*
|
|
* This custom element can also be instantiated via HTML using the syntax
|
|
* `<input is="x-bar"></input>`
|
|
*
|
|
*/
|
|
void registerElement(String tag, Type customElementClass,
|
|
{String extendsTag}) {
|
|
$if DART2JS
|
|
_registerCustomElement(JS('', 'window'), this, tag, customElementClass,
|
|
extendsTag);
|
|
$else
|
|
// Hack to setup an interceptor for HTMLElement so it isn't changed when a custom element is created.
|
|
var jsHTMLElementPrototype = js.JsNative.getProperty(js.JsNative.getProperty(js.context, 'HTMLElement'),'prototype');
|
|
_blink.Blink_Utils.defineInterceptor(jsHTMLElementPrototype, HtmlElement.instanceRuntimeType);
|
|
|
|
// Figure out which DOM class is being extended from the user's Dart class.
|
|
var classMirror = reflectClass(customElementClass);
|
|
|
|
var locationUri = classMirror.location.sourceUri.toString();
|
|
if (locationUri == 'dart:html' || locationUri == 'dart:svg') {
|
|
throw new DomException.jsInterop("HierarchyRequestError: Cannot register an existing dart:html or dart:svg type.");
|
|
}
|
|
|
|
if (classMirror.isAbstract) {
|
|
throw new DomException.jsInterop("HierarchyRequestError: Cannot register an abstract class.");
|
|
}
|
|
|
|
var jsClassName = _getJSClassName(classMirror);
|
|
if (jsClassName == null) {
|
|
// Only components derived from HTML* can be extended.
|
|
throw new DomException.jsInterop("HierarchyRequestError: Only HTML elements can be customized.");
|
|
}
|
|
|
|
var customClassType = _getDartHtmlClassName(classMirror);
|
|
|
|
if (extendsTag != null) {
|
|
var nativeElement = document.createElement(extendsTag);
|
|
|
|
// Trying to extend a native element is it the Dart class consistent with the
|
|
// extendsTag?
|
|
if (nativeElement.runtimeType != customClassType.reflectedType) {
|
|
var nativeElementClassMirror = reflectClass(nativeElement.runtimeType);
|
|
var customClassNativeElement = MirrorSystem.getName(customClassType.simpleName);
|
|
var extendsNativeElement = MirrorSystem.getName(nativeElementClassMirror.simpleName);
|
|
throw new DomException.jsInterop("HierarchyRequestError: Custom class type ($customClassNativeElement) and extendsTag class ($extendsNativeElement) don't match .");
|
|
}
|
|
} else if (customClassType.reflectedType != HtmlElement && customClassType.reflectedType != svg.SvgElement) {
|
|
var customClassName = MirrorSystem.getName(classMirror.simpleName);
|
|
var customClassElement = MirrorSystem.getName(customClassType.simpleName);
|
|
throw new DomException.jsInterop("HierarchyRequestError: Custom element $customClassName is a native $customClassElement should be derived from HtmlElement or SvgElement.");
|
|
}
|
|
|
|
if (_hasCreatedConstructor(classMirror)) {
|
|
// Start the hookup the JS way create an <x-foo> element that extends the
|
|
// <x-base> custom element. Inherit its prototype and signal what tag is
|
|
// inherited:
|
|
//
|
|
// var myProto = Object.create(HTMLElement.prototype);
|
|
// var myElement = document.registerElement('x-foo', {prototype: myProto});
|
|
var baseElement = js.JsNative.getProperty(js.context, jsClassName);
|
|
if (baseElement == null) {
|
|
// Couldn't find the HTML element so use a generic one.
|
|
baseElement = js.JsNative.getProperty(js.context, 'HTMLElement');
|
|
}
|
|
var elemProto = js.JsNative.callMethod(js.JsNative.getProperty(js.context, 'Object'), "create", [js.JsNative.getProperty(baseElement, 'prototype')]);
|
|
|
|
// TODO(terry): Hack to stop recursion re-creating custom element when the
|
|
// created() constructor of the custom element does e.g.,
|
|
//
|
|
// MyElement.created() : super.created() {
|
|
// this.innerHtml = "<b>I'm an x-foo-with-markup!</b>";
|
|
// }
|
|
//
|
|
// sanitizing causes custom element to created recursively
|
|
// until stack overflow.
|
|
//
|
|
// See https://github.com/dart-lang/sdk/issues/23666
|
|
int creating = 0; // TODO(jacobr): I think I broke thise case. Will fix monday.
|
|
|
|
// If any JS code is hooked we want to call it too.
|
|
var oldCreatedCallback = js.JsNative.getProperty(elemProto, 'createdCallback');
|
|
var oldAttributeChangedCallback = js.JsNative.getProperty(elemProto, 'attributeChangedCallback');
|
|
var oldAttachedCallback = js.JsNative.getProperty(elemProto, 'attachedCallback');
|
|
var oldDetachedCallback = js.JsNative.getProperty(elemProto, 'detachedCallback');
|
|
|
|
js.JsNative.setProperty(elemProto, 'createdCallback', js.allowInteropCaptureThis(($this) {
|
|
// The created callback has already been called by the very act of passing a JS
|
|
// custom element from JS to Dart.
|
|
|
|
// Make element's interceptor a CustomElementClass.
|
|
_blink.Blink_Utils.setInstanceInterceptorCustomUpgrade($this);
|
|
|
|
if (oldCreatedCallback != null)
|
|
oldCreatedCallback.apply([], thisArg: $this);
|
|
}));
|
|
js.JsNative.setProperty(elemProto, 'attributeChangedCallback', js.allowInteropCaptureThis(($this, attrName, oldVal, newVal) {
|
|
$this.attributeChanged(attrName, oldVal, newVal);
|
|
|
|
if (oldAttributeChangedCallback != null)
|
|
oldAttributeChangedCallback.apply([], thisArg: $this);
|
|
}));
|
|
js.JsNative.setProperty(elemProto, 'attachedCallback', js.allowInteropCaptureThis(($this) {
|
|
$this.attached();
|
|
|
|
if (oldAttachedCallback != null)
|
|
oldAttachedCallback.apply([], thisArg: $this);
|
|
}));
|
|
js.JsNative.setProperty(elemProto, 'detachedCallback', js.allowInteropCaptureThis(($this) {
|
|
$this.detached();
|
|
|
|
if (oldDetachedCallback != null)
|
|
oldDetachedCallback.apply([], thisArg: $this);
|
|
}));
|
|
// document.registerElement('x-foo', {prototype: elemProto, extends: extendsTag});
|
|
var jsMap = new js.JsObject.jsify({'prototype': elemProto, 'extends': extendsTag});
|
|
_blink.Blink_Utils.defineInterceptorCustomElement(elemProto, customElementClass);
|
|
js.JsNative.callMethod(document, 'registerElement', [tag, jsMap]);
|
|
}
|
|
$endif
|
|
}
|
|
|
|
/** *Deprecated*: use [registerElement] instead. */
|
|
@deprecated
|
|
@Experimental()
|
|
void register(String tag, Type customElementClass, {String extendsTag}) {
|
|
return registerElement(tag, customElementClass, extendsTag: extendsTag);
|
|
}
|
|
|
|
/**
|
|
* Static factory designed to expose `visibilitychange` events to event
|
|
* handlers that are not necessarily instances of [Document].
|
|
*
|
|
* See [EventStreamProvider] for usage information.
|
|
*/
|
|
@DomName('Document.visibilityChange')
|
|
@SupportedBrowser(SupportedBrowser.CHROME)
|
|
@SupportedBrowser(SupportedBrowser.FIREFOX)
|
|
@SupportedBrowser(SupportedBrowser.IE, '10')
|
|
@Experimental()
|
|
static const EventStreamProvider<Event> visibilityChangeEvent =
|
|
const _CustomEventStreamProvider<Event>(
|
|
_determineVisibilityChangeEventType);
|
|
|
|
static String _determineVisibilityChangeEventType(EventTarget e) {
|
|
$if DART2JS
|
|
if (JS('bool', '(typeof #.hidden !== "undefined")', e)) {
|
|
// Opera 12.10 and Firefox 18 and later support
|
|
return 'visibilitychange';
|
|
} else if (JS('bool', '(typeof #.mozHidden !== "undefined")', e)) {
|
|
return 'mozvisibilitychange';
|
|
} else if (JS('bool', '(typeof #.msHidden !== "undefined")', e)) {
|
|
return 'msvisibilitychange';
|
|
} else if (JS('bool', '(typeof #.webkitHidden !== "undefined")', e)) {
|
|
return 'webkitvisibilitychange';
|
|
}
|
|
return 'visibilitychange';
|
|
$else
|
|
return 'webkitvisibilitychange';
|
|
$endif
|
|
}
|
|
|
|
@SupportedBrowser(SupportedBrowser.CHROME)
|
|
@SupportedBrowser(SupportedBrowser.FIREFOX)
|
|
@SupportedBrowser(SupportedBrowser.IE, '10')
|
|
@Experimental()
|
|
Stream<Event> get onVisibilityChange =>
|
|
visibilityChangeEvent.forTarget(this);
|
|
|
|
/// Creates an element upgrader which can be used to change the Dart wrapper
|
|
/// type for elements.
|
|
///
|
|
/// The type specified must be a subclass of HtmlElement, when an element is
|
|
/// upgraded then the created constructor will be invoked on that element.
|
|
///
|
|
/// If the type is not a direct subclass of HtmlElement then the extendsTag
|
|
/// parameter must be provided.
|
|
@Experimental()
|
|
ElementUpgrader createElementUpgrader(Type type, {String extendsTag}) {
|
|
$if DART2JS
|
|
return new _JSElementUpgrader(this, type, extendsTag);
|
|
$else
|
|
return new _VMElementUpgrader(this, type, extendsTag);
|
|
$endif
|
|
}
|
|
}
|