OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 class _TextFactoryProvider { | |
6 | |
7 factory Text(String data) => _document._createTextNode(data); | |
8 } | |
9 | |
10 class _EventFactoryProvider { | |
11 factory Event(String type, [bool canBubble = true, | |
12 bool cancelable = true]) { | |
13 final _EventImpl e = _document._createEvent("Event"); | |
14 e._initEvent(type, canBubble, cancelable); | |
15 return e; | |
16 } | |
17 } | |
18 | |
19 class _MouseEventFactoryProvider { | |
20 factory MouseEvent(String type, Window view, int detail, | |
21 int screenX, int screenY, int clientX, int clientY, int button, | |
22 [bool canBubble = true, bool cancelable = true, bool ctrlKey = false, | |
23 bool altKey = false, bool shiftKey = false, bool metaKey = false, | |
24 EventTarget relatedTarget = null]) { | |
25 final e = _document._createEvent("MouseEvent"); | |
26 e._initMouseEvent(type, canBubble, cancelable, view, detail, | |
27 screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, | |
28 button, relatedTarget); | |
29 return e; | |
30 } | |
31 } | |
32 | |
33 class _CSSStyleDeclarationFactoryProvider { | |
34 factory CSSStyleDeclaration.css(String css) { | |
35 final style = new Element.tag('div').style; | |
36 style.cssText = css; | |
37 return style; | |
38 } | |
39 | |
40 factory CSSStyleDeclaration() { | |
41 return new CSSStyleDeclaration.css(''); | |
42 } | |
43 } | |
44 | |
45 final _START_TAG_REGEXP = const RegExp('<(\\w+)'); | |
46 class _ElementFactoryProvider { | |
47 static final _CUSTOM_PARENT_TAG_MAP = const { | |
48 'body' : 'html', | |
49 'head' : 'html', | |
50 'caption' : 'table', | |
51 'td': 'tr', | |
52 'colgroup': 'table', | |
53 'col' : 'colgroup', | |
54 'tr' : 'tbody', | |
55 'tbody' : 'table', | |
56 'tfoot' : 'table', | |
57 'thead' : 'table', | |
58 'track' : 'audio', | |
59 }; | |
60 | |
61 /** @domName Document.createElement */ | |
62 factory Element.html(String html) { | |
63 // TODO(jacobr): this method can be made more robust and performant. | |
64 // 1) Cache the dummy parent elements required to use innerHTML rather than | |
65 // creating them every call. | |
66 // 2) Verify that the html does not contain leading or trailing text nodes. | |
67 // 3) Verify that the html does not contain both <head> and <body> tags. | |
68 // 4) Detatch the created element from its dummy parent. | |
69 String parentTag = 'div'; | |
70 String tag; | |
71 final match = _START_TAG_REGEXP.firstMatch(html); | |
72 if (match !== null) { | |
73 tag = match.group(1).toLowerCase(); | |
74 if (_CUSTOM_PARENT_TAG_MAP.containsKey(tag)) { | |
75 parentTag = _CUSTOM_PARENT_TAG_MAP[tag]; | |
76 } | |
77 } | |
78 final _ElementImpl temp = new Element.tag(parentTag); | |
79 temp.innerHTML = html; | |
80 | |
81 Element element; | |
82 if (temp.elements.length == 1) { | |
83 element = temp.elements.first; | |
84 } else if (parentTag == 'html' && temp.elements.length == 2) { | |
85 // Work around for edge case in WebKit and possibly other browsers where | |
86 // both body and head elements are created even though the inner html | |
87 // only contains a head or body element. | |
88 element = temp.elements[tag == 'head' ? 0 : 1]; | |
89 } else { | |
90 throw new IllegalArgumentException('HTML had ${temp.elements.length} ' + | |
91 'top level elements but 1 expected'); | |
92 } | |
93 element.remove(); | |
94 return element; | |
95 } | |
96 | |
97 /** @domName Document.createElement */ | |
98 factory Element.tag(String tag) => _document._createElement(tag); | |
99 } | |
100 | |
101 class _DocumentFragmentFactoryProvider { | |
102 /** @domName Document.createDocumentFragment */ | |
103 factory DocumentFragment() => document.createDocumentFragment(); | |
104 | |
105 factory DocumentFragment.html(String html) { | |
106 final fragment = new DocumentFragment(); | |
107 fragment.innerHTML = html; | |
108 return fragment; | |
109 } | |
110 | |
111 // TODO(nweiz): enable this when XML is ported. | |
112 // factory DocumentFragment.xml(String xml) { | |
113 // final fragment = new DocumentFragment(); | |
114 // final e = new XMLElement.tag("xml"); | |
115 // e.innerHTML = xml; | |
116 // | |
117 // // Copy list first since we don't want liveness during iteration. | |
118 // final List nodes = new List.from(e.nodes); | |
119 // fragment.nodes.addAll(nodes); | |
120 // return fragment; | |
121 // } | |
122 | |
123 factory DocumentFragment.svg(String svg) { | |
124 final fragment = new DocumentFragment(); | |
125 final e = new SVGSVGElement(); | |
126 e.innerHTML = svg; | |
127 | |
128 // Copy list first since we don't want liveness during iteration. | |
129 final List nodes = new List.from(e.nodes); | |
130 fragment.nodes.addAll(nodes); | |
131 return fragment; | |
132 } | |
133 } | |
134 | |
135 class _SVGElementFactoryProvider { | |
136 factory SVGElement.tag(String tag) { | |
137 final Element temp = | |
138 _document._createElementNS("http://www.w3.org/2000/svg", tag); | |
139 return temp; | |
140 } | |
141 | |
142 factory SVGElement.svg(String svg) { | |
143 Element parentTag; | |
144 final match = _START_TAG_REGEXP.firstMatch(svg); | |
145 if (match != null && match.group(1).toLowerCase() == 'svg') { | |
146 parentTag = new Element.tag('div'); | |
147 } else { | |
148 parentTag = new SVGSVGElement(); | |
149 } | |
150 | |
151 parentTag.innerHTML = svg; | |
152 if (parentTag.elements.length == 1) return parentTag.nodes.removeLast(); | |
153 | |
154 throw new IllegalArgumentException('SVG had ${parentTag.elements.length} ' + | |
155 'top-level elements but 1 expected'); | |
156 } | |
157 } | |
158 | |
159 class _SVGSVGElementFactoryProvider { | |
160 factory SVGSVGElement() { | |
161 final el = new SVGElement.tag("svg"); | |
162 // The SVG spec requires the version attribute to match the spec version | |
163 el.attributes['version'] = "1.1"; | |
164 return el; | |
165 } | |
166 } | |
OLD | NEW |