aboutsummaryrefslogtreecommitdiff
path: root/catapult/third_party/polymer/components/iron-fit-behavior
diff options
context:
space:
mode:
Diffstat (limited to 'catapult/third_party/polymer/components/iron-fit-behavior')
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/.bower.json41
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/.github/ISSUE_TEMPLATE.md33
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/.gitignore1
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml24
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md77
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/README.md57
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/bower.json31
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html166
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html41
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/index.html30
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html611
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/test/index.html31
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/test/iron-fit-behavior.html1029
-rw-r--r--catapult/third_party/polymer/components/iron-fit-behavior/test/test-fit.html41
14 files changed, 2213 insertions, 0 deletions
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json b/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json
new file mode 100644
index 00000000..6078a5b7
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/.bower.json
@@ -0,0 +1,41 @@
+{
+ "name": "iron-fit-behavior",
+ "version": "1.2.7",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Fits an element inside another element",
+ "private": true,
+ "main": "iron-fit-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-fit-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": [],
+ "homepage": "https://github.com/PolymerElements/iron-fit-behavior",
+ "_release": "1.2.7",
+ "_resolution": {
+ "type": "version",
+ "tag": "v1.2.7",
+ "commit": "c4b8a39c910da28ca8846fe960c244ce2f64f7be"
+ },
+ "_source": "https://github.com/PolymerElements/iron-fit-behavior.git",
+ "_target": "^1.0.0",
+ "_originalSource": "PolymerElements/iron-fit-behavior"
+} \ No newline at end of file
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/.github/ISSUE_TEMPLATE.md b/catapult/third_party/polymer/components/iron-fit-behavior/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 00000000..0bd8a806
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,33 @@
+<!-- Instructions: https://github.com/PolymerElements/iron-fit-behavior/CONTRIBUTING.md#filing-issues -->
+### Description
+<!-- Example: The `paper-foo` element causes the page to turn pink when clicked. -->
+
+### Expected outcome
+
+<!-- Example: The page stays the same color. -->
+
+### Actual outcome
+
+<!-- Example: The page turns pink. -->
+
+### Live Demo
+<!-- Example: https://jsbin.com/cagaye/edit?html,output -->
+
+### Steps to reproduce
+
+<!-- Example
+1. Put a `paper-foo` element in the page.
+2. Open the page in a web browser.
+3. Click the `paper-foo` element.
+-->
+
+### Browsers Affected
+<!-- Check all that apply -->
+- [ ] Chrome
+- [ ] Firefox
+- [ ] Safari 9
+- [ ] Safari 8
+- [ ] Safari 7
+- [ ] Edge
+- [ ] IE 11
+- [ ] IE 10
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/.gitignore b/catapult/third_party/polymer/components/iron-fit-behavior/.gitignore
new file mode 100644
index 00000000..8d4ae253
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/.gitignore
@@ -0,0 +1 @@
+bower_components
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml b/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml
new file mode 100644
index 00000000..04f7693a
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/.travis.yml
@@ -0,0 +1,24 @@
+language: node_js
+sudo: required
+before_script:
+ - npm install -g bower polylint web-component-tester
+ - bower install
+ - polylint
+env:
+ global:
+ - secure: >-
+ L4lSnuQZDY+YcXYzBZSRKjJJ1rZf18Lc/8YDgQPfkMkAItrRHGR8vblBoKiPAmtvgNxztcpZxAXTiDy1vAeVv54QnX9b1JsuOs7rrQxB4BS04Dj7LdT6DDu1p/V09MJBN11lzLVxgpxljbumwGWE4gfpDl2+rjbBt7cRV5VkVnE=
+ - secure: >-
+ H7dHZ9FQvJszK2UMNZJiZmzOPET3muO/XvlkUc1x3KcUlV5/tD/404V05XfFMowH7DavHFYleZkb89deYjq9PHncO9c4bp4SHD7HKN4FaGyhzfpXjg66v3dZH/OcERjaas337uUE2jo/x1jCq4HJCz2bMVh+bvd4du1C/2OWarc=
+node_js: '6'
+addons:
+ firefox: latest
+ apt:
+ sources:
+ - google-chrome
+ packages:
+ - google-chrome-stable
+script:
+ - xvfb-run wct
+ - 'if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then wct -s ''default''; fi'
+dist: trusty
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md b/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md
new file mode 100644
index 00000000..093090d4
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/CONTRIBUTING.md
@@ -0,0 +1,77 @@
+<!--
+This file is autogenerated based on
+https://github.com/PolymerElements/ContributionGuide/blob/master/CONTRIBUTING.md
+
+If you edit that file, it will get updated everywhere else.
+If you edit this file, your changes will get overridden :)
+
+You can however override the jsbin link with one that's customized to this
+specific element:
+
+jsbin=https://jsbin.com/cagaye/edit?html,output
+-->
+
+# Polymer Elements
+## Guide for Contributors
+
+Polymer Elements are built in the open, and the Polymer authors eagerly encourage any and all forms of community contribution. When contributing, please follow these guidelines:
+
+### Filing Issues
+
+**If you are filing an issue to request a feature**, please provide a clear description of the feature. It can be helpful to describe answers to the following questions:
+
+ 1. **Who will use the feature?** _“As someone filling out a form…”_
+ 2. **When will they use the feature?** _“When I enter an invalid value…”_
+ 3. **What is the user’s goal?** _“I want to be visually notified that the value needs to be corrected…”_
+
+**If you are filing an issue to report a bug**, please provide:
+
+ 1. **A clear description of the bug and related expectations.** Consider using the following example template for reporting a bug:
+
+ ```markdown
+ The `paper-foo` element causes the page to turn pink when clicked.
+
+ ## Expected outcome
+
+ The page stays the same color.
+
+ ## Actual outcome
+
+ The page turns pink.
+
+ ## Steps to reproduce
+
+ 1. Put a `paper-foo` element in the page.
+ 2. Open the page in a web browser.
+ 3. Click the `paper-foo` element.
+ ```
+
+ 2. **A reduced test case that demonstrates the problem.** If possible, please include the test case as a JSBin. Start with this template to easily import and use relevant Polymer Elements: [https://jsbin.com/cagaye/edit?html,output](https://jsbin.com/cagaye/edit?html,output).
+
+ 3. **A list of browsers where the problem occurs.** This can be skipped if the problem is the same across all browsers.
+
+### Submitting Pull Requests
+
+**Before creating a pull request**, please ensure that an issue exists for the corresponding change in the pull request that you intend to make. **If an issue does not exist, please create one per the guidelines above**. The goal is to discuss the design and necessity of the proposed change with Polymer authors and community before diving into a pull request.
+
+When submitting pull requests, please provide:
+
+ 1. **A reference to the corresponding issue** or issues that will be closed by the pull request. Please refer to these issues in the pull request description using the following syntax:
+
+ ```markdown
+ (For a single issue)
+ Fixes #20
+
+ (For multiple issues)
+ Fixes #32, fixes #40
+ ```
+
+ 2. **A succinct description of the design** used to fix any related issues. For example:
+
+ ```markdown
+ This fixes #20 by removing styles that leaked which would cause the page to turn pink whenever `paper-foo` is clicked.
+ ```
+
+ 3. **At least one test for each bug fixed or feature added** as part of the pull request. Pull requests that fix bugs or add features without accompanying tests will not be considered.
+
+If a proposed change contains multiple commits, please [squash commits](https://www.google.com/url?q=http://blog.steveklabnik.com/posts/2012-11-08-how-to-squash-commits-in-a-github-pull-request) to as few as is necessary to succinctly express the change. A Polymer author can help you squash commits, so don’t be afraid to ask us if you need help with that!
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/README.md b/catapult/third_party/polymer/components/iron-fit-behavior/README.md
new file mode 100644
index 00000000..8dbc78e3
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/README.md
@@ -0,0 +1,57 @@
+
+<!---
+
+This README is automatically generated from the comments in these files:
+iron-fit-behavior.html
+
+Edit those files, and our readme bot will duplicate them over here!
+Edit this file, and the bot will squash your changes :)
+
+The bot does some handling of markdown. Please file a bug if it does the wrong
+thing! https://github.com/PolymerLabs/tedium/issues
+
+-->
+
+[![Build status](https://travis-ci.org/PolymerElements/iron-fit-behavior.svg?branch=master)](https://travis-ci.org/PolymerElements/iron-fit-behavior)
+
+_[Demo and API docs](https://elements.polymer-project.org/elements/iron-fit-behavior)_
+
+
+##Polymer.IronFitBehavior
+
+`Polymer.IronFitBehavior` fits an element in another element using `max-height` and `max-width`, and
+optionally centers it in the window or another element.
+
+The element will only be sized and/or positioned if it has not already been sized and/or positioned
+by CSS.
+
+| CSS properties | Action |
+| --- | --- |
+| `position` set | Element is not centered horizontally or vertically |
+| `top` or `bottom` set | Element is not vertically centered |
+| `left` or `right` set | Element is not horizontally centered |
+| `max-height` set | Element respects `max-height` |
+| `max-width` set | Element respects `max-width` |
+
+`Polymer.IronFitBehavior` can position an element into another element using
+`verticalAlign` and `horizontalAlign`. This will override the element's css position.
+
+```html
+ <div class="container">
+ <iron-fit-impl vertical-align="top" horizontal-align="auto">
+ Positioned into the container
+ </iron-fit-impl>
+ </div>
+```
+
+Use `noOverlap` to position the element around another element without overlapping it.
+
+```html
+ <div class="container">
+ <iron-fit-impl no-overlap vertical-align="auto" horizontal-align="auto">
+ Positioned around the container
+ </iron-fit-impl>
+ </div>
+```
+
+
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/bower.json b/catapult/third_party/polymer/components/iron-fit-behavior/bower.json
new file mode 100644
index 00000000..96dd4785
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/bower.json
@@ -0,0 +1,31 @@
+{
+ "name": "iron-fit-behavior",
+ "version": "1.2.7",
+ "license": "http://polymer.github.io/LICENSE.txt",
+ "description": "Fits an element inside another element",
+ "private": true,
+ "main": "iron-fit-behavior.html",
+ "keywords": [
+ "web-components",
+ "polymer",
+ "behavior"
+ ],
+ "authors": [
+ "The Polymer Authors"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "git://github.com/PolymerElements/iron-fit-behavior.git"
+ },
+ "dependencies": {
+ "polymer": "Polymer/polymer#^1.1.0"
+ },
+ "devDependencies": {
+ "iron-component-page": "PolymerElements/iron-component-page#^1.0.0",
+ "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0",
+ "test-fixture": "PolymerElements/test-fixture#^1.0.0",
+ "web-component-tester": "^4.0.0",
+ "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0"
+ },
+ "ignore": []
+}
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html b/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html
new file mode 100644
index 00000000..2c716e06
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/demo/index.html
@@ -0,0 +1,166 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+
+<head>
+
+ <title>iron-fit-behavior demo</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+ <link rel="import" href="simple-fit.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-snippet.html">
+ <link rel="import" href="../../iron-demo-helpers/demo-pages-shared-styles.html">
+
+ <style is="custom-style" include="demo-pages-shared-styles">
+ .centered {
+ min-width: 500px;
+ }
+ demo-snippet {
+ --demo-snippet-code: {
+ max-height: 250px;
+ }
+ }
+ </style>
+
+</head>
+
+<body unresolved class="centered">
+ <h3>
+ An element with <code>IronFitBehavior</code> can be centered in
+ <code>fitInto</code> or positioned around a <code>positionTarget</code>
+ </h3>
+ <demo-snippet>
+ <template>
+ <style>
+ .target {
+ cursor: pointer;
+ text-align: center;
+ display: inline-block;
+ box-sizing: border-box;
+ border: 1px solid;
+ width: 100px;
+ padding: 20px 0;
+ margin: 5px;
+ }
+
+ #myFit {
+ z-index: 10;
+ padding: 20px;
+ overflow: auto;
+ min-width: 100px;
+ min-height: 100px;
+ }
+
+ button {
+ background-color: white;
+ border-radius: 5px;
+ border-width: 1px;
+ }
+
+ button.selected {
+ background-color: #b3e5fc;
+ }
+ </style>
+ <template is="dom-bind">
+ <template is="dom-repeat" items="[[containers]]">
+ <div class="target" on-tap="updatePositionTarget">Target</div>
+ </template>
+ <simple-fit id="myFit" auto-fit-on-attach>
+ <h2>Align</h2>
+ <p>
+ <button on-tap="updateAlign" vertical-align="top">top</button>
+ <button on-tap="updateAlign" vertical-align="bottom">bottom</button>
+ <button on-tap="updateAlign" vertical-align="auto">auto</button>
+ <button on-tap="updateAlign" vertical-align>null</button>
+ </p>
+ <p>
+ <button on-tap="updateAlign" horizontal-align="left">left</button>
+ <button on-tap="updateAlign" horizontal-align="right">right</button>
+ <button on-tap="updateAlign" horizontal-align="auto">auto</button>
+ <button on-tap="updateAlign" horizontal-align>null</button>
+ </p>
+ <button on-tap="toggleNoOverlap">no overlap</button>
+ <button on-tap="toggleDynamicAlign">dynamic align</button>
+ </simple-fit>
+ <script>
+ var defaultTarget = Polymer.dom(myFit).parentNode;
+ var template = document.querySelector('template[is="dom-bind"]');
+
+ template.containers = new Array(30);
+
+ template.updatePositionTarget = function(e) {
+ var target = Polymer.dom(e).rootTarget;
+ target = myFit.positionTarget === target ? defaultTarget : target;
+ myFit.positionTarget.style.backgroundColor = '';
+ target.style.backgroundColor = 'orange';
+ myFit.positionTarget = target;
+ template.refit();
+ };
+
+ template._raf = null;
+ template.refit = function() {
+ template._raf && window.cancelAnimationFrame(template._raf);
+ template._raf = window.requestAnimationFrame(function() {
+ template._raf = null;
+ myFit.refit();
+ });
+ };
+
+ template.updateAlign = function(e) {
+ var target = Polymer.dom(e).rootTarget;
+ if (target.hasAttribute('horizontal-align')) {
+ myFit.horizontalAlign = target.getAttribute('horizontal-align');
+ var children = target.parentNode.querySelectorAll('[horizontal-align]');
+ for (var i = 0; i < children.length; i++) {
+ toggleClass(children[i], 'selected', children[i] === target);
+ }
+ }
+ if (target.hasAttribute('vertical-align')) {
+ myFit.verticalAlign = target.getAttribute('vertical-align');
+ var children = target.parentNode.querySelectorAll('[vertical-align]');
+ for (var i = 0; i < children.length; i++) {
+ toggleClass(children[i], 'selected', children[i] === target);
+ }
+ }
+ template.refit();
+ };
+
+ template.toggleNoOverlap = function(e) {
+ myFit.noOverlap = !myFit.noOverlap;
+ toggleClass(Polymer.dom(e).rootTarget, 'selected', myFit.noOverlap);
+ template.refit();
+ };
+
+ template.toggleDynamicAlign = function(e) {
+ myFit.dynamicAlign = !myFit.dynamicAlign;
+ toggleClass(Polymer.dom(e).rootTarget, 'selected', myFit.dynamicAlign);
+ template.refit();
+ };
+
+ // Listen for resize and scroll on window.
+ window.addEventListener('resize', template.refit);
+ window.addEventListener('scroll', template.refit);
+
+ function toggleClass(element, cssClass, condition) {
+ element.classList[condition ? 'add' : 'remove'](cssClass);
+ }
+ </script>
+ </template>
+ </template>
+ </demo-snippet>
+
+</body>
+
+</html>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html b/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html
new file mode 100644
index 00000000..2dc83fb7
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/demo/simple-fit.html
@@ -0,0 +1,41 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-fit-behavior.html">
+<link rel="import" href="../../paper-styles/color.html">
+
+<dom-module id="simple-fit">
+ <template>
+ <style>
+ :host {
+ background-color: var(--paper-light-blue-500);
+ color: white;
+ text-align: center;
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'simple-fit',
+
+ behaviors: [
+ Polymer.IronFitBehavior
+ ]
+
+ });
+
+</script>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/index.html b/catapult/third_party/polymer/components/iron-fit-behavior/index.html
new file mode 100644
index 00000000..5ffa7d61
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/index.html
@@ -0,0 +1,30 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+<head>
+
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
+
+ <title>iron-fit-behavior</title>
+
+ <script src="../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <link rel="import" href="../polymer/polymer.html">
+ <link rel="import" href="../iron-component-page/iron-component-page.html">
+
+</head>
+<body>
+
+ <iron-component-page></iron-component-page>
+
+</body>
+</html>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html b/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html
new file mode 100644
index 00000000..825b1360
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/iron-fit-behavior.html
@@ -0,0 +1,611 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+
+<link rel="import" href="../polymer/polymer.html">
+
+<script>
+/**
+`Polymer.IronFitBehavior` fits an element in another element using `max-height` and `max-width`, and
+optionally centers it in the window or another element.
+
+The element will only be sized and/or positioned if it has not already been sized and/or positioned
+by CSS.
+
+CSS properties | Action
+-----------------------------|-------------------------------------------
+`position` set | Element is not centered horizontally or vertically
+`top` or `bottom` set | Element is not vertically centered
+`left` or `right` set | Element is not horizontally centered
+`max-height` set | Element respects `max-height`
+`max-width` set | Element respects `max-width`
+
+`Polymer.IronFitBehavior` can position an element into another element using
+`verticalAlign` and `horizontalAlign`. This will override the element's css position.
+
+ <div class="container">
+ <iron-fit-impl vertical-align="top" horizontal-align="auto">
+ Positioned into the container
+ </iron-fit-impl>
+ </div>
+
+Use `noOverlap` to position the element around another element without overlapping it.
+
+ <div class="container">
+ <iron-fit-impl no-overlap vertical-align="auto" horizontal-align="auto">
+ Positioned around the container
+ </iron-fit-impl>
+ </div>
+
+Use `horizontalOffset, verticalOffset` to offset the element from its `positionTarget`;
+`Polymer.IronFitBehavior` will collapse these in order to keep the element
+within `fitInto` boundaries, while preserving the element's CSS margin values.
+
+ <div class="container">
+ <iron-fit-impl vertical-align="top" vertical-offset="20">
+ With vertical offset
+ </iron-fit-impl>
+ </div>
+
+
+@demo demo/index.html
+@polymerBehavior
+*/
+ Polymer.IronFitBehavior = {
+
+ properties: {
+
+ /**
+ * The element that will receive a `max-height`/`width`. By default it is the same as `this`,
+ * but it can be set to a child element. This is useful, for example, for implementing a
+ * scrolling region inside the element.
+ * @type {!Element}
+ */
+ sizingTarget: {
+ type: Object,
+ value: function() {
+ return this;
+ }
+ },
+
+ /**
+ * The element to fit `this` into.
+ */
+ fitInto: {
+ type: Object,
+ value: window
+ },
+
+ /**
+ * Will position the element around the positionTarget without overlapping it.
+ */
+ noOverlap: {
+ type: Boolean
+ },
+
+ /**
+ * The element that should be used to position the element. If not set, it will
+ * default to the parent node.
+ * @type {!Element}
+ */
+ positionTarget: {
+ type: Element
+ },
+
+ /**
+ * The orientation against which to align the element horizontally
+ * relative to the `positionTarget`. Possible values are "left", "right", "auto".
+ */
+ horizontalAlign: {
+ type: String
+ },
+
+ /**
+ * The orientation against which to align the element vertically
+ * relative to the `positionTarget`. Possible values are "top", "bottom", "auto".
+ */
+ verticalAlign: {
+ type: String
+ },
+
+ /**
+ * If true, it will use `horizontalAlign` and `verticalAlign` values as preferred alignment
+ * and if there's not enough space, it will pick the values which minimize the cropping.
+ */
+ dynamicAlign: {
+ type: Boolean
+ },
+
+ /**
+ * A pixel value that will be added to the position calculated for the
+ * given `horizontalAlign`, in the direction of alignment. You can think
+ * of it as increasing or decreasing the distance to the side of the
+ * screen given by `horizontalAlign`.
+ *
+ * If `horizontalAlign` is "left", this offset will increase or decrease
+ * the distance to the left side of the screen: a negative offset will
+ * move the dropdown to the left; a positive one, to the right.
+ *
+ * Conversely if `horizontalAlign` is "right", this offset will increase
+ * or decrease the distance to the right side of the screen: a negative
+ * offset will move the dropdown to the right; a positive one, to the left.
+ */
+ horizontalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * A pixel value that will be added to the position calculated for the
+ * given `verticalAlign`, in the direction of alignment. You can think
+ * of it as increasing or decreasing the distance to the side of the
+ * screen given by `verticalAlign`.
+ *
+ * If `verticalAlign` is "top", this offset will increase or decrease
+ * the distance to the top side of the screen: a negative offset will
+ * move the dropdown upwards; a positive one, downwards.
+ *
+ * Conversely if `verticalAlign` is "bottom", this offset will increase
+ * or decrease the distance to the bottom side of the screen: a negative
+ * offset will move the dropdown downwards; a positive one, upwards.
+ */
+ verticalOffset: {
+ type: Number,
+ value: 0,
+ notify: true
+ },
+
+ /**
+ * Set to true to auto-fit on attach.
+ */
+ autoFitOnAttach: {
+ type: Boolean,
+ value: false
+ },
+
+ /** @type {?Object} */
+ _fitInfo: {
+ type: Object
+ }
+ },
+
+ get _fitWidth() {
+ var fitWidth;
+ if (this.fitInto === window) {
+ fitWidth = this.fitInto.innerWidth;
+ } else {
+ fitWidth = this.fitInto.getBoundingClientRect().width;
+ }
+ return fitWidth;
+ },
+
+ get _fitHeight() {
+ var fitHeight;
+ if (this.fitInto === window) {
+ fitHeight = this.fitInto.innerHeight;
+ } else {
+ fitHeight = this.fitInto.getBoundingClientRect().height;
+ }
+ return fitHeight;
+ },
+
+ get _fitLeft() {
+ var fitLeft;
+ if (this.fitInto === window) {
+ fitLeft = 0;
+ } else {
+ fitLeft = this.fitInto.getBoundingClientRect().left;
+ }
+ return fitLeft;
+ },
+
+ get _fitTop() {
+ var fitTop;
+ if (this.fitInto === window) {
+ fitTop = 0;
+ } else {
+ fitTop = this.fitInto.getBoundingClientRect().top;
+ }
+ return fitTop;
+ },
+
+ /**
+ * The element that should be used to position the element,
+ * if no position target is configured.
+ */
+ get _defaultPositionTarget() {
+ var parent = Polymer.dom(this).parentNode;
+
+ if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
+ parent = parent.host;
+ }
+
+ return parent;
+ },
+
+ /**
+ * The horizontal align value, accounting for the RTL/LTR text direction.
+ */
+ get _localeHorizontalAlign() {
+ if (this._isRTL) {
+ // In RTL, "left" becomes "right".
+ if (this.horizontalAlign === 'right') {
+ return 'left';
+ }
+ if (this.horizontalAlign === 'left') {
+ return 'right';
+ }
+ }
+ return this.horizontalAlign;
+ },
+
+ attached: function() {
+ // Memoize this to avoid expensive calculations & relayouts.
+ // Make sure we do it only once
+ if (typeof this._isRTL === 'undefined') {
+ this._isRTL = window.getComputedStyle(this).direction == 'rtl';
+ }
+
+ this.positionTarget = this.positionTarget || this._defaultPositionTarget;
+ if (this.autoFitOnAttach) {
+ if (window.getComputedStyle(this).display === 'none') {
+ setTimeout(function() {
+ this.fit();
+ }.bind(this));
+ } else {
+ this.fit();
+ }
+ }
+ },
+
+ /**
+ * Positions and fits the element into the `fitInto` element.
+ */
+ fit: function() {
+ this.position();
+ this.constrain();
+ this.center();
+ },
+
+ /**
+ * Memoize information needed to position and size the target element.
+ * @suppress {deprecated}
+ */
+ _discoverInfo: function() {
+ if (this._fitInfo) {
+ return;
+ }
+ var target = window.getComputedStyle(this);
+ var sizer = window.getComputedStyle(this.sizingTarget);
+
+ this._fitInfo = {
+ inlineStyle: {
+ top: this.style.top || '',
+ left: this.style.left || '',
+ position: this.style.position || ''
+ },
+ sizerInlineStyle: {
+ maxWidth: this.sizingTarget.style.maxWidth || '',
+ maxHeight: this.sizingTarget.style.maxHeight || '',
+ boxSizing: this.sizingTarget.style.boxSizing || ''
+ },
+ positionedBy: {
+ vertically: target.top !== 'auto' ? 'top' : (target.bottom !== 'auto' ?
+ 'bottom' : null),
+ horizontally: target.left !== 'auto' ? 'left' : (target.right !== 'auto' ?
+ 'right' : null)
+ },
+ sizedBy: {
+ height: sizer.maxHeight !== 'none',
+ width: sizer.maxWidth !== 'none',
+ minWidth: parseInt(sizer.minWidth, 10) || 0,
+ minHeight: parseInt(sizer.minHeight, 10) || 0
+ },
+ margin: {
+ top: parseInt(target.marginTop, 10) || 0,
+ right: parseInt(target.marginRight, 10) || 0,
+ bottom: parseInt(target.marginBottom, 10) || 0,
+ left: parseInt(target.marginLeft, 10) || 0
+ }
+ };
+ },
+
+ /**
+ * Resets the target element's position and size constraints, and clear
+ * the memoized data.
+ */
+ resetFit: function() {
+ var info = this._fitInfo || {};
+ for (var property in info.sizerInlineStyle) {
+ this.sizingTarget.style[property] = info.sizerInlineStyle[property];
+ }
+ for (var property in info.inlineStyle) {
+ this.style[property] = info.inlineStyle[property];
+ }
+
+ this._fitInfo = null;
+ },
+
+ /**
+ * Equivalent to calling `resetFit()` and `fit()`. Useful to call this after
+ * the element or the `fitInto` element has been resized, or if any of the
+ * positioning properties (e.g. `horizontalAlign, verticalAlign`) is updated.
+ * It preserves the scroll position of the sizingTarget.
+ */
+ refit: function() {
+ var scrollLeft = this.sizingTarget.scrollLeft;
+ var scrollTop = this.sizingTarget.scrollTop;
+ this.resetFit();
+ this.fit();
+ this.sizingTarget.scrollLeft = scrollLeft;
+ this.sizingTarget.scrollTop = scrollTop;
+ },
+
+ /**
+ * Positions the element according to `horizontalAlign, verticalAlign`.
+ */
+ position: function() {
+ if (!this.horizontalAlign && !this.verticalAlign) {
+ // needs to be centered, and it is done after constrain.
+ return;
+ }
+ this._discoverInfo();
+
+ this.style.position = 'fixed';
+ // Need border-box for margin/padding.
+ this.sizingTarget.style.boxSizing = 'border-box';
+ // Set to 0, 0 in order to discover any offset caused by parent stacking contexts.
+ this.style.left = '0px';
+ this.style.top = '0px';
+
+ var rect = this.getBoundingClientRect();
+ var positionRect = this.__getNormalizedRect(this.positionTarget);
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+
+ var margin = this._fitInfo.margin;
+
+ // Consider the margin as part of the size for position calculations.
+ var size = {
+ width: rect.width + margin.left + margin.right,
+ height: rect.height + margin.top + margin.bottom
+ };
+
+ var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
+
+ var left = position.left + margin.left;
+ var top = position.top + margin.top;
+
+ // We first limit right/bottom within fitInto respecting the margin,
+ // then use those values to limit top/left.
+ var right = Math.min(fitRect.right - margin.right, left + rect.width);
+ var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
+
+ // Keep left/top within fitInto respecting the margin.
+ left = Math.max(fitRect.left + margin.left,
+ Math.min(left, right - this._fitInfo.sizedBy.minWidth));
+ top = Math.max(fitRect.top + margin.top,
+ Math.min(top, bottom - this._fitInfo.sizedBy.minHeight));
+
+ // Use right/bottom to set maxWidth/maxHeight, and respect minWidth/minHeight.
+ this.sizingTarget.style.maxWidth = Math.max(right - left, this._fitInfo.sizedBy.minWidth) + 'px';
+ this.sizingTarget.style.maxHeight = Math.max(bottom - top, this._fitInfo.sizedBy.minHeight) + 'px';
+
+ // Remove the offset caused by any stacking context.
+ this.style.left = (left - rect.left) + 'px';
+ this.style.top = (top - rect.top) + 'px';
+ },
+
+ /**
+ * Constrains the size of the element to `fitInto` by setting `max-height`
+ * and/or `max-width`.
+ */
+ constrain: function() {
+ if (this.horizontalAlign || this.verticalAlign) {
+ return;
+ }
+ this._discoverInfo();
+
+ var info = this._fitInfo;
+ // position at (0px, 0px) if not already positioned, so we can measure the natural size.
+ if (!info.positionedBy.vertically) {
+ this.style.position = 'fixed';
+ this.style.top = '0px';
+ }
+ if (!info.positionedBy.horizontally) {
+ this.style.position = 'fixed';
+ this.style.left = '0px';
+ }
+
+ // need border-box for margin/padding
+ this.sizingTarget.style.boxSizing = 'border-box';
+ // constrain the width and height if not already set
+ var rect = this.getBoundingClientRect();
+ if (!info.sizedBy.height) {
+ this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
+ }
+ if (!info.sizedBy.width) {
+ this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
+ }
+ },
+
+ /**
+ * @protected
+ * @deprecated
+ */
+ _sizeDimension: function(rect, positionedBy, start, end, extent) {
+ this.__sizeDimension(rect, positionedBy, start, end, extent);
+ },
+
+ /**
+ * @private
+ */
+ __sizeDimension: function(rect, positionedBy, start, end, extent) {
+ var info = this._fitInfo;
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+ var max = extent === 'Width' ? fitRect.width : fitRect.height;
+ var flip = (positionedBy === end);
+ var offset = flip ? max - rect[end] : rect[start];
+ var margin = info.margin[flip ? start : end];
+ var offsetExtent = 'offset' + extent;
+ var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
+ this.sizingTarget.style['max' + extent] = (max - margin - offset - sizingOffset) + 'px';
+ },
+
+ /**
+ * Centers horizontally and vertically if not already positioned. This also sets
+ * `position:fixed`.
+ */
+ center: function() {
+ if (this.horizontalAlign || this.verticalAlign) {
+ return;
+ }
+ this._discoverInfo();
+
+ var positionedBy = this._fitInfo.positionedBy;
+ if (positionedBy.vertically && positionedBy.horizontally) {
+ // Already positioned.
+ return;
+ }
+ // Need position:fixed to center
+ this.style.position = 'fixed';
+ // Take into account the offset caused by parents that create stacking
+ // contexts (e.g. with transform: translate3d). Translate to 0,0 and
+ // measure the bounding rect.
+ if (!positionedBy.vertically) {
+ this.style.top = '0px';
+ }
+ if (!positionedBy.horizontally) {
+ this.style.left = '0px';
+ }
+ // It will take in consideration margins and transforms
+ var rect = this.getBoundingClientRect();
+ var fitRect = this.__getNormalizedRect(this.fitInto);
+ if (!positionedBy.vertically) {
+ var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
+ this.style.top = top + 'px';
+ }
+ if (!positionedBy.horizontally) {
+ var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
+ this.style.left = left + 'px';
+ }
+ },
+
+ __getNormalizedRect: function(target) {
+ if (target === document.documentElement || target === window) {
+ return {
+ top: 0,
+ left: 0,
+ width: window.innerWidth,
+ height: window.innerHeight,
+ right: window.innerWidth,
+ bottom: window.innerHeight
+ };
+ }
+ return target.getBoundingClientRect();
+ },
+
+ __getCroppedArea: function(position, size, fitRect) {
+ var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
+ var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
+ return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
+ },
+
+
+ __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
+ // All the possible configurations.
+ // Ordered as top-left, top-right, bottom-left, bottom-right.
+ var positions = [{
+ verticalAlign: 'top',
+ horizontalAlign: 'left',
+ top: positionRect.top + this.verticalOffset,
+ left: positionRect.left + this.horizontalOffset
+ }, {
+ verticalAlign: 'top',
+ horizontalAlign: 'right',
+ top: positionRect.top + this.verticalOffset,
+ left: positionRect.right - size.width - this.horizontalOffset
+ }, {
+ verticalAlign: 'bottom',
+ horizontalAlign: 'left',
+ top: positionRect.bottom - size.height - this.verticalOffset,
+ left: positionRect.left + this.horizontalOffset
+ }, {
+ verticalAlign: 'bottom',
+ horizontalAlign: 'right',
+ top: positionRect.bottom - size.height - this.verticalOffset,
+ left: positionRect.right - size.width - this.horizontalOffset
+ }];
+
+ if (this.noOverlap) {
+ // Duplicate.
+ for (var i = 0, l = positions.length; i < l; i++) {
+ var copy = {};
+ for (var key in positions[i]) {
+ copy[key] = positions[i][key];
+ }
+ positions.push(copy);
+ }
+ // Horizontal overlap only.
+ positions[0].top = positions[1].top += positionRect.height;
+ positions[2].top = positions[3].top -= positionRect.height;
+ // Vertical overlap only.
+ positions[4].left = positions[6].left += positionRect.width;
+ positions[5].left = positions[7].left -= positionRect.width;
+ }
+
+ // Consider auto as null for coding convenience.
+ vAlign = vAlign === 'auto' ? null : vAlign;
+ hAlign = hAlign === 'auto' ? null : hAlign;
+
+ var position;
+ for (var i = 0; i < positions.length; i++) {
+ var pos = positions[i];
+
+ // If both vAlign and hAlign are defined, return exact match.
+ // For dynamicAlign and noOverlap we'll have more than one candidate, so
+ // we'll have to check the croppedArea to make the best choice.
+ if (!this.dynamicAlign && !this.noOverlap &&
+ pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
+ position = pos;
+ break;
+ }
+
+ // Align is ok if alignment preferences are respected. If no preferences,
+ // it is considered ok.
+ var alignOk = (!vAlign || pos.verticalAlign === vAlign) &&
+ (!hAlign || pos.horizontalAlign === hAlign);
+
+ // Filter out elements that don't match the alignment (if defined).
+ // With dynamicAlign, we need to consider all the positions to find the
+ // one that minimizes the cropped area.
+ if (!this.dynamicAlign && !alignOk) {
+ continue;
+ }
+
+ position = position || pos;
+ pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
+ var diff = pos.croppedArea - position.croppedArea;
+ // Check which crops less. If it crops equally, check if align is ok.
+ if (diff < 0 || (diff === 0 && alignOk)) {
+ position = pos;
+ }
+ // If not cropped and respects the align requirements, keep it.
+ // This allows to prefer positions overlapping horizontally over the
+ // ones overlapping vertically.
+ if (position.croppedArea === 0 && alignOk) {
+ break;
+ }
+ }
+
+ return position;
+ }
+
+ };
+</script>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/test/index.html b/catapult/third_party/polymer/components/iron-fit-behavior/test/index.html
new file mode 100644
index 00000000..fd047ea3
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/test/index.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html><!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+--><html><head>
+
+ <title>iron-fit-behavior tests</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../web-component-tester/browser.js"></script>
+
+ </head>
+ <body>
+
+ <script>
+ WCT.loadSuites([
+ 'iron-fit-behavior.html',
+ 'iron-fit-behavior.html?dom=shadow'
+ ]);
+ </script>
+
+
+
+</body></html>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/test/iron-fit-behavior.html b/catapult/third_party/polymer/components/iron-fit-behavior/test/iron-fit-behavior.html
new file mode 100644
index 00000000..7dcc15db
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/test/iron-fit-behavior.html
@@ -0,0 +1,1029 @@
+<!doctype html>
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<html>
+ <head>
+
+ <title>iron-fit-behavior tests</title>
+
+ <meta charset="utf-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+ <meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1, user-scalable=yes">
+
+ <script src="../../webcomponentsjs/webcomponents-lite.js"></script>
+
+ <script src="../../web-component-tester/browser.js"></script>
+ <link rel="import" href="test-fit.html">
+
+ <style>
+ body {
+ margin: 0;
+ padding: 0;
+ }
+
+ .absolute {
+ position: absolute;
+ top: 0;
+ left: 0;
+ }
+
+ .scrolling {
+ overflow: auto;
+ }
+
+ .sized-x {
+ width: 100px;
+ }
+
+ .sized-y {
+ height: 100px;
+ }
+
+ .positioned-left {
+ position: absolute;
+ left: 100px;
+ }
+
+ .positioned-right {
+ position: absolute;
+ right: 100px;
+ }
+
+ .positioned-top {
+ position: absolute;
+ top: 100px;
+ }
+
+ .positioned-bottom {
+ position: absolute;
+ bottom: 100px;
+ }
+
+ .with-max-width {
+ max-width: 500px;
+ }
+
+ .with-max-height {
+ max-height: 500px;
+ }
+
+ .with-margin {
+ margin: 20px;
+ }
+
+ .constrain {
+ position: fixed;
+ top: 20px;
+ left: 20px;
+ width: 150px;
+ height: 150px;
+ border: 1px solid black;
+ box-sizing: border-box;
+ }
+
+ .sizer {
+ width: 9999px;
+ height: 9999px;
+ }
+
+ </style>
+
+ </head>
+ <body>
+
+ <div class="constrain"></div>
+
+ <test-fixture id="basic">
+ <template>
+ <test-fit>
+ Basic
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="absolute">
+ <template>
+ <test-fit auto-fit-on-attach class="absolute">
+ Absolutely positioned
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="sized-xy">
+ <template>
+ <test-fit auto-fit-on-attach class="sized-x sized-y">
+ Sized (x/y), auto center/center
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="sized-x">
+ <template>
+ <test-fit auto-fit-on-attach class="sized-x">
+ Sized (x), auto center/center
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="positioned-xy">
+ <template>
+ <test-fit auto-fit-on-attach class="sized-x positioned-left positioned-top">
+ Sized (x/y), positioned/positioned
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="inline-positioned-xy">
+ <template>
+ <test-fit auto-fit-on-attach class="sized-x sized-y" style="position:absolute;left:100px;top:100px;">
+ Sized (x/y), positioned/positioned
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="sectioned">
+ <template>
+ <test-fit auto-fit-on-attach class="sized-x">
+ <div>
+ Sized (x), auto center/center with scrolling section
+ </div>
+ <div class="internal"></div>
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="constrain-target">
+ <template>
+ <div class="constrain">
+ <test-fit auto-fit-on-attach class="el sized-x sized-y">
+ <div>
+ Auto center/center to parent element
+ </div>
+ </test-fit>
+ </div>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="offscreen-container">
+ <template>
+ <div style="position: fixed; top: -1px; left: 0;">
+ <test-fit auto-fit-on-attach class="el sized-x">
+ <div>
+ Sized (x), auto center/center, container is offscreen
+ </div>
+ </test-fit>
+ </div>
+ </template>
+ </test-fixture>
+
+ <test-fixture id="scrollable">
+ <template>
+ <test-fit auto-fit-on-attach class="scrolling">
+ scrollable
+ <div class="sizer"></div>
+ </test-fit>
+ </template>
+ </test-fixture>
+
+ <template id="ipsum">
+ <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
+ </template>
+
+ <script>
+
+ function makeScrolling(el) {
+ el.classList.add('scrolling');
+ var template = document.getElementById('ipsum');
+ for (var i = 0; i < 20; i++) {
+ el.appendChild(template.content.cloneNode(true));
+ }
+ }
+
+ function intersects(r1, r2) {
+ return !(r2.left >= r1.right || r2.right <= r1.left || r2.top >= r1.bottom || r2.bottom <= r1.top);
+ }
+
+ suite('basic', function() {
+
+ var el;
+ setup(function() {
+ el = fixture('basic');
+ });
+
+ test('position() works without autoFitOnAttach', function() {
+ el.verticalAlign = 'top';
+ el.horizontalAlign = 'left';
+ el.position();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top ok');
+ assert.equal(rect.left, 0, 'left ok');
+ });
+
+ test('constrain() works without autoFitOnAttach', function() {
+ el.constrain();
+ var style = getComputedStyle(el);
+ assert.equal(style.maxWidth, window.innerWidth + 'px', 'maxWidth ok');
+ assert.equal(style.maxHeight, window.innerHeight + 'px', 'maxHeight ok');
+ });
+
+ test('center() works without autoFitOnAttach', function() {
+ el.center();
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ });
+
+ suite('manual positioning', function() {
+
+ test('css positioned element is not re-positioned', function() {
+ var el = fixture('positioned-xy');
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 100, 'top is unset');
+ assert.equal(rect.left, 100, 'left is unset');
+
+ });
+
+ test('inline positioned element is not re-positioned', function() {
+ var el = fixture('inline-positioned-xy');
+ var rect = el.getBoundingClientRect();
+ // need to measure document.body here because mocha sets a min-width on html,body, and
+ // the element is positioned wrt to that by css
+ var bodyRect = document.body.getBoundingClientRect();
+ assert.equal(rect.top, 100, 'top is unset');
+ assert.equal(rect.left, 100, 'left is unset');
+
+ el.refit();
+
+ rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 100, 'top is unset after refit');
+ assert.equal(rect.left, 100, 'left is unset after refit');
+
+ });
+
+ test('position property is preserved after', function() {
+ var el = fixture('absolute');
+ assert.equal(getComputedStyle(el).position, 'absolute', 'position:absolute is preserved');
+ });
+ });
+
+ suite('fit to window', function() {
+
+ test('sized element is centered in viewport', function() {
+ var el = fixture('sized-xy');
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ test('sized element with margin is centered in viewport', function() {
+ var el = fixture('sized-xy');
+ el.classList.add('with-margin');
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ test('sized element with transformed parent is centered in viewport', function() {
+ var constrain = fixture('constrain-target');
+ var el = Polymer.dom(constrain).querySelector('.el');
+ var rectBefore = el.getBoundingClientRect();
+ constrain.style.transform = 'translate3d(5px, 5px, 0)';
+ el.center();
+ var rectAfter = el.getBoundingClientRect();
+ assert.equal(rectBefore.top, rectAfter.top, 'top ok');
+ assert.equal(rectBefore.bottom, rectAfter.bottom, 'bottom ok');
+ assert.equal(rectBefore.left, rectAfter.left, 'left ok');
+ assert.equal(rectBefore.right, rectAfter.right, 'right ok');
+ });
+
+ test('scrolling element is centered in viewport', function() {
+ var el = fixture('sized-x');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ test('scrolling element is constrained to viewport height', function() {
+ var el = fixture('sized-x');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight, 'height is less than or equal to viewport height');
+ });
+
+ test('scrolling element with offscreen container is constrained to viewport height', function() {
+ var container = fixture('offscreen-container');
+ var el = Polymer.dom(container).querySelector('.el')
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight, 'height is less than or equal to viewport height');
+ });
+
+ test('scrolling element with max-height is centered in viewport', function() {
+ var el = fixture('sized-x');
+ el.classList.add('with-max-height');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ test('scrolling element with max-height respects max-height', function() {
+ var el = fixture('sized-x');
+ el.classList.add('with-max-height');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= 500, 'height is less than or equal to max-height');
+ });
+
+ test('css positioned, scrolling element is constrained to viewport height (top,left)', function() {
+ var el = fixture('positioned-xy');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight - 100, 'height is less than or equal to viewport height');
+ });
+
+ test('css positioned, scrolling element is constrained to viewport height (bottom, right)', function() {
+ var el = fixture('sized-x');
+ el.classList.add('positioned-bottom');
+ el.classList.add('positioned-right');
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight - 100, 'height is less than or equal to viewport height');
+ });
+
+ test('sized, scrolling element with margin is centered in viewport', function() {
+ var el = fixture('sized-x');
+ el.classList.add('with-margin');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.closeTo(rect.left - (window.innerWidth - rect.right), 0, 5, 'centered horizontally');
+ assert.closeTo(rect.top - (window.innerHeight - rect.bottom), 0, 5, 'centered vertically');
+ });
+
+ test('sized, scrolling element is constrained to viewport height', function() {
+ var el = fixture('sized-x');
+ el.classList.add('with-margin');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight - 20 * 2, 'height is less than or equal to viewport height');
+ });
+
+ test('css positioned, scrolling element with margin is constrained to viewport height (top, left)', function() {
+ var el = fixture('positioned-xy');
+ el.classList.add('with-margin');
+ makeScrolling(el);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight - 100 - 20 * 2, 'height is less than or equal to viewport height');
+ });
+
+ test('css positioned, scrolling element with margin is constrained to viewport height (bottom, right)', function() {
+ var el = fixture('sized-x');
+ el.classList.add('positioned-bottom');
+ el.classList.add('positioned-right');
+ el.classList.add('with-margin')
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight - 100 - 20 * 2, 'height is less than or equal to viewport height');
+ });
+
+ test('scrolling sizingTarget is constrained to viewport height', function() {
+ el = fixture('sectioned');
+ var internal = Polymer.dom(el).querySelector('.internal');
+ el.sizingTarget = internal;
+ makeScrolling(internal);
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isTrue(rect.height <= window.innerHeight, 'height is less than or equal to viewport height');
+ });
+
+ test('scrolling sizingTarget preserves scrolling position', function() {
+ el = fixture('scrollable');
+ el.scrollTop = 20;
+ el.scrollLeft = 20;
+ el.refit();
+ assert.equal(el.scrollTop, 20, 'scrollTop ok');
+ assert.equal(el.scrollLeft, 20, 'scrollLeft ok');
+ });
+
+ });
+
+ suite('fit to element', function() {
+
+ test('element fits in another element', function() {
+ var constrain = fixture('constrain-target');
+ var el = Polymer.dom(constrain).querySelector('.el')
+ makeScrolling(el);
+ el.fitInto = constrain;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ var crect = constrain.getBoundingClientRect();
+ assert.isTrue(rect.height <= crect.height, 'width is less than or equal to fitInto width');
+ assert.isTrue(rect.height <= crect.height, 'height is less than or equal to fitInto height');
+ });
+
+ test('element centers in another element', function() {
+ var constrain = fixture('constrain-target');
+ var el = Polymer.dom(constrain).querySelector('.el');
+ makeScrolling(el);
+ el.fitInto = constrain;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ var crect = constrain.getBoundingClientRect();
+ assert.closeTo(rect.left - crect.left - (crect.right - rect.right), 0, 5, 'centered horizontally in fitInto');
+ assert.closeTo(rect.top - crect.top - (crect.bottom - rect.bottom), 0, 5, 'centered vertically in fitInto');
+ });
+
+ test('element with max-width centers in another element', function() {
+ var constrain = document.querySelector('.constrain');
+ var el = fixture('sized-xy');
+ el.classList.add('with-max-width');
+ el.fitInto = constrain;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ var crect = constrain.getBoundingClientRect();
+ assert.closeTo(rect.left - crect.left - (crect.right - rect.right), 0, 5, 'centered horizontally in fitInto');
+ assert.closeTo(rect.top - crect.top - (crect.bottom - rect.bottom), 0, 5, 'centered vertically in fitInto');
+ });
+
+ test('positioned element fits in another element', function() {
+ var constrain = document.querySelector('.constrain');
+ // element's positionTarget is `body`, and fitInto is `constrain`.
+ var el = fixture('sized-xy');
+ el.verticalAlign = 'top';
+ el.horizontalAlign = 'left';
+ el.fitInto = constrain;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ var crect = constrain.getBoundingClientRect();
+ assert.equal(rect.top, crect.top, 'top ok');
+ assert.equal(rect.left, crect.left, 'left ok');
+ });
+
+ });
+
+ suite('horizontal/vertical align', function() {
+ var parent, parentRect;
+ var el, elRect;
+ var fitRect = {
+ left: 0,
+ top: 0,
+ right: window.innerWidth,
+ bottom: window.innerHeight,
+ width: window.innerWidth,
+ height: window.innerHeight
+ };
+
+ setup(function() {
+ parent = fixture('constrain-target');
+ parentRect = parent.getBoundingClientRect();
+ el = Polymer.dom(parent).querySelector('.el');
+ elRect = el.getBoundingClientRect();
+ });
+
+ test('intersects works', function() {
+ var base = {top: 0, bottom: 1, left:0, right: 1};
+ assert.isTrue(intersects(base, base), 'intersects itself');
+ assert.isFalse(intersects(base, {top:1, bottom: 2, left: 0, right: 1}), 'no intersect on edge');
+ assert.isFalse(intersects(base, {top:-2, bottom: -1, left: 0, right: 1}), 'no intersect on edge (negative values)');
+ assert.isFalse(intersects(base, {top:2, bottom: 3, left: 0, right: 1}), 'no intersect');
+ });
+
+ suite('when verticalAlign is top', function() {
+ test('element is aligned to the positionTarget top', function() {
+ el.verticalAlign = 'top';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top, 'top ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget top without overlapping it', function() {
+ // Allow enough space on the parent's bottom & right.
+ parent.style.width = '10px';
+ parent.style.height = '10px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'top';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element margin is considered as offset', function() {
+ el.verticalAlign = 'top';
+ el.style.marginTop = '10px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top + 10, 'top ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+
+ el.style.marginTop = '-10px';
+ el.refit();
+ rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top - 10, 'top ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('verticalOffset is applied', function() {
+ el.verticalAlign = 'top';
+ el.verticalOffset = 10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top + 10, 'top ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element is kept in viewport', function() {
+ el.verticalAlign = 'top';
+ // Make it go out of screen
+ el.verticalOffset = -1000;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top in viewport');
+ assert.isTrue(rect.height < elRect.height, 'reduced size');
+ });
+
+ test('negative verticalOffset does not crop element', function() {
+ // Push to the bottom of the screen.
+ parent.style.top = (window.innerHeight - 50) +'px';
+ el.verticalAlign = 'top';
+ el.verticalOffset = -10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, window.innerHeight - 60, 'top ok');
+ assert.equal(rect.bottom, window.innerHeight, 'bottom ok');
+ });
+
+ test('max-height is updated', function() {
+ parent.style.top = '-10px';
+ el.verticalAlign = 'top';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top ok');
+ assert.isBelow(rect.height, elRect.height, 'height ok');
+ });
+
+ test('min-height is preserved: element is displayed even if partially', function() {
+ parent.style.top = '-10px';
+ el.verticalAlign = 'top';
+ el.style.minHeight = elRect.height + 'px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top ok');
+ assert.equal(rect.height, elRect.height, 'min-height ok');
+ assert.isTrue(intersects(rect, fitRect), 'partially visible');
+ });
+
+ test('dynamicAlign will prefer bottom align if it minimizes the cropping', function() {
+ parent.style.top = '-10px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'top';
+ el.dynamicAlign = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom, 'bottom ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+ });
+
+ suite('when verticalAlign is bottom', function() {
+ test('element is aligned to the positionTarget bottom', function() {
+ el.verticalAlign = 'bottom';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom, 'bottom ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget bottom without overlapping it', function() {
+ el.verticalAlign = 'bottom';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element margin is considered as offset', function() {
+ el.verticalAlign = 'bottom';
+ el.style.marginBottom = '10px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom - 10, 'bottom ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+
+ el.style.marginBottom = '-10px';
+ el.refit();
+ rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom + 10, 'bottom ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('verticalOffset is applied', function() {
+ el.verticalAlign = 'bottom';
+ el.verticalOffset = 10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom - 10, 'bottom ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element is kept in viewport', function() {
+ el.verticalAlign = 'bottom';
+ // Make it go out of screen
+ el.verticalOffset = 1000;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top in viewport');
+ assert.isTrue(rect.height < elRect.height, 'reduced size');
+ });
+
+ test('element max-height is updated', function() {
+ parent.style.top = (100 - parentRect.height) + 'px';
+ el.verticalAlign = 'bottom';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, 100, 'bottom ok');
+ assert.equal(rect.height, 100, 'height ok');
+ });
+
+ test('min-height is preserved: element is displayed even if partially', function() {
+ parent.style.top = (elRect.height - 10 - parentRect.height) + 'px';
+ el.verticalAlign = 'bottom';
+ el.style.minHeight = elRect.height + 'px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, 0, 'top ok');
+ assert.equal(rect.height, elRect.height, 'min-height ok');
+ assert.isTrue(intersects(rect, fitRect), 'partially visible');
+ });
+
+ test('dynamicAlign will prefer top align if it minimizes the cropping', function() {
+ parent.style.top = (window.innerHeight - elRect.height) + 'px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'bottom';
+ el.dynamicAlign = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top, 'top ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+ });
+
+ suite('when verticalAlign is auto', function() {
+ test('element is aligned to the positionTarget top', function() {
+ el.verticalAlign = 'auto';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.top, parentRect.top, 'auto aligned to top');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget top without overlapping it', function() {
+ // Allow enough space on the parent's bottom & right.
+ parent.style.width = '10px';
+ parent.style.height = '10px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'auto';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ });
+
+ test('bottom is preferred to top if it diminishes the cropped area', function() {
+ // This would cause a cropping of the element, so it should automatically
+ // align to the bottom to avoid it.
+ parent.style.top = '-10px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'auto';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.bottom, parentRect.bottom, 'auto aligned to bottom');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ test('bottom is preferred to top if it diminishes the cropped area, without overlapping positionTarget', function() {
+ // This would cause a cropping of the element, so it should automatically
+ // align to the bottom to avoid it.
+ parent.style.top = '-10px';
+ parentRect = parent.getBoundingClientRect();
+ el.verticalAlign = 'auto';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ });
+ });
+
+ suite('when horizontalAlign is left', function() {
+ test('element is aligned to the positionTarget left', function() {
+ el.horizontalAlign = 'left';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left, 'left ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget left without overlapping it', function() {
+ // Make space at the parent's right.
+ parent.style.width = '10px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'left';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element margin is considered as offset', function() {
+ el.horizontalAlign = 'left';
+ el.style.marginLeft = '10px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left + 10, 'left ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+
+ el.style.marginLeft = '-10px';
+ el.refit();
+ rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left - 10, 'left ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('horizontalOffset is applied', function() {
+ el.horizontalAlign = 'left';
+ el.horizontalOffset = 10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left + 10, 'left ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element is kept in viewport', function() {
+ el.horizontalAlign = 'left';
+ // Make it go out of screen.
+ el.horizontalOffset = -1000;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, 0, 'left in viewport');
+ assert.isTrue(rect.width < elRect.width, 'reduced size');
+ });
+
+ test('negative horizontalOffset does not crop element', function() {
+ // Push to the bottom of the screen.
+ parent.style.left = (window.innerWidth - 50) +'px';
+ el.horizontalAlign = 'left';
+ el.horizontalOffset = -10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, window.innerWidth - 60, 'left ok');
+ assert.equal(rect.right, window.innerWidth, 'right ok');
+ });
+
+ test('element max-width is updated', function() {
+ parent.style.left = '-10px';
+ el.horizontalAlign = 'left';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, 0, 'left ok');
+ assert.isBelow(rect.width, elRect.width, 'width ok');
+ });
+
+ test('min-width is preserved: element is displayed even if partially', function() {
+ parent.style.left = '-10px';
+ el.style.minWidth = elRect.width + 'px';
+ el.horizontalAlign = 'left';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, 0, 'left ok');
+ assert.equal(rect.width, elRect.width, 'min-width ok');
+ assert.isTrue(intersects(rect, fitRect), 'partially visible');
+ });
+
+ test('dynamicAlign will prefer right align if it minimizes the cropping', function() {
+ parent.style.left = '-10px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'left';
+ el.dynamicAlign = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right, 'right ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ });
+
+ suite('when horizontalAlign is right', function() {
+ test('element is aligned to the positionTarget right', function() {
+ el.horizontalAlign = 'right';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right, 'right ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget right without overlapping it', function() {
+ // Make space at the parent's left.
+ parent.style.left = elRect.width + 'px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'right';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element margin is considered as offset', function() {
+ el.horizontalAlign = 'right';
+ el.style.marginRight = '10px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right - 10, 'right ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+
+ el.style.marginRight = '-10px';
+ el.refit();
+ rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right + 10, 'right ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('horizontalOffset is applied', function() {
+ el.horizontalAlign = 'right';
+ el.horizontalOffset = 10;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right - 10, 'right ok');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element is kept in viewport', function() {
+ el.horizontalAlign = 'right';
+ // Make it go out of screen.
+ el.horizontalOffset = 1000;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, 0, 'left in viewport');
+ assert.isTrue(rect.width < elRect.width, 'reduced width');
+ });
+
+ test('element max-width is updated', function() {
+ parent.style.left = (100 - parentRect.width) + 'px';
+ el.horizontalAlign = 'right';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, 100, 'right ok');
+ assert.equal(rect.width, 100, 'width ok');
+ });
+
+ test('min-width is preserved: element is displayed even if partially', function() {
+ parent.style.left = (elRect.width - 10 - parentRect.width) + 'px';
+ el.horizontalAlign = 'right';
+ el.style.minWidth = elRect.width + 'px';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, 0, 'left ok');
+ assert.equal(rect.width, elRect.width, 'min-width ok');
+ assert.isTrue(intersects(rect, fitRect), 'partially visible');
+ });
+
+ test('dynamicAlign will prefer left align if it minimizes the cropping', function() {
+ parent.style.left = (window.innerWidth - elRect.width) + 'px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'right';
+ el.dynamicAlign = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left, 'left ok');
+ assert.equal(rect.height, elRect.height, 'no cropping');
+ });
+
+ });
+
+ suite('when horizontalAlign is auto', function() {
+ test('element is aligned to the positionTarget left', function() {
+ el.horizontalAlign = 'auto';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left, 'auto aligned to left');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('element is aligned to the positionTarget left without overlapping positionTarget', function() {
+ // Make space at the parent's left.
+ parent.style.left = elRect.width + 'px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'auto';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ });
+
+ test('right is preferred to left if it diminishes the cropped area', function() {
+ // This would cause a cropping of the element, so it should automatically
+ // align to the right to avoid it.
+ parent.style.left = '-10px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'auto';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right, 'auto aligned to right');
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ });
+
+ test('right is preferred to left if it diminishes the cropped area, without overlapping positionTarget', function() {
+ // Make space at the parent's right.
+ parent.style.width = '10px';
+ parentRect = parent.getBoundingClientRect();
+ el.horizontalAlign = 'auto';
+ el.noOverlap = true;
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.width, elRect.width, 'no cropping');
+ assert.isFalse(intersects(rect, parentRect), 'no overlap');
+ });
+ });
+
+ suite('prefer horizontal overlap to vertical overlap', function() {
+ setup(function() {
+ el.noOverlap = true;
+ el.dynamicAlign = true;
+ // Make space around the positionTarget.
+ parent.style.top = elRect.height + 'px';
+ parent.style.left = elRect.width + 'px';
+ parent.style.width = '10px';
+ parent.style.height = '10px';
+ parentRect = parent.getBoundingClientRect();
+ });
+
+ test('top-left aligns to target bottom-left', function() {
+ el.verticalAlign = 'top';
+ el.horizontalAlign = 'left';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left, 'left ok');
+ assert.equal(rect.top, parentRect.bottom, 'top ok');
+ });
+
+ test('top-right aligns to target bottom-right', function() {
+ el.verticalAlign = 'top';
+ el.horizontalAlign = 'right';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right, 'right ok');
+ assert.equal(rect.top, parentRect.bottom, 'top ok');
+ });
+
+ test('bottom-left aligns to target top-left', function() {
+ el.verticalAlign = 'bottom';
+ el.horizontalAlign = 'left';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.left, parentRect.left, 'left ok');
+ assert.equal(rect.bottom, parentRect.top, 'bottom ok');
+ });
+
+ test('bottom-right aligns to target top-right', function() {
+ el.verticalAlign = 'bottom';
+ el.horizontalAlign = 'right';
+ el.refit();
+ var rect = el.getBoundingClientRect();
+ assert.equal(rect.right, parentRect.right, 'right ok');
+ assert.equal(rect.bottom, parentRect.top, 'bottom ok');
+ });
+
+ });
+
+ });
+ </script>
+
+ </body>
+</html>
diff --git a/catapult/third_party/polymer/components/iron-fit-behavior/test/test-fit.html b/catapult/third_party/polymer/components/iron-fit-behavior/test/test-fit.html
new file mode 100644
index 00000000..80626087
--- /dev/null
+++ b/catapult/third_party/polymer/components/iron-fit-behavior/test/test-fit.html
@@ -0,0 +1,41 @@
+<!--
+@license
+Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<link rel="import" href="../../polymer/polymer.html">
+<link rel="import" href="../iron-fit-behavior.html">
+
+<dom-module id="test-fit">
+ <template>
+ <style>
+ :host {
+ display: block;
+ background: black;
+ color: white;
+ padding: 8px;
+ }
+ </style>
+
+ <content></content>
+ </template>
+
+</dom-module>
+
+<script>
+
+ Polymer({
+
+ is: 'test-fit',
+
+ behaviors: [
+ Polymer.IronFitBehavior
+ ]
+
+ });
+
+</script>