chore: move core modules into core directory
BREAKING CHANGE: This change moves the http module into angular2/, so its import path is now angular2/http instead of http/http. Many other modules have also been moved around inside of angular2, but the public API paths have not changed as of this commit.
This commit is contained in:
468
modules/angular2/src/core/dom/browser_adapter.dart
Normal file
468
modules/angular2/src/core/dom/browser_adapter.dart
Normal file
@ -0,0 +1,468 @@
|
||||
library angular.core.facade.dom;
|
||||
|
||||
import 'dart:html';
|
||||
import 'dom_adapter.dart' show setRootDomAdapter;
|
||||
import 'generic_browser_adapter.dart' show GenericBrowserDomAdapter;
|
||||
import '../facade/browser.dart';
|
||||
import 'dart:js' as js;
|
||||
|
||||
// WARNING: Do not expose outside this class. Parsing HTML using this
|
||||
// sanitizer is a security risk.
|
||||
class _IdentitySanitizer implements NodeTreeSanitizer {
|
||||
void sanitizeTree(Node node) {}
|
||||
}
|
||||
|
||||
final _identitySanitizer = new _IdentitySanitizer();
|
||||
|
||||
final _keyCodeToKeyMap = const {
|
||||
8: 'Backspace',
|
||||
9: 'Tab',
|
||||
12: 'Clear',
|
||||
13: 'Enter',
|
||||
16: 'Shift',
|
||||
17: 'Control',
|
||||
18: 'Alt',
|
||||
19: 'Pause',
|
||||
20: 'CapsLock',
|
||||
27: 'Escape',
|
||||
32: ' ',
|
||||
33: 'PageUp',
|
||||
34: 'PageDown',
|
||||
35: 'End',
|
||||
36: 'Home',
|
||||
37: 'ArrowLeft',
|
||||
38: 'ArrowUp',
|
||||
39: 'ArrowRight',
|
||||
40: 'ArrowDown',
|
||||
45: 'Insert',
|
||||
46: 'Delete',
|
||||
65: 'a',
|
||||
66: 'b',
|
||||
67: 'c',
|
||||
68: 'd',
|
||||
69: 'e',
|
||||
70: 'f',
|
||||
71: 'g',
|
||||
72: 'h',
|
||||
73: 'i',
|
||||
74: 'j',
|
||||
75: 'k',
|
||||
76: 'l',
|
||||
77: 'm',
|
||||
78: 'n',
|
||||
79: 'o',
|
||||
80: 'p',
|
||||
81: 'q',
|
||||
82: 'r',
|
||||
83: 's',
|
||||
84: 't',
|
||||
85: 'u',
|
||||
86: 'v',
|
||||
87: 'w',
|
||||
88: 'x',
|
||||
89: 'y',
|
||||
90: 'z',
|
||||
91: 'OS',
|
||||
93: 'ContextMenu',
|
||||
96: '0',
|
||||
97: '1',
|
||||
98: '2',
|
||||
99: '3',
|
||||
100: '4',
|
||||
101: '5',
|
||||
102: '6',
|
||||
103: '7',
|
||||
104: '8',
|
||||
105: '9',
|
||||
106: '*',
|
||||
107: '+',
|
||||
109: '-',
|
||||
110: '.',
|
||||
111: '/',
|
||||
112: 'F1',
|
||||
113: 'F2',
|
||||
114: 'F3',
|
||||
115: 'F4',
|
||||
116: 'F5',
|
||||
117: 'F6',
|
||||
118: 'F7',
|
||||
119: 'F8',
|
||||
120: 'F9',
|
||||
121: 'F10',
|
||||
122: 'F11',
|
||||
123: 'F12',
|
||||
144: 'NumLock',
|
||||
145: 'ScrollLock'
|
||||
};
|
||||
|
||||
final bool _supportsTemplateElement = () {
|
||||
try {
|
||||
return new TemplateElement().content != null;
|
||||
} catch(_) {
|
||||
return false;
|
||||
}
|
||||
}();
|
||||
|
||||
class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
||||
js.JsFunction _setProperty;
|
||||
js.JsFunction _getProperty;
|
||||
js.JsFunction _hasProperty;
|
||||
Map<String, bool> _hasPropertyCache;
|
||||
BrowserDomAdapter() {
|
||||
_hasPropertyCache = new Map();
|
||||
_setProperty = js.context.callMethod(
|
||||
'eval', ['(function(el, prop, value) { el[prop] = value; })']);
|
||||
_getProperty = js.context
|
||||
.callMethod('eval', ['(function(el, prop) { return el[prop]; })']);
|
||||
_hasProperty = js.context
|
||||
.callMethod('eval', ['(function(el, prop) { return prop in el; })']);
|
||||
}
|
||||
static void makeCurrent() {
|
||||
setRootDomAdapter(new BrowserDomAdapter());
|
||||
}
|
||||
|
||||
bool hasProperty(Element element, String name) {
|
||||
// Always return true as the serverside version html_adapter.dart does so.
|
||||
// TODO: change this once we have schema support.
|
||||
// Note: This nees to kept in sync with html_adapter.dart!
|
||||
return true;
|
||||
}
|
||||
|
||||
void setProperty(Element element, String name, Object value) {
|
||||
var cacheKey = "${element.tagName}.${name}";
|
||||
var hasProperty = this._hasPropertyCache[cacheKey];
|
||||
if (hasProperty == null) {
|
||||
hasProperty = this._hasProperty.apply([element, name]);
|
||||
this._hasPropertyCache[cacheKey] = hasProperty;
|
||||
}
|
||||
if (hasProperty) {
|
||||
_setProperty.apply([element, name, value]);
|
||||
}
|
||||
}
|
||||
|
||||
getProperty(Element element, String name) =>
|
||||
_getProperty.apply([element, name]);
|
||||
|
||||
invoke(Element element, String methodName, List args) =>
|
||||
this.getProperty(element, methodName).apply(args, thisArg: element);
|
||||
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
logError(error) {
|
||||
window.console.error(error);
|
||||
}
|
||||
|
||||
log(error) {
|
||||
window.console.log(error);
|
||||
}
|
||||
|
||||
logGroup(error) {
|
||||
window.console.group(error);
|
||||
}
|
||||
|
||||
logGroupEnd() {
|
||||
window.console.groupEnd();
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, String> get attrToPropMap => const <String, String>{
|
||||
'class': 'className',
|
||||
'innerHtml': 'innerHTML',
|
||||
'readonly': 'readOnly',
|
||||
'tabindex': 'tabIndex',
|
||||
};
|
||||
|
||||
Element query(String selector) => document.querySelector(selector);
|
||||
|
||||
Element querySelector(el, String selector) => el.querySelector(selector);
|
||||
|
||||
ElementList querySelectorAll(el, String selector) =>
|
||||
el.querySelectorAll(selector);
|
||||
|
||||
void on(EventTarget element, String event, callback(arg)) {
|
||||
// due to https://code.google.com/p/dart/issues/detail?id=17406
|
||||
// addEventListener misses zones so we use element.on.
|
||||
element.on[event].listen(callback);
|
||||
}
|
||||
|
||||
Function onAndCancel(EventTarget element, String event, callback(arg)) {
|
||||
// due to https://code.google.com/p/dart/issues/detail?id=17406
|
||||
// addEventListener misses zones so we use element.on.
|
||||
var subscription = element.on[event].listen(callback);
|
||||
return subscription.cancel;
|
||||
}
|
||||
|
||||
void dispatchEvent(EventTarget el, Event evt) {
|
||||
el.dispatchEvent(evt);
|
||||
}
|
||||
|
||||
MouseEvent createMouseEvent(String eventType) =>
|
||||
new MouseEvent(eventType, canBubble: true);
|
||||
Event createEvent(String eventType) => new Event(eventType, canBubble: true);
|
||||
void preventDefault(Event evt) {
|
||||
evt.preventDefault();
|
||||
}
|
||||
|
||||
bool isPrevented(Event evt) {
|
||||
return evt.defaultPrevented;
|
||||
}
|
||||
|
||||
String getInnerHTML(Element el) => el.innerHtml;
|
||||
String getOuterHTML(Element el) => el.outerHtml;
|
||||
void setInnerHTML(Element el, String value) {
|
||||
el.innerHtml = value;
|
||||
}
|
||||
|
||||
String nodeName(Node el) => el.nodeName;
|
||||
String nodeValue(Node el) => el.nodeValue;
|
||||
String type(InputElement el) => el.type;
|
||||
Node content(TemplateElement el) => _supportsTemplateElement ? el.content : el;
|
||||
Node firstChild(el) => el.firstChild;
|
||||
Node nextSibling(Node el) => el.nextNode;
|
||||
Element parentElement(Node el) => el.parent;
|
||||
List<Node> childNodes(Node el) => el.childNodes;
|
||||
List childNodesAsList(Node el) => childNodes(el).toList();
|
||||
void clearNodes(Node el) {
|
||||
el.nodes = const [];
|
||||
}
|
||||
|
||||
void appendChild(Node el, Node node) {
|
||||
el.append(node);
|
||||
}
|
||||
|
||||
void removeChild(el, Node node) {
|
||||
node.remove();
|
||||
}
|
||||
|
||||
void replaceChild(Node el, Node newNode, Node oldNode) {
|
||||
oldNode.replaceWith(newNode);
|
||||
}
|
||||
|
||||
ChildNode remove(ChildNode el) {
|
||||
return el..remove();
|
||||
}
|
||||
|
||||
void insertBefore(Node el, node) {
|
||||
el.parentNode.insertBefore(node, el);
|
||||
}
|
||||
|
||||
void insertAllBefore(Node el, Iterable<Node> nodes) {
|
||||
el.parentNode.insertAllBefore(nodes, el);
|
||||
}
|
||||
|
||||
void insertAfter(Node el, Node node) {
|
||||
el.parentNode.insertBefore(node, el.nextNode);
|
||||
}
|
||||
|
||||
String getText(Node el) => el.text;
|
||||
void setText(Node el, String value) {
|
||||
el.text = value;
|
||||
}
|
||||
|
||||
String getValue(el) => el.value;
|
||||
void setValue(el, String value) {
|
||||
el.value = value;
|
||||
}
|
||||
|
||||
bool getChecked(InputElement el) => el.checked;
|
||||
void setChecked(InputElement el, bool isChecked) {
|
||||
el.checked = isChecked;
|
||||
}
|
||||
|
||||
Comment createComment(String text) {
|
||||
return new Comment(text);
|
||||
}
|
||||
|
||||
TemplateElement createTemplate(String html) {
|
||||
var t = new TemplateElement();
|
||||
// We do not sanitize because templates are part of the application code
|
||||
// not user code.
|
||||
t.setInnerHtml(html, treeSanitizer: _identitySanitizer);
|
||||
return t;
|
||||
}
|
||||
|
||||
Element createElement(String tagName, [HtmlDocument doc = null]) {
|
||||
if (doc == null) doc = document;
|
||||
return doc.createElement(tagName);
|
||||
}
|
||||
|
||||
Text createTextNode(String text, [HtmlDocument doc = null]) {
|
||||
return new Text(text);
|
||||
}
|
||||
|
||||
createScriptTag(String attrName, String attrValue,
|
||||
[HtmlDocument doc = null]) {
|
||||
if (doc == null) doc = document;
|
||||
var el = doc.createElement('SCRIPT');
|
||||
el.setAttribute(attrName, attrValue);
|
||||
return el;
|
||||
}
|
||||
|
||||
StyleElement createStyleElement(String css, [HtmlDocument doc = null]) {
|
||||
if (doc == null) doc = document;
|
||||
var el = doc.createElement('STYLE');
|
||||
el.text = css;
|
||||
return el;
|
||||
}
|
||||
|
||||
ShadowRoot createShadowRoot(Element el) => el.createShadowRoot();
|
||||
ShadowRoot getShadowRoot(Element el) => el.shadowRoot;
|
||||
Element getHost(Element el) => (el as ShadowRoot).host;
|
||||
clone(Node node) => node.clone(true);
|
||||
List<Node> getElementsByClassName(Element element, String name) =>
|
||||
element.getElementsByClassName(name);
|
||||
List<Node> getElementsByTagName(Element element, String name) =>
|
||||
element.querySelectorAll(name);
|
||||
List<String> classList(Element element) => element.classes.toList();
|
||||
void addClass(Element element, String classname) {
|
||||
element.classes.add(classname);
|
||||
}
|
||||
|
||||
void removeClass(Element element, String classname) {
|
||||
element.classes.remove(classname);
|
||||
}
|
||||
|
||||
bool hasClass(Element element, String classname) =>
|
||||
element.classes.contains(classname);
|
||||
|
||||
void setStyle(Element element, String stylename, String stylevalue) {
|
||||
element.style.setProperty(stylename, stylevalue);
|
||||
}
|
||||
|
||||
void removeStyle(Element element, String stylename) {
|
||||
element.style.removeProperty(stylename);
|
||||
}
|
||||
|
||||
String getStyle(Element element, String stylename) {
|
||||
return element.style.getPropertyValue(stylename);
|
||||
}
|
||||
|
||||
String tagName(Element element) => element.tagName;
|
||||
|
||||
Map<String, String> attributeMap(Element element) {
|
||||
return new Map.from(element.attributes);
|
||||
}
|
||||
|
||||
bool hasAttribute(Element element, String attribute) =>
|
||||
element.attributes.containsKey(attribute);
|
||||
|
||||
String getAttribute(Element element, String attribute) =>
|
||||
element.getAttribute(attribute);
|
||||
|
||||
void setAttribute(Element element, String name, String value) {
|
||||
element.setAttribute(name, value);
|
||||
}
|
||||
|
||||
void removeAttribute(Element element, String name) {
|
||||
//there is no removeAttribute method as of now in Dart:
|
||||
//https://code.google.com/p/dart/issues/detail?id=19934
|
||||
element.attributes.remove(name);
|
||||
}
|
||||
|
||||
Node templateAwareRoot(Element el) => el is TemplateElement ? el.content : el;
|
||||
|
||||
HtmlDocument createHtmlDocument() =>
|
||||
document.implementation.createHtmlDocument('fakeTitle');
|
||||
|
||||
HtmlDocument defaultDoc() => document;
|
||||
Rectangle getBoundingClientRect(el) => el.getBoundingClientRect();
|
||||
String getTitle() => document.title;
|
||||
void setTitle(String newTitle) {
|
||||
document.title = newTitle;
|
||||
}
|
||||
|
||||
bool elementMatches(n, String selector) =>
|
||||
n is Element && n.matches(selector);
|
||||
bool isTemplateElement(Element el) => el is TemplateElement;
|
||||
bool isTextNode(Node node) => node.nodeType == Node.TEXT_NODE;
|
||||
bool isCommentNode(Node node) => node.nodeType == Node.COMMENT_NODE;
|
||||
bool isElementNode(Node node) => node.nodeType == Node.ELEMENT_NODE;
|
||||
bool hasShadowRoot(Node node) {
|
||||
return node is Element && node.shadowRoot != null;
|
||||
}
|
||||
|
||||
bool isShadowRoot(Node node) {
|
||||
return node is ShadowRoot;
|
||||
}
|
||||
|
||||
Node importIntoDoc(Node node) {
|
||||
return document.importNode(node, true);
|
||||
}
|
||||
|
||||
Node adoptNode(Node node) {
|
||||
return document.adoptNode(node);
|
||||
}
|
||||
|
||||
bool isPageRule(CssRule rule) => rule is CssPageRule;
|
||||
bool isStyleRule(CssRule rule) => rule is CssStyleRule;
|
||||
bool isMediaRule(CssRule rule) => rule is CssMediaRule;
|
||||
bool isKeyframesRule(CssRule rule) => rule is CssKeyframesRule;
|
||||
String getHref(AnchorElement element) {
|
||||
return element.href;
|
||||
}
|
||||
|
||||
String getEventKey(KeyboardEvent event) {
|
||||
int keyCode = event.keyCode;
|
||||
return _keyCodeToKeyMap.containsKey(keyCode)
|
||||
? _keyCodeToKeyMap[keyCode]
|
||||
: 'Unidentified';
|
||||
}
|
||||
|
||||
getGlobalEventTarget(String target) {
|
||||
if (target == "window") {
|
||||
return window;
|
||||
} else if (target == "document") {
|
||||
return document;
|
||||
} else if (target == "body") {
|
||||
return document.body;
|
||||
}
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
return window.history;
|
||||
}
|
||||
|
||||
getLocation() {
|
||||
return window.location;
|
||||
}
|
||||
|
||||
getBaseHref() {
|
||||
var href = getBaseElementHref();
|
||||
if (href == null) {
|
||||
return null;
|
||||
}
|
||||
var baseUri = Uri.parse(href);
|
||||
return baseUri.path[0] == '/' ? baseUri.path : ('/' + baseUri.path);
|
||||
}
|
||||
|
||||
resetBaseElement() {
|
||||
baseElement = null;
|
||||
}
|
||||
|
||||
String getUserAgent() {
|
||||
return window.navigator.userAgent;
|
||||
}
|
||||
|
||||
void setData(Element element, String name, String value) {
|
||||
element.dataset[name] = value;
|
||||
}
|
||||
|
||||
String getData(Element element, String name) {
|
||||
return element.dataset[name];
|
||||
}
|
||||
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
setGlobalVar(String name, value) {
|
||||
js.context[name] = value;
|
||||
}
|
||||
}
|
||||
|
||||
var baseElement = null;
|
||||
String getBaseElementHref() {
|
||||
if (baseElement == null) {
|
||||
baseElement = document.querySelector('base');
|
||||
if (baseElement == null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return baseElement.getAttribute('href');
|
||||
}
|
340
modules/angular2/src/core/dom/browser_adapter.ts
Normal file
340
modules/angular2/src/core/dom/browser_adapter.ts
Normal file
@ -0,0 +1,340 @@
|
||||
import {List, MapWrapper, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent, global} from 'angular2/src/facade/lang';
|
||||
import {setRootDomAdapter} from './dom_adapter';
|
||||
import {GenericBrowserDomAdapter} from './generic_browser_adapter';
|
||||
|
||||
var _attrToPropMap = {
|
||||
'class': 'className',
|
||||
'innerHtml': 'innerHTML',
|
||||
'readonly': 'readOnly',
|
||||
'tabindex': 'tabIndex'
|
||||
};
|
||||
|
||||
const DOM_KEY_LOCATION_NUMPAD = 3;
|
||||
|
||||
// Map to convert some key or keyIdentifier values to what will be returned by getEventKey
|
||||
var _keyMap = {
|
||||
// The following values are here for cross-browser compatibility and to match the W3C standard
|
||||
// cf http://www.w3.org/TR/DOM-Level-3-Events-key/
|
||||
'\b': 'Backspace',
|
||||
'\t': 'Tab',
|
||||
'\x7F': 'Delete',
|
||||
'\x1B': 'Escape',
|
||||
'Del': 'Delete',
|
||||
'Esc': 'Escape',
|
||||
'Left': 'ArrowLeft',
|
||||
'Right': 'ArrowRight',
|
||||
'Up': 'ArrowUp',
|
||||
'Down': 'ArrowDown',
|
||||
'Menu': 'ContextMenu',
|
||||
'Scroll': 'ScrollLock',
|
||||
'Win': 'OS'
|
||||
};
|
||||
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
var _chromeNumKeyPadMap = {
|
||||
'A': '1',
|
||||
'B': '2',
|
||||
'C': '3',
|
||||
'D': '4',
|
||||
'E': '5',
|
||||
'F': '6',
|
||||
'G': '7',
|
||||
'H': '8',
|
||||
'I': '9',
|
||||
'J': '*',
|
||||
'K': '+',
|
||||
'M': '-',
|
||||
'N': '.',
|
||||
'O': '/',
|
||||
'\x60': '0',
|
||||
'\x90': 'NumLock'
|
||||
};
|
||||
|
||||
/* tslint:disable:requireParameterType */
|
||||
export class BrowserDomAdapter extends GenericBrowserDomAdapter {
|
||||
static makeCurrent() { setRootDomAdapter(new BrowserDomAdapter()); }
|
||||
hasProperty(element, name: string): boolean { return name in element; }
|
||||
setProperty(el: /*element*/ any, name: string, value: any) { el[name] = value; }
|
||||
getProperty(el: /*element*/ any, name: string): any { return el[name]; }
|
||||
invoke(el: /*element*/ any, methodName: string, args: List<any>): any {
|
||||
el[methodName].apply(el, args);
|
||||
}
|
||||
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
logError(error) { window.console.error(error); }
|
||||
|
||||
log(error) { window.console.log(error); }
|
||||
|
||||
logGroup(error) {
|
||||
if (window.console.group) {
|
||||
window.console.group(error);
|
||||
} else {
|
||||
window.console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
logGroupEnd() {
|
||||
if (window.console.groupEnd) {
|
||||
window.console.groupEnd();
|
||||
}
|
||||
}
|
||||
|
||||
get attrToPropMap(): any { return _attrToPropMap; }
|
||||
|
||||
query(selector: string): any { return document.querySelector(selector); }
|
||||
querySelector(el, selector: string): HTMLElement { return el.querySelector(selector); }
|
||||
querySelectorAll(el, selector: string): List<any> { return el.querySelectorAll(selector); }
|
||||
on(el, evt, listener) { el.addEventListener(evt, listener, false); }
|
||||
onAndCancel(el, evt, listener): Function {
|
||||
el.addEventListener(evt, listener, false);
|
||||
// Needed to follow Dart's subscription semantic, until fix of
|
||||
// https://code.google.com/p/dart/issues/detail?id=17406
|
||||
return () => { el.removeEventListener(evt, listener, false); };
|
||||
}
|
||||
dispatchEvent(el, evt) { el.dispatchEvent(evt); }
|
||||
createMouseEvent(eventType: string): MouseEvent {
|
||||
var evt: MouseEvent = document.createEvent('MouseEvent');
|
||||
evt.initEvent(eventType, true, true);
|
||||
return evt;
|
||||
}
|
||||
createEvent(eventType): Event {
|
||||
var evt: Event = document.createEvent('Event');
|
||||
evt.initEvent(eventType, true, true);
|
||||
return evt;
|
||||
}
|
||||
preventDefault(evt: Event) {
|
||||
evt.preventDefault();
|
||||
evt.returnValue = false;
|
||||
}
|
||||
isPrevented(evt: Event): boolean {
|
||||
return evt.defaultPrevented || isPresent(evt.returnValue) && !evt.returnValue;
|
||||
}
|
||||
getInnerHTML(el): string { return el.innerHTML; }
|
||||
getOuterHTML(el): string { return el.outerHTML; }
|
||||
nodeName(node: Node): string { return node.nodeName; }
|
||||
nodeValue(node: Node): string { return node.nodeValue; }
|
||||
type(node: HTMLInputElement): string { return node.type; }
|
||||
content(node: Node): Node {
|
||||
if (this.hasProperty(node, "content")) {
|
||||
return (<any>node).content;
|
||||
} else {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
firstChild(el): Node { return el.firstChild; }
|
||||
nextSibling(el): Node { return el.nextSibling; }
|
||||
parentElement(el): Node { return el.parentNode; }
|
||||
childNodes(el): List<Node> { return el.childNodes; }
|
||||
childNodesAsList(el): List<any> {
|
||||
var childNodes = el.childNodes;
|
||||
var res = ListWrapper.createFixedSize(childNodes.length);
|
||||
for (var i = 0; i < childNodes.length; i++) {
|
||||
res[i] = childNodes[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
clearNodes(el) {
|
||||
while (el.firstChild) {
|
||||
el.removeChild(el.firstChild);
|
||||
}
|
||||
}
|
||||
appendChild(el, node) { el.appendChild(node); }
|
||||
removeChild(el, node) { el.removeChild(node); }
|
||||
replaceChild(el: Node, newChild, oldChild) { el.replaceChild(newChild, oldChild); }
|
||||
remove(node): Node {
|
||||
node.parentNode.removeChild(node);
|
||||
return node;
|
||||
}
|
||||
insertBefore(el, node) { el.parentNode.insertBefore(node, el); }
|
||||
insertAllBefore(el, nodes) {
|
||||
ListWrapper.forEach(nodes, (n) => { el.parentNode.insertBefore(n, el); });
|
||||
}
|
||||
insertAfter(el, node) { el.parentNode.insertBefore(node, el.nextSibling); }
|
||||
setInnerHTML(el, value) { el.innerHTML = value; }
|
||||
getText(el): string { return el.textContent; }
|
||||
// TODO(vicb): removed Element type because it does not support StyleElement
|
||||
setText(el, value: string) { el.textContent = value; }
|
||||
getValue(el): string { return el.value; }
|
||||
setValue(el, value: string) { el.value = value; }
|
||||
getChecked(el): boolean { return el.checked; }
|
||||
setChecked(el, value: boolean) { el.checked = value; }
|
||||
createComment(text: string): Comment { return document.createComment(text); }
|
||||
createTemplate(html): HTMLElement {
|
||||
var t = document.createElement('template');
|
||||
t.innerHTML = html;
|
||||
return t;
|
||||
}
|
||||
createElement(tagName, doc = document): HTMLElement { return doc.createElement(tagName); }
|
||||
createTextNode(text: string, doc = document): Text { return doc.createTextNode(text); }
|
||||
createScriptTag(attrName: string, attrValue: string, doc = document): HTMLScriptElement {
|
||||
var el = <HTMLScriptElement>doc.createElement('SCRIPT');
|
||||
el.setAttribute(attrName, attrValue);
|
||||
return el;
|
||||
}
|
||||
createStyleElement(css: string, doc = document): HTMLStyleElement {
|
||||
var style = <HTMLStyleElement>doc.createElement('style');
|
||||
this.appendChild(style, this.createTextNode(css));
|
||||
return style;
|
||||
}
|
||||
createShadowRoot(el: HTMLElement): DocumentFragment { return (<any>el).createShadowRoot(); }
|
||||
getShadowRoot(el: HTMLElement): DocumentFragment { return (<any>el).shadowRoot; }
|
||||
getHost(el: HTMLElement): HTMLElement { return (<any>el).host; }
|
||||
clone(node: Node): Node { return node.cloneNode(true); }
|
||||
getElementsByClassName(element, name: string): List<HTMLElement> {
|
||||
return element.getElementsByClassName(name);
|
||||
}
|
||||
getElementsByTagName(element, name: string): List<HTMLElement> {
|
||||
return element.getElementsByTagName(name);
|
||||
}
|
||||
classList(element): List<any> {
|
||||
return <List<any>>Array.prototype.slice.call(element.classList, 0);
|
||||
}
|
||||
addClass(element, classname: string) { element.classList.add(classname); }
|
||||
removeClass(element, classname: string) { element.classList.remove(classname); }
|
||||
hasClass(element, classname: string): boolean { return element.classList.contains(classname); }
|
||||
setStyle(element, stylename: string, stylevalue: string) {
|
||||
element.style[stylename] = stylevalue;
|
||||
}
|
||||
removeStyle(element, stylename: string) { element.style[stylename] = null; }
|
||||
getStyle(element, stylename: string): string { return element.style[stylename]; }
|
||||
tagName(element): string { return element.tagName; }
|
||||
attributeMap(element): Map<string, string> {
|
||||
var res = new Map();
|
||||
var elAttrs = element.attributes;
|
||||
for (var i = 0; i < elAttrs.length; i++) {
|
||||
var attrib = elAttrs[i];
|
||||
res.set(attrib.name, attrib.value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
hasAttribute(element, attribute: string): boolean { return element.hasAttribute(attribute); }
|
||||
getAttribute(element, attribute: string): string { return element.getAttribute(attribute); }
|
||||
setAttribute(element, name: string, value: string) { element.setAttribute(name, value); }
|
||||
removeAttribute(element, attribute: string) { element.removeAttribute(attribute); }
|
||||
templateAwareRoot(el): any { return this.isTemplateElement(el) ? this.content(el) : el; }
|
||||
createHtmlDocument(): HTMLDocument {
|
||||
return document.implementation.createHTMLDocument('fakeTitle');
|
||||
}
|
||||
defaultDoc(): HTMLDocument { return document; }
|
||||
getBoundingClientRect(el): any {
|
||||
try {
|
||||
return el.getBoundingClientRect();
|
||||
} catch (e) {
|
||||
return {top: 0, bottom: 0, left: 0, right: 0, width: 0, height: 0};
|
||||
}
|
||||
}
|
||||
getTitle(): string { return document.title; }
|
||||
setTitle(newTitle: string) { document.title = newTitle || ''; }
|
||||
elementMatches(n, selector: string): boolean {
|
||||
var matches = false;
|
||||
if (n instanceof HTMLElement) {
|
||||
if (n.matches) {
|
||||
matches = n.matches(selector);
|
||||
} else if (n.msMatchesSelector) {
|
||||
matches = n.msMatchesSelector(selector);
|
||||
} else if (n.webkitMatchesSelector) {
|
||||
matches = n.webkitMatchesSelector(selector);
|
||||
}
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
isTemplateElement(el: any): boolean {
|
||||
return el instanceof HTMLElement && el.nodeName == "TEMPLATE";
|
||||
}
|
||||
isTextNode(node: Node): boolean { return node.nodeType === Node.TEXT_NODE; }
|
||||
isCommentNode(node: Node): boolean { return node.nodeType === Node.COMMENT_NODE; }
|
||||
isElementNode(node: Node): boolean { return node.nodeType === Node.ELEMENT_NODE; }
|
||||
hasShadowRoot(node): boolean { return node instanceof HTMLElement && isPresent(node.shadowRoot); }
|
||||
isShadowRoot(node): boolean { return node instanceof DocumentFragment; }
|
||||
importIntoDoc(node: Node): any {
|
||||
var toImport = node;
|
||||
if (this.isTemplateElement(node)) {
|
||||
toImport = this.content(node);
|
||||
}
|
||||
return document.importNode(toImport, true);
|
||||
}
|
||||
adoptNode(node: Node): any { return document.adoptNode(node); }
|
||||
isPageRule(rule): boolean { return rule.type === CSSRule.PAGE_RULE; }
|
||||
isStyleRule(rule): boolean { return rule.type === CSSRule.STYLE_RULE; }
|
||||
isMediaRule(rule): boolean { return rule.type === CSSRule.MEDIA_RULE; }
|
||||
isKeyframesRule(rule): boolean { return rule.type === CSSRule.KEYFRAMES_RULE; }
|
||||
getHref(el: Element): string { return (<any>el).href; }
|
||||
getEventKey(event): string {
|
||||
var key = event.key;
|
||||
if (isBlank(key)) {
|
||||
key = event.keyIdentifier;
|
||||
// keyIdentifier is defined in the old draft of DOM Level 3 Events implemented by Chrome and
|
||||
// Safari
|
||||
// cf
|
||||
// http://www.w3.org/TR/2007/WD-DOM-Level-3-Events-20071221/events.html#Events-KeyboardEvents-Interfaces
|
||||
if (isBlank(key)) {
|
||||
return 'Unidentified';
|
||||
}
|
||||
if (key.startsWith('U+')) {
|
||||
key = String.fromCharCode(parseInt(key.substring(2), 16));
|
||||
if (event.location === DOM_KEY_LOCATION_NUMPAD && _chromeNumKeyPadMap.hasOwnProperty(key)) {
|
||||
// There is a bug in Chrome for numeric keypad keys:
|
||||
// https://code.google.com/p/chromium/issues/detail?id=155654
|
||||
// 1, 2, 3 ... are reported as A, B, C ...
|
||||
key = _chromeNumKeyPadMap[key];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_keyMap.hasOwnProperty(key)) {
|
||||
key = _keyMap[key];
|
||||
}
|
||||
return key;
|
||||
}
|
||||
getGlobalEventTarget(target: string): EventTarget {
|
||||
if (target == "window") {
|
||||
return window;
|
||||
} else if (target == "document") {
|
||||
return document;
|
||||
} else if (target == "body") {
|
||||
return document.body;
|
||||
}
|
||||
}
|
||||
getHistory(): History { return window.history; }
|
||||
getLocation(): Location { return window.location; }
|
||||
getBaseHref(): string {
|
||||
var href = getBaseElementHref();
|
||||
if (isBlank(href)) {
|
||||
return null;
|
||||
}
|
||||
return relativePath(href);
|
||||
}
|
||||
resetBaseElement(): void { baseElement = null; }
|
||||
getUserAgent(): string { return window.navigator.userAgent; }
|
||||
setData(element, name: string, value: string) {
|
||||
this.setAttribute(element, 'data-' + name, value);
|
||||
}
|
||||
getData(element, name: string): string { return this.getAttribute(element, 'data-' + name); }
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
setGlobalVar(name: string, value: any) { global[name] = value; }
|
||||
}
|
||||
|
||||
|
||||
var baseElement = null;
|
||||
function getBaseElementHref(): string {
|
||||
if (isBlank(baseElement)) {
|
||||
baseElement = document.querySelector('base');
|
||||
if (isBlank(baseElement)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return baseElement.getAttribute('href');
|
||||
}
|
||||
|
||||
// based on urlUtils.js in AngularJS 1
|
||||
var urlParsingNode = null;
|
||||
function relativePath(url): string {
|
||||
if (isBlank(urlParsingNode)) {
|
||||
urlParsingNode = document.createElement("a");
|
||||
}
|
||||
urlParsingNode.setAttribute('href', url);
|
||||
return (urlParsingNode.pathname.charAt(0) === '/') ? urlParsingNode.pathname :
|
||||
'/' + urlParsingNode.pathname;
|
||||
}
|
135
modules/angular2/src/core/dom/dom_adapter.ts
Normal file
135
modules/angular2/src/core/dom/dom_adapter.ts
Normal file
@ -0,0 +1,135 @@
|
||||
import {BaseException, isBlank} from 'angular2/src/facade/lang';
|
||||
|
||||
export var DOM: DomAdapter;
|
||||
|
||||
export function setRootDomAdapter(adapter: DomAdapter) {
|
||||
if (isBlank(DOM)) {
|
||||
DOM = adapter;
|
||||
}
|
||||
}
|
||||
|
||||
function _abstract() {
|
||||
return new BaseException('This method is abstract');
|
||||
}
|
||||
|
||||
/* tslint:disable:requireParameterType */
|
||||
/**
|
||||
* Provides DOM operations in an environment-agnostic way.
|
||||
*/
|
||||
export class DomAdapter {
|
||||
hasProperty(element, name: string): boolean { throw _abstract(); }
|
||||
setProperty(el: Element, name: string, value: any) { throw _abstract(); }
|
||||
getProperty(el: Element, name: string): any { throw _abstract(); }
|
||||
invoke(el: Element, methodName: string, args: List<any>): any { throw _abstract(); }
|
||||
|
||||
logError(error) { throw _abstract(); }
|
||||
log(error) { throw _abstract(); }
|
||||
logGroup(error) { throw _abstract(); }
|
||||
logGroupEnd() { throw _abstract(); }
|
||||
|
||||
/**
|
||||
* Maps attribute names to their corresponding property names for cases
|
||||
* where attribute name doesn't match property name.
|
||||
*/
|
||||
get attrToPropMap(): StringMap<string, string> { throw _abstract(); }
|
||||
|
||||
parse(templateHtml: string) { throw _abstract(); }
|
||||
query(selector: string): any { throw _abstract(); }
|
||||
querySelector(el, selector: string): HTMLElement { throw _abstract(); }
|
||||
querySelectorAll(el, selector: string): List<any> { throw _abstract(); }
|
||||
on(el, evt, listener) { throw _abstract(); }
|
||||
onAndCancel(el, evt, listener): Function { throw _abstract(); }
|
||||
dispatchEvent(el, evt) { throw _abstract(); }
|
||||
createMouseEvent(eventType): any { throw _abstract(); }
|
||||
createEvent(eventType: string): any { throw _abstract(); }
|
||||
preventDefault(evt) { throw _abstract(); }
|
||||
isPrevented(evt): boolean { throw _abstract(); }
|
||||
getInnerHTML(el): string { throw _abstract(); }
|
||||
getOuterHTML(el): string { throw _abstract(); }
|
||||
nodeName(node): string { throw _abstract(); }
|
||||
nodeValue(node): string { throw _abstract(); }
|
||||
type(node): string { throw _abstract(); }
|
||||
content(node): any { throw _abstract(); }
|
||||
firstChild(el): Node { throw _abstract(); }
|
||||
nextSibling(el): Node { throw _abstract(); }
|
||||
parentElement(el): Node { throw _abstract(); }
|
||||
childNodes(el): List<Node> { throw _abstract(); }
|
||||
childNodesAsList(el): List<Node> { throw _abstract(); }
|
||||
clearNodes(el) { throw _abstract(); }
|
||||
appendChild(el, node) { throw _abstract(); }
|
||||
removeChild(el, node) { throw _abstract(); }
|
||||
replaceChild(el, newNode, oldNode) { throw _abstract(); }
|
||||
remove(el): Node { throw _abstract(); }
|
||||
insertBefore(el, node) { throw _abstract(); }
|
||||
insertAllBefore(el, nodes) { throw _abstract(); }
|
||||
insertAfter(el, node) { throw _abstract(); }
|
||||
setInnerHTML(el, value) { throw _abstract(); }
|
||||
getText(el): string { throw _abstract(); }
|
||||
setText(el, value: string) { throw _abstract(); }
|
||||
getValue(el): string { throw _abstract(); }
|
||||
setValue(el, value: string) { throw _abstract(); }
|
||||
getChecked(el): boolean { throw _abstract(); }
|
||||
setChecked(el, value: boolean) { throw _abstract(); }
|
||||
createComment(text: string): any { throw _abstract(); }
|
||||
createTemplate(html): HTMLElement { throw _abstract(); }
|
||||
createElement(tagName, doc = null): HTMLElement { throw _abstract(); }
|
||||
createTextNode(text: string, doc = null): Text { throw _abstract(); }
|
||||
createScriptTag(attrName: string, attrValue: string, doc = null): HTMLElement {
|
||||
throw _abstract();
|
||||
}
|
||||
createStyleElement(css: string, doc = null): HTMLStyleElement { throw _abstract(); }
|
||||
createShadowRoot(el): any { throw _abstract(); }
|
||||
getShadowRoot(el): any { throw _abstract(); }
|
||||
getHost(el): any { throw _abstract(); }
|
||||
getDistributedNodes(el): List<Node> { throw _abstract(); }
|
||||
clone /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/ { throw _abstract(); }
|
||||
getElementsByClassName(element, name: string): List<HTMLElement> { throw _abstract(); }
|
||||
getElementsByTagName(element, name: string): List<HTMLElement> { throw _abstract(); }
|
||||
classList(element): List<any> { throw _abstract(); }
|
||||
addClass(element, classname: string) { throw _abstract(); }
|
||||
removeClass(element, classname: string) { throw _abstract(); }
|
||||
hasClass(element, classname: string): boolean { throw _abstract(); }
|
||||
setStyle(element, stylename: string, stylevalue: string) { throw _abstract(); }
|
||||
removeStyle(element, stylename: string) { throw _abstract(); }
|
||||
getStyle(element, stylename: string): string { throw _abstract(); }
|
||||
tagName(element): string { throw _abstract(); }
|
||||
attributeMap(element): Map<string, string> { throw _abstract(); }
|
||||
hasAttribute(element, attribute: string): boolean { throw _abstract(); }
|
||||
getAttribute(element, attribute: string): string { throw _abstract(); }
|
||||
setAttribute(element, name: string, value: string) { throw _abstract(); }
|
||||
removeAttribute(element, attribute: string) { throw _abstract(); }
|
||||
templateAwareRoot(el) { throw _abstract(); }
|
||||
createHtmlDocument(): HTMLDocument { throw _abstract(); }
|
||||
defaultDoc(): HTMLDocument { throw _abstract(); }
|
||||
getBoundingClientRect(el) { throw _abstract(); }
|
||||
getTitle(): string { throw _abstract(); }
|
||||
setTitle(newTitle: string) { throw _abstract(); }
|
||||
elementMatches(n, selector: string): boolean { throw _abstract(); }
|
||||
isTemplateElement(el: any): boolean { throw _abstract(); }
|
||||
isTextNode(node): boolean { throw _abstract(); }
|
||||
isCommentNode(node): boolean { throw _abstract(); }
|
||||
isElementNode(node): boolean { throw _abstract(); }
|
||||
hasShadowRoot(node): boolean { throw _abstract(); }
|
||||
isShadowRoot(node): boolean { throw _abstract(); }
|
||||
importIntoDoc /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/ { throw _abstract(); }
|
||||
adoptNode /*<T extends Node>*/ (node: Node /*T*/): Node /*T*/ { throw _abstract(); }
|
||||
isPageRule(rule): boolean { throw _abstract(); }
|
||||
isStyleRule(rule): boolean { throw _abstract(); }
|
||||
isMediaRule(rule): boolean { throw _abstract(); }
|
||||
isKeyframesRule(rule): boolean { throw _abstract(); }
|
||||
getHref(element): string { throw _abstract(); }
|
||||
getEventKey(event): string { throw _abstract(); }
|
||||
resolveAndSetHref(element, baseUrl: string, href: string) { throw _abstract(); }
|
||||
cssToRules(css: string): List<any> { throw _abstract(); }
|
||||
supportsDOMEvents(): boolean { throw _abstract(); }
|
||||
supportsNativeShadowDOM(): boolean { throw _abstract(); }
|
||||
getGlobalEventTarget(target: string): any { throw _abstract(); }
|
||||
getHistory(): History { throw _abstract(); }
|
||||
getLocation(): Location { throw _abstract(); }
|
||||
getBaseHref(): string { throw _abstract(); }
|
||||
resetBaseElement(): void { throw _abstract(); }
|
||||
getUserAgent(): string { throw _abstract(); }
|
||||
setData(element, name: string, value: string) { throw _abstract(); }
|
||||
getData(element, name: string): string { throw _abstract(); }
|
||||
setGlobalVar(name: string, value: any) { throw _abstract(); }
|
||||
}
|
40
modules/angular2/src/core/dom/generic_browser_adapter.ts
Normal file
40
modules/angular2/src/core/dom/generic_browser_adapter.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isPresent, isFunction} from 'angular2/src/facade/lang';
|
||||
import {DomAdapter} from './dom_adapter';
|
||||
|
||||
/**
|
||||
* Provides DOM operations in any browser environment.
|
||||
*/
|
||||
export class GenericBrowserDomAdapter extends DomAdapter {
|
||||
getDistributedNodes(el: HTMLElement): List<Node> { return (<any>el).getDistributedNodes(); }
|
||||
resolveAndSetHref(el: HTMLAnchorElement, baseUrl: string, href: string) {
|
||||
el.href = href == null ? baseUrl : baseUrl + '/../' + href;
|
||||
}
|
||||
cssToRules(css: string): List<any> {
|
||||
var style = this.createStyleElement(css);
|
||||
this.appendChild(this.defaultDoc().head, style);
|
||||
var rules = [];
|
||||
if (isPresent(style.sheet)) {
|
||||
// TODO(sorvell): Firefox throws when accessing the rules of a stylesheet
|
||||
// with an @import
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=625013
|
||||
try {
|
||||
var rawRules = (<any>style.sheet).cssRules;
|
||||
rules = ListWrapper.createFixedSize(rawRules.length);
|
||||
for (var i = 0; i < rawRules.length; i++) {
|
||||
rules[i] = rawRules[i];
|
||||
}
|
||||
} catch (e) {
|
||||
//
|
||||
}
|
||||
} else {
|
||||
// console.warn('sheet not found', style);
|
||||
}
|
||||
this.remove(style);
|
||||
return rules;
|
||||
}
|
||||
supportsDOMEvents(): boolean { return true; }
|
||||
supportsNativeShadowDOM(): boolean {
|
||||
return isFunction((<any>this.defaultDoc().body).createShadowRoot);
|
||||
}
|
||||
}
|
423
modules/angular2/src/core/dom/html_adapter.dart
Normal file
423
modules/angular2/src/core/dom/html_adapter.dart
Normal file
@ -0,0 +1,423 @@
|
||||
library angular2.dom.htmlAdapter;
|
||||
|
||||
import 'dom_adapter.dart';
|
||||
import 'package:html/parser.dart' as parser;
|
||||
import 'package:html/dom.dart';
|
||||
import 'dart:io';
|
||||
|
||||
class Html5LibDomAdapter implements DomAdapter {
|
||||
static void makeCurrent() {
|
||||
setRootDomAdapter(new Html5LibDomAdapter());
|
||||
}
|
||||
|
||||
hasProperty(element, String name) {
|
||||
// This is needed for serverside compile to generate the right getters/setters.
|
||||
// TODO: change this once we have property schema support.
|
||||
// Attention: Keep this in sync with browser_adapter.dart!
|
||||
return true;
|
||||
}
|
||||
|
||||
void setProperty(Element element, String name, Object value) =>
|
||||
throw 'not implemented';
|
||||
|
||||
getProperty(Element element, String name) => throw 'not implemented';
|
||||
|
||||
invoke(Element element, String methodName, List args) =>
|
||||
throw 'not implemented';
|
||||
|
||||
logError(error) {
|
||||
stderr.writeln('${error}');
|
||||
}
|
||||
|
||||
log(error) {
|
||||
stdout.writeln('${error}');
|
||||
}
|
||||
|
||||
logGroup(error) {
|
||||
stdout.writeln('${error}');
|
||||
}
|
||||
|
||||
logGroupEnd() {}
|
||||
|
||||
@override
|
||||
final attrToPropMap = const {
|
||||
'innerHtml': 'innerHTML',
|
||||
'readonly': 'readOnly',
|
||||
'tabindex': 'tabIndex',
|
||||
};
|
||||
|
||||
@override
|
||||
getGlobalEventTarget(String target) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
getTitle() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
setTitle(String newTitle) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
String getEventKey(event) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
void replaceChild(el, newNode, oldNode) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic getBoundingClientRect(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
Element parse(String templateHtml) => parser.parse(templateHtml).firstChild;
|
||||
query(selector) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
querySelector(el, String selector) {
|
||||
return el.querySelector(selector);
|
||||
}
|
||||
|
||||
List querySelectorAll(el, String selector) {
|
||||
return el.querySelectorAll(selector);
|
||||
}
|
||||
|
||||
on(el, evt, listener) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
Function onAndCancel(el, evt, listener) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
dispatchEvent(el, evt) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createMouseEvent(eventType) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createEvent(eventType) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
preventDefault(evt) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
isPrevented(evt) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getInnerHTML(el) {
|
||||
return el.innerHtml;
|
||||
}
|
||||
|
||||
getOuterHTML(el) {
|
||||
return el.outerHtml;
|
||||
}
|
||||
|
||||
String nodeName(node) {
|
||||
switch (node.nodeType) {
|
||||
case Node.ELEMENT_NODE:
|
||||
return (node as Element).localName;
|
||||
case Node.TEXT_NODE:
|
||||
return '#text';
|
||||
default:
|
||||
throw 'not implemented for type ${node.nodeType}. '
|
||||
'See http://www.w3.org/TR/DOM-Level-3-Core/core.html#ID-1950641247'
|
||||
' for node types definitions.';
|
||||
}
|
||||
}
|
||||
|
||||
String nodeValue(node) => node.data;
|
||||
String type(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
content(node) {
|
||||
return node;
|
||||
}
|
||||
|
||||
firstChild(el) => el is NodeList ? el.first : el.firstChild;
|
||||
|
||||
nextSibling(el) {
|
||||
final parentNode = el.parentNode;
|
||||
if (parentNode == null) return null;
|
||||
final siblings = parentNode.nodes;
|
||||
final index = siblings.indexOf(el);
|
||||
if (index < siblings.length - 1) {
|
||||
return siblings[index + 1];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
parentElement(el) {
|
||||
return el.parent;
|
||||
}
|
||||
|
||||
List childNodes(el) => el.nodes;
|
||||
List childNodesAsList(el) => el.nodes;
|
||||
clearNodes(el) {
|
||||
el.nodes.forEach((e) => e.remove());
|
||||
}
|
||||
|
||||
appendChild(el, node) => el.append(node.remove());
|
||||
removeChild(el, node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
remove(el) => el.remove();
|
||||
insertBefore(el, node) {
|
||||
if (el.parent == null) throw '$el must have a parent';
|
||||
el.parent.insertBefore(node, el);
|
||||
}
|
||||
|
||||
insertAllBefore(el, nodes) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
insertAfter(el, node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
setInnerHTML(el, value) {
|
||||
el.innerHtml = value;
|
||||
}
|
||||
|
||||
getText(el) {
|
||||
return el.text;
|
||||
}
|
||||
|
||||
setText(el, String value) => el.text = value;
|
||||
|
||||
getValue(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
setValue(el, String value) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getChecked(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
setChecked(el, bool value) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createComment(String text) => new Comment(text);
|
||||
createTemplate(String html) => createElement('template')..innerHtml = html;
|
||||
createElement(tagName, [doc]) {
|
||||
return new Element.tag(tagName);
|
||||
}
|
||||
|
||||
createTextNode(String text, [doc]) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createScriptTag(String attrName, String attrValue, [doc]) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createStyleElement(String css, [doc]) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
createShadowRoot(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getShadowRoot(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getHost(el) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
clone(node) => node.clone(true);
|
||||
getElementsByClassName(element, String name) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getElementsByTagName(element, String name) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
List classList(element) => element.classes.toList();
|
||||
|
||||
addClass(element, String classname) {
|
||||
element.classes.add(classname);
|
||||
}
|
||||
|
||||
removeClass(element, String classname) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
hasClass(element, String classname) => element.classes.contains(classname);
|
||||
|
||||
setStyle(element, String stylename, String stylevalue) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
removeStyle(element, String stylename) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getStyle(element, String stylename) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
String tagName(element) => element.localName;
|
||||
|
||||
attributeMap(element) {
|
||||
// `attributes` keys can be {@link AttributeName}s.
|
||||
var map = <String, String>{};
|
||||
element.attributes.forEach((key, value) {
|
||||
map['$key'] = value;
|
||||
});
|
||||
return map;
|
||||
}
|
||||
|
||||
hasAttribute(element, String attribute) {
|
||||
// `attributes` keys can be {@link AttributeName}s.
|
||||
return element.attributes.keys.any((key) => '$key' == attribute);
|
||||
}
|
||||
|
||||
getAttribute(element, String attribute) {
|
||||
// `attributes` keys can be {@link AttributeName}s.
|
||||
var key = element.attributes.keys.firstWhere((key) => '$key' == attribute,
|
||||
orElse: () {});
|
||||
return element.attributes[key];
|
||||
}
|
||||
|
||||
setAttribute(element, String name, String value) {
|
||||
element.attributes[name] = value;
|
||||
}
|
||||
|
||||
removeAttribute(element, String attribute) {
|
||||
element.attributes.remove(attribute);
|
||||
}
|
||||
|
||||
templateAwareRoot(el) => el;
|
||||
|
||||
createHtmlDocument() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
defaultDoc() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool elementMatches(n, String selector) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isTemplateElement(Element el) {
|
||||
return el != null && el.localName.toLowerCase() == 'template';
|
||||
}
|
||||
|
||||
bool isTextNode(node) => node.nodeType == Node.TEXT_NODE;
|
||||
bool isCommentNode(node) => node.nodeType == Node.COMMENT_NODE;
|
||||
|
||||
bool isElementNode(node) => node.nodeType == Node.ELEMENT_NODE;
|
||||
|
||||
bool hasShadowRoot(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isShadowRoot(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
importIntoDoc(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
adoptNode(node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isPageRule(rule) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isStyleRule(rule) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isMediaRule(rule) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool isKeyframesRule(rule) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
String getHref(element) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
void resolveAndSetHref(element, baseUrl, href) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
List cssToRules(String css) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
List getDistributedNodes(Node) {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
bool supportsDOMEvents() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool supportsNativeShadowDOM() {
|
||||
return false;
|
||||
}
|
||||
|
||||
getHistory() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getLocation() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
getBaseHref() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
resetBaseElement() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
String getUserAgent() {
|
||||
throw 'not implemented';
|
||||
}
|
||||
|
||||
void setData(Element element, String name, String value) {
|
||||
this.setAttribute(element, 'data-${name}', value);
|
||||
}
|
||||
|
||||
String getData(Element element, String name) {
|
||||
return this.getAttribute(element, 'data-${name}');
|
||||
}
|
||||
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
setGlobalVar(String name, value) {
|
||||
// noop on the server
|
||||
}
|
||||
}
|
3
modules/angular2/src/core/dom/parse5_adapter.dart
Normal file
3
modules/angular2/src/core/dom/parse5_adapter.dart
Normal file
@ -0,0 +1,3 @@
|
||||
library angular2.src.dom.parse5_adapter;
|
||||
|
||||
// no dart implementation
|
730
modules/angular2/src/core/dom/parse5_adapter.ts
Normal file
730
modules/angular2/src/core/dom/parse5_adapter.ts
Normal file
@ -0,0 +1,730 @@
|
||||
var parse5 = require('parse5');
|
||||
var parser = new parse5.Parser(parse5.TreeAdapters.htmlparser2);
|
||||
var serializer = new parse5.Serializer(parse5.TreeAdapters.htmlparser2);
|
||||
var treeAdapter = parser.treeAdapter;
|
||||
|
||||
var cssParse = require('css').parse;
|
||||
|
||||
var url = require('url');
|
||||
|
||||
import {List, MapWrapper, ListWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {DomAdapter, setRootDomAdapter} from './dom_adapter';
|
||||
import {BaseException, isPresent, isBlank, global} from 'angular2/src/facade/lang';
|
||||
import {SelectorMatcher, CssSelector} from 'angular2/src/render/dom/compiler/selector';
|
||||
|
||||
var _attrToPropMap = {
|
||||
'class': 'className',
|
||||
'innerHtml': 'innerHTML',
|
||||
'readonly': 'readOnly',
|
||||
'tabindex': 'tabIndex',
|
||||
};
|
||||
var defDoc = null;
|
||||
|
||||
var mapProps = ['attribs', 'x-attribsNamespace', 'x-attribsPrefix'];
|
||||
|
||||
function _notImplemented(methodName) {
|
||||
return new BaseException('This method is not implemented in Parse5DomAdapter: ' + methodName);
|
||||
}
|
||||
|
||||
/* tslint:disable:requireParameterType */
|
||||
export class Parse5DomAdapter extends DomAdapter {
|
||||
static makeCurrent() { setRootDomAdapter(new Parse5DomAdapter()); }
|
||||
|
||||
hasProperty(element, name: string): boolean {
|
||||
return _HTMLElementPropertyList.indexOf(name) > -1;
|
||||
}
|
||||
// TODO(tbosch): don't even call this method when we run the tests on server side
|
||||
// by not using the DomRenderer in tests. Keeping this for now to make tests happy...
|
||||
setProperty(el: /*element*/ any, name: string, value: any) {
|
||||
if (name === 'innerHTML') {
|
||||
this.setInnerHTML(el, value);
|
||||
} else if (name === 'className') {
|
||||
el.attribs["class"] = el.className = value;
|
||||
} else {
|
||||
el[name] = value;
|
||||
}
|
||||
}
|
||||
// TODO(tbosch): don't even call this method when we run the tests on server side
|
||||
// by not using the DomRenderer in tests. Keeping this for now to make tests happy...
|
||||
getProperty(el: /*element*/ any, name: string): any { return el[name]; }
|
||||
|
||||
logError(error) { console.error(error); }
|
||||
|
||||
log(error) { console.log(error); }
|
||||
|
||||
logGroup(error) { console.log(error); }
|
||||
|
||||
logGroupEnd() {}
|
||||
|
||||
get attrToPropMap() { return _attrToPropMap; }
|
||||
|
||||
query(selector) { throw _notImplemented('query'); }
|
||||
querySelector(el, selector: string): any { return this.querySelectorAll(el, selector)[0]; }
|
||||
querySelectorAll(el, selector: string): List<any> {
|
||||
var res = [];
|
||||
var _recursive = (result, node, selector, matcher) => {
|
||||
var cNodes = node.childNodes;
|
||||
if (cNodes && cNodes.length > 0) {
|
||||
for (var i = 0; i < cNodes.length; i++) {
|
||||
var childNode = cNodes[i];
|
||||
if (this.elementMatches(childNode, selector, matcher)) {
|
||||
result.push(childNode);
|
||||
}
|
||||
_recursive(result, childNode, selector, matcher);
|
||||
}
|
||||
}
|
||||
};
|
||||
var matcher = new SelectorMatcher();
|
||||
matcher.addSelectables(CssSelector.parse(selector));
|
||||
_recursive(res, el, selector, matcher);
|
||||
return res;
|
||||
}
|
||||
elementMatches(node, selector: string, matcher = null): boolean {
|
||||
if (this.isElementNode(node) && selector === '*') {
|
||||
return true;
|
||||
}
|
||||
var result = false;
|
||||
if (selector && selector.charAt(0) == "#") {
|
||||
result = this.getAttribute(node, 'id') == selector.substring(1);
|
||||
} else if (selector) {
|
||||
var result = false;
|
||||
if (matcher == null) {
|
||||
matcher = new SelectorMatcher();
|
||||
matcher.addSelectables(CssSelector.parse(selector));
|
||||
}
|
||||
|
||||
var cssSelector = new CssSelector();
|
||||
cssSelector.setElement(this.tagName(node));
|
||||
if (node.attribs) {
|
||||
for (var attrName in node.attribs) {
|
||||
cssSelector.addAttribute(attrName, node.attribs[attrName]);
|
||||
}
|
||||
}
|
||||
var classList = this.classList(node);
|
||||
for (var i = 0; i < classList.length; i++) {
|
||||
cssSelector.addClassName(classList[i]);
|
||||
}
|
||||
|
||||
matcher.match(cssSelector, function(selector, cb) { result = true; });
|
||||
}
|
||||
return result;
|
||||
}
|
||||
on(el, evt, listener) {
|
||||
var listenersMap: StringMap<any, any> = el._eventListenersMap;
|
||||
if (isBlank(listenersMap)) {
|
||||
var listenersMap: StringMap<any, any> = StringMapWrapper.create();
|
||||
el._eventListenersMap = listenersMap;
|
||||
}
|
||||
var listeners = StringMapWrapper.get(listenersMap, evt);
|
||||
if (isBlank(listeners)) {
|
||||
listeners = [];
|
||||
}
|
||||
listeners.push(listener);
|
||||
StringMapWrapper.set(listenersMap, evt, listeners);
|
||||
}
|
||||
onAndCancel(el, evt, listener): Function {
|
||||
this.on(el, evt, listener);
|
||||
return () => {
|
||||
ListWrapper.remove(StringMapWrapper.get<List<any>>(el._eventListenersMap, evt), listener);
|
||||
};
|
||||
}
|
||||
dispatchEvent(el, evt) {
|
||||
if (isBlank(evt.target)) {
|
||||
evt.target = el;
|
||||
}
|
||||
if (isPresent(el._eventListenersMap)) {
|
||||
var listeners: any = StringMapWrapper.get(el._eventListenersMap, evt.type);
|
||||
if (isPresent(listeners)) {
|
||||
for (var i = 0; i < listeners.length; i++) {
|
||||
listeners[i](evt);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isPresent(el.parent)) {
|
||||
this.dispatchEvent(el.parent, evt);
|
||||
}
|
||||
if (isPresent(el._window)) {
|
||||
this.dispatchEvent(el._window, evt);
|
||||
}
|
||||
}
|
||||
createMouseEvent(eventType): Event { return this.createEvent(eventType); }
|
||||
createEvent(eventType: string): Event {
|
||||
var evt = <Event>{
|
||||
type: eventType,
|
||||
defaultPrevented: false,
|
||||
preventDefault: () => { evt.defaultPrevented = true; }
|
||||
};
|
||||
return evt;
|
||||
}
|
||||
preventDefault(evt) { evt.returnValue = false; }
|
||||
isPrevented(evt): boolean { return isPresent(evt.returnValue) && !evt.returnValue; }
|
||||
getInnerHTML(el): string { return serializer.serialize(this.templateAwareRoot(el)); }
|
||||
getOuterHTML(el): string {
|
||||
serializer.html = '';
|
||||
serializer._serializeElement(el);
|
||||
return serializer.html;
|
||||
}
|
||||
nodeName(node): string { return node.tagName; }
|
||||
nodeValue(node): string { return node.nodeValue; }
|
||||
type(node: any): string { throw _notImplemented('type'); }
|
||||
content(node): string { return node.childNodes[0]; }
|
||||
firstChild(el): Node { return el.firstChild; }
|
||||
nextSibling(el): Node { return el.nextSibling; }
|
||||
parentElement(el): Node { return el.parent; }
|
||||
childNodes(el): Node[] { return el.childNodes; }
|
||||
childNodesAsList(el): List<any> {
|
||||
var childNodes = el.childNodes;
|
||||
var res = ListWrapper.createFixedSize(childNodes.length);
|
||||
for (var i = 0; i < childNodes.length; i++) {
|
||||
res[i] = childNodes[i];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
clearNodes(el) {
|
||||
while (el.childNodes.length > 0) {
|
||||
this.remove(el.childNodes[0]);
|
||||
}
|
||||
}
|
||||
appendChild(el, node) {
|
||||
this.remove(node);
|
||||
treeAdapter.appendChild(this.templateAwareRoot(el), node);
|
||||
}
|
||||
removeChild(el, node) {
|
||||
if (ListWrapper.contains(el.childNodes, node)) {
|
||||
this.remove(node);
|
||||
}
|
||||
}
|
||||
remove(el): HTMLElement {
|
||||
var parent = el.parent;
|
||||
if (parent) {
|
||||
var index = parent.childNodes.indexOf(el);
|
||||
parent.childNodes.splice(index, 1);
|
||||
}
|
||||
var prev = el.previousSibling;
|
||||
var next = el.nextSibling;
|
||||
if (prev) {
|
||||
prev.next = next;
|
||||
}
|
||||
if (next) {
|
||||
next.prev = prev;
|
||||
}
|
||||
el.prev = null;
|
||||
el.next = null;
|
||||
el.parent = null;
|
||||
return el;
|
||||
}
|
||||
insertBefore(el, node) {
|
||||
this.remove(node);
|
||||
treeAdapter.insertBefore(el.parent, node, el);
|
||||
}
|
||||
insertAllBefore(el, nodes) {
|
||||
ListWrapper.forEach(nodes, (n) => { this.insertBefore(el, n); });
|
||||
}
|
||||
insertAfter(el, node) {
|
||||
if (el.nextSibling) {
|
||||
this.insertBefore(el.nextSibling, node);
|
||||
} else {
|
||||
this.appendChild(el.parent, node);
|
||||
}
|
||||
}
|
||||
setInnerHTML(el, value) {
|
||||
this.clearNodes(el);
|
||||
var content = parser.parseFragment(value);
|
||||
for (var i = 0; i < content.childNodes.length; i++) {
|
||||
treeAdapter.appendChild(el, content.childNodes[i]);
|
||||
}
|
||||
}
|
||||
getText(el): string {
|
||||
if (this.isTextNode(el)) {
|
||||
return el.data;
|
||||
} else if (isBlank(el.childNodes) || el.childNodes.length == 0) {
|
||||
return "";
|
||||
} else {
|
||||
var textContent = "";
|
||||
for (var i = 0; i < el.childNodes.length; i++) {
|
||||
textContent += this.getText(el.childNodes[i]);
|
||||
}
|
||||
return textContent;
|
||||
}
|
||||
}
|
||||
setText(el, value: string) {
|
||||
if (this.isTextNode(el)) {
|
||||
el.data = value;
|
||||
} else {
|
||||
this.clearNodes(el);
|
||||
if (value !== '') treeAdapter.insertText(el, value);
|
||||
}
|
||||
}
|
||||
getValue(el): string { return el.value; }
|
||||
setValue(el, value: string) { el.value = value; }
|
||||
getChecked(el): boolean { return el.checked; }
|
||||
setChecked(el, value: boolean) { el.checked = value; }
|
||||
createComment(text: string): Comment { return treeAdapter.createCommentNode(text); }
|
||||
createTemplate(html): HTMLElement {
|
||||
var template = treeAdapter.createElement("template", 'http://www.w3.org/1999/xhtml', []);
|
||||
var content = parser.parseFragment(html);
|
||||
treeAdapter.appendChild(template, content);
|
||||
return template;
|
||||
}
|
||||
createElement(tagName): HTMLElement {
|
||||
return treeAdapter.createElement(tagName, 'http://www.w3.org/1999/xhtml', []);
|
||||
}
|
||||
createTextNode(text: string): Text { throw _notImplemented('createTextNode'); }
|
||||
createScriptTag(attrName: string, attrValue: string): HTMLElement {
|
||||
return treeAdapter.createElement("script", 'http://www.w3.org/1999/xhtml',
|
||||
[{name: attrName, value: attrValue}]);
|
||||
}
|
||||
createStyleElement(css: string): HTMLStyleElement {
|
||||
var style = this.createElement('style');
|
||||
this.setText(style, css);
|
||||
return <HTMLStyleElement>style;
|
||||
}
|
||||
createShadowRoot(el): HTMLElement {
|
||||
el.shadowRoot = treeAdapter.createDocumentFragment();
|
||||
el.shadowRoot.parent = el;
|
||||
return el.shadowRoot;
|
||||
}
|
||||
getShadowRoot(el): Element { return el.shadowRoot; }
|
||||
getHost(el): string { return el.host; }
|
||||
getDistributedNodes(el: any): List<Node> { throw _notImplemented('getDistributedNodes'); }
|
||||
clone(node: Node): Node {
|
||||
var _recursive = (node) => {
|
||||
var nodeClone = Object.create(Object.getPrototypeOf(node));
|
||||
for (var prop in node) {
|
||||
var desc = Object.getOwnPropertyDescriptor(node, prop);
|
||||
if (desc && 'value' in desc && typeof desc.value !== 'object') {
|
||||
nodeClone[prop] = node[prop];
|
||||
}
|
||||
}
|
||||
nodeClone.parent = null;
|
||||
nodeClone.prev = null;
|
||||
nodeClone.next = null;
|
||||
nodeClone.children = null;
|
||||
|
||||
mapProps.forEach(mapName => {
|
||||
if (isPresent(node[mapName])) {
|
||||
nodeClone[mapName] = {};
|
||||
for (var prop in node[mapName]) {
|
||||
nodeClone[mapName][prop] = node[mapName][prop];
|
||||
}
|
||||
}
|
||||
});
|
||||
var cNodes = node.children;
|
||||
if (cNodes) {
|
||||
var cNodesClone = new Array(cNodes.length);
|
||||
for (var i = 0; i < cNodes.length; i++) {
|
||||
var childNode = cNodes[i];
|
||||
var childNodeClone = _recursive(childNode);
|
||||
cNodesClone[i] = childNodeClone;
|
||||
if (i > 0) {
|
||||
childNodeClone.prev = cNodesClone[i - 1];
|
||||
cNodesClone[i - 1].next = childNodeClone;
|
||||
}
|
||||
childNodeClone.parent = nodeClone;
|
||||
}
|
||||
nodeClone.children = cNodesClone;
|
||||
}
|
||||
return nodeClone;
|
||||
};
|
||||
return _recursive(node);
|
||||
}
|
||||
getElementsByClassName(element, name: string): List<HTMLElement> {
|
||||
return this.querySelectorAll(element, "." + name);
|
||||
}
|
||||
getElementsByTagName(element: any, name: string): List<HTMLElement> {
|
||||
throw _notImplemented('getElementsByTagName');
|
||||
}
|
||||
classList(element): List<string> {
|
||||
var classAttrValue = null;
|
||||
var attributes = element.attribs;
|
||||
if (attributes && attributes.hasOwnProperty("class")) {
|
||||
classAttrValue = attributes["class"];
|
||||
}
|
||||
return classAttrValue ? classAttrValue.trim().split(/\s+/g) : [];
|
||||
}
|
||||
addClass(element, classname: string) {
|
||||
var classList = this.classList(element);
|
||||
var index = classList.indexOf(classname);
|
||||
if (index == -1) {
|
||||
classList.push(classname);
|
||||
element.attribs["class"] = element.className = ListWrapper.join(classList, " ");
|
||||
}
|
||||
}
|
||||
removeClass(element, classname: string) {
|
||||
var classList = this.classList(element);
|
||||
var index = classList.indexOf(classname);
|
||||
if (index > -1) {
|
||||
classList.splice(index, 1);
|
||||
element.attribs["class"] = element.className = ListWrapper.join(classList, " ");
|
||||
}
|
||||
}
|
||||
hasClass(element, classname: string): boolean {
|
||||
return ListWrapper.contains(this.classList(element), classname);
|
||||
}
|
||||
_readStyleAttribute(element) {
|
||||
var styleMap = {};
|
||||
var attributes = element.attribs;
|
||||
if (attributes && attributes.hasOwnProperty("style")) {
|
||||
var styleAttrValue = attributes["style"];
|
||||
var styleList = styleAttrValue.split(/;+/g);
|
||||
for (var i = 0; i < styleList.length; i++) {
|
||||
if (styleList[i].length > 0) {
|
||||
var elems = styleList[i].split(/:+/g);
|
||||
styleMap[elems[0].trim()] = elems[1].trim();
|
||||
}
|
||||
}
|
||||
}
|
||||
return styleMap;
|
||||
}
|
||||
_writeStyleAttribute(element, styleMap) {
|
||||
var styleAttrValue = "";
|
||||
for (var key in styleMap) {
|
||||
var newValue = styleMap[key];
|
||||
if (newValue && newValue.length > 0) {
|
||||
styleAttrValue += key + ":" + styleMap[key] + ";";
|
||||
}
|
||||
}
|
||||
element.attribs["style"] = styleAttrValue;
|
||||
}
|
||||
setStyle(element, stylename: string, stylevalue: string) {
|
||||
var styleMap = this._readStyleAttribute(element);
|
||||
styleMap[stylename] = stylevalue;
|
||||
this._writeStyleAttribute(element, styleMap);
|
||||
}
|
||||
removeStyle(element, stylename: string) { this.setStyle(element, stylename, null); }
|
||||
getStyle(element, stylename: string): string {
|
||||
var styleMap = this._readStyleAttribute(element);
|
||||
return styleMap.hasOwnProperty(stylename) ? styleMap[stylename] : "";
|
||||
}
|
||||
tagName(element): string { return element.tagName == "style" ? "STYLE" : element.tagName; }
|
||||
attributeMap(element): Map<string, string> {
|
||||
var res = new Map();
|
||||
var elAttrs = treeAdapter.getAttrList(element);
|
||||
for (var i = 0; i < elAttrs.length; i++) {
|
||||
var attrib = elAttrs[i];
|
||||
res.set(attrib.name, attrib.value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
hasAttribute(element, attribute: string): boolean {
|
||||
return element.attribs && element.attribs.hasOwnProperty(attribute);
|
||||
}
|
||||
getAttribute(element, attribute: string): string {
|
||||
return element.attribs && element.attribs.hasOwnProperty(attribute) ?
|
||||
element.attribs[attribute] :
|
||||
null;
|
||||
}
|
||||
setAttribute(element, attribute: string, value: string) {
|
||||
if (attribute) {
|
||||
element.attribs[attribute] = value;
|
||||
}
|
||||
}
|
||||
removeAttribute(element, attribute: string) {
|
||||
if (attribute) {
|
||||
StringMapWrapper.delete(element.attribs, attribute);
|
||||
}
|
||||
}
|
||||
templateAwareRoot(el): any { return this.isTemplateElement(el) ? this.content(el) : el; }
|
||||
createHtmlDocument(): Document {
|
||||
var newDoc = treeAdapter.createDocument();
|
||||
newDoc.title = "fake title";
|
||||
var head = treeAdapter.createElement("head", null, []);
|
||||
var body = treeAdapter.createElement("body", 'http://www.w3.org/1999/xhtml', []);
|
||||
this.appendChild(newDoc, head);
|
||||
this.appendChild(newDoc, body);
|
||||
StringMapWrapper.set(newDoc, "head", head);
|
||||
StringMapWrapper.set(newDoc, "body", body);
|
||||
StringMapWrapper.set(newDoc, "_window", StringMapWrapper.create());
|
||||
return newDoc;
|
||||
}
|
||||
defaultDoc(): Document {
|
||||
if (defDoc === null) {
|
||||
defDoc = this.createHtmlDocument();
|
||||
}
|
||||
return defDoc;
|
||||
}
|
||||
getBoundingClientRect(el): any { return {left: 0, top: 0, width: 0, height: 0}; }
|
||||
getTitle(): string { return this.defaultDoc().title || ""; }
|
||||
setTitle(newTitle: string) { this.defaultDoc().title = newTitle; }
|
||||
isTemplateElement(el: any): boolean {
|
||||
return this.isElementNode(el) && this.tagName(el) === "template";
|
||||
}
|
||||
isTextNode(node): boolean { return treeAdapter.isTextNode(node); }
|
||||
isCommentNode(node): boolean { return treeAdapter.isCommentNode(node); }
|
||||
isElementNode(node): boolean { return node ? treeAdapter.isElementNode(node) : false; }
|
||||
hasShadowRoot(node): boolean { return isPresent(node.shadowRoot); }
|
||||
isShadowRoot(node): boolean { return this.getShadowRoot(node) == node; }
|
||||
importIntoDoc(node): any { return this.clone(node); }
|
||||
adoptNode(node): any { return node; }
|
||||
isPageRule(rule): boolean {
|
||||
return rule.type === 6; // CSSRule.PAGE_RULE
|
||||
}
|
||||
isStyleRule(rule): boolean {
|
||||
return rule.type === 1; // CSSRule.MEDIA_RULE
|
||||
}
|
||||
isMediaRule(rule): boolean {
|
||||
return rule.type === 4; // CSSRule.MEDIA_RULE
|
||||
}
|
||||
isKeyframesRule(rule): boolean {
|
||||
return rule.type === 7; // CSSRule.KEYFRAMES_RULE
|
||||
}
|
||||
getHref(el): string { return el.href; }
|
||||
resolveAndSetHref(el, baseUrl: string, href: string) {
|
||||
if (href == null) {
|
||||
el.href = baseUrl;
|
||||
} else {
|
||||
el.href = url.resolve(baseUrl, href);
|
||||
}
|
||||
}
|
||||
_buildRules(parsedRules, css?) {
|
||||
var rules = [];
|
||||
for (var i = 0; i < parsedRules.length; i++) {
|
||||
var parsedRule = parsedRules[i];
|
||||
var rule: StringMap<string, any> = StringMapWrapper.create();
|
||||
StringMapWrapper.set(rule, "cssText", css);
|
||||
StringMapWrapper.set(rule, "style", {content: "", cssText: ""});
|
||||
if (parsedRule.type == "rule") {
|
||||
StringMapWrapper.set(rule, "type", 1);
|
||||
StringMapWrapper.set(rule, "selectorText", parsedRule.selectors.join(", ")
|
||||
.replace(/\s{2,}/g, " ")
|
||||
.replace(/\s*~\s*/g, " ~ ")
|
||||
.replace(/\s*\+\s*/g, " + ")
|
||||
.replace(/\s*>\s*/g, " > ")
|
||||
.replace(/\[(\w+)=(\w+)\]/g, '[$1="$2"]'));
|
||||
if (isBlank(parsedRule.declarations)) {
|
||||
continue;
|
||||
}
|
||||
for (var j = 0; j < parsedRule.declarations.length; j++) {
|
||||
var declaration = parsedRule.declarations[j];
|
||||
StringMapWrapper.set(StringMapWrapper.get(rule, "style"), declaration.property,
|
||||
declaration.value);
|
||||
StringMapWrapper.get(rule, "style").cssText +=
|
||||
declaration.property + ": " + declaration.value + ";";
|
||||
}
|
||||
} else if (parsedRule.type == "media") {
|
||||
StringMapWrapper.set(rule, "type", 4);
|
||||
StringMapWrapper.set(rule, "media", {mediaText: parsedRule.media});
|
||||
if (parsedRule.rules) {
|
||||
StringMapWrapper.set(rule, "cssRules", this._buildRules(parsedRule.rules));
|
||||
}
|
||||
}
|
||||
rules.push(rule);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
cssToRules(css: string): List<any> {
|
||||
css = css.replace(/url\(\'(.+)\'\)/g, 'url($1)');
|
||||
var rules = [];
|
||||
var parsedCSS = cssParse(css, {silent: true});
|
||||
if (parsedCSS.stylesheet && parsedCSS.stylesheet.rules) {
|
||||
rules = this._buildRules(parsedCSS.stylesheet.rules, css);
|
||||
}
|
||||
return rules;
|
||||
}
|
||||
supportsDOMEvents(): boolean { return false; }
|
||||
supportsNativeShadowDOM(): boolean { return false; }
|
||||
getGlobalEventTarget(target: string): any {
|
||||
if (target == "window") {
|
||||
return (<any>this.defaultDoc())._window;
|
||||
} else if (target == "document") {
|
||||
return this.defaultDoc();
|
||||
} else if (target == "body") {
|
||||
return this.defaultDoc().body;
|
||||
}
|
||||
}
|
||||
getBaseHref(): string { throw 'not implemented'; }
|
||||
resetBaseElement(): void { throw 'not implemented'; }
|
||||
getHistory(): History { throw 'not implemented'; }
|
||||
getLocation(): Location { throw 'not implemented'; }
|
||||
getUserAgent(): string { return "Fake user agent"; }
|
||||
getData(el, name: string): string { return this.getAttribute(el, 'data-' + name); }
|
||||
setData(el, name: string, value: string) { this.setAttribute(el, 'data-' + name, value); }
|
||||
// TODO(tbosch): move this into a separate environment class once we have it
|
||||
setGlobalVar(name: string, value: any) { global[name] = value; }
|
||||
}
|
||||
|
||||
// TODO: build a proper list, this one is all the keys of a HTMLInputElement
|
||||
var _HTMLElementPropertyList = [
|
||||
"webkitEntries",
|
||||
"incremental",
|
||||
"webkitdirectory",
|
||||
"selectionDirection",
|
||||
"selectionEnd",
|
||||
"selectionStart",
|
||||
"labels",
|
||||
"validationMessage",
|
||||
"validity",
|
||||
"willValidate",
|
||||
"width",
|
||||
"valueAsNumber",
|
||||
"valueAsDate",
|
||||
"value",
|
||||
"useMap",
|
||||
"defaultValue",
|
||||
"type",
|
||||
"step",
|
||||
"src",
|
||||
"size",
|
||||
"required",
|
||||
"readOnly",
|
||||
"placeholder",
|
||||
"pattern",
|
||||
"name",
|
||||
"multiple",
|
||||
"min",
|
||||
"minLength",
|
||||
"maxLength",
|
||||
"max",
|
||||
"list",
|
||||
"indeterminate",
|
||||
"height",
|
||||
"formTarget",
|
||||
"formNoValidate",
|
||||
"formMethod",
|
||||
"formEnctype",
|
||||
"formAction",
|
||||
"files",
|
||||
"form",
|
||||
"disabled",
|
||||
"dirName",
|
||||
"checked",
|
||||
"defaultChecked",
|
||||
"autofocus",
|
||||
"autocomplete",
|
||||
"alt",
|
||||
"align",
|
||||
"accept",
|
||||
"onautocompleteerror",
|
||||
"onautocomplete",
|
||||
"onwaiting",
|
||||
"onvolumechange",
|
||||
"ontoggle",
|
||||
"ontimeupdate",
|
||||
"onsuspend",
|
||||
"onsubmit",
|
||||
"onstalled",
|
||||
"onshow",
|
||||
"onselect",
|
||||
"onseeking",
|
||||
"onseeked",
|
||||
"onscroll",
|
||||
"onresize",
|
||||
"onreset",
|
||||
"onratechange",
|
||||
"onprogress",
|
||||
"onplaying",
|
||||
"onplay",
|
||||
"onpause",
|
||||
"onmousewheel",
|
||||
"onmouseup",
|
||||
"onmouseover",
|
||||
"onmouseout",
|
||||
"onmousemove",
|
||||
"onmouseleave",
|
||||
"onmouseenter",
|
||||
"onmousedown",
|
||||
"onloadstart",
|
||||
"onloadedmetadata",
|
||||
"onloadeddata",
|
||||
"onload",
|
||||
"onkeyup",
|
||||
"onkeypress",
|
||||
"onkeydown",
|
||||
"oninvalid",
|
||||
"oninput",
|
||||
"onfocus",
|
||||
"onerror",
|
||||
"onended",
|
||||
"onemptied",
|
||||
"ondurationchange",
|
||||
"ondrop",
|
||||
"ondragstart",
|
||||
"ondragover",
|
||||
"ondragleave",
|
||||
"ondragenter",
|
||||
"ondragend",
|
||||
"ondrag",
|
||||
"ondblclick",
|
||||
"oncuechange",
|
||||
"oncontextmenu",
|
||||
"onclose",
|
||||
"onclick",
|
||||
"onchange",
|
||||
"oncanplaythrough",
|
||||
"oncanplay",
|
||||
"oncancel",
|
||||
"onblur",
|
||||
"onabort",
|
||||
"spellcheck",
|
||||
"isContentEditable",
|
||||
"contentEditable",
|
||||
"outerText",
|
||||
"innerText",
|
||||
"accessKey",
|
||||
"hidden",
|
||||
"webkitdropzone",
|
||||
"draggable",
|
||||
"tabIndex",
|
||||
"dir",
|
||||
"translate",
|
||||
"lang",
|
||||
"title",
|
||||
"childElementCount",
|
||||
"lastElementChild",
|
||||
"firstElementChild",
|
||||
"children",
|
||||
"onwebkitfullscreenerror",
|
||||
"onwebkitfullscreenchange",
|
||||
"nextElementSibling",
|
||||
"previousElementSibling",
|
||||
"onwheel",
|
||||
"onselectstart",
|
||||
"onsearch",
|
||||
"onpaste",
|
||||
"oncut",
|
||||
"oncopy",
|
||||
"onbeforepaste",
|
||||
"onbeforecut",
|
||||
"onbeforecopy",
|
||||
"shadowRoot",
|
||||
"dataset",
|
||||
"classList",
|
||||
"className",
|
||||
"outerHTML",
|
||||
"innerHTML",
|
||||
"scrollHeight",
|
||||
"scrollWidth",
|
||||
"scrollTop",
|
||||
"scrollLeft",
|
||||
"clientHeight",
|
||||
"clientWidth",
|
||||
"clientTop",
|
||||
"clientLeft",
|
||||
"offsetParent",
|
||||
"offsetHeight",
|
||||
"offsetWidth",
|
||||
"offsetTop",
|
||||
"offsetLeft",
|
||||
"localName",
|
||||
"prefix",
|
||||
"namespaceURI",
|
||||
"id",
|
||||
"style",
|
||||
"attributes",
|
||||
"tagName",
|
||||
"parentElement",
|
||||
"textContent",
|
||||
"baseURI",
|
||||
"ownerDocument",
|
||||
"nextSibling",
|
||||
"previousSibling",
|
||||
"lastChild",
|
||||
"firstChild",
|
||||
"childNodes",
|
||||
"parentNode",
|
||||
"nodeType",
|
||||
"nodeValue",
|
||||
"nodeName",
|
||||
"closure_lm_714617",
|
||||
"__jsaction"
|
||||
];
|
Reference in New Issue
Block a user