OLD | NEW |
---|---|
(Empty) | |
1 --- | |
2 layout: default | |
3 title: "Dart Web Components" | |
4 rel: | |
5 author: siggi-cherem | |
6 description: "A brief introduction to Dart web components." | |
7 has-permalinks: true | |
8 --- | |
9 | |
10 # {{ page.title }} | |
11 _Written by ...<br /> | |
Kathy Walrath
2012/10/09 23:16:57
update the next 3 lines (of course)
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done. thanks :) - I looked at the other articles,
| |
12 July 2012 <br /> | |
13 Updated: September 2012_ | |
14 | |
15 ## Dart web components | |
Kathy Walrath
2012/10/09 23:16:57
Delete this line
(already covered by page.title,
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
16 | |
17 {% comment %} | |
18 | |
19 README --- General notes about editing this file: | |
20 | |
21 * This file is processed by liquid, which evaluates {{ var }} and removes the | |
22 \{\{ and \}\} symbols from the code. Because we use \{\{\}\} in our template | |
23 expressions, we need to escape them in a special way. Unfortunately using | |
24 \{\{\}\} within code makes the backslash show up. There are 2 ways to work | |
25 around this: | |
26 * Doing {{'{{'}}: lyquid evaluates it as a string expression returning \{\{. | |
27 * Using \{\% raw \%\} blocks. | |
28 | |
29 * the codesample blocks are an extension added to jekyll written as 'liquid' | |
30 blocks. The meaning of a block like this: | |
31 \{\% codesample 80 \%\} | |
32 | |
33 text | |
34 \{\% sample 10 20 url \%\} | |
35 \{\% endcodesample \%\} | |
36 is that we'll create a table, the first colum will have sample source code (in | |
37 this case "text"). This code can have a \{\% highlight \%\} section, but other | |
38 than that, no markdown is supported here :(. The column width is specified as | |
39 the first argument of the codesample tag above it (in this example 80 means | |
40 80%). The \{\% sample \%\} tag defines the width, height, and url for an iframe | |
41 that will contain the runnining version of the code sample. | |
42 | |
43 {% endcomment %} | |
44 | |
45 [Dart web components][dwc] are a combination of templating, data-binding, and | |
Kathy Walrath
2012/10/09 23:16:57
GLOBAL: data-binding -> data binding
(If you were
Kathy Walrath
2012/10/09 23:16:57
Are web components really techniques? I think of t
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
nice, thanks. Done.
| |
46 encapsulation techniques for writing web applications at scale. | |
47 | |
48 There are many UI frameworks in the web intended for writing web applications in | |
Kathy Walrath
2012/10/09 23:16:57
"There are..." is a vague way to start (those 2 wo
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
49 JS, for example [backbone], [ember.js][ember], and [angularjs][angular]. | |
50 Recently, the web community has been pushing to include some of the common ideas | |
51 of these frameworks directly into browser platform. A result of that has been | |
Kathy Walrath
2012/10/09 23:16:57
into -> into the
A result of that -> A result
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
52 added features like Shadow Dom and [Web Components][wc], and other experimental | |
Kathy Walrath
2012/10/09 23:16:57
No link to Shadow DOM?
We should standardize on t
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
Jennifer Messerly
2012/10/10 01:18:29
Could you add a link to Shadow DOM?
http://dvcs.w3
| |
53 and cool ideas like [Model Driven Views][mdv]. | |
54 | |
55 Dart web components have a similar role in Dart. They are the result of | |
Kathy Walrath
2012/10/09 23:16:57
Could be shorter/clearer. How about.
Dart web com
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
56 combining together design ideas of web components and model-driven views, and | |
57 adapting them to include Dart in the picture. The dart web component tools will | |
Kathy Walrath
2012/10/09 23:16:57
I was confused by "dart web component tools". We u
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
good points... fixed.
| |
58 take advantage of advanced browser features if they exist in your browser, but | |
59 otherwise they will emulate any missing feature. | |
60 | |
61 In this article, we'll walk through some examples that illustrate how to write | |
62 and use Dart Web Components. Soon we'll be creating a document with a detailed | |
63 specification (link TBR), and another document with instructions on how to use | |
64 the Dart Web Component tools (link TBR). | |
65 | |
66 ## MDV Templates in Dart | |
Kathy Walrath
2012/10/09 23:16:57
Templates -> templates
(we use Title Caps for pag
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
67 | |
68 Most UI frameworks provide some form of templating to declare views with a | |
69 succint declarative syntax. Dart web components follow closely | |
Kathy Walrath
2012/10/09 23:16:57
follow closely -> closely follow
Kathy Walrath
2012/10/09 23:16:57
succint -> succinct
follow closely -> closely foll
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
70 the syntax of [Model Driven Views][mdv] (MDV), which is basically | |
Kathy Walrath
2012/10/09 23:16:57
the syntax of ... MDV -> the MDV syntax
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
71 HTML with small extensions to enable the following features: | |
72 | |
73 * **one-way data-binding**: how to embed data into your UI; | |
Kathy Walrath
2012/10/09 23:16:57
We usually capitalize the first words in a list. A
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
Done.
| |
74 * **two-way data-binding**: how to keep data in sync with UI changes; | |
75 * **events listeners**: how to easily attach code that reacts to UI events; | |
76 * **conditionals**: how to selectively show parts of the UI; and | |
77 * **loops**: how to construct lists and tables by iterating over collections. | |
78 | |
79 We made some changes to make sure that using Dart with MDV feels natural, but | |
80 otherwise all the concepts from MDV are available here. Let's take a look at | |
81 examples for each of these features. | |
82 | |
83 ### Data-bindings | |
Kathy Walrath
2012/10/09 23:16:57
Should this be "One-way data binding"?
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
yes :) thanks
| |
84 | |
85 You can inject data in your template by simply using `{{'{{'}} expresions }}`. | |
Kathy Walrath
2012/10/09 23:16:57
"by simply using" -> "using"
expresions ->
expres
Siggi Cherem (dart-lang)
2012/10/09 23:51:08
good point, no it should be singular
| |
86 The example below shows a simple hello world program where the value of the dart | |
87 top-level variable `dataValue` is injected in the page automatically. The | |
88 right column shows the app generated from this code running in an iframe. | |
89 | |
90 {% codesample 90 %} | |
91 {% highlight html %} | |
92 {% raw %} | |
93 <html><body> | |
94 <div>Hello {{dataValue}}!</div> | |
95 <script type="application/dart"> | |
96 String dataValue; | |
97 main() { | |
98 var today = new Date.now(); | |
99 dataValue = 'world ${today.year}-${today.month}-${today.day}'; | |
100 } | |
101 </script> | |
102 </body></html> | |
103 {% endraw %} | |
104 {% endhighlight %} | |
105 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/helloworld.html.html %} | |
106 {% endcodesample %} | |
107 | |
108 The template expression we just saw above is what we call a **one-way data | |
109 binding**. Like in many other UI libraries and frameworks, we automatically | |
110 watch for changes in your data and ensure the UI is up-to-date whenever the data | |
111 changes. | |
112 | |
113 Dart web components do this by using the `watchers.dart` library (included with | |
114 the dart web components package). You can listen for changes and notify everyone | |
115 when changes might occur. The following example illustrates how you would | |
116 manually use this library: | |
117 | |
118 {% codesample 90 %} | |
119 {% highlight html %} | |
120 {% raw %} | |
121 <html><body> | |
122 <div>Hello counter: {{count}}</div> | |
123 <script type="application/dart"> | |
124 import 'dart:html'; | |
125 import 'package:web_components/watcher.dart' as watchers; | |
126 int count; | |
127 main() { | |
128 count = 0; | |
129 window.setInterval(() { | |
130 count++; | |
131 watchers.dispatch(); | |
132 }, 1000); | |
133 } | |
134 </script> | |
135 </body></html> | |
136 {% endraw %} | |
137 {% endhighlight %} | |
138 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/counter.html.html %} | |
139 {% endcodesample %} | |
140 | |
141 The code manually invokes `watchers.dispatch()` to make a change visible to the | |
142 UI. Every now and then it is useful to access watchers directly, but we have | |
143 found that we often don't have to manually write these calls. In particular, | |
144 Dart web components will automatically make the dispatch call when using | |
145 common features like two-way binding and attaching event listeners. | |
146 | |
147 ### Two-way data bindings | |
148 | |
149 Two-way data bindings lets us define that we want a DOM element's value | |
150 (typically an input box or a check box) to be kept in sync with the value of a | |
151 Dart variable. The following example creates a two way binding between `str` and | |
152 `input.value`. We declare this binding by writing the attribute | |
153 `data-bind="value:str"`. | |
154 | |
155 {% codesample 90 %} | |
156 {% highlight html %} | |
157 {% raw %} | |
158 <html><body> | |
159 <div> | |
160 Input: | |
161 <input type="text" data-bind="value:str" placeholder="type something here"> | |
162 <div> Value: {{str}}</div> | |
163 <div> Length: {{str.length}}</div> | |
164 </div> | |
165 <script type="application/dart"> | |
166 String str = ''; | |
167 main() {} | |
168 </script> | |
169 </body></html> | |
170 {% endraw %} | |
171 {% endhighlight %} | |
172 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/twoway.html.html %} | |
173 {% endcodesample %} | |
174 | |
175 This is a simple example where Dart web components automatically dispatch | |
176 events for data-model changes. In particular, whenever you update the value of | |
177 the text box, the string and it's length will be updated in other parts of the | |
178 UI. | |
179 | |
180 ### Data-binding expressions | |
181 | |
182 We want to make Dart web components have, to a great extend, feature and design | |
183 parity with MDV. For this reason, we try to match the same syntax of their | |
184 template language where it is appropriate. MDV restricts data-binding | |
185 expressions to an expression language containing variables, field dereferences, | |
186 and array accesses. This means that expressions in MDV templates would likely be | |
187 valid Dart and valid JS as well. That also means that advanced Dart expressions | |
188 are not valid between `{{'{{'}}expressions}}`, however you can always hide | |
189 complex expressions under a getter in Dart and use the getter property within | |
190 the template. | |
191 | |
192 A full specification of the expression syntax will be available soon in our | |
193 [specification document (link TBR)][]. | |
194 | |
195 ### Conditionals | |
196 | |
197 Template conditionals allow you to selectively activate parts of the UI. We | |
198 write a conditional by wrapping a portion of the UI in a `<template>` tag and | |
199 writing the condition in an attribute of the form `instantiate="if expr"`. For | |
200 instance, the following example only shows `They match!` when both input boxes | |
201 have the same text: | |
202 | |
203 {% codesample 90 %} | |
204 {% highlight html %} | |
205 {% raw %} | |
206 <html><body> | |
207 <div> | |
208 <div> Input1: <input type="text" data-bind="value:str1"></div> | |
209 <div> Input2: <input type="text" data-bind="value:str2"></div> | |
210 <template instantiate="if str1 == str2"> | |
211 <div>They match!</div> | |
212 </template> | |
213 </div> | |
214 <script type="application/dart"> | |
215 String str1 = ''; | |
216 String str2 = ''; | |
217 main() {} | |
218 </script> | |
219 </body></html> | |
220 {% endraw %} | |
221 {% endhighlight %} | |
222 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/matchstrings.html.html %} | |
223 {% endcodesample %} | |
224 | |
225 ### Loops | |
226 | |
227 Template loops allow us to iterate over iterable Dart collections. The following | |
228 example shows a fun little app that has search as you type. We use the two-way | |
229 data-binding to store the `query` string, then we compute a filtered set of | |
230 results and display it using a looping construct. | |
231 | |
232 {% codesample 90 %} | |
233 {% highlight html %} | |
234 {% raw %} | |
235 <html><body> | |
236 <div> | |
237 <span>Search for something:</span> | |
238 <input type="text" data-bind="value:query"> | |
239 <div> | |
240 <template instantiate='if noMatches'><span>No matches</span></template> | |
241 <template instantiate='if !noMatches'><span>Top results:</span></template> | |
242 </div> | |
243 <div><ul> | |
244 <template iterate='fruit in results'> | |
245 <li>{{fruit}}</li> | |
246 </template> | |
247 </ul></div> | |
248 </div> | |
249 <script type="application/dart"> | |
250 String query = ''; | |
251 List<String> values = const [ 'Apple', 'Apricot', 'Avocado', 'Banana', | |
252 'Blackberry', 'Blackcurrant', 'Blueberry', 'Currant', 'Cherry', | |
253 'Clementine', 'Date', 'Durian', 'Fig', 'Gooseberry', 'Grape', | |
254 'Grapefruit', 'Guava', 'Huckleberry', 'Kiwi', 'Lemon', 'Lime', | |
255 'Lychee', 'Mandarine', 'Mango', 'Cantaloupe', 'Honeydew melon', | |
256 'Nectarine', 'Orange', 'Peach', 'Pear', 'Plum', 'Pineapple', | |
257 'Pomegranate', 'Raspberry', 'Redcurrant', 'Star fruit', 'Strawberry', | |
258 'Tangerine', 'Tomato', 'Watermelon']; | |
259 | |
260 List<String> get results { | |
261 var res = values.filter( | |
262 (v) => v.toLowerCase().contains(query.toLowerCase())); | |
263 if (res.length > 20) { | |
264 res.length = 20; | |
265 res.add('... and many more'); | |
266 } | |
267 return res; | |
268 } | |
269 | |
270 bool get noMatches => results.isEmpty(); | |
271 | |
272 main() {} | |
273 </script> | |
274 </body></html> | |
275 {% endraw %} | |
276 {% endhighlight %} | |
277 {% sample 300px 600px http://dart-lang.github.com/dart-web-components/example/ex plainer/fruitsearch.html.html %} | |
278 {% endcodesample %} | |
279 | |
280 | |
281 ### Listen to UI events | |
282 | |
283 Templates also gives us a succint way to listen for arbitrary UI events and | |
284 associate those events with Dart code. We do this by using `data-action` | |
285 attributes. Here is an example that listens for click events: | |
286 | |
287 {% codesample 90 %} | |
288 {% highlight html %} | |
289 {% raw %} | |
290 <html><body> | |
291 <div> | |
292 <button data-action="click:increment">Click me</button> | |
293 <span>(click count: {{count}})</span> | |
294 </div> | |
295 <script type="application/dart"> | |
296 int count = 0; | |
297 void increment(e) { count++; } | |
298 main() {} | |
299 </script> | |
300 </body></html> | |
301 {% endraw %} | |
302 {% endhighlight %} | |
303 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/clickcount.html.html %} | |
304 {% endcodesample %} | |
305 | |
306 | |
307 ### Templating summary | |
308 | |
309 Templates solve one part of the problem in building web applications: reducing | |
310 the amount of boilerplate code that is used to set up a typical | |
311 model-view-viewmodel architecture. One-way databindings, two-way databindings, | |
312 and data-action listeners, help reduce the need for manually creating controller | |
313 objects that do these bindings by hand. If we combine bindings, conditionals, | |
314 and loops, we have a formula to create simple and sophisticated views in a | |
315 declarative fashion. | |
316 | |
317 However, templating alone is not enough. We need mechanisms to encapsulate and | |
318 abstract views so we can scale to build larger web apps. This is were we need | |
319 web components. | |
320 | |
321 ## Web Components in Dart | |
322 | |
323 Web components provide a way to create encapsulated reusable views, which will | |
324 be useful to build medium and large applications. A web component basically | |
325 includes a view, some data, and behavior. In our case, views are described in | |
326 terms of templates, while data and behavior are written directly in Dart. | |
327 | |
328 ### Declaring a component | |
329 | |
330 Web components are declared using a special `<element>` tag. For example, we can | |
331 take the click-count example above and make it a component as follows: | |
332 | |
333 {% highlight html %} | |
334 {% raw %} | |
335 <html><body> | |
336 <element name="x-counter" constructor="CounterComponent" extends="div"> | |
337 <template> | |
338 <div> | |
339 <button data-action="click:increment">Click me</button> | |
340 <span>(click count: {{count}})</span> | |
341 </div> | |
342 </template> | |
343 <script type="application/dart"> | |
344 import 'package:web_components/web_component.dart'; | |
345 | |
346 class CounterComponent extends WebComponent { | |
347 int count = 0; | |
348 void increment(e) { count++; } | |
349 } | |
350 </script> | |
351 </element> | |
352 <!-- more below... --> | |
353 </body></html> | |
354 {% endraw %} | |
355 {% endhighlight %} | |
356 | |
357 The `<element>` tag basically declares a component whose view is defined | |
358 under the child `<template>` tag, and whose behavior code is embedded or sourced | |
359 by the child `<script>` tag. | |
360 | |
361 Components can be thought as if they are extending DOM nodes, their declaration | |
362 indicates which DOM node they extend from using the `extends` attribute. The | |
363 attribute `constructor="CounterComponent"` indicates that this component's | |
364 behavior is defined in the `CounterComponent` class. Today, this class must | |
365 extend from `WebComponent`, but in the future it will be possible to extend | |
366 directly from the DOM Node that we declared in the `extends` attribute. For | |
367 instance, `class CounterComponent extends DivElement ...`. | |
368 | |
369 The `<element>` tag also declares the component's name with the `name` | |
370 attribute. This name will be used to instantiate this component later on. | |
371 | |
372 ### Instantiating a component | |
373 | |
374 Instantiating a component can be done in two ways: using its name as a tag, e.g. | |
375 `<x-counter></x-counter>` or using setting the `is` attribute on the | |
376 tag that the component extends from. For example, | |
377 | |
378 {% codesample 90 %} | |
379 {% highlight html %} | |
380 {% raw %} | |
381 <html><body> | |
382 <!-- ... element declared as above --> | |
383 <div is="x-counter"></div> | |
384 <script type="application/dart"> | |
385 main(){} | |
386 </script> | |
387 </body></html> | |
388 {% endraw %} | |
389 {% endhighlight %} | |
390 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent.html.html %} | |
391 {% endcodesample %} | |
392 | |
393 | |
394 ### Passing data to a component | |
395 | |
396 All of the public fields in a component declaration can be initialized directly | |
397 when we instantiate a component. We can do this by writing a special | |
398 `data-value` attribute in the HTML. For instance, the following example | |
399 instantiates two click-counter components (declared just like above), but | |
400 initializes the `count` field of the component to a different value each time. | |
401 | |
402 {% codesample 90 %} | |
403 {% highlight html %} | |
404 {% raw %} | |
405 <html><body> | |
406 <!-- ... element declared as above --> | |
407 <div is="x-counter" data-value="count: myNumber"></div> | |
408 <div is="x-counter" data-value="count: 5"></div> | |
409 <script type="application/dart"> | |
410 int myNumber = 12; | |
411 main(){} | |
412 </script> | |
413 </body></html> | |
414 {% endraw %} | |
415 {% endhighlight %} | |
416 {% sample 300px 200px http://dart-lang.github.com/dart-web-components/example/ex plainer/countcomponent5.html.html %} | |
417 {% endcodesample %} | |
418 | |
419 ### Working at scale | |
420 | |
421 When developing larger web applications, it is really useful to be able to split | |
422 the work and divide pieces of your application in multiple files. It is also | |
423 useful to create reusable components that you embed in several places of your | |
424 application or even across several applications. | |
425 | |
426 Web components allows us to do import other components using `<link | |
427 rel="components">` tags. For example, suppose we created a file | |
428 `clickcounter.html` that contains the declaration of the click-counter component | |
429 as we had above. Then, our last example could be rewritten as follows: | |
430 | |
431 {% highlight html %} | |
432 {% raw %} | |
433 <html> | |
434 <head> | |
435 <link rel="components" href="clickcounter.html"> | |
436 </head> | |
437 <body> | |
438 <div is="x-counter" data-value="count: myNumber"></div> | |
439 <div is="x-counter" data-value="count: 5"></div> | |
440 <script type="application/dart"> | |
441 int myNumber = 12; | |
442 main(){} | |
443 </script> | |
444 </body> | |
445 </html> | |
446 {% endraw %} | |
447 {% endhighlight %} | |
448 | |
449 ### Upcoming features | |
450 | |
451 We are still adding features and making changes to Dart web components. Here are | |
452 some of the features we are working on: | |
453 | |
454 * Support for sub-components. Using a special `<content>` tag, a component | |
455 can embed nodes that will be provided when instantiating it. For instance, | |
456 you could write a component that puts a frame around an image as follows: | |
457 | |
458 {% highlight html %} | |
459 {% raw %} | |
460 <html> | |
461 <body> | |
462 <element name="x-myframe"> | |
463 <template> | |
464 <!-- some complex wrapping happens here ... --> | |
465 <div class="framestyle">...<content></content>...</div> | |
466 </template> | |
467 </element> | |
468 | |
469 <div is="x-myframe"> | |
470 <!-- img will be included where we wrote <content> above --> | |
471 <img src="..."> | |
472 </div> | |
473 </body> | |
474 </html> | |
475 {% endraw %} | |
476 {% endhighlight %} | |
477 | |
478 * Alternative MDV conditional and listing constructs. Instead of using a | |
479 `<template>` tags, you will be able to use `instantiate` and | |
480 `iterate` attributes directly on any element. This is important because in | |
481 some parts of the HTML is not valid to write `<template>` tags. For example, | |
482 this feature will make it possible to iterate on table rows and cells. | |
483 | |
484 ## Developing and using Dart web components | |
485 | |
486 We are making several tools available to make it easy to create and deploy | |
487 projects that use dart web components. We have a compiler tool that can be run | |
488 offline to generate efficient code for your components. The generated code will | |
489 try to use the native features available in browsers, but otherwise it will | |
490 resort to other techniques to ensure that the semantics of dart web components | |
491 are the same everywhere. | |
492 | |
493 We have added integration with the Dart editor, so that changes to source files | |
494 can be compiled automatically in the background. We are also developing an | |
495 extension for dartium that will be able to compile components on the fly as | |
496 you load them. Both the editor and dartium integration will provide you with a | |
497 smooth edit/refresh cycle. | |
498 | |
499 More details about our tools will be available soon [(link TBR)][]. | |
500 | |
501 ## Exploring More | |
502 | |
503 There are many resources to explore and learn more about Dart web components. | |
504 Check out our Dartisans episode on this topic: | |
505 | |
506 <iframe width="560" height="315" src="http://www.youtube.com/embed/zUdQkSwslzc" frameborder="0" allowfullscreen></iframe> | |
507 | |
508 You can also follow the project in [github][dwc], track and file bugs in our | |
509 [issue tracker][bugs], and play with other examples in our repo, like our port | |
510 of [todomvc][todomvcindwc]. | |
511 | |
512 If you have any questions, feel free to send us email directly at | |
513 [misc@dartlang.org](mailto:misc@dartlang.org). | |
514 | |
515 | |
516 [wc]: http://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html | |
517 [mdv]: http://code.google.com/p/mdv/ | |
518 [dwc]: https://github.com/dart-lang/dart-web-components/ | |
519 [bugs]: https://github.com/dart-lang/dart-web-components/issues | |
520 [backbone]: http://backbonejs.org/ | |
521 [angular]: http://angularjs.org/ | |
522 [ember]: http://emberjs.com/ | |
523 [todomvcindwc]: https://github.com/dart-lang/dart-web-components/tree/master/exa mple/todomvc | |
OLD | NEW |