├── .github └── ISSUE_TEMPLATE.md ├── .gitignore ├── .test_config ├── AUTHORS ├── CHANGELOG.md ├── LICENSE ├── PATENTS ├── README.md ├── bin └── new_element.dart ├── codereview.settings ├── lib ├── init.dart ├── polymer.dart ├── polymer.html ├── polymer_micro.dart ├── polymer_micro.html ├── polymer_mini.dart ├── polymer_mini.html ├── src │ ├── common │ │ ├── behavior.dart │ │ ├── declarations.dart │ │ ├── js_proxy.dart │ │ ├── listen.dart │ │ ├── observe.dart │ │ ├── polymer_descriptor.dart │ │ ├── polymer_mixin.dart │ │ ├── polymer_register.dart │ │ ├── polymer_serialize.dart │ │ ├── property.dart │ │ ├── reflectable.dart │ │ └── util.dart │ ├── js │ │ ├── polymer_base_dart.html │ │ ├── polymer_bind_dart.html │ │ └── undefined.dart │ └── template │ │ ├── array_selector.dart │ │ ├── dom_bind.dart │ │ ├── dom_if.dart │ │ └── dom_repeat.dart └── transformer.dart ├── pubspec.yaml └── test ├── common.dart └── src ├── common ├── behavior_composition_test.dart ├── behavior_composition_test.html ├── behavior_test.dart ├── behavior_test.html ├── js_proxy_test.dart ├── js_proxy_test.html ├── polymer_descriptor_test.dart ├── polymer_descriptor_test.html ├── polymer_mixin_test.dart ├── polymer_mixin_test.html ├── polymer_register_test.dart └── polymer_register_test.html ├── micro ├── attributes_test.dart ├── attributes_test.html ├── lifecycle_callbacks_test.dart └── lifecycle_callbacks_test.html ├── mini ├── bottom_up_ready_test.dart ├── bottom_up_ready_test.html ├── default_values_test.dart ├── default_values_test.html ├── dom_distribution_test.dart ├── dom_distribution_test.html ├── template_stamping_test.dart └── template_stamping_test.html ├── standard ├── attribute_binding_test.dart ├── attribute_binding_test.html ├── computed_properties_test.dart ├── computed_properties_test.html ├── event_listener_test.dart ├── event_listener_test.html ├── node_finding_test.dart ├── node_finding_test.html ├── property_binding_test.dart ├── property_binding_test.html ├── property_change_callbacks_test.dart ├── property_change_callbacks_test.html ├── property_change_notification_test.dart ├── property_change_notification_test.html ├── read_only_properties_test.dart ├── read_only_properties_test.html ├── reflect_to_attribute_test.dart └── reflect_to_attribute_test.html └── template ├── array_selector_test.dart ├── array_selector_test.html ├── dom_bind_test.dart ├── dom_bind_test.html ├── dom_if_test.dart ├── dom_if_test.html ├── dom_repeat_test.dart ├── dom_repeat_test.html ├── templatizer_test.dart └── templatizer_test.html /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 10 | ### Description 11 | 12 | 13 | #### Steps to Reproduce 14 | 22 | 23 | #### Expected Results 24 | 25 | 26 | #### Actual Results 27 | 28 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Don’t commit the following directories created by pub. 2 | .pub 3 | /build/ 4 | packages 5 | .packages 6 | 7 | # Or the files created by dart2js. 8 | *.dart.js 9 | *.dart.precompiled.js 10 | *.js_ 11 | *.js.deps 12 | *.js.map 13 | *.sw? 14 | .idea/ 15 | *.iml 16 | 17 | # Include when developing application packages. 18 | pubspec.lock 19 | .analysis_options 20 | -------------------------------------------------------------------------------- /.test_config: -------------------------------------------------------------------------------- 1 | { 2 | "test_package": { 3 | "platforms": ["dartium"] 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | # Names should be added to this file with this pattern: 2 | # 3 | # For individuals: 4 | # Name 5 | # 6 | # For organizations: 7 | # Organization 8 | # 9 | Google Inc. <*@google.com> 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | #### 1.0.0-rc.19 2 | * Update analyzer, html, and reflectable versions. 3 | 4 | #### 1.0.0-rc.18 5 | * Update tests because of `notifyPath` signature change 6 | 7 | #### 1.0.0-rc.17 8 | * Update reflectable version to allow latest. 9 | * Fixed some analyzer hints. 10 | 11 | #### 1.0.0-rc.16 12 | * Added new properties on `DomRepeat` : `initialCount`, `renderedItemCount` 13 | and `targetFramerate` 14 | * Temporarily fixed reflectable version to `<0.5.3` due to 15 | [#690](https://github.com/dart-lang/polymer-dart/issues/690). 16 | 17 | #### 1.0.0-rc.15 18 | * Fix a bug where calling `set` on a property from a behavior wouldn't update 19 | the property on the Dart element. 20 | 21 | #### 1.0.0-rc.14 22 | * Added support for adding `@reflectable` to arbitrary static fields on 23 | both element classes and behavior mixins. 24 | * **Breaking Change**: Extending polymer element classes will no longer work. 25 | Specifically, `@property`, `@reflectable`, `@observe`, `@listen`, etc from 26 | your super class will no longer be picked up. These must all be moved into a 27 | behavior class which both elements mix in. 28 | 29 | #### 1.0.0-rc.13 30 | * Transformer will now throw if given unrecognized options. 31 | 32 | #### 1.0.0-rc.12 33 | * Update to work with polymer_interop v1.0.0-rc.8. The main difference relates 34 | to events. On the JS side of things, regular `Event` objects are sometimes 35 | used to mimic `CustomEvent` objects, and a `detail` field is just added. 36 | This means that Polymer Dart now treats any `Event` with a `detail` field as 37 | a `CustomEvent`, so they are wrapped with the `CustomEventWrapper` class. 38 | You can always get at the original event by using the `original` property. 39 | 40 | #### 1.0.0-rc.11 41 | * Added a polymer transformer which wraps up both the web_components and 42 | reflectable transformers into one more consumable package. Use it just like 43 | the web_components transformer: 44 | 45 | transformers: 46 | - polymer: 47 | entry_points: 48 | - web/index.html 49 | 50 | #### 1.0.0-rc.10 51 | * Update to reflectable `^0.5.0` and analyzer `^0.27.0` versions. 52 | * Added back the `new_element` generator script. 53 | 54 | #### 1.0.0-rc.9 55 | * `DomRepeatModel.item` is now deprecated, although it will properly use the 56 | `as` attribute for now. The `[]` operator has been added in its place. 57 | 58 | #### 1.0.0-rc.8 59 | * Update to work with reflectable ^0.4.0. 60 | 61 | #### 1.0.0-rc.7 62 | * Add version constraint on reflectable <0.3.4 until issue #651 is resolved. 63 | 64 | #### 1.0.0-rc.6 65 | * Add a test/example for `Templatizer` behavior. 66 | * Fix a few minor strong mode type errors. 67 | 68 | #### 1.0.0-rc.5 69 | * Update to work with `polymer_interop` version `1.0.0-rc.4`. 70 | 71 | #### 1.0.0-rc.4 72 | * Throw on `registered` and `beforeRegister` instance methods if they 73 | are annotated with `@reflectable`. 74 | * Added support for static `registered` and `beforeRegister` methods, which 75 | will be invoked with the JS prototype for the element at registration time. 76 | These are supported for both behaviors and elements. 77 | * Fixed the `items` setter for the `DomRepeat` wrapper. 78 | * Temporarily added an analyzer constraint of `<0.26.1+15` to work around 79 | [#24735](https://github.com/dart-lang/sdk/issues/24735). 80 | 81 | #### 1.0.0-rc.3 82 | * Annotations are no longer needed on both the getter and setter for fields, 83 | [#621](https://github.com/dart-lang/polymer-dart/issues/621). 84 | 85 | #### 1.0.0-rc.2 86 | * The `@eventHandler` annotation has been replaced with the more general 87 | `@reflectable` annotation. 88 | * All fields/methods on `JsProxy` objects which you want to expose to JS need 89 | to be annotated with `@reflectable`. This results in dramatic code size 90 | improvement at relatively minimal cost to the user. 91 | 92 | #### 1.0.0-rc.1 93 | * Port of polymer js 1.1. 94 | * This is a ground up rewrite, and has multiple breaking changes. See the 95 | [wiki](https://github.com/dart-lang/polymer-dart/wiki) for more information. 96 | 97 | #### 0.16.3+2 98 | * Fix invalid warning about missing polymer.html import from the linter. 99 | * Update logging package to `<0.12.0`. 100 | 101 | #### 0.16.3+1 102 | * Update observe to 0.13.1. 103 | 104 | #### 0.16.3 105 | * Update analyzer to <0.26.0. 106 | 107 | #### 0.16.2 108 | * Add support for the new `link[rel="x-dart-test"]` tags from the `test` 109 | package to the transformer. 110 | * The `Future` returned from the default `main` method in 111 | `package:polymer/init.dart` now guarantees that it will not complete until 112 | all `@initMethod` and `@whenPolymerReady` functions have been executed. This 113 | is to support writing tests inside these methods using the new `test` 114 | package. 115 | * Fix the bootstrap file to return the original result of main. 116 | 117 | #### 0.16.1+4 118 | * Use `polymer_interop` for everything polymer js related. Projects which only 119 | provide/use wrappers around js elements should be able to switch to using that 120 | package instead of this one. 121 | 122 | #### 0.16.1+3 123 | * Update polymer js version to 0.5.5. 124 | 125 | #### 0.16.1+2 126 | * Update pubspec from `html5lib` to `html`. 127 | 128 | #### 0.16.1+1 129 | * Switch `html5lib` package dependency to `html`. 130 | 131 | #### 0.16.1 132 | * Added `@whenPolymerReady` annotation for functions. This will call the 133 | function once `Polymer.onReady` completes, reducing the boilerplate in entry 134 | points to the following: 135 | 136 | import 'package:polymer/polymer.dart'; 137 | export 'package:polymer/init.dart'; 138 | 139 | @whenPolymerReady 140 | void onReady() { 141 | /// Custom setup code here. 142 | } 143 | 144 | #### 0.16.0+7 145 | * Switch to using `initWebComponents` internally which gives better guarantees 146 | around development time ordering of initializers. This should fix most 147 | issues related to element registration order. 148 | 149 | #### 0.16.0+6 150 | * Update `args` constraint. 151 | * Pass `bindingStartDelimiters` to the `ImportInlinerTransformer` so it can 152 | handle bindings in urls appropriately, 153 | [#35](https://github.com/dart-lang/polymer-dart/issues/35). 154 | 155 | #### 0.16.0+5 156 | * Update `web_components` constraint. 157 | 158 | #### 0.16.0+4 159 | * Fix static configuration for exported libraries. 160 | 161 | #### 0.16.0+3 162 | * Increase upper bound of `smoke` package to `<0.4.0`. 163 | 164 | #### 0.16.0+2 165 | * Update the polyfill injector to work properly for entry points that live in 166 | sub-folders. 167 | 168 | #### 0.16.0+1 169 | * Update analyzer and code_transformers versions and use new mock sdk from 170 | code_transformers. 171 | 172 | #### 0.16.0 173 | * `initPolymer` now returns a `Future` instead of a `Zone`. This will 174 | likely affect most polymer applications. 175 | 176 | Given a current program: 177 | 178 | main() => initPolymer().run(realMain); 179 | realMain() => ... 180 | 181 | This should be translated to: 182 | 183 | main() => initPolymer().then((zone) => zone.run(realMain)); 184 | realMain() => ... 185 | 186 | Or alternatively, you can use an @initMethod: 187 | 188 | main() => initPolymer(); 189 | 190 | @initMethod 191 | realMain() => ... 192 | 193 | * Dropped support for the experimental bootstrap. 194 | * The `polymer` transformer is now integrated with the `initialize` 195 | transformer. This means you can now use `@HtmlImport` on library directives. 196 | This allows producers of elements to declare their own html dependencies so 197 | consumers don't have to know about your html imports at all. See 198 | [web_components 0.10.2](https://github.com/dart-lang/web-components/blob/master/CHANGELOG.md#0102) 199 | for more information on @HtmlImport. 200 | * The `startPolymer` method no longer takes a `deployMode` argument. This is 201 | meant as an internal-only method and should not affect apps. It also now 202 | returns a `Future`. 203 | * The transformer has been heavily refactored and may behave slightly 204 | differently. Please file any bugs related to this at 205 | https://github.com/dart-lang/polymer-dart/issues/new. 206 | 207 | #### 0.15.5+4 208 | * Fix for [#23](https://github.com/dart-lang/polymer-dart/issues/23) (0.15.5+3 209 | missed an invocation of the observe transformer). 210 | 211 | #### 0.15.5+3 212 | * Pass more state to the observe transformer so it won't output log files in 213 | release mode. 214 | 215 | #### 0.15.5+2 216 | * Update duplicate css file message. 217 | 218 | #### 0.15.5+1 219 | * Changes order in which CustomTags are registered to guarantee that the order 220 | is deterministic and that within a library superclasses are registered 221 | before subclasses. This fixes 222 | [17](https://github.com/dart-lang/polymer-dart/issues/17). 223 | 224 | #### 0.15.5 225 | * Update to polymer js version 226 | [0.5.2](https://github.com/Polymer/polymer/releases/tag/0.5.2). This fixes 227 | [11](https://github.com/dart-lang/polymer-dart/issues/11). 228 | 229 | #### 0.15.4 230 | * Fix template if when using template attribute 231 | [209](https://github.com/Polymer/TemplateBinding/issues/209). 232 | * Renamed `injectBoundHTML` to `injectBoundHtml` and changed its signature to 233 | use named instead of positional optional arguments. Also added support for 234 | custom `NodeValidator` and/or `TreeSanitizer`. The old version still exists 235 | for now with an `@deprecated` annotation. 236 | 237 | #### 0.15.3+1 238 | * Fix logic for detecting when the compiler is linting within an 239 | `auto-binding-dart` template element. This removes some false positive 240 | warnings. 241 | 242 | #### 0.15.3 243 | * Narrow the constraint on observe to ensure that new features are reflected 244 | in polymer's version. 245 | 246 | #### 0.15.2 247 | * Upgraded to polymer js version 248 | [0.5.1](https://github.com/Polymer/polymer/releases/tag/0.5.1). 249 | **Dart Note**: Since dirty checking is only a development feature for 250 | Polymer Dart, we did not include the functionality to stop dirty checks in 251 | inactive windows. 252 | * `polymer.js` is now the unminified version, and `polymer.min.js` is the 253 | minified version. 254 | * Fixed bug where polymer js was creating instances of extended elements in 255 | order to check if they had been registered. All dart custom elements now get 256 | registered with polymer js using the HTMLElement prototype. 257 | 258 | #### 0.15.1+5 259 | * Increase code_transformers lower bound and use shared transformers from it. 260 | 261 | #### 0.15.1+4 262 | * Fix double-registration bug when using exports 263 | [21439](http://dartbug.com/21439). 264 | 265 | #### 0.15.1+3 266 | * Make sure that `dart_support.js` is always appended after `platform.js`, 267 | [21435](http://dartbug.com/21435). 268 | 269 | #### 0.15.1+2 270 | * Handle and warn about cases where a script file is included twice from the 271 | same entrypoint [21332](http://dartbug.com/21332). 272 | 273 | #### 0.15.1+1 274 | * Fix typo in error message polymer#42 275 | 276 | #### 0.15.1 277 | * Upgraded to polymer [0.4.2][] 278 | * No need to include dart_support.js in your entrypoints anymore. 279 | 280 | #### 0.15.0+1 281 | * Widen web_components version constraint. 282 | 283 | #### 0.15.0 284 | * Upgraded to polymer 0.4.1 285 | * Added Polymer.forceReady method. This forces a ready state regardless of 286 | whether or not there are still polymer-element declarations waiting for 287 | their class definitions to be loaded. 288 | * Added Polymer.waitingFor method. This returns a list of all polymer-element 289 | declarations that are still waiting for their class definitions to be 290 | loaded. 291 | * Add runtime checking of the waitingFor queue and print to the console if a 292 | deadlock situation is suspected to help diagnose the white screen of death. 293 | * Added injectBoundHTML instance method. This can be used to dynamically 294 | inject html that is bound to your current element into a target element. 295 | 296 | #### 0.14.3 297 | * Warn if the same css file is inlined more than once, 298 | [19996](http://dartbug.com/19996). 299 | * Don't start moving elements from head to body until we find the first 300 | import, [20826](http://dartbug.com/20826). 301 | * Add option to not inject platform.js in the build output 302 | [20865](http://dartbug.com/20865). To use, set `inject_platform_js` to 303 | false in the polymer transformer config section of your pubspec.yaml: 304 | 305 | transformers: 306 | - polymer: 307 | inject_platform_js: false 308 | ... 309 | 310 | #### 0.14.2+1 311 | * Fix findController function for js or dart wrapped elements. This fixes 312 | event bindings when using paper-dialog and probably some other cases, 313 | [20931](http://dartbug.com/20931). 314 | 315 | #### 0.14.2 316 | * Polymer will now create helpful index pages in all folders containing entry 317 | points and in their parent folders, in debug mode only 318 | [20963](http://dartbug.com/20963). 319 | 320 | #### 0.14.1 321 | * The build.dart file no longer requires a list of entry points, and you can 322 | replace the entire file with `export 'package:polymer/default_build.dart';` 323 | [20396](http://dartbug.com/20396). 324 | * Inlined imports from the head of the document now get inserted inside a 325 | hidden div, similar to the js vulcanizer [20943](http://dartbug.com/20943). 326 | 327 | #### 0.14.0+1 328 | * Small style improvements on error/warnings page. 329 | 330 | #### 0.14.0 331 | * Upgraded to polymer 0.4.0 ([polymer-dev#d66a86e][d66a86e]). 332 | * The platform.js script is no longer required in Chrome or Dartium 333 | (version 36). You can now remove this from your projects for development, 334 | and it will be injected when running pub build or pub serve. If you would 335 | like the option to not inject platform.js at all in the built output (if you 336 | are deploying to chrome exclusively), please star this bug 337 | http://dartbug.com/20865. 338 | * Fixed invalid linter warning when using event handlers inside an 339 | `auto-binding-dart` template, [20913](http://dartbug.com/20913). 340 | 341 | #### 0.13.1 342 | * Upgraded error messages to have a unique and stable identifier. This 343 | requires a version of `code_transformers` newer than `0.2.3`. 344 | * Upgraded minimum version constraint on `args` to `0.11.0`. 345 | 346 | #### 0.13.0+3 347 | * Added a warning about flashes of unstyled content if we can detect a 348 | situation that would cause it [20751](http://dartbug.com/20751). 349 | 350 | #### 0.13.0+2 351 | * Update internal transformers to delete .concat.js and .map files when in 352 | release mode, saving about 1MB of space in the built output. 353 | 354 | #### 0.13.0+1 355 | * Bug fix for http://dartbug.com/18171. Elements that extend other elements 356 | but don't have a template will still inherit styles from those elements. 357 | * Bug fix for http://dartbug.com/20544. Better runtime logging when attributes 358 | are defined on an element but have no corresponding property on the class. 359 | 360 | #### 0.13.0 361 | * Update to match polymer 0.3.5 ([polymer-dev#5d00e4b][5d00e4b]). There was a 362 | breaking change in the web_components package where selecting non-rendered 363 | elements doesn't work, but it shouldn't affect most people. See 364 | https://github.com/Polymer/ShadowDOM/issues/495. 365 | 366 | #### 0.12.2+1 367 | * Small bug fix for `polymer:new_element` 368 | 369 | #### 0.12.2 370 | * Fix for [20539](http://dartbug.com/20539). Log widget will now html escape 371 | messages. 372 | * Fix for [20538](http://dartbug.com/20538). Log widget will now surface lint 373 | logs from imported files. 374 | * Backward compatible change to prepare for upcoming change of the user agent 375 | in Dartium. 376 | * `pub run polymer:new_element` now supports specifying a base class. 377 | **Note**: only native DOM types and custom elements written in Dart can be 378 | extended. Elements adapted from Javascript (like core- and paper- elements) 379 | cannot be extended. 380 | * other bug fixes in `polymer:new_entry`. 381 | 382 | #### 0.12.1 383 | * **New**: When running in pub-serve, any warnings and errors detected by the 384 | polymer transformers will be displayed in the lower-right corner of your 385 | entrypoint page. You can opt-out by adding this option to your pubspec: 386 | 387 | transformers: 388 | - polymer: 389 | ... 390 | inject_build_logs_in_output: false 391 | 392 | * **New**: there are now two template generators in the polymer package! On 393 | any project that depends on polymer, you can create template files for a new 394 | custom element by invoking: 395 | 396 | pub run polymer:new_element element-name [-o output_dir] 397 | 398 | And, if you invoke: 399 | 400 | pub run polymer:new_entry web/index.html 401 | 402 | we will create a new entry-point file and add it to your pubspec for you. 403 | 404 | * Added the ability to override the stylesheet inlining behavior. There is now 405 | an option exposed in the pubspec.yaml called `inline_stylesheets`. There are 406 | two possible values, a boolean or a map. If only a boolean is supplied then 407 | that will set the global default behavior. If a map is supplied, then the 408 | keys should be file paths, and the value is a boolean. You can use the 409 | special key 'default' to set the default value. 410 | 411 | For example, the following would change the default to not inline any 412 | styles, except for the foo.css file in your web folder and the bar.css file 413 | under the foo packages lib directory: 414 | 415 | transformers: 416 | - polymer: 417 | ... 418 | inline_stylesheets: 419 | default: false 420 | web/foo.css: true 421 | packages/foo/bar.css: true 422 | 423 | 424 | * Bug fix for http://dartbug.com/20286. Bindings in url attributes will no 425 | longer throw an error. 426 | 427 | 428 | #### 0.12.0+7 429 | * Widen the constraint on `unittest`. 430 | 431 | #### 0.12.0+6 432 | * Widen the constraint on analyzer. 433 | * Support for `_src` and similar attributes in polymer transformers. 434 | 435 | #### 0.12.0+5 436 | * Raise the lower bound on the source_maps constraint to exclude incompatible 437 | versions. 438 | 439 | #### 0.12.0+4 440 | * Widen the constraint on source_maps. 441 | 442 | #### 0.12.0+3 443 | * Fix a final use of `getLocationMessage`. 444 | 445 | #### 0.12.0+2 446 | * Widen the constraint on barback. 447 | 448 | #### 0.12.0+1 449 | * Switch from `source_maps`' `Span` class to `source_span`'s `SourceSpan` 450 | class. 451 | 452 | #### 0.12.0 453 | * Updated to match polymer 0.3.4 ([polymer-dev#6ad2d61][6ad2d61]), this 454 | includes the following changes: 455 | * added @ComputedProperty 456 | * @published can now be written using the readValue/writeValue helper 457 | methods to match the same timing semantics as Javscript properties. 458 | * underlying packages are also updated. Some noticeable changes are: 459 | * observe: path-observers syntax is slightly different 460 | * polymer_expressions: updating the value of an expression will issue a 461 | notification. 462 | * template_binding: better NodeBind interop support (for 463 | two-way bindings with JS polymer elements). 464 | * Several fixes for CSP, including a cherry-pick from polymer.js 465 | [commit#3b690ad][3b690ad]. 466 | * Fix for [17596](https://code.google.com/p/dart/issues/detail?id=17596) 467 | * Fix for [19770](https://code.google.com/p/dart/issues/detail?id=19770) 468 | 469 | #### 0.11.0+5 470 | * fixes web_components version in dependencies 471 | 472 | #### 0.11.0+4 473 | * workaround for bug 474 | [19653](https://code.google.com/p/dart/issues/detail?id=19653) 475 | 476 | #### 0.11.0+3 477 | * update readme 478 | 479 | #### 0.11.0+2 480 | * bug fix: event listeners were not in the dirty-checking zone 481 | * bug fix: dispatch event in auto-binding 482 | 483 | #### 0.11.0+1 484 | * Added a workaround for bug in HTML imports (issue 485 | [19650](https://code.google.com/p/dart/issues/detail?id=19650)). 486 | 487 | #### 0.11.0 488 | * **breaking change**: platform.js and dart_support.js must be specified in 489 | your entry points at the beginning of ``. 490 | * **breaking change**: polymer.html is not required in entrypoints, but it is 491 | required from files that use ``. 492 | * **breaking change**: enteredView/leftView were renamed to attached/detached. 493 | The old lifecycle methods will not be invoked. 494 | * **breaking change**: Event bindings with `@` are no longer supported. 495 | * **breaking change**: `@published` by default is no longer reflected as an 496 | attribute by default. This might break if you try to use the attribute in 497 | places like CSS selectors. To make it reflected back to an attribute use 498 | `@PublishedProperty(reflect: true)`. 499 | 500 | #### 0.10.1 501 | * Reduce the analyzer work by mocking a small subset of the core libraries. 502 | 503 | #### 0.10.0+1 504 | * Better error message on failures in pub-serve/pub-build when pubspec.yaml 505 | is missing or has a wrong configuration for the polymer transformers. 506 | 507 | #### 0.10.0 508 | * Interop with polymer-js elements now works. 509 | * Polymer polyfills are now consolidated in package:web_components, which is 510 | identical to platform.js from http://polymer-project.org. 511 | * The output of pub-build no longer uses mirrors. We replace all uses of 512 | mirrors with code generation. 513 | * **breaking change**: Declaring a polymer app requires an extra import to 514 | `` 515 | * **breaking change**: "noscript" polymer-elements are created by polymer.js, 516 | and therefore cannot be extended (subtyped) in Dart. They can still be used 517 | by Dart elements or applications, however. 518 | * New feature: `@ObserveProperty('foo bar.baz') myMethod() {...}` will cause 519 | myMethod to be called when "foo" or "bar.baz" changes. 520 | * Updated for 0.10.0-dev package:observe and package:template_binding changes. 521 | * **breaking change**: @initMethod and @CustomTag are only supported on 522 | public classes/methods. 523 | 524 | #### 0.9.5 525 | * Improvements on how to handle cross-package HTML imports. 526 | 527 | #### 0.9.4 528 | * Removes unused dependency on csslib. 529 | 530 | #### 0.9.3+3 531 | * Removes workaround now that mirrors implement a missing feature. Requires 532 | SDK >= 1.1.0-dev.5.0. 533 | 534 | #### 0.9.3+2 535 | * Fix rare canonicalization bug 536 | [15694](https://code.google.com/p/dart/issues/detail?id=15694) 537 | 538 | #### 0.9.3+1 539 | * Fix type error in runner.dart 540 | [15649](https://code.google.com/p/dart/issues/detail?id=15649). 541 | 542 | #### 0.9.3 543 | * pub-build now runs the linter automatically 544 | 545 | #### 0.9.2+4 546 | * fix linter on SVG and MathML tags with XML namespaces 547 | 548 | #### 0.9.2+3 549 | * fix [15574](https://code.google.com/p/dart/issues/detail?id=15574), 550 | event bindings in dart2js, by working around issue 551 | [15573](https://code.google.com/p/dart/issues/detail?id=15573) 552 | 553 | #### 0.9.2+2 554 | * fix enteredView in dart2js, by using custom_element >= 0.9.1+1 555 | 556 | [0.4.2]: https://github.com/Polymer/polymer-dev/commit/8c339cf8614eb65145ec1ccbdba7ecbadf65b343 557 | [6ad2d61]:https://github.com/Polymer/polymer-dev/commit/6a3e1b0e2a0bbe546f6896b3f4f064950d7aee8f 558 | [3b690ad]:https://github.com/Polymer/polymer-dev/commit/3b690ad0d995a7ea339ed601075de2f84d92bafd 559 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012 The Polymer Authors. All rights reserved. 2 | // 3 | // Redistribution and use in source and binary forms, with or without 4 | // modification, are permitted provided that the following conditions are 5 | // met: 6 | // 7 | // * Redistributions of source code must retain the above copyright 8 | // notice, this list of conditions and the following disclaimer. 9 | // * Redistributions in binary form must reproduce the above 10 | // copyright notice, this list of conditions and the following disclaimer 11 | // in the documentation and/or other materials provided with the 12 | // distribution. 13 | // * Neither the name of Google Inc. nor the names of its 14 | // contributors may be used to endorse or promote products derived from 15 | // this software without specific prior written permission. 16 | // 17 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 18 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 20 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 21 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 22 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 23 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Additional IP Rights Grant (Patents) 2 | 3 | "This implementation" means the copyrightable works distributed by 4 | Google as part of the Polymer project. 5 | 6 | Google hereby grants to You a perpetual, worldwide, non-exclusive, 7 | no-charge, royalty-free, irrevocable (except as stated in this section) 8 | patent license to make, have made, use, offer to sell, sell, import, 9 | transfer and otherwise run, modify and propagate the contents of this 10 | implementation of Polymer, where such license applies only to those 11 | patent claims, both currently owned or controlled by Google and acquired 12 | in the future, licensable by Google that are necessarily infringed by 13 | this implementation of Polymer. This grant does not include claims 14 | that would be infringed only as a consequence of further modification of 15 | this implementation. If you or your agent or exclusive licensee 16 | institute or order or agree to the institution of patent litigation 17 | against any entity (including a cross-claim or counterclaim in a 18 | lawsuit) alleging that this implementation of Polymer or any code 19 | incorporated within this implementation of Polymer constitutes 20 | direct or contributory patent infringement, or inducement of patent 21 | infringement, then any patent rights granted to you under this License 22 | for this implementation of Polymer shall terminate as of the date 23 | such litigation is filed. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Polymer.dart 2 | ============ 3 | 4 | Polymer.dart is a set of comprehensive UI and utility components 5 | for building web applications. 6 | With Polymer.dart's custom elements, templating, data binding, 7 | and other features, 8 | you can quickly build structured, encapsulated, client-side web apps. 9 | 10 | Polymer.dart is a Dart port of 11 | [Polymer][polymer] created and maintained by the Dart team. 12 | The Dart team is collaborating with the Polymer team to ensure that polymer.dart 13 | elements and polyfills are fully compatible with Polymer. 14 | 15 | Polymer.dart replaces Web UI, which has been deprecated. 16 | 17 | 18 | Learn More 19 | ---------- 20 | 21 | * The [Polymer.dart][wiki] homepage 22 | contains a list of features, project status, 23 | installation instructions, tips for upgrading from Web UI, 24 | and links to other documentation. 25 | 26 | * See our [TodoMVC][todo_mvc] example on github. 27 | 28 | * For more information about Dart, see . 29 | 30 | Try It Now 31 | ----------- 32 | Add the polymer.dart package to your pubspec.yaml file: 33 | 34 | ```yaml 35 | dependencies: 36 | polymer: ^1.0.0 37 | ``` 38 | 39 | Instead of using `any`, we recommend using version ranges to avoid getting your 40 | project broken on each release. Using a version range lets you upgrade your 41 | package at your own pace. You can find the latest version number at 42 | . 43 | 44 | **Note**: While in `release_candidate` stage, we recommend that you pin to a 45 | specific version: 46 | 47 | ```yaml 48 | dependencies: 49 | polymer: 1.0.0-rc.1 50 | ``` 51 | 52 | Building and Deploying 53 | ---------------------- 54 | 55 | To build a deployable version of your app, add the polymer transformer to your 56 | pubspec.yaml file: 57 | 58 | ```yaml 59 | transformers: 60 | - polymer: 61 | entry_points: 62 | - web/index.html 63 | ``` 64 | 65 | Then, run `pub build`. 66 | 67 | Testing 68 | ------- 69 | 70 | Polymer elements can be tested using either the original `unittest` or new 71 | `test` packages. Just make sure to wait for `initPolymer()` to complete before 72 | running your tests: 73 | 74 | ```dart 75 | @TestOn('browser') 76 | import 'package:polymer/polymer.dart'; 77 | import 'package:test/test.dart'; 78 | 79 | void main() async { 80 | await initPolymer(); 81 | // Define your tests/groups here. 82 | } 83 | ``` 84 | 85 | You will also need to define a custom html file for your test (see the README 86 | for the [test][test] package for more information on this). 87 | 88 | **Note**: If you are using the new `test` package, it is important that you add 89 | the `test` transformer after the `polymer` transformer, so it should look 90 | roughly like this: 91 | 92 | ```yaml 93 | transformer: 94 | - polymer: 95 | entry_points: 96 | - test/my_test.html 97 | - test/pub_serve: 98 | $include: test/**_test{.*,}.dart 99 | ``` 100 | 101 | Contacting Us 102 | ------------- 103 | 104 | Please file issues in our [Issue Tracker][issues] or contact us on the 105 | [Dart Web UI mailing list][mailinglist]. 106 | 107 | [issues]: https://github.com/dart-lang/polymer-dart/issues/new 108 | [mailinglist]: https://groups.google.com/a/dartlang.org/forum/?fromgroups#!forum/web 109 | [wiki]: https://github.com/dart-lang/polymer-dart/wiki 110 | [polymer]: http://www.polymer-project.org/ 111 | [todo_mvc]: https://github.com/dart-lang/sample-todomvc-polymer/ 112 | [test]: https://github.com/dart-lang/test 113 | -------------------------------------------------------------------------------- /bin/new_element.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | /// Script to create boilerplate for a Polymer element. 6 | /// Produces .dart and .html files for the element. 7 | /// 8 | /// Run this script with pub run: 9 | /// 10 | /// pub run polymer:new_element element-name [-o output_dir] 11 | /// 12 | library polymer.bin.new_element; 13 | 14 | import 'dart:io'; 15 | import 'package:args/args.dart'; 16 | import 'package:path/path.dart' as path; 17 | 18 | void printUsage(ArgParser parser) { 19 | print('pub run polymer:new_element [-o output_dir] element-name'); 20 | print(parser.usage); 21 | } 22 | 23 | void main(List args) { 24 | var parser = new ArgParser(allowTrailingOptions: true); 25 | 26 | parser.addOption('output-dir', abbr: 'o', help: 'Output directory'); 27 | parser.addFlag('help', abbr: 'h'); 28 | 29 | var options, element; 30 | try { 31 | options = parser.parse(args); 32 | if (options['help']) { 33 | printUsage(parser); 34 | return; 35 | } 36 | if (options.rest == null || options.rest.isEmpty) { 37 | throw new FormatException('No element specified'); 38 | } 39 | element = options.rest[0]; 40 | if (!_isPolymerElement(element)) { 41 | throw new FormatException('Must specify polymer-element to create.\n' 42 | 'polymer-element must be all lowercase with at least 1 hyphen.'); 43 | } 44 | } catch (e) { 45 | print('$e\n'); 46 | printUsage(parser); 47 | exitCode = 1; 48 | return; 49 | } 50 | 51 | var outputDir; 52 | 53 | var outputPath = options['output-dir']; 54 | 55 | if (outputPath == null) { 56 | if ((new File('pubspec.yaml')).existsSync()) { 57 | print('When creating elements in root directory of package, ' 58 | '-o must be specified'); 59 | exitCode = 1; 60 | return; 61 | } 62 | outputDir = (new Directory('.')).resolveSymbolicLinksSync(); 63 | } else { 64 | var outputDirLocation = new Directory(outputPath); 65 | if (!outputDirLocation.existsSync()) { 66 | outputDirLocation.createSync(recursive: true); 67 | } 68 | outputDir = (new Directory(outputPath)).resolveSymbolicLinksSync(); 69 | } 70 | 71 | var pubspecDir = _findDirWithFile(outputDir, 'pubspec.yaml'); 72 | 73 | if (pubspecDir == null) { 74 | print('Could not find pubspec.yaml when walking up from $outputDir'); 75 | exitCode = 1; 76 | return; 77 | } 78 | 79 | var length = path.split(pubspecDir).length; 80 | var distanceToPackageRoot = path.split(outputDir).length - length; 81 | 82 | // See dartbug.com/20076 for the algorithm used here. 83 | if (distanceToPackageRoot > 0) { 84 | if (path.split(outputDir)[length] == 'lib') { 85 | distanceToPackageRoot++; 86 | } else { 87 | distanceToPackageRoot--; 88 | } 89 | } 90 | 91 | try { 92 | _createBoilerPlate(element, outputDir, distanceToPackageRoot); 93 | } on Exception catch (e, t) { 94 | print('Error creating files in $outputDir'); 95 | print('$e $t'); 96 | exitCode = 1; 97 | return; 98 | } 99 | 100 | return; 101 | } 102 | 103 | String _findDirWithFile(String dir, String filename) { 104 | while (!new File(path.join(dir, filename)).existsSync()) { 105 | var parentDir = path.dirname(dir); 106 | // If we reached root and failed to find it, bail. 107 | if (parentDir == dir) return null; 108 | dir = parentDir; 109 | } 110 | return dir; 111 | } 112 | 113 | bool _isPolymerElement(String element) { 114 | return element.contains('-') && (element.toLowerCase() == element); 115 | } 116 | 117 | String _toCamelCase(String s) { 118 | var segments = s.split('-'); 119 | return segments.map((s) => s[0].toUpperCase() + s.substring(1)).join(''); 120 | } 121 | 122 | void _createBoilerPlate( 123 | String element, String directory, int distanceToPackageRoot) { 124 | 125 | var capitalizedName = _toCamelCase(element); 126 | var underscoreName = element.replaceAll('-', '_'); 127 | 128 | String html = ''' 129 | 130 | 140 | 141 | '''; 142 | 143 | String htmlFile = path.join(directory, underscoreName + '.html'); 144 | new File(htmlFile).writeAsStringSync(html); 145 | 146 | String dart = ''' 147 | @HtmlImport('$underscoreName.html') 148 | import 'package:polymer/polymer.dart'; 149 | import 'package:web_components/web_components.dart' show HtmlImport; 150 | 151 | /** 152 | * A Polymer $element element. 153 | */ 154 | @PolymerRegister('$element') 155 | class $capitalizedName extends PolymerElement { 156 | 157 | /// Constructor used to create instance of ${capitalizedName}. 158 | ${capitalizedName}.created() : super.created(); 159 | 160 | /* 161 | * Optional lifecycle methods - uncomment if needed. 162 | * 163 | 164 | /// Called when an instance of $element is inserted into the DOM. 165 | attached() { 166 | super.attached(); 167 | } 168 | 169 | /// Called when an instance of $element is removed from the DOM. 170 | detached() { 171 | super.detached(); 172 | } 173 | 174 | /// Called when an attribute (such as a class) of an instance of 175 | /// $element is added, changed, or removed. 176 | attributeChanged(String name, String oldValue, String newValue) { 177 | } 178 | 179 | /// Called when $element has been fully prepared (Shadow DOM created, 180 | /// property observers set up, event listeners attached). 181 | ready() { 182 | } 183 | 184 | */ 185 | 186 | } 187 | '''; 188 | 189 | String dartFile = path.join(directory, underscoreName + '.dart'); 190 | new File(dartFile).writeAsStringSync(dart); 191 | 192 | print('Successfully created:'); 193 | print(' ' + path.absolute(path.join(directory, underscoreName + '.dart'))); 194 | print(' ' + path.absolute(path.join(directory, underscoreName + '.html'))); 195 | } 196 | -------------------------------------------------------------------------------- /codereview.settings: -------------------------------------------------------------------------------- 1 | CODE_REVIEW_SERVER: http://codereview.chromium.org/ 2 | VIEW_VC: https://github.com/dart-lang/polymer-dart/commit/ 3 | CC_LIST: reviews@dartlang.org 4 | -------------------------------------------------------------------------------- /lib/init.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.lib.init; 5 | 6 | import 'dart:async'; 7 | import 'dart:js'; 8 | import 'dart:html'; 9 | import 'package:reflectable/reflectable.dart'; 10 | import 'package:web_components/web_components.dart'; 11 | import 'src/common/js_proxy.dart'; 12 | import 'src/common/polymer_register.dart'; 13 | 14 | main() => initPolymer(); 15 | 16 | Future initPolymer() async { 17 | await initWebComponents(typeFilter: [HtmlImport], initAll: false); 18 | // Make sure polymer is loaded first. 19 | _setUpPropertyChanged(); 20 | await initWebComponents( 21 | typeFilter: [CustomElement, CustomElementProxy, PolymerRegister], 22 | initAll: true); 23 | // TODO(jakemac): Better solution to this, see 24 | // https://github.com/dart-lang/polymer-dart/issues/611 25 | document.body.attributes.remove('unresolved'); 26 | } 27 | 28 | final _polymerDart = context['Polymer']['Dart']; 29 | 30 | void _setUpPropertyChanged() { 31 | _polymerDart['propertyChanged'] = (instance, path, newValue) { 32 | if (instance is List) { 33 | // We only care about `splices` for Lists. This does mean we don't support 34 | // setting special properties of custom List implementations though. 35 | if (path == 'splices') { 36 | // Only apply splices once, if multiple elements have a binding set up 37 | // for the same list then they will each get called here. 38 | var alreadyApplied = newValue['_applied']; 39 | if (alreadyApplied == true) return; 40 | newValue['_applied'] = true; 41 | 42 | var splices = newValue['indexSplices']; 43 | for (var splice in splices) { 44 | var index = splice['index']; 45 | var removed = splice['removed']; 46 | if (removed != null && removed.length > 0) { 47 | instance.removeRange(index, index + removed.length); 48 | } 49 | var addedCount = splice['addedCount']; 50 | var original = splice['object'] as JsArray; 51 | instance.insertAll(index, 52 | original.getRange(index, addedCount + index).map(convertToDart)); 53 | } 54 | } else if (path == 'length') { 55 | // Ignore this case, wait for `splices`. 56 | return; 57 | } else if (path is int) { 58 | instance[path] = convertToDart(newValue); 59 | } else { 60 | throw 'Only `splices`, `length`, and index paths are supported for ' 61 | 'list types, found $path.'; 62 | } 63 | } else if (instance is Map) { 64 | instance[path] = convertToDart(newValue); 65 | } else { 66 | var instanceMirror = jsProxyReflectable.reflect(instance); 67 | // Catch errors for read only properties. Checking for setters using 68 | // reflection is too slow. 69 | // https://github.com/dart-lang/polymer-dart/issues/590 70 | try { 71 | instanceMirror.invokeSetter(path, convertToDart(newValue)); 72 | } on NoSuchMethodError catch (_) {} on NoSuchCapabilityError catch (_) { 73 | // TODO(jakemac): Remove once 74 | // https://github.com/dart-lang/reflectable/issues/30 is fixed. 75 | 76 | } 77 | } 78 | }; 79 | } 80 | -------------------------------------------------------------------------------- /lib/polymer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | @HtmlImport('polymer.html') 5 | @HtmlImport('src/js/polymer_base_dart.html') 6 | library polymer.lib.polymer; 7 | 8 | import 'package:web_components/web_components.dart' show HtmlImport; 9 | export 'polymer_mini.dart'; 10 | export 'src/common/reflectable.dart'; 11 | export 'src/common/listen.dart'; 12 | export 'src/common/observe.dart'; 13 | export 'src/template/array_selector.dart'; 14 | export 'src/template/dom_bind.dart'; 15 | export 'src/template/dom_if.dart'; 16 | export 'src/template/dom_repeat.dart'; 17 | -------------------------------------------------------------------------------- /lib/polymer.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /lib/polymer_micro.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | @HtmlImport('polymer_micro.html') 5 | library polymer.lib.polymer_micro; 6 | 7 | import 'dart:html'; 8 | 9 | import 'package:polymer_interop/polymer_interop.dart'; 10 | export 'package:polymer_interop/polymer_interop.dart'; 11 | import 'package:web_components/web_components.dart' show HtmlImport; 12 | export 'src/common/behavior.dart'; 13 | import 'src/common/polymer_mixin.dart'; 14 | export 'src/common/polymer_mixin.dart'; 15 | export 'src/common/polymer_register.dart'; 16 | export 'src/common/polymer_serialize.dart'; 17 | export 'src/common/js_proxy.dart'; 18 | export 'src/common/property.dart'; 19 | export 'init.dart' show initPolymer; 20 | 21 | class PolymerElement extends HtmlElement with PolymerMixin, PolymerBase { 22 | PolymerElement.created() : super.created() { 23 | polymerCreated(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/polymer_micro.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /lib/polymer_mini.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | @HtmlImport('polymer_mini.html') 5 | library polymer.lib.polymer_mini; 6 | 7 | import 'package:web_components/web_components.dart' show HtmlImport; 8 | export 'polymer_micro.dart'; 9 | -------------------------------------------------------------------------------- /lib/polymer_mini.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 11 | 14 | -------------------------------------------------------------------------------- /lib/src/common/behavior.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.behavior; 5 | 6 | import 'dart:js'; 7 | 8 | import 'package:polymer_interop/polymer_interop.dart' show BehaviorAnnotation; 9 | export 'package:polymer_interop/polymer_interop.dart' 10 | show BehaviorAnnotation, BehaviorProxy; 11 | @GlobalQuantifyMetaCapability(Behavior, jsProxyReflectable) 12 | import 'package:reflectable/reflectable.dart'; 13 | 14 | import 'js_proxy.dart'; 15 | import 'polymer_descriptor.dart'; 16 | 17 | Map _behaviorsByType = {}; 18 | 19 | /// Custom js object containing some helper methods for dart. 20 | final JsObject _polymerDart = context['Polymer']['Dart']; 21 | 22 | // Annotation class for behaviors written in dart. 23 | class Behavior implements BehaviorAnnotation { 24 | JsObject getBehavior(Type type) { 25 | return _behaviorsByType.putIfAbsent(type, () { 26 | var obj = createBehaviorDescriptor(type); 27 | ClassMirror typeMirror = jsProxyReflectable.reflectType(type); 28 | 29 | // Check superinterfaces for additional behaviors. 30 | var behaviors = []; 31 | for (var interface in typeMirror.superinterfaces) { 32 | var meta = 33 | interface.metadata.firstWhere(_isBehavior, orElse: () => null); 34 | if (meta == null) continue; 35 | if (!interface.hasBestEffortReflectedType) { 36 | throw 'Unable to get `bestEffortReflectedType` for class ' 37 | '${interface.simpleName}.'; 38 | } 39 | behaviors.add(meta.getBehavior(interface.bestEffortReflectedType)); 40 | } 41 | 42 | // If we have no additional behaviors, then just return `obj`. 43 | if (behaviors.isEmpty) return obj; 44 | 45 | // If we do have dependent behaviors, return the list of all of them, 46 | // adding `obj` to the end. 47 | behaviors.add(obj); 48 | return new JsArray.from(behaviors); 49 | }); 50 | } 51 | 52 | const Behavior(); 53 | } 54 | 55 | const behavior = const Behavior(); 56 | 57 | bool _isBehavior(instance) => instance is BehaviorAnnotation; 58 | -------------------------------------------------------------------------------- /lib/src/common/declarations.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.declarations; 5 | 6 | import 'dart:js'; 7 | 8 | import 'package:reflectable/reflectable.dart'; 9 | 10 | import '../../polymer_micro.dart'; 11 | 12 | final JsObject _polymerDart = context['Polymer']['Dart']; 13 | 14 | List mixinsFor(Type type, Reflectable reflectionClass, 15 | {bool where(ClassMirror mirror)}) { 16 | var typeMirror = reflectionClass.reflectType(type); 17 | var mixins = []; 18 | var superClass = _getSuper(typeMirror); 19 | while (superClass != null && !_isPolymerMixin(superClass.mixin)) { 20 | var mixin = superClass.mixin; 21 | if (mixin != superClass && (where == null || where(mixin))) { 22 | mixins.add(mixin); 23 | } 24 | superClass = _getSuper(superClass); 25 | } 26 | return mixins.reversed.toList(); 27 | } 28 | 29 | /// Retrieves all the declarations for a class, given a [Reflectable] instance. 30 | /// If a [_WhereFn] is supplied then it only returns the declarations which 31 | /// return true from that. 32 | Map declarationsFor( 33 | Type type, Reflectable reflectionClass, 34 | {bool where(String name, DeclarationMirror declaration), 35 | bool includeSuper: true}) { 36 | var typeMirror = reflectionClass.reflectType(type); 37 | var declarations = {}; 38 | var superClass = typeMirror; 39 | while (superClass != null && !_isPolymerMixin(superClass.mixin)) { 40 | superClass.declarations.forEach((name, declaration) { 41 | if (declarations.containsKey(name)) return; 42 | if (where != null && !where(name, declaration)) return; 43 | declarations[name] = declaration; 44 | }); 45 | superClass = includeSuper ? _getSuper(superClass) : null; 46 | } 47 | return declarations; 48 | } 49 | 50 | bool _isPolymerMixin(ClassMirror clazz) { 51 | return clazz.hasReflectedType && 52 | (clazz.reflectedType == PolymerMixin || 53 | clazz.reflectedType == PolymerBase); 54 | } 55 | 56 | ClassMirror _getSuper(ClassMirror clazz) { 57 | // Currently throws post-transform if superclass isn't annotated with a 58 | // [Reflectable] class. 59 | try { 60 | return clazz.superclass; 61 | } catch (e) { 62 | return null; 63 | } 64 | } 65 | 66 | bool isFinal(DeclarationMirror declaration) { 67 | if (declaration is VariableMirror) return declaration.isFinal; 68 | if (declaration is MethodMirror && declaration.isGetter) { 69 | return !hasSetter(declaration); 70 | } 71 | return false; 72 | } 73 | 74 | bool isProperty(DeclarationMirror declaration) { 75 | if (declaration is VariableMirror) return true; 76 | if (declaration is MethodMirror) return !declaration.isRegularMethod; 77 | return false; 78 | } 79 | 80 | bool isRegularMethod(DeclarationMirror declaration) { 81 | return declaration is MethodMirror && 82 | !declaration.isStatic && 83 | declaration.isRegularMethod; 84 | } 85 | 86 | bool isSetter(DeclarationMirror declaration) { 87 | return declaration is MethodMirror && declaration.isSetter; 88 | } 89 | 90 | bool hasSetter(MethodMirror getterDeclaration) { 91 | assert(getterDeclaration.isGetter); 92 | var owner = getterDeclaration.owner; 93 | assert(owner is LibraryMirror || owner is ClassMirror); 94 | return owner.declarations.containsKey('${getterDeclaration.simpleName}='); 95 | } 96 | 97 | void addDeclarationToPrototype( 98 | String name, Type type, DeclarationMirror declaration, JsObject prototype) { 99 | if (isProperty(declaration)) { 100 | var descriptor = { 101 | 'get': _polymerDart.callMethod('propertyAccessorFactory', [ 102 | name, 103 | (dartInstance) { 104 | var mirror = (declaration as dynamic).isStatic 105 | ? jsProxyReflectable.reflectType(type) 106 | : jsProxyReflectable.reflect(dartInstance); 107 | return convertToJs(mirror.invokeGetter(name)); 108 | } 109 | ]), 110 | 'configurable': false, 111 | }; 112 | if (!isFinal(declaration)) { 113 | descriptor['set'] = _polymerDart.callMethod('propertySetterFactory', [ 114 | name, 115 | (dartInstance, value) { 116 | var mirror = (declaration as dynamic).isStatic 117 | ? jsProxyReflectable.reflectType(type) 118 | : jsProxyReflectable.reflect(dartInstance); 119 | mirror.invokeSetter(name, convertToDart(value)); 120 | } 121 | ]); 122 | } 123 | // Add a proxy getter/setter for this property. 124 | context['Object'].callMethod( 125 | 'defineProperty', [prototype, name, new JsObject.jsify(descriptor),]); 126 | } else if (declaration is MethodMirror) { 127 | // TODO(jakemac): consolidate this code with the code in properties.dart. 128 | prototype[name] = _polymerDart.callMethod('invokeDartFactory', [ 129 | (dartInstance, arguments) { 130 | var newArgs = arguments.map((arg) => convertToDart(arg)).toList(); 131 | var mirror = declaration.isStatic 132 | ? jsProxyReflectable.reflectType(type) 133 | : jsProxyReflectable.reflect(dartInstance); 134 | return convertToJs(mirror.invoke(name, newArgs)); 135 | } 136 | ]); 137 | } else { 138 | throw 'Unrecognized declaration `$name` for type `$type`: $declaration'; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /lib/src/common/js_proxy.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.lib.src.common.js_proxy; 5 | 6 | import 'dart:html'; 7 | import 'dart:js'; 8 | 9 | import 'package:polymer_interop/polymer_interop.dart'; 10 | export 'package:polymer_interop/polymer_interop.dart' 11 | show convertToDart, convertToJs; 12 | import 'package:reflectable/reflectable.dart'; 13 | 14 | import 'behavior.dart'; 15 | import 'declarations.dart'; 16 | import 'reflectable.dart'; 17 | 18 | /// Mixin this class to get js proxy support! If a [JsProxy] is passed to 19 | /// [convertToJs] then you will get back a [JsObject] which is fully usable from 20 | /// JS, but proxies all method calls and properties to the dart instance. 21 | /// Calling [convertToDart] on that [JsObject] will also return the original 22 | /// dart instance (not a copy). 23 | @jsProxyReflectable 24 | abstract class JsProxy implements JsProxyInterface { 25 | /// Lazily create proxy constructors! 26 | static Map _jsProxyConstructors = {}; 27 | 28 | /// Whether to introduce a cache layer and make operations read from the 29 | /// cache. By default JsProxys have no cache and the proxy reads values 30 | /// directly from the Dart object. This is primarily useful for objects that 31 | /// you pass in empty, and the javascript code will populate. It should be 32 | /// used carefully since its easy to get the two objects out of sync. 33 | bool useCache = false; 34 | 35 | /// The Javascript constructor that will be used to build proxy objects for 36 | /// this class. 37 | JsFunction get jsProxyConstructor { 38 | var type = runtimeType; 39 | return _jsProxyConstructors.putIfAbsent( 40 | type, () => _buildJsConstructorForType(type)); 41 | } 42 | 43 | JsObject _jsProxy; 44 | JsObject get jsProxy { 45 | if (_jsProxy == null) _jsProxy = _buildJsProxy(this); 46 | return _jsProxy; 47 | } 48 | } 49 | 50 | /// Wraps an instance of a dart class in a js proxy. 51 | JsObject _buildJsProxy(JsProxy instance) { 52 | var constructor = instance.jsProxyConstructor; 53 | var proxy = new JsObject(constructor); 54 | setDartInstance(proxy, instance); 55 | if (instance.useCache) { 56 | proxy['__cache__'] = new JsObject(context['Object']); 57 | } 58 | 59 | return proxy; 60 | } 61 | 62 | const _knownMethodAndPropertyNames = 63 | 'hostAttributes|created|attached|detached|attributeChanged|ready|serialize' 64 | '|deserialize|registered|beforeRegister'; 65 | 66 | /// The [Reflectable] class which gives you the ability to do everything that 67 | /// PolymerElements and JsProxies need to do. 68 | class JsProxyReflectable extends Reflectable { 69 | const JsProxyReflectable() 70 | : super.fromList(const [ 71 | const InstanceInvokeMetaCapability(PolymerReflectable), 72 | const InstanceInvokeCapability(_knownMethodAndPropertyNames), 73 | metadataCapability, 74 | declarationsCapability, 75 | typeAnnotationQuantifyCapability, 76 | typeCapability, 77 | typeRelationsCapability, 78 | subtypeQuantifyCapability, 79 | const SuperclassQuantifyCapability(HtmlElement, 80 | excludeUpperBound: true), 81 | const StaticInvokeCapability(_knownMethodAndPropertyNames), 82 | const StaticInvokeMetaCapability(PolymerReflectable), 83 | correspondingSetterQuantifyCapability 84 | ]); 85 | } 86 | 87 | const jsProxyReflectable = const JsProxyReflectable(); 88 | 89 | final JsObject _polymerDart = context['Polymer']['Dart']; 90 | 91 | /// Given a dart type, this creates a javascript constructor and prototype 92 | /// which can act as a proxy for it. 93 | JsFunction _buildJsConstructorForType(Type dartType) { 94 | var constructor = _polymerDart.callMethod('functionFactory'); 95 | var prototype = new JsObject(context['Object']); 96 | 97 | var declarations = 98 | declarationsFor(dartType, jsProxyReflectable, where: (name, declaration) { 99 | // Skip declarations from [BehaviorProxy] classes. These should not 100 | // read/write from the dart class. 101 | return !declaration.owner.metadata.any((m) => m is BehaviorProxy); 102 | }); 103 | declarations.forEach((name, declaration) => 104 | addDeclarationToPrototype(name, dartType, declaration, prototype)); 105 | 106 | constructor['prototype'] = prototype; 107 | return constructor; 108 | } 109 | -------------------------------------------------------------------------------- /lib/src/common/listen.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.lib.src.common.listen; 5 | 6 | import 'reflectable.dart'; 7 | 8 | /// Annotation class for methods, calls the annotated method when the named 9 | /// event is fired. Equivalent to the `listeners` object in polymer js, see 10 | /// https://www.polymer-project.org/1.0/docs/devguide/events.html#event-listeners. 11 | class Listen extends PolymerReflectable { 12 | final String eventName; 13 | const Listen(this.eventName) : super(); 14 | } 15 | -------------------------------------------------------------------------------- /lib/src/common/observe.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.lib.src.common.observe; 5 | 6 | import 'reflectable.dart'; 7 | 8 | /// Annotation class for methods, should match the argument string portion of 9 | /// a regular `observers` entry from polymer js, see 10 | /// https://www.polymer-project.org/1.0/docs/devguide/properties.html#multi-property-observers 11 | /// for more details. 12 | /// 13 | /// For example, given this `observers` object in js: 14 | /// 15 | /// observers: [ 16 | /// 'updateImage(preload, src, size)' 17 | /// ] 18 | /// 19 | /// This would the the equivalent using the [Observe] annotation: 20 | /// 21 | /// @Observe('preload, src, size`) 22 | /// updateImage(bool preload, String src, String size) { 23 | /// ... 24 | /// } 25 | class Observe extends PolymerReflectable { 26 | final String properties; 27 | const Observe(this.properties) : super(); 28 | } 29 | -------------------------------------------------------------------------------- /lib/src/common/polymer_descriptor.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.micro.properties; 5 | 6 | import 'dart:html'; 7 | import 'dart:js'; 8 | 9 | import 'package:reflectable/reflectable.dart'; 10 | 11 | import 'behavior.dart'; 12 | import 'declarations.dart'; 13 | import 'js_proxy.dart'; 14 | import 'listen.dart'; 15 | import 'observe.dart'; 16 | import 'polymer_register.dart'; 17 | import 'property.dart'; 18 | import 'reflectable.dart'; 19 | import 'util.dart'; 20 | import '../js/undefined.dart'; 21 | 22 | /// Creates a javascript object which can be passed to polymer js to register 23 | /// an element, given a dart [Type] and a [PolymerRegister] annotation. 24 | JsObject createPolymerDescriptor(Type type, PolymerRegister annotation) { 25 | return _createDescriptor(type) 26 | ..['is'] = annotation.tagName 27 | ..['extends'] = annotation.extendsTag 28 | ..['behaviors'] = _buildBehaviorsList(type); 29 | } 30 | 31 | /// Creates a javascript object which can be used as a behavior by polymer js, 32 | /// given a dart [Type] and a [PolymerRegister] annotation. 33 | JsObject createBehaviorDescriptor(Type type) { 34 | return _createDescriptor(type, true); 35 | } 36 | 37 | /// Shared descriptor between polymer elements and behaviors 38 | JsObject _createDescriptor(Type type, [bool isBehavior = false]) { 39 | var descriptor = new JsObject.jsify({ 40 | 'properties': _buildPropertiesObject(type), 41 | 'observers': _buildObserversObject(type), 42 | 'listeners': _buildListenersObject(type), 43 | '__isPolymerDart__': true, 44 | }); 45 | _setupLifecycleMethods(type, descriptor, isBehavior); 46 | _setupReflectableMethods(type, descriptor); 47 | _setupReflectableProperties(type, descriptor); 48 | _setupHostAttributes(type, descriptor); 49 | _setupRegistrationMethods(type, descriptor); 50 | 51 | return descriptor; 52 | } 53 | 54 | /// Custom js object containing some helper methods for dart. 55 | final JsObject _polymerDart = context['Polymer']['Dart']; 56 | 57 | /// Returns a list of [DeclarationMirror]s for all fields annotated as a 58 | /// [Property]. 59 | Map propertyDeclarationsFor(Type type) { 60 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 61 | where: (name, declaration) { 62 | if (isRegularMethod(declaration) || isSetter(declaration)) return false; 63 | return declaration.metadata.any((d) => d is Property); 64 | }); 65 | } 66 | 67 | // Set up the `properties` descriptor object. 68 | Map _buildPropertiesObject(Type type) { 69 | var declarations = propertyDeclarationsFor(type); 70 | var properties = {}; 71 | declarations.forEach((String name, DeclarationMirror declaration) { 72 | // Build a properties object for this property. 73 | properties[name] = _getPropertyInfoForType(type, declaration); 74 | }); 75 | return properties; 76 | } 77 | 78 | /// All @Observe annotated methods. 79 | Map _observeMethodsFor(Type type) { 80 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 81 | where: (name, declaration) { 82 | if (!isRegularMethod(declaration)) return false; 83 | return declaration.metadata.any((d) => d is Observe); 84 | }); 85 | } 86 | 87 | /// Set up the `observers` descriptor object, see 88 | /// https://www.polymer-project.org/1.0/docs/devguide/properties.html#multi-property-observers 89 | List _buildObserversObject(Type type) { 90 | var declarations = _observeMethodsFor(type); 91 | var observers = []; 92 | declarations.forEach((String name, DeclarationMirror declaration) { 93 | Observe observe = declaration.metadata.firstWhere((e) => e is Observe); 94 | // Build a properties object for this property. 95 | observers.add('$name(${observe.properties})'); 96 | }); 97 | return observers; 98 | } 99 | 100 | /// All @Listen annotated methods. 101 | Map _listenMethodsFor(Type type) { 102 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 103 | where: (name, declaration) { 104 | if (!isRegularMethod(declaration)) return false; 105 | return declaration.metadata.any((d) => d is Listen); 106 | }); 107 | } 108 | 109 | /// Set up the `listeners` descriptor object, see 110 | /// https://www.polymer-project.org/1.0/docs/devguide/events.html#event-listeners 111 | Map _buildListenersObject(Type type) { 112 | var declarations = _listenMethodsFor(type); 113 | var listeners = {}; 114 | declarations.forEach((String name, DeclarationMirror declaration) { 115 | for (Listen listen in declaration.metadata.where((e) => e is Listen)) { 116 | listeners[listen.eventName] = name; 117 | } 118 | }); 119 | return listeners; 120 | } 121 | 122 | const _lifecycleMethods = const [ 123 | 'ready', 124 | 'attached', 125 | 'created', 126 | 'detached', 127 | 'attributeChanged', 128 | ]; 129 | 130 | const _serializeMethods = const ['serialize', 'deserialize']; 131 | 132 | /// All lifecycle methods for a type. 133 | Map _lifecycleMethodsFor(Type type) { 134 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 135 | where: (name, declaration) { 136 | if (declaration is MethodMirror && declaration.isRegularMethod) { 137 | return _lifecycleMethods.contains(name) || 138 | _serializeMethods.contains(name); 139 | } 140 | return false; 141 | }); 142 | } 143 | 144 | /// Set up a proxy for the lifecyle methods, if they exists on the dart class. 145 | /// If its a behavior we expect most of these 146 | void _setupLifecycleMethods(Type type, JsObject prototype, 147 | [bool isBehavior = false]) { 148 | var declarations = _lifecycleMethodsFor(type); 149 | declarations.forEach((String name, MethodMirror declaration) { 150 | if (_lifecycleMethods.contains(name)) { 151 | if (!declaration.isStatic && isBehavior) { 152 | throw 'Lifecycle methods on behaviors must be static methods, found ' 153 | '`$name` on `$type`. The first argument to these methods is the' 154 | 'instance.'; 155 | } else if (declaration.isStatic && !isBehavior) { 156 | throw 'Lifecycle methods on elements must not be static methods, found ' 157 | '`$name` on class `$type`.'; 158 | } 159 | } 160 | prototype[name] = _polymerDart.callMethod('invokeDartFactory', [ 161 | (dartInstance, arguments) { 162 | var newArgs = []; 163 | var mirror; 164 | if (declaration.isStatic) { 165 | mirror = jsProxyReflectable.reflectType(type); 166 | newArgs.add(dartInstance); 167 | } else { 168 | mirror = jsProxyReflectable.reflect(dartInstance); 169 | } 170 | newArgs.addAll(arguments.map((arg) => convertToDart(arg))); 171 | return mirror.invoke(name, newArgs); 172 | } 173 | ]); 174 | }); 175 | } 176 | 177 | /// All methods annotated with @reflectable. 178 | Map _reflectableMethodsFor(Type type) { 179 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 180 | where: (name, declaration) { 181 | if (declaration is MethodMirror && declaration.isRegularMethod) { 182 | return declaration.metadata.any((d) => d is PolymerReflectable); 183 | } 184 | return false; 185 | }); 186 | } 187 | 188 | /// Set up a proxy for any method with an @reflectable annotation. 189 | void _setupReflectableMethods(Type type, JsObject prototype) { 190 | var declarations = _reflectableMethodsFor(type); 191 | declarations.forEach((String name, MethodMirror declaration) { 192 | // Error on anything in `_registrationMethods`. 193 | if (_registrationMethods.contains(name)) { 194 | if (declaration.isStatic) return; 195 | throw 'Disallowed instance method `$name` with @reflectable annotation ' 196 | 'on the `${declaration.owner.simpleName}` class, since it has a ' 197 | 'special meaning in Polymer. You can either rename the method or' 198 | 'change it to a static method. If it is a static method it will be ' 199 | 'invoked with the JS prototype of the element at registration time.'; 200 | } 201 | 202 | // Add the method. 203 | addDeclarationToPrototype(name, type, declaration, prototype); 204 | }); 205 | } 206 | 207 | /// All properties annotated with a [Reflectable] but not a [Property] since 208 | /// those are handled separately. 209 | Map _reflectablePropertiesFor(Type type) { 210 | return declarationsFor(type, jsProxyReflectable, includeSuper: false, 211 | where: (name, declaration) { 212 | if (declaration is MethodMirror && declaration.isRegularMethod) { 213 | return false; 214 | } 215 | return declaration.metadata 216 | .any((d) => d is PolymerReflectable && d is! Property); 217 | }); 218 | } 219 | 220 | /// Set up all @reflectable properties (that aren't marked with @property) 221 | void _setupReflectableProperties(Type type, JsObject prototype) { 222 | var declarations = _reflectablePropertiesFor(type); 223 | declarations.forEach((name, declaration) => 224 | addDeclarationToPrototype(name, type, declaration, prototype)); 225 | } 226 | 227 | /// Add the hostAttributes property to the prototype if it exists. 228 | void _setupHostAttributes(Type type, JsObject prototype) { 229 | var typeMirror = jsProxyReflectable.reflectType(type); 230 | var hostAttributes = readHostAttributes(typeMirror); 231 | if (hostAttributes != null) { 232 | prototype['hostAttributes'] = hostAttributes; 233 | } 234 | } 235 | 236 | final _registrationMethods = const ['registered', 'beforeRegister']; 237 | 238 | /// Sets up any static methods contained in `_staticRegistrationMethods`. 239 | void _setupRegistrationMethods(Type type, JsObject prototype) { 240 | var typeMirror = jsProxyReflectable.reflectType(type); 241 | for (String name in _registrationMethods) { 242 | var method = typeMirror.staticMembers[name]; 243 | if (method == null || method is! MethodMirror) continue; 244 | prototype[name] = _polymerDart.callMethod('invokeDartFactory', [ 245 | (dartInstance, arguments) { 246 | // Dartium hack, the proto has HtmlElement on its proto chain so 247 | // it thinks its an HtmlElement. 248 | if (dartInstance is HtmlElement) { 249 | dartInstance = new JsObject.fromBrowserObject(dartInstance); 250 | } 251 | 252 | var newArgs = [dartInstance] 253 | ..addAll(arguments.map((arg) => convertToDart(arg))); 254 | typeMirror.invoke(name, newArgs); 255 | } 256 | ]); 257 | } 258 | } 259 | 260 | /// Object that represents a property that was not found. 261 | final _emptyPropertyInfo = {'defined': false}; 262 | 263 | /// Compute or return from cache information about `property` for `t`. 264 | Map _getPropertyInfoForType(Type type, DeclarationMirror declaration) { 265 | assert(declaration is VariableMirror || declaration is MethodMirror); 266 | var jsPropertyType; 267 | var isFinal; 268 | var typeMirror; 269 | if (declaration is VariableMirror) { 270 | typeMirror = declaration.type; 271 | isFinal = declaration.isFinal; 272 | } else if (declaration is MethodMirror) { 273 | assert(declaration.isGetter); 274 | typeMirror = declaration.returnType; 275 | isFinal = !hasSetter(declaration); 276 | } 277 | if (typeMirror is ClassMirror && typeMirror.hasBestEffortReflectedType) { 278 | jsPropertyType = jsType(typeMirror.bestEffortReflectedType); 279 | } 280 | 281 | Property annotation = declaration.metadata.firstWhere((a) => a is Property); 282 | var property = { 283 | 'defined': true, 284 | 'notify': annotation.notify, 285 | 'observer': annotation.observer, 286 | 'reflectToAttribute': annotation.reflectToAttribute, 287 | 'computed': annotation.computed, 288 | 'value': _polymerDart.callMethod('invokeDartFactory', [ 289 | (dartInstance, _) { 290 | var instanceMirror = jsProxyReflectable.reflect(dartInstance); 291 | var value = 292 | convertToJs(instanceMirror.invokeGetter(declaration.simpleName)); 293 | if (value == null) return polymerDartUndefined; 294 | return value; 295 | } 296 | ]), 297 | }; 298 | if (isFinal) { 299 | property['readOnly'] = true; 300 | } 301 | if (jsPropertyType != null) { 302 | property['type'] = jsPropertyType; 303 | } 304 | return property; 305 | } 306 | 307 | bool _isBehavior(instance) => instance is BehaviorAnnotation; 308 | bool _hasBehaviorMeta(ClassMirror clazz) => clazz.metadata.any(_isBehavior); 309 | 310 | /// List of [JsObjects]s representing the behaviors for an element. 311 | JsArray _buildBehaviorsList(Type type) { 312 | // All behavior mixins, in order. 313 | var allBehaviors = 314 | mixinsFor(type, jsProxyReflectable).where(_hasBehaviorMeta); 315 | // The distilled list of behaviors. 316 | var behaviorStack = new List(); 317 | 318 | // Verify behavior ordering and build up `behaviorStack`. 319 | for (var behavior in allBehaviors) { 320 | for (var interface in behavior.superinterfaces.reversed) { 321 | if (!_hasBehaviorMeta(interface)) continue; 322 | if (behaviorStack.isEmpty || behaviorStack.removeLast() != interface) { 323 | _throwInvalidMixinOrder(type, behavior); 324 | } 325 | } 326 | 327 | // Get the js object for the behavior from the annotation, and add it. 328 | behaviorStack.add(behavior); 329 | } 330 | 331 | return new JsArray.from([_polymerDart['InteropBehavior']] 332 | ..addAll(behaviorStack.map((ClassMirror behavior) { 333 | BehaviorAnnotation meta = behavior.metadata.firstWhere(_isBehavior); 334 | if (!behavior.hasBestEffortReflectedType) { 335 | throw 'Unable to get `bestEffortReflectedType` for behavior ' 336 | '${behavior.simpleName}.'; 337 | } 338 | return meta.getBehavior(behavior.bestEffortReflectedType); 339 | }))); 340 | } 341 | 342 | // Throws an error about expected mixins that must precede the [clazz] mixin. 343 | void _throwInvalidMixinOrder(Type type, ClassMirror mixin) { 344 | var expected = mixin.superinterfaces 345 | .where(_hasBehaviorMeta) 346 | .map((clazz) => clazz.simpleName) 347 | .join(', '); 348 | throw 'Unexpected mixin ordering on type $type. The ${mixin.simpleName} ' 349 | 'mixin must be immediately preceded by the following mixins, in this ' 350 | 'order: $expected'; 351 | } 352 | 353 | /// Given a [Type] return the [JsObject] representation of that type. 354 | /// TODO(jakemac): Make this more robust, specifically around Lists. 355 | dynamic jsType(Type type) { 356 | var typeString = '$type'; 357 | if (typeString.startsWith('JsArray<')) typeString = 'List'; 358 | if (typeString.startsWith('List<')) typeString = 'List'; 359 | if (typeString.startsWith('Map<')) typeString = 'Map'; 360 | switch (typeString) { 361 | case 'int': 362 | case 'double': 363 | case 'num': 364 | return context['Number']; 365 | case 'bool': 366 | return context['Boolean']; 367 | case 'List': 368 | case 'JsArray': 369 | return context['Array']; 370 | case 'DateTime': 371 | return context['Date']; 372 | case 'String': 373 | return context['String']; 374 | case 'Map': 375 | case 'JsObject': 376 | return context['Object']; 377 | default: 378 | // Just return the Dart type 379 | return type; 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /lib/src/common/polymer_mixin.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.polymer_js_proxy; 5 | 6 | import 'dart:js'; 7 | import 'package:web_components/web_components.dart'; 8 | import 'js_proxy.dart'; 9 | 10 | /// Basic api for re-using the polymer js prototypes. 11 | @jsProxyReflectable 12 | abstract class PolymerMixin implements CustomElementProxyMixin { 13 | JsObject _proxy; 14 | 15 | JsObject get jsElement { 16 | if (_proxy == null) { 17 | _proxy = new JsObject.fromBrowserObject(this); 18 | } 19 | return _proxy; 20 | } 21 | 22 | void polymerCreated() { 23 | jsElement.callMethod('originalPolymerCreatedCallback'); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/src/common/polymer_register.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.polymer_register; 5 | 6 | import 'dart:js'; 7 | import 'package:web_components/web_components.dart' show CustomElementProxy; 8 | import 'polymer_descriptor.dart'; 9 | 10 | class PolymerRegister extends CustomElementProxy { 11 | final Map hostAttributes; 12 | 13 | const PolymerRegister(String tagName, 14 | {String extendsTag, this.hostAttributes}) 15 | : super(tagName, extendsTag: extendsTag); 16 | 17 | void initialize(Type type) { 18 | // Register the element via polymer js. 19 | context.callMethod('Polymer', [createPolymerDescriptor(type, this)]); 20 | // Register the dart type as a proxy. 21 | super.initialize(type); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /lib/src/common/polymer_serialize.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.polymer_serialize; 5 | 6 | import 'dart:js'; 7 | import 'js_proxy.dart'; 8 | import 'polymer_mixin.dart'; 9 | import 'polymer_descriptor.dart'; 10 | 11 | /// Mixin for Polymer serialization methods. 12 | /// 13 | /// This should only be used if the [serialize] and [deserialize] methods need 14 | /// to be overridden to support additional Dart types. Any types not explicitly 15 | /// handled by the overridden method should defer to the original method by 16 | /// calling the base class's implementation. 17 | abstract class PolymerSerialize implements PolymerMixin { 18 | JsObject get jsElement; 19 | 20 | /// Serializes the [value] into a [String]. 21 | String serialize(value) { 22 | var result = _polymerDartSerialize.apply([convertToJs(value)]); 23 | 24 | return (result != null) ? result.toString() : null; 25 | } 26 | 27 | /// Deserializes the [value] into an object of the given [type]. 28 | dynamic deserialize(String value, Type type) { 29 | return convertToDart(_polymerDartDeserialize.apply([value, jsType(type)])); 30 | } 31 | } 32 | 33 | final JsObject _polymer = context['Polymer']; 34 | final JsFunction _polymerDartSerialize = _polymer['Dart']['serialize']; 35 | final JsFunction _polymerDartDeserialize = _polymer['Dart']['deserialize']; 36 | -------------------------------------------------------------------------------- /lib/src/common/property.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.property; 5 | 6 | import 'reflectable.dart'; 7 | 8 | /// Use this to mark a field on a class as a polymer property. 9 | class Property extends PolymerReflectable { 10 | /// Fire *-change events to support two way binding. 11 | final bool notify; 12 | 13 | /// Name of a method to call when the property changes. 14 | final String observer; 15 | 16 | /// Whether or not this property should be reflected back to the attribute. 17 | final bool reflectToAttribute; 18 | 19 | /// Provided for computed properties. 20 | final String computed; 21 | 22 | const Property( 23 | {this.notify: false, 24 | this.observer, 25 | this.reflectToAttribute: false, 26 | this.computed}); 27 | } 28 | 29 | const property = const Property(); 30 | -------------------------------------------------------------------------------- /lib/src/common/reflectable.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.reflectable; 5 | 6 | /// Indicates that a field or method is reflectable. This means it will be 7 | /// available to templates and any other string references. 8 | class PolymerReflectable { 9 | const PolymerReflectable(); 10 | } 11 | 12 | const reflectable = const PolymerReflectable(); 13 | -------------------------------------------------------------------------------- /lib/src/common/util.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.common.util; 5 | 6 | import 'dart:html'; 7 | import 'dart:js'; 8 | import 'package:reflectable/reflectable.dart'; 9 | 10 | /// Converts the static `hostAttributes` property of the supplied [ClassMirror] 11 | /// to a [JsObject] and reports nice errors for failure cases. 12 | JsObject readHostAttributes(ClassMirror classMirror) { 13 | if (!classMirror.staticMembers.containsKey('hostAttributes')) return null; 14 | var hostAttributes = classMirror.invokeGetter('hostAttributes'); 15 | if (hostAttributes is! Map) { 16 | throw '`hostAttributes` on ${classMirror.simpleName} must be a `Map`, ' 17 | 'but got a ${hostAttributes.runtimeType}'; 18 | } 19 | try { 20 | return new JsObject.jsify(hostAttributes); 21 | } catch (e) { 22 | window.console.error(''' 23 | Invalid value for `hostAttributes` on ${classMirror.simpleName}. 24 | Must be a Map which is compatible with `new JsObject.jsify(...)`. 25 | 26 | Original Exception: 27 | $e'''); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/src/js/polymer_base_dart.html: -------------------------------------------------------------------------------- 1 | 6 | 96 | -------------------------------------------------------------------------------- /lib/src/js/polymer_bind_dart.html: -------------------------------------------------------------------------------- 1 | 6 | 59 | -------------------------------------------------------------------------------- /lib/src/js/undefined.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.js.js_undefined; 5 | 6 | import 'dart:js'; 7 | 8 | /// TODO(jakemac): Remove once we get 9 | /// https://github.com/dart-lang/sdk/issues/24088. 10 | final polymerDartUndefined = context['Polymer']['Dart']['undefined']; 11 | -------------------------------------------------------------------------------- /lib/src/template/array_selector.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.template.array_selector; 5 | 6 | import 'dart:html'; 7 | import 'package:web_components/web_components.dart'; 8 | import 'package:polymer/polymer.dart'; 9 | 10 | @CustomElementProxy('array-selector') 11 | class ArraySelector extends HtmlElement 12 | with CustomElementProxyMixin, PolymerBase { 13 | ArraySelector.created() : super.created(); 14 | 15 | /// An array containing items from which selection will be made. 16 | List get items => convertToDart(jsElement['items']); 17 | void set items(List newVal) => jsElement.callMethod('set', ['items', items]); 18 | 19 | /// When `multi` is true, this is an array that contains any selected. 20 | /// When `multi` is false, this is the currently selected item, or `null` 21 | /// if no item is selected. 22 | dynamic get selected => convertToDart(jsElement['selected']); 23 | 24 | /// When `multi` is false, this is the currently selected item, or `null` 25 | /// if no item is selected. 26 | dynamic get selectedItem => convertToDart(jsElement['selectedItem']); 27 | void set selectedItem(newVal) { 28 | jsElement['selectedItem'] = convertToJs(newVal); 29 | } 30 | 31 | /// When `true`, calling `select` on an item that is already selected 32 | /// will deselect the item. 33 | bool get toggle => jsElement['toggle']; 34 | void set toggle(bool newVal) { 35 | jsElement.callMethod('set', ['toggle', newVal]); 36 | } 37 | 38 | /// When `true`, multiple items may be selected at once (in this case, 39 | /// `selected` is an array of currently selected items). When `false`, 40 | /// only one item may be selected at a time. 41 | bool get multi => jsElement['multi']; 42 | void set multi(bool newVal) { 43 | jsElement.callMethod('set', ['multi', newVal]); 44 | } 45 | 46 | /// Deselects the given item if it is already selected. 47 | void deselect(item) => jsElement.callMethod('deselect', [convertToJs(item)]); 48 | 49 | /// Selects the given item. When `toggle` is true, this will automatically 50 | /// deselect the item if already selected. 51 | void select(item) => jsElement.callMethod('select', [convertToJs(item)]); 52 | } 53 | -------------------------------------------------------------------------------- /lib/src/template/dom_bind.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2014, 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 | library polymer.src.template.dom_bind; 5 | 6 | import 'dart:html'; 7 | // Needed to ensure `polymer.html` import. 8 | import 'package:polymer/polymer.dart'; 9 | import 'package:web_components/web_components.dart'; 10 | 11 | @CustomElementProxy('dom-bind', extendsTag: 'template') 12 | class DomBind extends TemplateElement 13 | with CustomElementProxyMixin, PolymerBase { 14 | DomBind.created() : super.created(); 15 | 16 | void render() { 17 | jsElement.callMethod('render'); 18 | } 19 | 20 | /// Retrieve arbitrary values from the dom-bind instance. 21 | operator [](String key) => convertToDart(jsElement[key]); 22 | 23 | /// Set arbitrary values on the dom-bind instance. These will be available 24 | /// to the template bindings. 25 | operator []=(String key, value) => set(key, value); 26 | } 27 | -------------------------------------------------------------------------------- /lib/src/template/dom_if.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.template.dom_if; 5 | 6 | import 'dart:html'; 7 | // Needed to ensure `polymer.html` import. 8 | import 'package:polymer/polymer.dart'; 9 | import 'package:web_components/web_components.dart'; 10 | 11 | @CustomElementProxy('dom-if', extendsTag: 'template') 12 | class DomIf extends TemplateElement with CustomElementProxyMixin, PolymerBase { 13 | DomIf.created() : super.created(); 14 | 15 | void render() => jsElement.callMethod('render'); 16 | } 17 | -------------------------------------------------------------------------------- /lib/src/template/dom_repeat.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2015, 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 | library polymer.src.template.dom_repeat; 5 | 6 | import 'dart:html'; 7 | import 'dart:js'; 8 | import 'package:web_components/web_components.dart'; 9 | // Needed to ensure `polymer.html` import. 10 | import 'package:polymer/polymer.dart'; 11 | 12 | @CustomElementProxy('dom-repeat', extendsTag: 'template') 13 | class DomRepeat extends TemplateElement 14 | with CustomElementProxyMixin, PolymerBase { 15 | DomRepeat.created() : super.created(); 16 | 17 | /// An array containing items determining how many instances of the template 18 | /// to stamp and that that each template instance should bind to. 19 | List get items => convertToDart(jsElement['items']); 20 | void set items(List newVal) { 21 | jsElement.callMethod('set', ['items', convertToJs(newVal)]); 22 | } 23 | 24 | /// The name of the variable to add to the binding scope for the array 25 | /// element associated with a given template instance. 26 | String get as => jsElement['as']; 27 | void set as(String newVal) { 28 | jsElement.callMethod('set', ['as', newVal]); 29 | } 30 | 31 | /// The name of the variable to add to the binding scope with the index 32 | /// for the row. If `sort` is provided, the index will reflect the 33 | /// sorted order (rather than the original array order). 34 | String get indexAs => jsElement['indexAs']; 35 | void set indexAs(String newVal) { 36 | jsElement.callMethod('set', ['indexAs', newVal]); 37 | } 38 | 39 | /// A function that should determine the sort order of the items. This 40 | /// property should either be provided as a string, indicating a method 41 | /// name on the element's host, or else be an actual function. The 42 | /// function should match the sort function passed to `Array.sort`. 43 | /// Using a sort function has no effect on the underlying `items` array. 44 | dynamic get sort => convertToDart(jsElement['sort']); 45 | void set sort(newVal) { 46 | if (newVal is Function) { 47 | var original = newVal; 48 | newVal = (a, b) => original(convertToDart(a), convertToDart(b)); 49 | } 50 | jsElement.callMethod('set', ['sort', newVal]); 51 | } 52 | 53 | /// A function that can be used to filter items out of the view. This 54 | /// property should either be provided as a string, indicating a method 55 | /// name on the element's host, or else be an actual function. The 56 | /// function should match the sort function passed to `Array.filter`. 57 | /// Using a filter function has no effect on the underlying `items` array. 58 | dynamic get filter => convertToDart(jsElement['filter']); 59 | void set filter(newVal) { 60 | if (newVal is Function) { 61 | var original = newVal; 62 | newVal = (element, [index, array]) => 63 | original(convertToDart(element), index, convertToDart(array)); 64 | } 65 | jsElement.callMethod('set', ['filter', newVal]); 66 | } 67 | 68 | /// When using a `filter` or `sort` function, the `observe` property 69 | /// should be set to a space-separated list of the names of item 70 | /// sub-fields that should trigger a re-sort or re-filter when changed. 71 | /// These should generally be fields of `item` that the sort or filter 72 | /// function depends on. 73 | String get observe => jsElement['observe']; 74 | void set observe(String newVal) { 75 | jsElement.callMethod('set', ['observe', newVal]); 76 | } 77 | 78 | /// When using a `filter` or `sort` function, the `delay` property 79 | /// determines a debounce time after a change to observed item 80 | /// properties that must pass before the filter or sort is re-run. 81 | /// This is useful in rate-limiting shuffing of the view when 82 | /// item changes may be frequent. 83 | num get delay => jsElement['delay']; 84 | void set delay(num newVal) { 85 | jsElement.callMethod('set', ['delay', newVal]); 86 | } 87 | 88 | /// Defines an initial count of template instances to render after setting 89 | /// the `items` array, before the next paint, and puts the `dom-repeat` 90 | /// into "chunking mode". The remaining items will be created and rendered 91 | /// incrementally at each animation frame therof until all instances have 92 | /// been rendered. 93 | num get initialCount => jsElement['initialCount']; 94 | void set initialCount(num newVal) { 95 | jsElement.callMethod('set',['initialCount',newVal]); 96 | } 97 | 98 | /// Count of currently rendered items after `filter` (if any) has been applied. 99 | /// If "chunking mode" is enabled, `renderedItemCount` is updated each time a 100 | /// set of template instances is rendered. 101 | num get renderedItemCount => jsElement['renderedItemCount']; 102 | 103 | /// When `initialCount` is used, this property defines a frame rate to 104 | /// target by throttling the number of instances rendered each frame to 105 | /// not exceed the budget for the target frame rate. Setting this to a 106 | /// higher number will allow lower latency and higher throughput for 107 | /// things like event handlers, but will result in a longer time for the 108 | /// remaining items to complete rendering. 109 | num get targetFramerate => jsElement['targetFramerate']; 110 | void set targetFramerate(num newVal) { 111 | jsElement.callMethod('set',['targetFramerate',newVal]); 112 | } 113 | 114 | void render() => jsElement.callMethod('render'); 115 | 116 | /// Returns the template "model" associated with a given element, which 117 | /// serves as the binding scope for the template instance the element is 118 | /// contained in. A template model is an instance of `Polymer.Base`, and 119 | /// should be used to manipulate data associated with this template instance. 120 | /// 121 | /// Example: 122 | /// 123 | /// var model = modelForElement(el); 124 | /// if (model.index < 10) { 125 | /// model.set('item.checked', true); 126 | /// } 127 | DomRepeatModel modelForElement(Element element) { 128 | var proxy = jsElement.callMethod('modelForElement', [element]); 129 | if (proxy is HtmlElement) { 130 | proxy = new JsObject.fromBrowserObject(proxy); 131 | } 132 | return new DomRepeatModel(proxy); 133 | } 134 | 135 | /// Returns the actual `model.item` for an element. 136 | itemForElement(Element element) => 137 | convertToDart(jsElement.callMethod('itemForElement', [element])); 138 | } 139 | 140 | // Dart wrapper for template models that come back from dom-repeat. 141 | class DomRepeatModel extends Object with PolymerBase { 142 | /// The underlying [JsObject] representing the template instance. 143 | final JsObject jsElement; 144 | 145 | /// The `as` property from the dom-repeat element. 146 | final String itemName; 147 | 148 | /// Gets the instance from the original list which is bound to this model. 149 | /// 150 | /// Note: This is deprecated and the `[]` operator should be used instead. 151 | @deprecated 152 | get item => convertToDart(jsElement[itemName]); 153 | 154 | /// The index of the current template model in the original [List]. 155 | int get index => jsElement['index']; 156 | 157 | /// Generic operators for reading and writing values to this template 158 | /// instance. 159 | operator [](String key) => convertToDart(jsElement[key]); 160 | operator []=(String key, value) { 161 | jsElement[key] = convertToJs(value); 162 | } 163 | 164 | DomRepeatModel(JsObject jsElement) 165 | : this.jsElement = jsElement, 166 | this.itemName = _getItemName(jsElement); 167 | factory DomRepeatModel.fromEvent(e) { 168 | if (e is CustomEventWrapper) e = e.original; 169 | var proxy = new JsObject.fromBrowserObject(e)['model']; 170 | if (proxy is HtmlElement) { 171 | proxy = new JsObject.fromBrowserObject(proxy); 172 | } 173 | 174 | return new DomRepeatModel(proxy); 175 | } 176 | } 177 | 178 | String _getItemName(JsObject domRepeatModel) { 179 | var host = domRepeatModel['dataHost'] as TemplateElement; 180 | var itemName = host.attributes['as']; 181 | return itemName != null ? itemName : 'item'; 182 | } 183 | -------------------------------------------------------------------------------- /lib/transformer.dart: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2016, 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 | library polymer.transformer; 5 | 6 | import 'package:barback/barback.dart'; 7 | import 'package:path/path.dart' as path; 8 | import 'package:reflectable/transformer.dart'; 9 | import 'package:web_components/transformer.dart'; 10 | 11 | class PolymerTransformerGroup implements TransformerGroup { 12 | final Iterable phases; 13 | 14 | PolymerTransformerGroup(BarbackSettings settings) 15 | : phases = createDeployPhases(settings); 16 | 17 | PolymerTransformerGroup.asPlugin(BarbackSettings settings) : this(settings); 18 | } 19 | 20 | /// Create deploy phases for Polymer. 21 | List> createDeployPhases(BarbackSettings settings) { 22 | /// Validate the settings 23 | const validOptions = const ['entry_points']; 24 | for (var option in settings.configuration.keys) { 25 | if (validOptions.contains(option)) continue; 26 | throw 'Invalid option ``$option` supplied to polymer transformer. ' 27 | 'The recognized options are ${validOptions.join(' ')}.'; 28 | } 29 | 30 | var options = new TransformOptions( 31 | _readFileList(settings.configuration['entry_points']) 32 | .map(_systemToAssetPath) 33 | .toList(), 34 | settings.mode == BarbackMode.RELEASE); 35 | 36 | return [ 37 | /// Must happen first, temporarily rewrites tags to 38 | /// tags. 39 | [new RewriteXDartTestToScript(options.entryPoints)], 40 | [new ScriptCompactorTransformer(options.entryPoints)], 41 | [new WebComponentsTransformer(options)], 42 | [ 43 | new ImportInlinerTransformer( 44 | options.entryPoints, ['[[', '{{']) 45 | ], 46 | [ 47 | new ReflectableTransformer.asPlugin(new BarbackSettings( 48 | _reflectableConfiguration(settings.configuration), settings.mode)) 49 | ], 50 | 51 | /// Must happen last, rewrites 52 | /// tags back to 53 | /// tags. 54 | [new RewriteScriptToXDartTest(options.entryPoints)], 55 | ]; 56 | } 57 | 58 | /// Convert system paths to asset paths (asset paths are posix style). 59 | String _systemToAssetPath(String assetPath) { 60 | if (path.Style.platform != path.Style.windows) return assetPath; 61 | return path.posix.joinAll(path.split(assetPath)); 62 | } 63 | 64 | List _readFileList(value) { 65 | var files = []; 66 | bool error; 67 | if (value is List) { 68 | files = value; 69 | error = value.any((e) => e is! String); 70 | } else if (value is String) { 71 | files = [value]; 72 | error = false; 73 | } else { 74 | error = true; 75 | } 76 | if (error) { 77 | print('Invalid value for "entry_points" in the polymer transformer.'); 78 | } 79 | return files; 80 | } 81 | 82 | Map _reflectableConfiguration(Map originalConfiguration) { 83 | return { 84 | 'formatted': originalConfiguration['formatted'], 85 | 'supressWarnings': originalConfiguration['supressWarnings'], 86 | 'entry_points': _readFileList(originalConfiguration['entry_points']) 87 | .map((e) => e.replaceFirst('.html', '.bootstrap.initialize.dart')) 88 | .toList(), 89 | }; 90 | } 91 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: polymer 2 | version: 1.0.0-rc.19 3 | author: Polymer.dart Authors 4 | description: > 5 | Polymer.dart is a new type of library for the web, built on top of Web 6 | Components, and designed to leverage the evolving web platform on modern 7 | browsers. 8 | homepage: https://www.dartlang.org/polymer-dart/ 9 | dependencies: 10 | analyzer: '>=0.27.0 <0.30.0' 11 | args: ^0.13.3 12 | barback: '>=0.14.2 <0.16.0' 13 | html: '>=0.12.0 <0.14.0' 14 | initialize: '>=0.5.1+3 <0.7.0' 15 | path: ^1.3.0 16 | polymer_interop: ^1.0.0-rc.10 17 | reflectable: '>=0.5.0 <2.0.0' 18 | web_components: '>=0.11.3 <0.13.0' 19 | dev_dependencies: 20 | browser: ^0.10.0 21 | test: ^0.12.3 22 | transformers: 23 | - polymer: 24 | entry_points: 25 | - test/src/common/behavior_test.html 26 | - test/src/common/behavior_composition_test.html 27 | - test/src/common/js_proxy_test.html 28 | - test/src/common/polymer_descriptor_test.html 29 | - test/src/common/polymer_mixin_test.html 30 | - test/src/common/polymer_register_test.html 31 | - test/src/micro/attributes_test.html 32 | - test/src/micro/lifecycle_callbacks_test.html 33 | - test/src/mini/bottom_up_ready_test.html 34 | - test/src/mini/default_values_test.html 35 | - test/src/mini/dom_distribution_test.html 36 | - test/src/mini/template_stamping_test.html 37 | - test/src/standard/attribute_binding_test.html 38 | - test/src/standard/computed_properties_test.html 39 | - test/src/standard/event_listener_test.html 40 | - test/src/standard/node_finding_test.html 41 | - test/src/standard/property_binding_test.html 42 | - test/src/standard/property_change_callbacks_test.html 43 | - test/src/standard/property_change_notification_test.html 44 | - test/src/standard/read_only_properties_test.html 45 | - test/src/standard/reflect_to_attribute_test.html 46 | - test/src/template/array_selector_test.html 47 | - test/src/template/dom_bind_test.html 48 | - test/src/template/dom_if_test.html 49 | - test/src/template/dom_repeat_test.html 50 | - test/src/template/templatizer_test.html 51 | $include: test/**_test{.*,}.{dart,html} 52 | - test/pub_serve: 53 | $include: test/**_test{.*,}.dart 54 | environment: 55 | sdk: '>=1.9.0 <=2.0.0' 56 | -------------------------------------------------------------------------------- /test/common.dart: -------------------------------------------------------------------------------- 1 | //Copyright (c) 2015, 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 | library polymer_dart.test.common; 5 | 6 | import 'dart:async'; 7 | import 'dart:html'; 8 | 9 | Future wait(int milliseconds) { 10 | return new Future.delayed(new Duration(milliseconds: milliseconds)); 11 | } 12 | 13 | /// Given an `id` of a `