Index: src/site/docs/tutorials/polymer-intro/index.markdown |
diff --git a/src/site/docs/tutorials/polymer-intro/index.markdown b/src/site/docs/tutorials/polymer-intro/index.markdown |
new file mode 100644 |
index 0000000000000000000000000000000000000000..0824abd3dd3fe8f544823137c911eae95c69aded |
--- /dev/null |
+++ b/src/site/docs/tutorials/polymer-intro/index.markdown |
@@ -0,0 +1,497 @@ |
+--- |
+layout: default |
+title: "Define a Custom Element" |
+description: "Create a custom HTML element using Polymer." |
+has-permalinks: true |
+tutorial: |
+ id: polymer-intro |
+next: fetchdata |
+next-title: "Fetch Data Dynamically" |
+prev: shared-pkgs |
+prev-title: "Install Shared Packages" |
+--- |
+ |
+{% capture whats_the_point %} |
+ |
+* Polymer.dart is the next evolution of Web UI. |
+* Everything in Polymer.dart is an element. |
+* Custom elements provide semantically meaningful encapsulation. |
+* Use Polymer.dart to build custom elements. |
+* Bind Dart data to HTML elements. |
+* Declaratively bind event handlers to elements. |
+ |
+{% endcapture %} |
+ |
+{% capture sample_links %} |
+ |
+<p> |
+Get the source code for the samples featured in this target:</p> |
+ |
+<ul> |
+ <li> |
+ <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch" |
+ target="_blank">stopwatch</a> |
+ </li> |
+</ul> |
+ |
+{% endcapture %} |
+ |
+{% capture content %} |
+ |
+<div class="tute-target-title"> |
+<h1>{{page.title}}</h1> |
+<h3>Create a custom HTML element using Polymer</h3> |
+</div> |
+ |
+A custom element is an HTML element you can define yourself, |
+encapsulating appearance and/or behavior |
+within semantically meaningful HTML. |
+ |
+<aside class="alert"> |
+ Custom elements are one feature of |
+<a href="http://www.polymer-project.org/" |
+ target="_blank">Polymer</a>, |
+a new type of library for the web based on Web Components. |
+<a href="http://www.dartlang.org/polymer-dart/" |
+ target="_blank">Polymer.dart</a> |
+is the Dart implementation of Polymer. |
+(Note: Polymer supersedes Web UI.) |
+</aside> |
+ |
+* [An example](#an-example) |
+* [Installing Polymer.dart](#getting-polymer-dart) |
+* [Including Polymer.dart in your application](#bootstrap) |
+* [Instantiating a custom element](#instantiating) |
+* [Defining a custom element](#define-element) |
+* [Providing a template for the custom element](#providing-a-template) |
+* [Providing a script for the custom element](#providing-a-script) |
+* [Overiding life-cycle methods](#life-cycle-methods) |
+* [Using data binding](#data-binding) |
+* [Setting up event handlers declaratively](#event-handlers) |
+* [Querying the Shadow DOM](#in-the-shadows) |
+* [Styling a custom element](#scoped-css) |
+* [Other resources](#other-resources) |
+ |
+##An example |
+ |
+In the example running below, |
+the LemonChiffon area outlined in black |
+is a custom element implemented using Polymer. |
+ |
+<strong>Try it!</strong> |
+Start and stop the stopwatch. |
+Reset the stopwatch to 00:00 using the **Reset** button. |
+ |
+<iframe class="running-app-frame" |
+ style="height:220px;width:230px;" |
+ src="examples/stopwatch/out/web/index.html"> |
+</iframe> |
+ |
+To place this custom element on an HTML page, |
+import the file with the custom element definition |
+and use the name of the element as an HTML tag: |
+ |
+{% prettify html %} |
+<link rel="import" href="tute_stopwatch.html"> |
+... |
+<tute-stopwatch></tute-stopwatch> |
+{% endprettify %} |
+ |
+The counting text, the three buttons along with their actions, |
+and the style are all contained within the custom element. |
+The definition of the custom element encapsulates and |
+hides the implementation details, |
+which as the user of the element, you care nothing about. |
+ |
+When you use developer tools to inspect the element, |
+you see just the custom element's begin and end tags. |
+ |
+ |
+ |
+With custom elements, you can easily create new kinds of elements |
+that have semantically meaningful tags and that are easy to share, |
+reuse, and read. |
+ |
+###Overview of the example files |
+ |
+Three main source files implement the Stopwatch example: |
+ |
+<dl> |
+ <dt> |
+ <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/index.html" target="_blank">index.html</a> |
+ </dt> |
+ <dd> |
+ The primary HTML file for the app. |
+ Includes the Polymer bootstrap script and instantiates the custom element. |
+ </dd> |
+ <dt> |
+ <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.html" target="_blank">tute_stopwatch.html</a> |
+ </dt> |
+ <dd> |
+ The HTML code that defines the custom element. |
+ </dd> |
+ <dt> |
+ <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.dart" target="_blank">tute_stopwatch.dart</a> |
+ </dt> |
+ <dd> |
+ The Dart class that implements the custom element. |
+ </dd> |
+</dl> |
+ |
+The following diagram shows the structure of the example |
+app and its use of custom elements. |
+ |
+ |
+ |
+##Installing Polymer.dart {#getting-polymer-dart} |
+ |
+To use the features provided by Polymer.dart, |
+you need to install the Polymer package. |
+If you are unfamiliar with installing packages, |
+refer to |
+<a href="/docs/tutorials/shared-pkgs/">Install Shared Packages</a>, |
+which describes the process in detail. |
+ |
+In brief, to install the Polymer package: |
+ |
+* In the application's `pubspec.yaml` file, |
+add the package to the list of dependencies |
+by adding the package name, `polymer`, to the list. |
+YAML is whitespace-sensitive, |
+so take care to indent the package name as shown: |
+ |
+  |
+ |
+* Run `pub install`, |
+which recursively installs the polymer.dart package |
+and all the packages that it depends on. |
+If you are using Dart Editor, |
+when you save pubspec.yaml |
+the editor automatically runs `pub install` for you. |
+If you are using command line tools, |
+you can run it with the command `pub install`. |
+ |
+##Including Polymer.dart in your application {#bootstrap} |
+ |
+To use Polymer.dart features such as custom elements, |
+you need to include Polymer in both |
+the HTML side and the Dart side of your app. |
+ |
+* In the primary HTML file for your app, |
+include `packages/polymer/boot.js` |
+in the <head> section. |
+When using this script, |
+you do not need to define a top-level `main()` function, |
+although you can. |
+**Note:** Use this script instead of `packages/browser/dart.js`. |
+ |
+  |
+ |
+* In your Dart code, import the Polymer library: |
+ |
+  |
+ |
+##Instantiating a custom element {#instantiating} |
+ |
+To create an instance of a custom element, |
+use the name of the custom element just as you would any normal HTML tag. |
+In this example, the tag name is `tute-stopwatch`. |
+ |
+ |
+ |
+Using best practices, |
+the custom element definition is in a separate file. |
+Use `link [rel="import"]` to import the HTML definition file as shown. |
+ |
+##Defining a custom element {#define-element} |
+ |
+The definition for the <tute-stopwatch> element is |
+in |
+<a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.html" target="_blank">tute_stopwatch.html</a>. |
+A custom element definition should be in its own |
+source file so that it can be included by other files. |
+An HTML file that contains the definition for a custom element |
+does not need <html>, <head>, or <body> tags. |
+ |
+To define a custom element, |
+use the <polymer-element> tag and provide a name. |
+ |
+{% prettify html %} |
+<polymer-element name="tute-stopwatch"> |
+ ... |
+</polymer-element> |
+{% endprettify %} |
+ |
+A custom element name must have at least one hyphen (`-`). |
+We advise using an identifiable prefix to |
+avoid naming conflicts with elements shared by others |
+and to help identify the project from which the element originates. |
+For example, for tutorial custom elements, we use the prefix `tute`. |
+ |
+Within the <polymer-element> tag, |
+you can provide a template (appearance) and a script (behavior). |
+UI widgets, like our Stopwatch example, |
+typically have both a template and a script, |
+but neither is required. |
+A custom element with a script and no template is purely functional. |
+A custom element with a template and no script is purely visual. |
+ |
+{% prettify html %} |
+<polymer-element name="tute-stopwatch"> |
+ <template> |
+ ... |
+ </template> |
+ <script type="application/dart" src="tute_stopwatch.dart"> |
+ </script> |
+</polymer-element> |
+{% endprettify %} |
+ |
+<dl> |
+ <dt> <template> </dt> |
+ <dd> |
+ Describes the custom element's structure—its user interface. |
+ The template comprises any valid HTML code within the <template> tag. |
+ When the custom element is instantiated, |
+ the instance is created from the template. |
+ The template can include CSS styles within a <style> tag. |
+ </dd> |
+ |
+ <dt> <script> </dt> |
+ <dd markdown="1"> Specifies a Dart script. |
+ For custom elements, the Dart script is a Dart class |
+ that implements the behavior of the element. |
+ The class typically overrides some |
+ life-cycle methods and provides event handlers |
+ that join the UI with its programmatic behavior. |
+ In this example, the script is in |
+ <a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web/polymer-intro/stopwatch/web/tute_stopwatch.dart" target="_blank">tute_stopwatch.dart</a>. |
+ </dd> |
+</dl> |
+ |
+##Providing a template for the custom element {#providing-a-template} |
+ |
+Here's the template code for the tute-stopwatch element: |
+ |
+ |
+ |
+The tute-stopwatch template uses a <style> tag, which is optional. |
+These styles are scoped; they affect only |
+the appearance of the custom element and the elements it contains. |
+More about scoped CSS in [Styling a custom element](#scoped-css). |
+ |
+The rest of the code within the <template> tag |
+is normal HTML, with two exceptions: |
+ |
+|---|---| |
+| `{``{``counter}}` | Uses a Polymer syntax to [bind Dart data](#data-binding) to the HTML page. The double curly braces are commonly known as a "double mustache". | |
+| `on-click` | Uses Polymer [declarative event mapping](#event-handlers), which allows you to set up event handlers for a UI element. `on-click` sets up an event handler for mouse clicks. Polymer has mappings for other event types, such as `on-change` for input change events. | |
+{: .table} |
+ |
+Let's take a look at the structure of the Dart code |
+before we get into the details of data binding, event handlers, |
+and scoped CSS. |
+ |
+##Providing a script for the custom element {#providing-a-script} |
+ |
+On the Dart side, a class implements the behavior of the custom element. |
+You associate the Dart class with the custom element using the `@CustomTag` |
+annotation and the name of the custom element. |
+ |
+ |
+ |
+This diagram gives an overview of the TuteStopwatch class: |
+ |
+ |
+ |
+Any Dart class that backs a Polymer element must subclass PolymerElement. |
+If you want to use data binding, the class must also use ObservableMixin. |
+ |
+{% comment %} |
+[xx: more about PolymerElement] |
+[xx: more about ObservableMixin] |
+{% endcomment %} |
+ |
+The class can respond to life-cycle milestones |
+by overriding [life-cycle methods](#life-cycle-methods). |
+For example, the TuteStopwatch class overrides the `inserted()` |
+method—which is called when the element is inserted |
+into the DOM—to initialize the app. |
+ |
+The `start()` method is an event handler for the **Start** button. |
+The event handler is declaratively connected to the button. |
+Refer to [Setting up event handlers declaratively](#event-handlers) to see how. |
+ |
+##Overriding life-cycle methods {#life-cycle-methods} |
+ |
+A custom element has four life-cycle methods |
+that it can override: |
+ |
+|---|---| |
+| `created()` | Called when an instance of a custom element is created. | |
+| `inserted()` | Called when an instance of a custom element is inserted into the DOM. | |
+| `removed()` | Called when an instance of a custom element is removed from the DOM. | |
+| `attributeChanged()` | Called when an attribute, such as `class`, of an instance of the custom element is added, changed, or removed. | |
+{: .table} |
+ |
+You can override any of these life-cycle methods. |
+The overriding method |
+*must* call the super class method first. |
+ |
+The Stopwatch app overrides the `inserted()` method because it |
+needs a reference to each of the three buttons |
+so that it can enable and disable them. |
+When a tute-stopwatch custom element is inserted into the DOM |
+the buttons have been created, so the references to them |
+will be available when the inserted() method is called. |
+You'll notice that it gets the buttons by |
+[querying the custom element's shadow root](#in-the-shadows). |
+ |
+{% prettify dart %} |
+void inserted() { |
+ super.inserted(); |
+ startButton = getShadowRoot('tute-stopwatch').query('#startButton'); |
+ stopButton = getShadowRoot('tute-stopwatch').query('#stopButton'); |
+ resetButton = getShadowRoot('tute-stopwatch').query('#resetButton'); |
+ |
+ stopButton.disabled = true; |
+ resetButton.disabled = true; |
+} |
+{% endprettify %} |
+ |
+##Using data binding {#data-binding} |
+ |
+In the HTML definition of a custom element, |
+use double curly brackets to embed Dart data into the webpage. |
+In your Dart code, use the `@observable` annotation |
+to mark the embedded data. |
+Here, the data is a string called `counter`. |
+ |
+ |
+ |
+The tute-stopwatch element uses a periodic |
+<a href="https://api.dartlang.org/dart_async/Timer.html" target="_blank">Timer</a> |
+to fire an event every second. |
+When the Timer fires, it calls the `updateTimer()` method, |
+which modifies the `counter` string. |
+Polymer takes care of updating the HTML page with the new string. |
+ |
+This type of binding is called _one-way data binding_ |
+because the data can change only on the Dart side. |
+Polymer also supports two-way data binding. |
+In two-way data binding, when data changes on the HTML side—for example |
+with an input element—the value in the Dart code changes to match. |
+ |
+You can use expressions within the double curly brackets. |
+<a href="http://pub.dartlang.org/packages/polymer_expressions" |
+ target="_blank">Polymer expressions</a> |
+provide the default syntax. Examples of allowable expressions include: |
+ |
+|---|---| |
+| `{``{``myObject.aProperty}}` | Property access. | |
+| `{``{``!empty}}` | Operators, like the logical not operator. | |
+| `{``{``myList[3]}}` | List indexing. | |
+| `{``{``myFilter()}}` | Data filtering. | |
+{: .table} |
+ |
+##Setting up event handlers declaratively {#event-handlers} |
+ |
+This example has three buttons, each |
+with an event handler that is written in Dart, |
+but attached to the button declaratively from HTML. |
+ |
+ |
+ |
+In HTML, use the `on-click` attribute |
+to attach a mouse click handler to an HTML element. |
+The value of the attribute must be the name of a method |
+in the class that implements the custom element. |
+When the user clicks the button, the specified method is called |
+with three parameters: |
+ |
+* An |
+<a href="https://api.dartlang.org/dart_html/Event.html" target="_blank">Event</a> |
+that contains information about the event, |
+such as its type and when it occurred. |
+ |
+* The _detail_ object can provide additional, event-specific information. |
+ |
+* The <a href="https://api.dartlang.org/dart_html/Node.html" target="_blank">Node</a> |
+that fired the event—the **Start** button in this case. |
+ |
+You can attach event handlers for other kinds of events. |
+For example, you can use `on-change` to handle events for input text elements |
+when the text changes. |
+ |
+Refer to |
+[Declarative event mapping](http://www.polymer-project.org/polymer.html#declarative-event-mapping) |
+for further details. |
+ |
+##Querying the shadow root {#in-the-shadows} |
+ |
+The Shadow DOM is key to encapsulation. |
+The DOM subtree for a custom element is |
+hidden from outside of the custom element. |
+ |
+ |
+ |
+You can programmatically get items from the Shadow DOM |
+by querying a custom element's _shadow root_—a |
+special node from which an instance of a custom element is rendered. |
+ |
+{% prettify dart %} |
+startButton = getShadowRoot('tute-stopwatch').query('#startbutton'); |
+stopButton = getShadowRoot('tute-stopwatch').query('#stopbutton'); |
+resetButton = getShadowRoot('tute-stopwatch').query('#resetbutton'); |
+{% endprettify %} |
+ |
+Call `getShadowRoot()` with the name of the custom element. |
+The `getShadowRoot()` method returns the shadow root element |
+for this instance of the specified element. |
+Use `query()` with a CSS selector to get the element(s) of interest. |
+ |
+Note that this code uses `query()` to get each button by ID. |
+By querying the shadow root object rather than the DOM, |
+you are guaranteed to get the objects from within the custom element, |
+not from anywhere else on the page. |
+ |
+##Styling a custom element {#scoped-css} |
+ |
+You can optionally include CSS styles for your custom element |
+that apply only to the contents of the custom element. |
+ |
+ |
+ |
+The `@host` rule allows you to target and style an element internally, |
+from within its definition. |
+The `:scope` pseudo-class refers to the custom element itself. |
+The only selectors that work in `@host` are those targeting the host element itself. |
+So you don't need to worry about naming conflicts on the page. |
+Any CSS selectors within the template need to be unique only within the template. |
+ |
+For further details about styling custom elements, |
+refer to |
+[A Guide to Styling Elements](http://www.polymer-project.org/articles/styling-elements.html) |
+ |
+##Other resources |
+ |
+Use these other resources to learn more about Polymer: |
+ |
+* The tutorial |
+<a href="https://github.com/dart-lang/dart-tutorials-samples/tree/master/web" |
+ target="_blank">github repo</a> |
+ contains many examples that use Polymer, |
+ including samples that have been converted from Web UI. |
+ |
+* The |
+<a href="http://www.dartlang.org/polymer-dart/" |
+ target="_blank">Polymer.dart</a> homepage provides information |
+ specific to the Dart port of the Polymer project. |
+ |
+* The Polymer project website |
+<a href="http://www.polymer-project.org/" |
+ target="_blank">polymer-project.org</a> |
+ contains information about the Polymer project as a whole. |
+ |
+{% endcapture %} |
+ |
+{% include tutorial.html %} |