Neues Initialrelease mit IonicMaterial
25
www/lib/angular-material/.bower.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "angular-material",
|
||||
"version": "0.10.0",
|
||||
"ignore": [],
|
||||
"dependencies": {
|
||||
"angular": "^1.3.0 || >1.4.0-beta.0",
|
||||
"angular-animate": "^1.3.0 || >1.4.0-beta.0",
|
||||
"angular-aria": "^1.3.15 || >1.4.0-beta.0"
|
||||
},
|
||||
"main": [
|
||||
"angular-material.js",
|
||||
"angular-material.css"
|
||||
],
|
||||
"homepage": "https://github.com/angular/bower-material",
|
||||
"_release": "0.10.0",
|
||||
"_resolution": {
|
||||
"type": "version",
|
||||
"tag": "v0.10.0",
|
||||
"commit": "1e48d39c2be9aa2bf6ebb212f978947d7e52e608"
|
||||
},
|
||||
"_source": "git://github.com/angular/bower-material.git",
|
||||
"_target": "~0.10.0",
|
||||
"_originalSource": "angular-material",
|
||||
"_direct": true
|
||||
}
|
||||
5
www/lib/angular-material/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
*.log
|
||||
*.sw*
|
||||
.DS_STORE
|
||||
/.idea/
|
||||
default-theme.css
|
||||
1599
www/lib/angular-material/CHANGELOG.md
Normal file
21
www/lib/angular-material/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2014 Google, Inc. http://angularjs.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
211
www/lib/angular-material/README.md
Normal file
@@ -0,0 +1,211 @@
|
||||
This repo is for distribution on `npm` and `bower`. The source for this module is in the
|
||||
[main Angular Material repo](https://github.com/angular/material).
|
||||
Please file issues and pull requests against that repo.
|
||||
|
||||
## Installing Angular Material
|
||||
|
||||
You can install this package locally either with `npm`, `jspm`, or `bower`.
|
||||
|
||||
### npm
|
||||
|
||||
```shell
|
||||
# To install latest formal release
|
||||
npm install angular-material
|
||||
|
||||
# To install latest release and update package.json
|
||||
npm install angular-material --save-dev
|
||||
|
||||
# To install from HEAD of master
|
||||
npm install http://github.com/angular/bower-material/tarball/master
|
||||
|
||||
# To view all installed package
|
||||
npm list;
|
||||
```
|
||||
|
||||
### jspm
|
||||
|
||||
```shell
|
||||
# To install latest formal release
|
||||
jspm install angular-material;
|
||||
|
||||
# To install from HEAD of master
|
||||
jspm install angular-material=github:angular/bower-material@master;
|
||||
|
||||
# To view all installed package versions
|
||||
jspm inspect;
|
||||
```
|
||||
|
||||
Now you can use `require('angular-material')` when installing with npm or jsmp and using Browserify or Webpack.
|
||||
|
||||
### bower
|
||||
|
||||
```shell
|
||||
# To get the latest stable version, use bower from the command line.
|
||||
bower install angular-material
|
||||
|
||||
# To get the most recent, last committed-to-master version use:
|
||||
bower install angular-material#master
|
||||
|
||||
# To save the bower settings for future use:
|
||||
bower install angular-material --save
|
||||
|
||||
# Later, you can use easily update with:
|
||||
bower update
|
||||
```
|
||||
|
||||
> Please note that Angular Material requires **Angular 1.3.x** or higher.
|
||||
|
||||
|
||||
## Using the Angular Material Library
|
||||
|
||||
Now that you have installed the Angular libraries, simply include the scripts and
|
||||
stylesheet in your main HTML file, in the order shown in the example below. Note that npm
|
||||
will install the files under `/node_modules/angular-material/` and bower will install them
|
||||
under `/bower_components/angular-material/`.
|
||||
|
||||
### npm
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="stylesheet" href="/node_modules/angular-material/angular-material.css">
|
||||
</head>
|
||||
<body ng-app="YourApp">
|
||||
|
||||
<div ng-controller="YourController">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/node_modules/angular/angular.js"></script>
|
||||
<script src="/node_modules/angular-aria/angular-aria.js"></script>
|
||||
<script src="/node_modules/angular-animate/angular-animate.js"></script>
|
||||
<script src="/node_modules/angular-material/angular-material.js"></script>
|
||||
<script>
|
||||
|
||||
// Include app dependency on ngMaterial
|
||||
|
||||
angular.module( 'YourApp', [ 'ngMaterial' ] )
|
||||
.controller("YourController", YourController );
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### bower
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no" />
|
||||
<link rel="stylesheet" href="/bower_components/angular-material/angular-material.css">
|
||||
</head>
|
||||
<body ng-app="YourApp">
|
||||
|
||||
<div ng-controller="YourController">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="/bower_components/angular/angular.js"></script>
|
||||
<script src="/bower_components/angular-aria/angular-aria.js"></script>
|
||||
<script src="/bower_components/angular-animate/angular-animate.js"></script>
|
||||
<script src="/bower_components/angular-material/angular-material.js"></script>
|
||||
<script>
|
||||
|
||||
// Include app dependency on ngMaterial
|
||||
|
||||
angular.module( 'YourApp', [ 'ngMaterial' ] )
|
||||
.controller("YourController", YourController );
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
## Using the CDN
|
||||
|
||||
CDN versions of Angular Material are now available at
|
||||
[Google Hosted Libraries](https://developers.google.com/speed/libraries/devguide#angularmaterial).
|
||||
|
||||
With the Google CDN, you will not need to download local copies of the distribution files.
|
||||
Instead simply reference the CDN urls to easily use those remote library files.
|
||||
This is especially useful when using online tools such as CodePen, Plunkr, or jsFiddle.
|
||||
|
||||
```html
|
||||
<head>
|
||||
|
||||
<!-- Angular Material CSS now available via Google CDN; version 0.9.4 used here -->
|
||||
<link rel="stylesheet" href="//ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<!-- Angular Material Dependencies -->
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-animate.min.js"></script>
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular-aria.min.js"></script>
|
||||
|
||||
<!-- Angular Material Javascript now available via Google CDN; version 0.9.4 used here -->
|
||||
<script src="//ajax.googleapis.com/ajax/libs/angular_material/0.9.4/angular-material.min.js"></script>
|
||||
|
||||
</body>
|
||||
```
|
||||
|
||||
> Note that the above sample references the 0.9.4 CDN release. Your version will change
|
||||
based on the latest stable release version.
|
||||
|
||||
## Jasmine Testing with Angular Material
|
||||
|
||||
<br/>
|
||||
If you are using Angular Material and will be using Jasmine to test your own custom application code, you will need to also load two (2) Angular mock files:
|
||||
|
||||
* Angular Mocks - **angular-mocks.js** from `/node_modules/angular-mocks/angular-mocks.js`
|
||||
* Angular Material Mocks - **angular-material-mocks.js** from `/node_modules/angular-material/angular-material-mocks.js`
|
||||
|
||||
<br/>
|
||||
|
||||
Shown below is a karma-configuration file (`karma.conf.js`) sample that may be a useful template for your own testing purposes:<br/><br/>
|
||||
|
||||
```js
|
||||
module.exports = function(config) {
|
||||
|
||||
var SRC = [
|
||||
'src/myApp/**/*.js',
|
||||
'test/myApp/**/*.spec.js'
|
||||
];
|
||||
|
||||
var LIBS = [
|
||||
'node_modules/angular/angular.js',
|
||||
'node_modules/angular-animate/angular-animate.js',
|
||||
'node_modules/angular-aria/angular-aria.js',
|
||||
'node_modules/angular-material/angular-material.js',
|
||||
|
||||
'node_modules/angular-mocks/angular-mocks.js',
|
||||
'node_modules/angular-material/angular-material-mocks.js'
|
||||
];
|
||||
|
||||
config.set({
|
||||
|
||||
basePath: __dirname + '/..',
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
files: LIBS.concat(SRC),
|
||||
|
||||
port: 9876,
|
||||
reporters: ['progress'],
|
||||
colors: true,
|
||||
|
||||
autoWatch: false,
|
||||
singleRun: true,
|
||||
browsers: ['PhantomJS,Chrome']
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
```
|
||||
|
||||
77
www/lib/angular-material/angular-material-mocks.js
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
*
|
||||
* Angular-Material-Mocks
|
||||
*
|
||||
* Developers interested in running their own custom unit tests WITH angular-material.js loaded...
|
||||
* must also include this *mocks* file. Similar to `angular-mocks.js`, `angular-material-mocks.js`
|
||||
* will override and disable specific Angular Material performance settings:
|
||||
*
|
||||
* - Disabled Theme CSS rule generations
|
||||
* - Forces $mdAria.expectWithText() to be synchronous
|
||||
* - Mocks $$rAF.throttle()
|
||||
* - Captures flush exceptions from $$rAF
|
||||
*
|
||||
*/
|
||||
(function(window, angular, undefined) {
|
||||
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name ngMaterial-mock
|
||||
* @packageName angular-material-mocks
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* The `ngMaterial-mock` module provides support
|
||||
*
|
||||
*/
|
||||
angular.module('ngMaterial-mock', ['ngMock', 'material.core'])
|
||||
.config(['$provide', function($provide) {
|
||||
|
||||
/**
|
||||
* Angular Material dynamically generates Style tags
|
||||
* based on themes and palletes; for each ng-app.
|
||||
*
|
||||
* For testing, we want to disable generation and
|
||||
* <style> DOM injections. So we clear the huge THEME
|
||||
* styles while testing...
|
||||
*/
|
||||
$provide.constant('$MD_THEME_CSS', '/**/');
|
||||
|
||||
/**
|
||||
* Intercept to make .expectWithText() to be synchronous
|
||||
*/
|
||||
$provide.decorator('$mdAria', function($delegate){
|
||||
|
||||
$delegate.expectWithText = function(element, attrName){
|
||||
$delegate.expect(element, attrName, element.text().trim());
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
|
||||
/**
|
||||
* Add throttle() and wrap .flush() to catch `no callbacks present`
|
||||
* errors
|
||||
*/
|
||||
$provide.decorator('$$rAF', function throttleInjector($delegate){
|
||||
|
||||
$delegate.throttle = function(cb) {
|
||||
return function() {
|
||||
cb.apply(this, arguments);
|
||||
};
|
||||
};
|
||||
|
||||
var ngFlush = $delegate.flush;
|
||||
$delegate.flush = function() {
|
||||
try { ngFlush(); }
|
||||
catch(e) { ; }
|
||||
};
|
||||
|
||||
return $delegate;
|
||||
});
|
||||
|
||||
}]);
|
||||
|
||||
})(window, window.angular);
|
||||
7183
www/lib/angular-material/angular-material.css
Normal file
15406
www/lib/angular-material/angular-material.js
vendored
Normal file
6
www/lib/angular-material/angular-material.min.css
vendored
Normal file
14
www/lib/angular-material/angular-material.min.js
vendored
Normal file
14
www/lib/angular-material/bower.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "angular-material",
|
||||
"version": "0.10.0",
|
||||
"ignore": [],
|
||||
"dependencies": {
|
||||
"angular": "^1.3.0 || >1.4.0-beta.0",
|
||||
"angular-animate": "^1.3.0 || >1.4.0-beta.0",
|
||||
"angular-aria": "^1.3.15 || >1.4.0-beta.0"
|
||||
},
|
||||
"main": [
|
||||
"angular-material.js",
|
||||
"angular-material.css"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"><g><g><rect fill="none" width="24" height="24"/><path fill="#7d7d7d" d="M16,1H4C2.9,1,2,1.9,2,3v14h2V3h12V1z M19,5H8C6.9,5,6,5.9,6,7v14c0,1.1,0.9,2,2,2h11c1.1,0,2-0.9,2-2V7C21,5.9,20.1,5,19,5z M19,21H8V7h11V21z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 365 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><rect fill="none" width="48" height="48"/><path fill="#7d7d7d" d="M32,2H8C5.8,2,4,3.8,4,6v28h4V6h24V2z M38,10H16c-2.2,0-4,1.8-4,4v28c0,2.2,1.8,4,4,4h22c2.2,0,4-1.8,4-4V14C42,11.8,40.2,10,38,10z M38,42H16V14h22V42z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 374 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><g><path fill="#7d7d7d" d="M40,4H8C5.8,4,4,5.8,4,8l0,32c0,2.2,1.8,4,4,4h32c2.2,0,4-1.8,4-4V8C44,5.8,42.2,4,40,4z M38,8v6h-4c-1.1,0-2,0.9-2,2v4h6v6h-6v14h-6V26h-4v-6h4v-5c0-3.9,3.1-7,7-7H38z"/></g><g><rect fill="none" width="48" height="48"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 403 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><path fill="#159F5C" d="M23,4C13.6,4,6,11.6,6,21s7.6,17,17,17h1v7c9.7-4.7,16-15,16-24C40,11.6,32.4,4,23,4z M22,22l-2,4h-3l2-4h-3v-6h6V22zM30,22l-2,4h-3l2-4h-3v-6h6V22z"/><rect x="0" fill="none" width="48" height="48"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 376 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><path fill="#7d7d7d" d="M40,8H8c-2.2,0-4,1.8-4,4l0,24c0,2.2,1.8,4,4,4h32c2.2,0,4-1.8,4-4V12C44,9.8,42.2,8,40,8z M40,16L24,26L8,16v-4l16,10l16-10V16z"/><rect fill="none" width="48" height="48"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 351 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><path fill="#7d7d7d" d="M40,4H8C5.8,4,4,5.8,4,8l0,36l8-8h28c2.2,0,4-1.8,4-4V8C44,5.8,42.2,4,40,4z M36,28H12v-4h24V28z M36,22H12v-4h24V22zM36,16H12v-4h24V16z"/><rect x="0" fill="none" width="48" height="48"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 365 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="24px"height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"><g><g><g><path d="M19,8H5c-1.7,0-3,1.3-3,3v6h4v4h12v-4h4v-6C22,9.3,20.7,8,19,8z M16,19H8v-5h8V19z M19,12c-0.6,0-1-0.4-1-1s0.4-1,1-1c0.6,0,1,0.4,1,1S19.6,12,19,12z M18,3H6v4h12V3z" fill="#7d7d7d"/></g><rect fill="none" width="24" height="24"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 393 B |
@@ -0,0 +1,2 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="48px" height="48px" viewBox="0 0 48 48" enable-background="new 0 0 48 48" xml:space="preserve"><g><g><g><path fill="#7d7d7d" d="M40,4H8C5.8,4,4,5.8,4,8l0,32c0,2.2,1.8,4,4,4h32c2.2,0,4-1.8,4-4V8C44,5.8,42.2,4,40,4z M35.4,18.7c-0.1,9.2-6,15.6-14.8,16c-3.6,0.2-6.3-1-8.6-2.5c2.7,0.4,6-0.6,7.8-2.2c-2.6-0.3-4.2-1.6-4.9-3.8c0.8,0.1,1.6,0.1,2.3-0.1
|
||||
c-2.4-0.8-4.1-2.3-4.2-5.3c0.7,0.3,1.4,0.6,2.3,0.6c-1.8-1-3.1-4.7-1.6-7.2c2.6,2.9,5.8,5.3,11,5.6c-1.3-5.6,6.1-8.6,9.2-4.9c1.3-0.3,2.4-0.8,3.4-1.3c-0.4,1.3-1.2,2.2-2.2,2.9c1.1-0.1,2.1-0.4,2.9-0.8C37.5,16.9,36.4,17.9,35.4,18.7z"/></g><g><rect fill="none" width="48" height="48"/></g></g></g></svg>
|
||||
|
After Width: | Height: | Size: 680 B |
@@ -0,0 +1 @@
|
||||
<svg version="1.1" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"><g><g><rect x="-618" y="-2232" fill="none" width="1400" height="3600"/></g></g><g><g><rect fill="none" width="24" height="24"/><path fill="#7d7d7d" d="M19.4,10c-0.7-3.4-3.7-6-7.4-6C9.1,4,6.6,5.6,5.4,8C2.3,8.4,0,10.9,0,14c0,3.3,2.7,6,6,6h13c2.8,0,5-2.2,5-5C24,12.4,21.9,10.2,19.4,10z M14,13v4h-4v-4H7l5-5l5,5H14z"/></g></g></svg>
|
||||
|
After Width: | Height: | Size: 466 B |
@@ -0,0 +1,39 @@
|
||||
.custom-chips {
|
||||
.md-chip {
|
||||
position: relative;
|
||||
padding-right: 35px;
|
||||
.md-chip-remove-container {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
margin-right: 0;
|
||||
height: 24px;
|
||||
button.vegetablechip {
|
||||
position: relative;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
line-height: 30px;
|
||||
text-align: center;
|
||||
background: rgba(black, 0.3);
|
||||
border-radius: 50%;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
transition: background 0.15s linear;
|
||||
display: block;
|
||||
md-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate3d(-50%, -50%, 0) scale(0.7);
|
||||
color: white;
|
||||
fill: white;
|
||||
}
|
||||
&:hover, &:focus {
|
||||
background: rgba(red, 0.8);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
md-content.autocomplete {
|
||||
min-height: 250px;
|
||||
}
|
||||
.md-item-text.compact {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px;
|
||||
}
|
||||
.contact-item {
|
||||
box-sizing: border-box;
|
||||
&.selected {
|
||||
opacity: 0.5;
|
||||
h3 {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
.md-list-item-text {
|
||||
padding: 14px 0;
|
||||
h3 {
|
||||
margin: 0 !important;
|
||||
padding: 0;
|
||||
line-height: 1.2em !important;
|
||||
}
|
||||
h3, p {
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
@media (min-width: 900px) {
|
||||
float: left;
|
||||
width: 33%;
|
||||
}
|
||||
}
|
||||
|
||||
md-contact-chips {
|
||||
margin-bottom : 10px;
|
||||
}
|
||||
|
||||
.md-chips {
|
||||
padding: 5px 0 8px;
|
||||
}
|
||||
|
||||
|
||||
.fixedRows {
|
||||
height: 250px;
|
||||
overflow:hidden;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
md-icon {
|
||||
width:50%;height:50%
|
||||
}
|
||||
|
||||
md-icon svg {
|
||||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.s64 {
|
||||
font-size:64px;
|
||||
}
|
||||
|
||||
.s32 {
|
||||
|
||||
font-size:48px;
|
||||
|
||||
}
|
||||
|
||||
md-icon.fa {
|
||||
display:block;
|
||||
padding-left:0px;
|
||||
}
|
||||
|
||||
md-icon.s32 span {
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
md-grid-list {
|
||||
margin: 8px; }
|
||||
.gray {
|
||||
background: #f5f5f5; }
|
||||
.green {
|
||||
background: #b9f6ca; }
|
||||
.yellow {
|
||||
background: #ffff8d; }
|
||||
.blue {
|
||||
background: #84ffff; }
|
||||
.darkBlue {
|
||||
background: #80d8ff; }
|
||||
.deepBlue {
|
||||
background: #448aff; }
|
||||
.purple {
|
||||
background: #b388ff; }
|
||||
.lightPurple {
|
||||
background: #8c9eff; }
|
||||
.red {
|
||||
background: #ff8a80; }
|
||||
.pink {
|
||||
background: #ff80ab; }
|
||||
|
||||
md-grid-tile {
|
||||
-webkit-transition: all 500ms ease-out 100ms;
|
||||
-moz-transition: all 500ms ease-out 100ms;
|
||||
-o-transition: all 500ms ease-out 100ms;
|
||||
transition: all 500ms ease-out 100ms;
|
||||
}
|
||||
|
||||
md-grid-tile md-grid-tile-footer {
|
||||
background: rgba(0,0,0,.68);
|
||||
height: 36px;
|
||||
|
||||
}
|
||||
|
||||
md-grid-tile-footer figcaption {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
md-grid-tile-footer figcaption h3 {
|
||||
margin:0px;
|
||||
font-weight:700;
|
||||
width:100%;
|
||||
text-align:center;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
md-icon {
|
||||
width:50%;height:50%
|
||||
}
|
||||
|
||||
md-icon svg {
|
||||
-webkit-border-radius: 50%;
|
||||
-moz-border-radius: 50%;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.s64 {
|
||||
font-size:64px;
|
||||
}
|
||||
|
||||
.s32 {
|
||||
|
||||
font-size:48px;
|
||||
|
||||
}
|
||||
|
||||
md-icon.fa {
|
||||
display:block;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
md-icon.s32 span {
|
||||
padding-left:8px;
|
||||
}
|
||||
|
||||
md-grid-list {
|
||||
margin: 8px; }
|
||||
.gray {
|
||||
background: #f5f5f5; }
|
||||
.green {
|
||||
background: #b9f6ca; }
|
||||
.yellow {
|
||||
background: #ffff8d; }
|
||||
.blue {
|
||||
background: #84ffff; }
|
||||
.darkBlue {
|
||||
background: #80d8ff; }
|
||||
.deepBlue {
|
||||
background: #448aff; }
|
||||
.purple {
|
||||
background: #b388ff; }
|
||||
.lightPurple {
|
||||
background: #8c9eff; }
|
||||
.red {
|
||||
background: #ff8a80; }
|
||||
.pink {
|
||||
background: #ff80ab; }
|
||||
|
||||
|
||||
md-grid-tile {
|
||||
transition: all 300ms ease-out 50ms;
|
||||
}
|
||||
|
||||
|
||||
md-grid-tile md-icon {
|
||||
padding-bottom: 32px;
|
||||
}
|
||||
|
||||
md-grid-tile md-grid-tile-footer {
|
||||
background: rgba(0,0,0,.68);
|
||||
height: 36px;
|
||||
|
||||
}
|
||||
|
||||
md-grid-tile-footer figcaption {
|
||||
width:100%;
|
||||
}
|
||||
|
||||
md-grid-tile-footer figcaption h3 {
|
||||
margin: 0;
|
||||
font-weight:700;
|
||||
width:100%;
|
||||
text-align:center;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 479 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 665 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 636 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 636 B |
@@ -0,0 +1,26 @@
|
||||
<svg><defs>
|
||||
<g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"/></g>
|
||||
<g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"/></g>
|
||||
<g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"/></g>
|
||||
<g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
|
||||
<g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"/></g>
|
||||
<g id="account-child"><circle cx="12" cy="13.49" r="1.5"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 2.5c1.24 0 2.25 1.01 2.25 2.25S13.24 9 12 9 9.75 7.99 9.75 6.75 10.76 4.5 12 4.5zm5 10.56v2.5c-.45.41-.96.77-1.5 1.05v-.68c0-.34-.17-.65-.46-.92-.65-.62-1.89-1.02-3.04-1.02-.96 0-1.96.28-2.65.73l-.17.12-.21.17c.78.47 1.63.72 2.54.82l1.33.15c.37.04.66.36.66.75 0 .29-.16.53-.4.66-.28.15-.64.09-.95.09-.35 0-.69-.01-1.03-.05-.5-.06-.99-.17-1.46-.33-.49-.16-.97-.38-1.42-.64-.22-.13-.44-.27-.65-.43l-.31-.24c-.04-.02-.28-.18-.28-.23v-4.28c0-1.58 2.63-2.78 5-2.78s5 1.2 5 2.78v1.78z"/></g>
|
||||
<g id="account-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></g>
|
||||
<g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
|
||||
<g id="add-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
|
||||
<g id="add-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
|
||||
<g id="add-circle-outline"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
|
||||
<g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"/></g>
|
||||
<g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
|
||||
<g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"/></g>
|
||||
<g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C10.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1.65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"/></g>
|
||||
<g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"/></g>
|
||||
<g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g>
|
||||
<g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"/></g>
|
||||
<g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></g>
|
||||
<g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"/></g>
|
||||
<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></g>
|
||||
<g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"/></g>
|
||||
<g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"/></g>
|
||||
<g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"/></g>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,26 @@
|
||||
<svg><defs>
|
||||
<g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g>
|
||||
<g id="domain"><path d="M12 7V3H2v18h20V7H12zM6 19H4v-2h2v2zm0-4H4v-2h2v2zm0-4H4V9h2v2zm0-4H4V5h2v2zm4 12H8v-2h2v2zm0-4H8v-2h2v2zm0-4H8V9h2v2zm0-4H8V5h2v2zm10 12h-8v-2h2v-2h-2v-2h2v-2h-2V9h8v10zm-2-8h-2v2h2v-2zm0 4h-2v2h2v-2z"/></g>
|
||||
<g id="group"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></g>
|
||||
<g id="group-add"><path d="M8 10H5V7H3v3H0v2h3v3h2v-3h3v-2zm10 1c1.66 0 2.99-1.34 2.99-3S19.66 5 18 5c-.32 0-.63.05-.91.14.57.81.9 1.79.9 2.86s-.34 2.04-.9 2.86c.28.09.59.14.91.14zm-5 0c1.66 0 2.99-1.34 2.99-3S14.66 5 13 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm6.62 2.16c.83.73 1.38 1.66 1.38 2.84v2h3v-2c0-1.54-2.37-2.49-4.38-2.84zM13 13c-2 0-6 1-6 3v2h12v-2c0-2-4-3-6-3z"/></g>
|
||||
<g id="location-city"><path d="M15 11V5l-3-3-3 3v2H3v14h18V11h-6zm-8 8H5v-2h2v2zm0-4H5v-2h2v2zm0-4H5V9h2v2zm6 8h-2v-2h2v2zm0-4h-2v-2h2v2zm0-4h-2V9h2v2zm0-4h-2V5h2v2zm6 12h-2v-2h2v2zm0-4h-2v-2h2v2z"/></g>
|
||||
<g id="mood"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm3.5-9c.83 0 1.5-.67 1.5-1.5S16.33 8 15.5 8 14 8.67 14 9.5s.67 1.5 1.5 1.5zm-7 0c.83 0 1.5-.67 1.5-1.5S9.33 8 8.5 8 7 8.67 7 9.5 7.67 11 8.5 11zm3.5 6.5c2.33 0 4.31-1.46 5.11-3.5H6.89c.8 2.04 2.78 3.5 5.11 3.5z"/></g>
|
||||
<g id="notifications"><path d="M11.5 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6.5-6v-5.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-2.87.68-5 3.25-5 6.32V16l-2 2v1h17v-1l-2-2z"/></g>
|
||||
<g id="notifications-none"><path d="M11.5 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6.5-6v-5.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-2.87.68-5 3.25-5 6.32V16l-2 2v1h17v-1l-2-2zm-2 1H7v-6.5C7 8.01 9.01 6 11.5 6S16 8.01 16 10.5V17z"/></g>
|
||||
<g id="notifications-off"><path d="M11.5 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zM18 10.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-.51.12-.99.32-1.45.56L18 14.18V10.5zm-.27 8.5l2 2L21 19.73 4.27 3 3 4.27l2.92 2.92C5.34 8.16 5 9.29 5 10.5V16l-2 2v1h14.73z"/></g>
|
||||
<g id="notifications-on"><path d="M6.58 3.58L5.15 2.15C2.76 3.97 1.18 6.8 1.03 10h2c.15-2.65 1.51-4.97 3.55-6.42zM19.97 10h2c-.15-3.2-1.73-6.03-4.13-7.85l-1.43 1.43c2.05 1.45 3.41 3.77 3.56 6.42zm-1.97.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-2.87.68-5 3.25-5 6.32V16l-2 2v1h17v-1l-2-2v-5.5zM11.5 22c.14 0 .27-.01.4-.04.65-.13 1.19-.58 1.44-1.18.1-.24.16-.5.16-.78h-4c0 1.1.9 2 2 2z"/></g>
|
||||
<g id="notifications-paused"><path d="M11.5 22c1.1 0 2-.9 2-2h-4c0 1.1.9 2 2 2zm6.5-6v-5.5c0-3.07-2.13-5.64-5-6.32V3.5c0-.83-.67-1.5-1.5-1.5S10 2.67 10 3.5v.68c-2.87.68-5 3.25-5 6.32V16l-2 2v1h17v-1l-2-2zm-4-6.2l-2.8 3.4H14V15H9v-1.8l2.8-3.4H9V8h5v1.8z"/></g>
|
||||
<g id="pages"><path d="M3 5v6h5L7 7l4 1V3H5c-1.1 0-2 .9-2 2zm5 8H3v6c0 1.1.9 2 2 2h6v-5l-4 1 1-4zm9 4l-4-1v5h6c1.1 0 2-.9 2-2v-6h-5l1 4zm2-14h-6v5l4-1-1 4h5V5c0-1.1-.9-2-2-2z"/></g>
|
||||
<g id="party-mode"><path d="M20 4h-3.17L15 2H9L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 3c1.63 0 3.06.79 3.98 2H12c-1.66 0-3 1.34-3 3 0 .35.07.69.18 1H7.1c-.06-.32-.1-.66-.1-1 0-2.76 2.24-5 5-5zm0 10c-1.63 0-3.06-.79-3.98-2H12c1.66 0 3-1.34 3-3 0-.35-.07-.69-.18-1h2.08c.07.32.1.66.1 1 0 2.76-2.24 5-5 5z"/></g>
|
||||
<g id="people"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"/></g>
|
||||
<g id="people-outline"><path d="M16.5 13c-1.2 0-3.07.34-4.5 1-1.43-.67-3.3-1-4.5-1C5.33 13 1 14.08 1 16.25V19h22v-2.75c0-2.17-4.33-3.25-6.5-3.25zm-4 4.5h-10v-1.25c0-.54 2.56-1.75 5-1.75s5 1.21 5 1.75v1.25zm9 0H14v-1.25c0-.46-.2-.86-.52-1.22.88-.3 1.96-.53 3.02-.53 2.44 0 5 1.21 5 1.75v1.25zM7.5 12c1.93 0 3.5-1.57 3.5-3.5S9.43 5 7.5 5 4 6.57 4 8.5 5.57 12 7.5 12zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 5.5c1.93 0 3.5-1.57 3.5-3.5S18.43 5 16.5 5 13 6.57 13 8.5s1.57 3.5 3.5 3.5zm0-5.5c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2z"/></g>
|
||||
<g id="person"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></g>
|
||||
<g id="person-add"><path d="M15 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm-9-2V7H4v3H1v2h3v3h2v-3h3v-2H6zm9 4c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/></g>
|
||||
<g id="person-outline"><path d="M12 5.9c1.16 0 2.1.94 2.1 2.1s-.94 2.1-2.1 2.1S9.9 9.16 9.9 8s.94-2.1 2.1-2.1m0 9c2.97 0 6.1 1.46 6.1 2.1v1.1H5.9V17c0-.64 3.13-2.1 6.1-2.1M12 4C9.79 4 8 5.79 8 8s1.79 4 4 4 4-1.79 4-4-1.79-4-4-4zm0 9c-2.67 0-8 1.34-8 4v3h16v-3c0-2.66-5.33-4-8-4z"/></g>
|
||||
<g id="plus-one"><path d="M10 8H8v4H4v2h4v4h2v-4h4v-2h-4zm4.5-1.92V7.9l2.5-.5V18h2V5z"/></g>
|
||||
<g id="poll"><path d="M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zM9 17H7v-7h2v7zm4 0h-2V7h2v10zm4 0h-2v-4h2v4z"/></g>
|
||||
<g id="public"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/></g>
|
||||
<g id="school"><path d="M5 13.18v4L12 21l7-3.82v-4L12 17l-7-3.82zM12 3L1 9l11 6 9-4.91V17h2V9L12 3z"/></g>
|
||||
<g id="share"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81 1.66 0 3-1.34 3-3s-1.34-3-3-3-3 1.34-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9c-1.66 0-3 1.34-3 3s1.34 3 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.16c-.05.21-.08.43-.08.65 0 1.61 1.31 2.92 2.92 2.92 1.61 0 2.92-1.31 2.92-2.92s-1.31-2.92-2.92-2.92z"/></g>
|
||||
<g id="whatshot"><path d="M13.5.67s.74 2.65.74 4.8c0 2.06-1.35 3.73-3.41 3.73-2.07 0-3.63-1.67-3.63-3.73l.03-.36C5.21 7.51 4 10.62 4 14c0 4.42 3.58 8 8 8s8-3.58 8-8C20 8.61 17.41 3.8 13.5.67zM11.71 19c-1.78 0-3.22-1.4-3.22-3.14 0-1.62 1.05-2.76 2.81-3.12 1.77-.36 3.6-1.21 4.62-2.58.39 1.29.59 2.65.59 4.04 0 2.65-2.15 4.8-4.8 4.8z"/></g>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 6.8 KiB |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="addShoppingCart"><g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 503 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 665 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 636 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 665 B |
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g id="cake"><path d="M12 6c1.11 0 2-.9 2-2 0-.38-.1-.73-.29-1.03L12 0l-1.71 2.97c-.19.3-.29.65-.29 1.03 0 1.1.9 2 2 2zm4.6 9.99l-1.07-1.07-1.08 1.07c-1.3 1.3-3.58 1.31-4.89 0l-1.07-1.07-1.09 1.07C6.75 16.64 5.88 17 4.96 17c-.73 0-1.4-.23-1.96-.61V21c0 .55.45 1 1 1h16c.55 0 1-.45 1-1v-4.61c-.56.38-1.23.61-1.96.61-.92 0-1.79-.36-2.44-1.01zM18 9h-5V7h-2v2H6c-1.66 0-3 1.34-3 3v1.54c0 1.08.88 1.96 1.96 1.96.52 0 1.02-.2 1.38-.57l2.14-2.13 2.13 2.13c.74.74 2.03.74 2.77 0l2.14-2.13 2.13 2.13c.37.37.86.57 1.38.57 1.08 0 1.96-.88 1.96-1.96V12C21 10.34 19.66 9 18 9z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 636 B |
@@ -0,0 +1,26 @@
|
||||
<svg><defs>
|
||||
<g id="3d-rotation"><path d="M7.52 21.48C4.25 19.94 1.91 16.76 1.55 13H.05C.56 19.16 5.71 24 12 24l.66-.03-3.81-3.81-1.33 1.32zm.89-6.52c-.19 0-.37-.03-.52-.08-.16-.06-.29-.13-.4-.24-.11-.1-.2-.22-.26-.37-.06-.14-.09-.3-.09-.47h-1.3c0 .36.07.68.21.95.14.27.33.5.56.69.24.18.51.32.82.41.3.1.62.15.96.15.37 0 .72-.05 1.03-.15.32-.1.6-.25.83-.44s.42-.43.55-.72c.13-.29.2-.61.2-.97 0-.19-.02-.38-.07-.56-.05-.18-.12-.35-.23-.51-.1-.16-.24-.3-.4-.43-.17-.13-.37-.23-.61-.31.2-.09.37-.2.52-.33.15-.13.27-.27.37-.42.1-.15.17-.3.22-.46.05-.16.07-.32.07-.48 0-.36-.06-.68-.18-.96-.12-.28-.29-.51-.51-.69-.2-.19-.47-.33-.77-.43C9.1 8.05 8.76 8 8.39 8c-.36 0-.69.05-1 .16-.3.11-.57.26-.79.45-.21.19-.38.41-.51.67-.12.26-.18.54-.18.85h1.3c0-.17.03-.32.09-.45s.14-.25.25-.34c.11-.09.23-.17.38-.22.15-.05.3-.08.48-.08.4 0 .7.1.89.31.19.2.29.49.29.86 0 .18-.03.34-.08.49-.05.15-.14.27-.25.37-.11.1-.25.18-.41.24-.16.06-.36.09-.58.09H7.5v1.03h.77c.22 0 .42.02.6.07s.33.13.45.23c.12.11.22.24.29.4.07.16.1.35.1.57 0 .41-.12.72-.35.93-.23.23-.55.33-.95.33zm8.55-5.92c-.32-.33-.7-.59-1.14-.77-.43-.18-.92-.27-1.46-.27H12v8h2.3c.55 0 1.06-.09 1.51-.27.45-.18.84-.43 1.16-.76.32-.33.57-.73.74-1.19.17-.47.26-.99.26-1.57v-.4c0-.58-.09-1.1-.26-1.57-.18-.47-.43-.87-.75-1.2zm-.39 3.16c0 .42-.05.79-.14 1.13-.1.33-.24.62-.43.85-.19.23-.43.41-.71.53-.29.12-.62.18-.99.18h-.91V9.12h.97c.72 0 1.27.23 1.64.69.38.46.57 1.12.57 1.99v.4zM12 0l-.66.03 3.81 3.81 1.33-1.33c3.27 1.55 5.61 4.72 5.96 8.48h1.5C23.44 4.84 18.29 0 12 0z"/></g>
|
||||
<g id="accessibility"><path d="M12 2c1.1 0 2 .9 2 2s-.9 2-2 2-2-.9-2-2 .9-2 2-2zm9 7h-6v13h-2v-6h-2v6H9V9H3V7h18v2z"/></g>
|
||||
<g id="account-balance"><path d="M4 10v7h3v-7H4zm6 0v7h3v-7h-3zM2 22h19v-3H2v3zm14-12v7h3v-7h-3zm-4.5-9L2 6v2h19V6l-9.5-5z"/></g>
|
||||
<g id="account-balance-wallet"><path d="M21 18v1c0 1.1-.9 2-2 2H5c-1.11 0-2-.9-2-2V5c0-1.1.89-2 2-2h14c1.1 0 2 .9 2 2v1h-9c-1.11 0-2 .9-2 2v8c0 1.1.89 2 2 2h9zm-9-2h10V8H12v8zm4-2.5c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/></g>
|
||||
<g id="account-box"><path d="M3 5v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2H5c-1.11 0-2 .9-2 2zm12 4c0 1.66-1.34 3-3 3s-3-1.34-3-3 1.34-3 3-3 3 1.34 3 3zm-9 8c0-2 4-3.1 6-3.1s6 1.1 6 3.1v1H6v-1z"/></g>
|
||||
<g id="account-child"><circle cx="12" cy="13.49" r="1.5"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 2.5c1.24 0 2.25 1.01 2.25 2.25S13.24 9 12 9 9.75 7.99 9.75 6.75 10.76 4.5 12 4.5zm5 10.56v2.5c-.45.41-.96.77-1.5 1.05v-.68c0-.34-.17-.65-.46-.92-.65-.62-1.89-1.02-3.04-1.02-.96 0-1.96.28-2.65.73l-.17.12-.21.17c.78.47 1.63.72 2.54.82l1.33.15c.37.04.66.36.66.75 0 .29-.16.53-.4.66-.28.15-.64.09-.95.09-.35 0-.69-.01-1.03-.05-.5-.06-.99-.17-1.46-.33-.49-.16-.97-.38-1.42-.64-.22-.13-.44-.27-.65-.43l-.31-.24c-.04-.02-.28-.18-.28-.23v-4.28c0-1.58 2.63-2.78 5-2.78s5 1.2 5 2.78v1.78z"/></g>
|
||||
<g id="account-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z"/></g>
|
||||
<g id="add"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></g>
|
||||
<g id="add-box"><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-2 10h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
|
||||
<g id="add-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm5 11h-4v4h-2v-4H7v-2h4V7h2v4h4v2z"/></g>
|
||||
<g id="add-circle-outline"><path d="M13 7h-2v4H7v2h4v4h2v-4h4v-2h-4V7zm-1-5C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></g>
|
||||
<g id="add-shopping-cart"><path d="M11 9h2V6h3V4h-3V1h-2v3H8v2h3v3zm-4 9c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2zm10 0c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2zm-9.83-3.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.86-7.01L19.42 4h-.01l-1.1 2-2.76 5H8.53l-.13-.27L6.16 6l-.95-2-.94-2H1v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.13 0-.25-.11-.25-.25z"/></g>
|
||||
<g id="alarm"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12.5 8H11v6l4.75 2.85.75-1.23-4-2.37V8zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7z"/></g>
|
||||
<g id="alarm-add"><path d="M7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm1-11h-2v3H8v2h3v3h2v-3h3v-2h-3V9z"/></g>
|
||||
<g id="alarm-off"><path d="M12 6c3.87 0 7 3.13 7 7 0 .84-.16 1.65-.43 2.4l1.52 1.52c.58-1.19.91-2.51.91-3.92 0-4.97-4.03-9-9-9-1.41 0-2.73.33-3.92.91L9.6 6.43C10.35 6.16 11.16 6 12 6zm10-.28l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM2.92 2.29L1.65 3.57 2.98 4.9l-1.11.93 1.42 1.42 1.11-.94.8.8C3.83 8.69 3 10.75 3 13c0 4.97 4.02 9 9 9 2.25 0 4.31-.83 5.89-2.2l2.2 2.2 1.27-1.27L3.89 3.27l-.97-.98zm13.55 16.1C15.26 19.39 13.7 20 12 20c-3.87 0-7-3.13-7-7 0-1.7.61-3.26 1.61-4.47l9.86 9.86zM8.02 3.28L6.6 1.86l-.86.71 1.42 1.42.86-.71z"/></g>
|
||||
<g id="alarm-on"><path d="M22 5.72l-4.6-3.86-1.29 1.53 4.6 3.86L22 5.72zM7.88 3.39L6.6 1.86 2 5.71l1.29 1.53 4.59-3.85zM12 4c-4.97 0-9 4.03-9 9s4.02 9 9 9c4.97 0 9-4.03 9-9s-4.03-9-9-9zm0 16c-3.87 0-7-3.13-7-7s3.13-7 7-7 7 3.13 7 7-3.13 7-7 7zm-1.46-5.47L8.41 12.4l-1.06 1.06 3.18 3.18 6-6-1.06-1.06-4.93 4.95z"/></g>
|
||||
<g id="android"><path d="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5V19h1c.55 0 1-.45 1-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0-1.5.67-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5-.67 1.5-1.5v-7c0-.83-.67-1.5-1.5-1.5zm-4.97-5.84l1.3-1.3c.2-.2.2-.51 0-.71-.2-.2-.51-.2-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0-1.86.23-2.66.63L7.85.15c-.2-.2-.51-.2-.71 0-.2.2-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0-1.99-.97-3.75-2.47-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/></g>
|
||||
<g id="announcement"><path d="M20 2H4c-1.1 0-1.99.9-1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 9h-2V5h2v6zm0 4h-2v-2h2v2z"/></g>
|
||||
<g id="apps"><path d="M4 8h4V4H4v4zm6 12h4v-4h-4v4zm-6 0h4v-4H4v4zm0-6h4v-4H4v4zm6 0h4v-4h-4v4zm6-10v4h4V4h-4zm-6 4h4V4h-4v4zm6 6h4v-4h-4v4zm0 6h4v-4h-4v4z"/></g>
|
||||
<g id="archive"><path d="M20.54 5.23l-1.39-1.68C18.88 3.21 18.47 3 18 3H6c-.47 0-.88.21-1.16.55L3.46 5.23C3.17 5.57 3 6.02 3 6.5V19c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V6.5c0-.48-.17-.93-.46-1.27zM12 17.5L6.5 12H10v-2h4v2h3.5L12 17.5zM5.12 5l.81-1h12l.94 1H5.12z"/></g>
|
||||
<g id="arrow-back"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/></g>
|
||||
<g id="arrow-drop-down"><path d="M7 10l5 5 5-5z"/></g>
|
||||
<g id="arrow-drop-down-circle"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 12l-4-4h8l-4 4z"/></g>
|
||||
<g id="arrow-drop-up"><path d="M7 14l5-5 5 5z"/></g>
|
||||
</defs></svg>
|
||||
|
After Width: | Height: | Size: 6.9 KiB |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M20 4h-16c-1.1 0-1.99.9-1.99 2l-.01 12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2v-12c0-1.1-.9-2-2-2zm0 4l-8 5-8-5v-2l8 5 8-5v2z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 269 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 261 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
<path d="M6.62 10.79c1.44 2.83 3.76 5.14 6.59 6.59l2.2-2.2c.27-.27.67-.36 1.02-.24 1.12.37 2.33.57 3.57.57.55 0 1 .45 1 1v3.49c0 .55-.45 1-1 1-9.39 0-17-7.61-17-17 0-.55.45-1 1-1h3.5c.55 0 1 .45 1 1 0 1.25.2 2.45.57 3.57.11.35.03.74-.25 1.02l-2.2 2.2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 394 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M12 2c-3.87 0-7 3.13-7 7 0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0 9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z"/>
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 307 B |
18
www/lib/angular-material/demos/input/demoIcons/style.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
.inputIconDemo {
|
||||
min-height:48px;
|
||||
}
|
||||
|
||||
|
||||
md-input-container:not(.md-input-invalid) > md-icon.email {
|
||||
color : green;
|
||||
}
|
||||
md-input-container:not(.md-input-invalid) > md-icon.name {
|
||||
color : dodgerblue;
|
||||
}
|
||||
|
||||
md-input-container.md-input-invalid > md-icon.email,
|
||||
md-input-container.md-input-invalid > md-icon.name,
|
||||
{
|
||||
color : red;
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
@@ -0,0 +1,13 @@
|
||||
md-content {
|
||||
background-color: transparent !important;
|
||||
md-tabs {
|
||||
background: #f6f6f6;
|
||||
border: 1px solid #e1e1e1;
|
||||
md-tabs-canvas {
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
md-content {
|
||||
background-color: transparent !important;
|
||||
md-tabs {
|
||||
border: 1px solid #e1e1e1;
|
||||
md-tab-content {
|
||||
background: #f6f6f6;
|
||||
}
|
||||
md-tabs-canvas {
|
||||
background: white;
|
||||
}
|
||||
}
|
||||
h1:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
md-input-container {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.remove-tab {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.demo-tab > div > div {
|
||||
padding: 25px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.edit-form input {
|
||||
width: 100%;
|
||||
}
|
||||
md-tabs {
|
||||
border-bottom: 1px solid rgba(0,0,0,0.12);
|
||||
}
|
||||
md-tab[disabled] {
|
||||
opacity: 0.5;
|
||||
}
|
||||
label {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.long > input {
|
||||
width: 264px;
|
||||
}
|
||||
.md-button.add-tab {
|
||||
transform: translateY(5px);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
md-tab-content {
|
||||
padding: 25px;
|
||||
&:nth-child(1) {
|
||||
background-color: #42A5F5;
|
||||
}
|
||||
&:nth-child(2) {
|
||||
background-color: #689F38;
|
||||
}
|
||||
&:nth-child(3) {
|
||||
background-color: #26C6DA;
|
||||
}
|
||||
}
|
||||
.after-tabs-area {
|
||||
> span {
|
||||
margin-top:25px;
|
||||
padding-right: 15px;
|
||||
vertical-align: middle;
|
||||
line-height: 30px;
|
||||
height: 35px;
|
||||
}
|
||||
> md-checkbox {
|
||||
margin-top:26px;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
|
||||
<path d="M0 0h24v24h-24z" fill="none"/>
|
||||
<path d="M12 21.35l-1.45-1.32c-5.15-4.67-8.55-7.75-8.55-11.53 0-3.08 2.42-5.5 5.5-5.5 1.74 0 3.41.81 4.5 2.09 1.09-1.28 2.76-2.09 4.5-2.09 3.08 0 5.5 2.42 5.5 5.5 0 3.78-3.4 6.86-8.55 11.54l-1.45 1.31z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 344 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path d="M0 0h18v18h-18z" fill="none"/>
|
||||
<path d="M2 13.5h14v-1.5h-14v1.5zm0-4h14v-1.5h-14v1.5zm0-5.5v1.5h14v-1.5h-14z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 220 B |
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 18 18">
|
||||
<path d="M0 0h18v18h-18z" fill="none"/>
|
||||
<path d="M9 5.5c.83 0 1.5-.67 1.5-1.5s-.67-1.5-1.5-1.5-1.5.67-1.5 1.5.67 1.5 1.5 1.5zm0 2c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5zm0 5c-.83 0-1.5.67-1.5 1.5s.67 1.5 1.5 1.5 1.5-.67 1.5-1.5-.67-1.5-1.5-1.5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 378 B |
12
www/lib/angular-material/index.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// Should already be required, here for clarity
|
||||
require('angular');
|
||||
|
||||
// Load Angular and dependent libs
|
||||
require('angular-animate');
|
||||
require('angular-aria');
|
||||
|
||||
// Now load Angular Material
|
||||
require('./angular-material');
|
||||
|
||||
// Export namespace
|
||||
module.exports = 'ngMaterial';
|
||||
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-autocomplete.md-THEME_NAME-theme {
|
||||
background: '{{background-50}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme[disabled] {
|
||||
background: '{{background-100}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme button md-icon path {
|
||||
fill: '{{background-600}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme button:after {
|
||||
background: '{{background-600-0.3}}'; }
|
||||
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme {
|
||||
background: '{{background-50}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li {
|
||||
color: '{{background-900}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li .highlight {
|
||||
color: '{{background-600}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li:hover, .md-autocomplete-suggestions.md-THEME_NAME-theme li.selected {
|
||||
background: '{{background-200}}'; }
|
||||
@@ -0,0 +1,220 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
@-webkit-keyframes md-autocomplete-list-out {
|
||||
0% {
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in; }
|
||||
|
||||
100% {
|
||||
height: 0;
|
||||
opacity: 0; } }
|
||||
@keyframes md-autocomplete-list-out {
|
||||
0% {
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in; }
|
||||
|
||||
100% {
|
||||
height: 0;
|
||||
opacity: 0; } }
|
||||
|
||||
@-webkit-keyframes md-autocomplete-list-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 40px; } }
|
||||
|
||||
@keyframes md-autocomplete-list-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 40px; } }
|
||||
|
||||
md-autocomplete {
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
min-width: 190px; }
|
||||
md-autocomplete[disabled] input {
|
||||
cursor: not-allowed; }
|
||||
md-autocomplete[md-floating-label] {
|
||||
padding-bottom: 26px;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
height: auto; }
|
||||
md-autocomplete[md-floating-label] md-input-container {
|
||||
padding-bottom: 0; }
|
||||
md-autocomplete[md-floating-label] md-autocomplete-wrap {
|
||||
height: auto; }
|
||||
md-autocomplete[md-floating-label] button {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 30px;
|
||||
height: 30px; }
|
||||
md-autocomplete md-autocomplete-wrap {
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
height: 40px; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate] {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: none; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate] .md-container {
|
||||
transition: none;
|
||||
top: auto;
|
||||
height: 3px; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-enter {
|
||||
transition: opacity 0.15s linear; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-enter.ng-enter-active {
|
||||
opacity: 1; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-leave {
|
||||
transition: opacity 0.15s linear; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-leave.ng-leave-active {
|
||||
opacity: 0; }
|
||||
md-autocomplete input:not(.md-input) {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
outline: none;
|
||||
background: transparent; }
|
||||
md-autocomplete input:not(.md-input)::-ms-clear {
|
||||
display: none; }
|
||||
md-autocomplete button {
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
background: transparent;
|
||||
margin: auto 5px; }
|
||||
md-autocomplete button:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
bottom: -6px;
|
||||
left: -6px;
|
||||
border-radius: 50%;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
md-autocomplete button:focus {
|
||||
outline: none; }
|
||||
md-autocomplete button:focus:after {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1; }
|
||||
md-autocomplete button md-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate3d(-50%, -50%, 0) scale(0.9);
|
||||
transform: translate3d(-50%, -50%, 0) scale(0.9); }
|
||||
md-autocomplete button md-icon path {
|
||||
stroke-width: 0; }
|
||||
md-autocomplete button.ng-enter {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
transition: -webkit-transform 0.15s ease-out;
|
||||
transition: transform 0.15s ease-out; }
|
||||
md-autocomplete button.ng-enter.ng-enter-active {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
md-autocomplete button.ng-leave {
|
||||
transition: -webkit-transform 0.15s ease-out;
|
||||
transition: transform 0.15s ease-out; }
|
||||
md-autocomplete button.ng-leave.ng-leave-active {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0); }
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-autocomplete input {
|
||||
border: 1px solid #fff; }
|
||||
md-autocomplete li:focus {
|
||||
color: #fff; } }
|
||||
|
||||
.md-autocomplete-suggestions {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
max-height: 225.5px;
|
||||
z-index: 100; }
|
||||
.md-autocomplete-suggestions li {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
padding: 0 15px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
transition: background 0.15s linear;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis; }
|
||||
.md-autocomplete-suggestions li.ng-enter, .md-autocomplete-suggestions li.ng-hide-remove {
|
||||
transition: none;
|
||||
-webkit-animation: md-autocomplete-list-in 0.2s;
|
||||
animation: md-autocomplete-list-in 0.2s; }
|
||||
.md-autocomplete-suggestions li.ng-leave, .md-autocomplete-suggestions li.ng-hide-add {
|
||||
transition: none;
|
||||
-webkit-animation: md-autocomplete-list-out 0.2s;
|
||||
animation: md-autocomplete-list-out 0.2s; }
|
||||
.md-autocomplete-suggestions li:focus {
|
||||
outline: none; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-autocomplete, .md-autocomplete-suggestions {
|
||||
border: 1px solid #fff; } }
|
||||
951
www/lib/angular-material/modules/closure/autocomplete/autocomplete.js
vendored
Normal file
@@ -0,0 +1,951 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.autocomplete');
|
||||
goog.require('ng.material.components.icon');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.autocomplete
|
||||
*/
|
||||
/*
|
||||
* @see js folder for autocomplete implementation
|
||||
*/
|
||||
angular.module('material.components.autocomplete', [
|
||||
'material.core',
|
||||
'material.components.icon'
|
||||
]);
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.controller('MdAutocompleteCtrl', MdAutocompleteCtrl);
|
||||
|
||||
var ITEM_HEIGHT = 41,
|
||||
MAX_HEIGHT = 5.5 * ITEM_HEIGHT,
|
||||
MENU_PADDING = 8;
|
||||
|
||||
function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $mdTheming, $window,
|
||||
$animate, $rootElement, $attrs) {
|
||||
//-- private variables
|
||||
var ctrl = this,
|
||||
itemParts = $scope.itemsExpr.split(/ in /i),
|
||||
itemExpr = itemParts[1],
|
||||
elements = null,
|
||||
promise = null,
|
||||
cache = {},
|
||||
noBlur = false,
|
||||
selectedItemWatchers = [],
|
||||
hasFocus = false,
|
||||
lastCount = 0;
|
||||
|
||||
//-- public variables with handlers
|
||||
defineProperty('hidden', handleHiddenChange, true);
|
||||
|
||||
//-- public variables
|
||||
ctrl.scope = $scope;
|
||||
ctrl.parent = $scope.$parent;
|
||||
ctrl.itemName = itemParts[0];
|
||||
ctrl.matches = [];
|
||||
ctrl.loading = false;
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = null;
|
||||
ctrl.messages = [];
|
||||
ctrl.id = $mdUtil.nextUid();
|
||||
ctrl.isDisabled = null;
|
||||
ctrl.isRequired = null;
|
||||
|
||||
//-- public methods
|
||||
ctrl.keydown = keydown;
|
||||
ctrl.blur = blur;
|
||||
ctrl.focus = focus;
|
||||
ctrl.clear = clearValue;
|
||||
ctrl.select = select;
|
||||
ctrl.listEnter = onListEnter;
|
||||
ctrl.listLeave = onListLeave;
|
||||
ctrl.mouseUp = onMouseup;
|
||||
ctrl.getCurrentDisplayValue = getCurrentDisplayValue;
|
||||
ctrl.registerSelectedItemWatcher = registerSelectedItemWatcher;
|
||||
ctrl.unregisterSelectedItemWatcher = unregisterSelectedItemWatcher;
|
||||
|
||||
return init();
|
||||
|
||||
//-- initialization methods
|
||||
|
||||
/**
|
||||
* Initialize the controller, setup watchers, gather elements
|
||||
*/
|
||||
function init () {
|
||||
$mdUtil.initOptionalProperties($scope, $attrs, { searchText: null, selectedItem: null } );
|
||||
$mdTheming($element);
|
||||
configureWatchers();
|
||||
$timeout(function () {
|
||||
gatherElements();
|
||||
focusElement();
|
||||
moveDropdown();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dropdown's position and applies the new styles to the menu element
|
||||
* @returns {*}
|
||||
*/
|
||||
function positionDropdown () {
|
||||
if (!elements) return $timeout(positionDropdown, 0, false);
|
||||
var hrect = elements.wrap.getBoundingClientRect(),
|
||||
vrect = elements.snap.getBoundingClientRect(),
|
||||
root = elements.root.getBoundingClientRect(),
|
||||
top = vrect.bottom - root.top,
|
||||
bot = root.bottom - vrect.top,
|
||||
left = hrect.left - root.left,
|
||||
width = hrect.width,
|
||||
styles = {
|
||||
left: left + 'px',
|
||||
minWidth: width + 'px',
|
||||
maxWidth: Math.max(hrect.right - root.left, root.right - hrect.left) - MENU_PADDING + 'px'
|
||||
};
|
||||
if (top > bot && root.height - hrect.bottom - MENU_PADDING < MAX_HEIGHT) {
|
||||
styles.top = 'auto';
|
||||
styles.bottom = bot + 'px';
|
||||
styles.maxHeight = Math.min(MAX_HEIGHT, hrect.top - root.top - MENU_PADDING) + 'px';
|
||||
} else {
|
||||
styles.top = top + 'px';
|
||||
styles.bottom = 'auto';
|
||||
styles.maxHeight = Math.min(MAX_HEIGHT, root.bottom - hrect.bottom - MENU_PADDING) + 'px';
|
||||
}
|
||||
elements.$.ul.css(styles);
|
||||
$timeout(correctHorizontalAlignment, 0, false);
|
||||
|
||||
/**
|
||||
* Makes sure that the menu doesn't go off of the screen on either side.
|
||||
*/
|
||||
function correctHorizontalAlignment () {
|
||||
var dropdown = elements.ul.getBoundingClientRect(),
|
||||
styles = {};
|
||||
if (dropdown.right > root.right - MENU_PADDING) {
|
||||
styles.left = (hrect.right - dropdown.width) + 'px';
|
||||
}
|
||||
elements.$.ul.css(styles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the dropdown menu to the body tag in order to avoid z-index and overflow issues.
|
||||
*/
|
||||
function moveDropdown () {
|
||||
if (!elements.$.root.length) return;
|
||||
$mdTheming(elements.$.ul);
|
||||
elements.$.ul.detach();
|
||||
elements.$.root.append(elements.$.ul);
|
||||
if ($animate.pin) $animate.pin(elements.$.ul, $rootElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends focus to the input element.
|
||||
*/
|
||||
function focusElement () {
|
||||
if ($scope.autofocus) elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up any watchers used by autocomplete
|
||||
*/
|
||||
function configureWatchers () {
|
||||
var wait = parseInt($scope.delay, 10) || 0;
|
||||
$attrs.$observe('disabled', function (value) { ctrl.isDisabled = value; });
|
||||
$attrs.$observe('required', function (value) { ctrl.isRequired = value !== null; });
|
||||
$scope.$watch('searchText', wait ? $mdUtil.debounce(handleSearchText, wait) : handleSearchText);
|
||||
registerSelectedItemWatcher(selectedItemChange);
|
||||
$scope.$watch('selectedItem', handleSelectedItemChange);
|
||||
angular.element($window).on('resize', positionDropdown);
|
||||
$scope.$on('$destroy', cleanup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any events or leftover elements created by this controller
|
||||
*/
|
||||
function cleanup () {
|
||||
angular.element($window).off('resize', positionDropdown);
|
||||
elements.$.ul.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers all of the elements needed for this controller
|
||||
*/
|
||||
function gatherElements () {
|
||||
elements = {
|
||||
main: $element[0],
|
||||
ul: $element.find('ul')[0],
|
||||
input: $element.find('input')[0],
|
||||
wrap: $element.find('md-autocomplete-wrap')[0],
|
||||
root: document.body
|
||||
};
|
||||
elements.li = elements.ul.getElementsByTagName('li');
|
||||
elements.snap = getSnapTarget();
|
||||
elements.$ = getAngularElements(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the element that the menu will base its position on
|
||||
* @returns {*}
|
||||
*/
|
||||
function getSnapTarget () {
|
||||
for (var element = $element; element.length; element = element.parent()) {
|
||||
if (angular.isDefined(element.attr('md-autocomplete-snap'))) return element[0];
|
||||
}
|
||||
return elements.wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers angular-wrapped versions of each element
|
||||
* @param elements
|
||||
* @returns {{}}
|
||||
*/
|
||||
function getAngularElements (elements) {
|
||||
var obj = {};
|
||||
for (var key in elements) {
|
||||
obj[key] = angular.element(elements[key]);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
//-- event/change handlers
|
||||
|
||||
/**
|
||||
* Handles changes to the `hidden` property.
|
||||
* @param hidden
|
||||
* @param oldHidden
|
||||
*/
|
||||
function handleHiddenChange (hidden, oldHidden) {
|
||||
if (!hidden && oldHidden) positionDropdown();
|
||||
if (!hidden) {
|
||||
if (elements) $timeout(function () { $mdUtil.disableScrollAround(elements.ul); }, 0, false);
|
||||
} else {
|
||||
$mdUtil.enableScrolling();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user mouses over the dropdown menu, ignore blur events.
|
||||
*/
|
||||
function onListEnter () {
|
||||
noBlur = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user's mouse leaves the menu, blur events may hide the menu again.
|
||||
*/
|
||||
function onListLeave () {
|
||||
noBlur = false;
|
||||
if (!hasFocus) ctrl.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the mouse button is released, send focus back to the input field.
|
||||
*/
|
||||
function onMouseup () {
|
||||
elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes to the selected item.
|
||||
* @param selectedItem
|
||||
* @param previousSelectedItem
|
||||
*/
|
||||
function selectedItemChange (selectedItem, previousSelectedItem) {
|
||||
if (selectedItem) {
|
||||
$scope.searchText = getDisplayValue(selectedItem);
|
||||
}
|
||||
if ($scope.itemChange && selectedItem !== previousSelectedItem)
|
||||
$scope.itemChange(getItemScope(selectedItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls any external watchers listening for the selected item. Used in conjunction with
|
||||
* `registerSelectedItemWatcher`.
|
||||
* @param selectedItem
|
||||
* @param previousSelectedItem
|
||||
*/
|
||||
function handleSelectedItemChange(selectedItem, previousSelectedItem) {
|
||||
for (var i = 0; i < selectedItemWatchers.length; ++i) {
|
||||
selectedItemWatchers[i](selectedItem, previousSelectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called when the selected item changes.
|
||||
* @param cb
|
||||
*/
|
||||
function registerSelectedItemWatcher(cb) {
|
||||
if (selectedItemWatchers.indexOf(cb) == -1) {
|
||||
selectedItemWatchers.push(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a function previously registered for selected item changes.
|
||||
* @param cb
|
||||
*/
|
||||
function unregisterSelectedItemWatcher(cb) {
|
||||
var i = selectedItemWatchers.indexOf(cb);
|
||||
if (i != -1) {
|
||||
selectedItemWatchers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes to the searchText property.
|
||||
* @param searchText
|
||||
* @param previousSearchText
|
||||
*/
|
||||
function handleSearchText (searchText, previousSearchText) {
|
||||
ctrl.index = getDefaultIndex();
|
||||
//-- do nothing on init
|
||||
if (searchText === previousSearchText) return;
|
||||
//-- clear selected item if search text no longer matches it
|
||||
if (searchText !== getDisplayValue($scope.selectedItem)) $scope.selectedItem = null;
|
||||
else return;
|
||||
//-- trigger change event if available
|
||||
if ($scope.textChange && searchText !== previousSearchText)
|
||||
$scope.textChange(getItemScope($scope.selectedItem));
|
||||
//-- cancel results if search text is not long enough
|
||||
if (!isMinLengthMet()) {
|
||||
ctrl.loading = false;
|
||||
ctrl.matches = [];
|
||||
ctrl.hidden = shouldHide();
|
||||
updateMessages();
|
||||
} else {
|
||||
handleQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input blur event, determines if the dropdown should hide.
|
||||
*/
|
||||
function blur () {
|
||||
hasFocus = false;
|
||||
if (!noBlur) ctrl.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input focus event, determines if the dropdown should show.
|
||||
*/
|
||||
function focus () {
|
||||
hasFocus = true;
|
||||
//-- if searchText is null, let's force it to be a string
|
||||
if (!angular.isString($scope.searchText)) $scope.searchText = '';
|
||||
if ($scope.minLength > 0) return;
|
||||
ctrl.hidden = shouldHide();
|
||||
if (!ctrl.hidden) handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles keyboard input.
|
||||
* @param event
|
||||
*/
|
||||
function keydown (event) {
|
||||
switch (event.keyCode) {
|
||||
case $mdConstant.KEY_CODE.DOWN_ARROW:
|
||||
if (ctrl.loading) return;
|
||||
event.preventDefault();
|
||||
ctrl.index = Math.min(ctrl.index + 1, ctrl.matches.length - 1);
|
||||
updateScroll();
|
||||
updateMessages();
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.UP_ARROW:
|
||||
if (ctrl.loading) return;
|
||||
event.preventDefault();
|
||||
ctrl.index = ctrl.index < 0 ? ctrl.matches.length - 1 : Math.max(0, ctrl.index - 1);
|
||||
updateScroll();
|
||||
updateMessages();
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.TAB:
|
||||
case $mdConstant.KEY_CODE.ENTER:
|
||||
if (ctrl.hidden || ctrl.loading || ctrl.index < 0 || ctrl.matches.length < 1) return;
|
||||
event.preventDefault();
|
||||
select(ctrl.index);
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.ESCAPE:
|
||||
ctrl.matches = [];
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = getDefaultIndex();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
//-- getters
|
||||
|
||||
/**
|
||||
* Returns the minimum length needed to display the dropdown.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getMinLength () {
|
||||
return angular.isNumber($scope.minLength) ? $scope.minLength : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display value for an item.
|
||||
* @param item
|
||||
* @returns {*}
|
||||
*/
|
||||
function getDisplayValue (item) {
|
||||
return (item && $scope.itemText) ? $scope.itemText(getItemScope(item)) : item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locals object for compiling item templates.
|
||||
* @param item
|
||||
* @returns {{}}
|
||||
*/
|
||||
function getItemScope (item) {
|
||||
if (!item) return;
|
||||
var locals = {};
|
||||
if (ctrl.itemName) locals[ctrl.itemName] = item;
|
||||
return locals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default index based on whether or not autoselect is enabled.
|
||||
* @returns {number}
|
||||
*/
|
||||
function getDefaultIndex () {
|
||||
return $scope.autoselect ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the menu should be hidden.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function shouldHide () {
|
||||
if (!isMinLengthMet()) return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display value of the current item.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getCurrentDisplayValue () {
|
||||
return getDisplayValue(ctrl.matches[ctrl.index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the minimum length is met by the search text.
|
||||
* @returns {*}
|
||||
*/
|
||||
function isMinLengthMet () {
|
||||
return angular.isDefined($scope.searchText) && $scope.searchText.length >= getMinLength();
|
||||
}
|
||||
|
||||
//-- actions
|
||||
|
||||
/**
|
||||
* Defines a public property with a handler and a default value.
|
||||
* @param key
|
||||
* @param handler
|
||||
* @param value
|
||||
*/
|
||||
function defineProperty (key, handler, value) {
|
||||
Object.defineProperty(ctrl, key, {
|
||||
get: function () { return value; },
|
||||
set: function (newValue) {
|
||||
var oldValue = value;
|
||||
value = newValue;
|
||||
handler(newValue, oldValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the item at the given index.
|
||||
* @param index
|
||||
*/
|
||||
function select (index) {
|
||||
$scope.selectedItem = ctrl.matches[index];
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = 0;
|
||||
ctrl.matches = [];
|
||||
//-- force form to update state for validation
|
||||
$timeout(function () {
|
||||
elements.$.input.controller('ngModel').$setViewValue(getDisplayValue($scope.selectedItem) ||
|
||||
$scope.searchText);
|
||||
ctrl.hidden = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the searchText value and selected item.
|
||||
*/
|
||||
function clearValue () {
|
||||
$scope.searchText = '';
|
||||
select(-1);
|
||||
|
||||
// Per http://www.w3schools.com/jsref/event_oninput.asp
|
||||
var eventObj = document.createEvent('CustomEvent');
|
||||
eventObj.initCustomEvent('input', true, true, {value: $scope.searchText});
|
||||
elements.input.dispatchEvent(eventObj);
|
||||
|
||||
elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the results for the provided search text.
|
||||
* @param searchText
|
||||
*/
|
||||
function fetchResults (searchText) {
|
||||
var items = $scope.$parent.$eval(itemExpr),
|
||||
term = searchText.toLowerCase();
|
||||
if (angular.isArray(items)) {
|
||||
handleResults(items);
|
||||
} else if (items) {
|
||||
ctrl.loading = true;
|
||||
if (items.success) items.success(handleResults);
|
||||
if (items.then) items.then(handleResults);
|
||||
if (items.error) items.error(function () { ctrl.loading = false; });
|
||||
}
|
||||
function handleResults (matches) {
|
||||
cache[term] = matches;
|
||||
if (searchText !== $scope.searchText) return; //-- just cache the results if old request
|
||||
ctrl.loading = false;
|
||||
promise = null;
|
||||
ctrl.matches = matches;
|
||||
ctrl.hidden = shouldHide();
|
||||
updateMessages();
|
||||
positionDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ARIA messages
|
||||
*/
|
||||
function updateMessages () {
|
||||
ctrl.messages = [ getCountMessage(), getCurrentDisplayValue() ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ARIA message for how many results match the current query.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getCountMessage () {
|
||||
if (lastCount === ctrl.matches.length) return '';
|
||||
lastCount = ctrl.matches.length;
|
||||
switch (ctrl.matches.length) {
|
||||
case 0: return 'There are no matches available.';
|
||||
case 1: return 'There is 1 match available.';
|
||||
default: return 'There are ' + ctrl.matches.length + ' matches available.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the focused element is within view.
|
||||
*/
|
||||
function updateScroll () {
|
||||
if (!elements.li[ctrl.index]) return;
|
||||
var li = elements.li[ctrl.index],
|
||||
top = li.offsetTop,
|
||||
bot = top + li.offsetHeight,
|
||||
hgt = elements.ul.clientHeight;
|
||||
if (top < elements.ul.scrollTop) {
|
||||
elements.ul.scrollTop = top;
|
||||
} else if (bot > elements.ul.scrollTop + hgt) {
|
||||
elements.ul.scrollTop = bot - hgt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the query to gather the results for the current searchText. Attempts to return cached
|
||||
* results first, then forwards the process to `fetchResults` if necessary.
|
||||
*/
|
||||
function handleQuery () {
|
||||
var searchText = $scope.searchText,
|
||||
term = searchText.toLowerCase();
|
||||
//-- cancel promise if a promise is in progress
|
||||
if (promise && promise.cancel) {
|
||||
promise.cancel();
|
||||
promise = null;
|
||||
}
|
||||
//-- if results are cached, pull in cached results
|
||||
if (!$scope.noCache && cache[term]) {
|
||||
ctrl.matches = cache[term];
|
||||
updateMessages();
|
||||
} else {
|
||||
fetchResults(searchText);
|
||||
}
|
||||
if (hasFocus) ctrl.hidden = shouldHide();
|
||||
}
|
||||
|
||||
}
|
||||
MdAutocompleteCtrl.$inject = ["$scope", "$element", "$mdUtil", "$mdConstant", "$timeout", "$mdTheming", "$window", "$animate", "$rootElement", "$attrs"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocomplete', MdAutocomplete);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdAutocomplete
|
||||
* @module material.components.autocomplete
|
||||
*
|
||||
* @description
|
||||
* `<md-autocomplete>` is a special input component with a drop-down of all possible matches to a custom query.
|
||||
* This component allows you to provide real-time suggestions as the user types in the input area.
|
||||
*
|
||||
* To start, you will need to specify the required parameters and provide a template for your results.
|
||||
* The content inside `md-autocomplete` will be treated as a template.
|
||||
*
|
||||
* In more complex cases, you may want to include other content such as a message to display when
|
||||
* no matches were found. You can do this by wrapping your template in `md-item-template` and adding
|
||||
* a tag for `md-not-found`. An example of this is shown below.
|
||||
* ### Validation
|
||||
*
|
||||
* You can use `ng-messages` to include validation the same way that you would normally validate;
|
||||
* however, if you want to replicate a standard input with a floating label, you will have to do the
|
||||
* following:
|
||||
*
|
||||
* - Make sure that your template is wrapped in `md-item-template`
|
||||
* - Add your `ng-messages` code inside of `md-autocomplete`
|
||||
* - Add your validation properties to `md-autocomplete` (ie. `required`)
|
||||
* - Add a `name` to `md-autocomplete` (to be used on the generated `input`)
|
||||
*
|
||||
* There is an example below of how this should look.
|
||||
*
|
||||
*
|
||||
* @param {expression} md-items An expression in the format of `item in items` to iterate over matches for your search.
|
||||
* @param {expression=} md-selected-item-change An expression to be run each time a new item is selected
|
||||
* @param {expression=} md-search-text-change An expression to be run each time the search text updates
|
||||
* @param {string=} md-search-text A model to bind the search query text to
|
||||
* @param {object=} md-selected-item A model to bind the selected item to
|
||||
* @param {string=} md-item-text An expression that will convert your object to a single string.
|
||||
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
|
||||
* @param {boolean=} md-no-cache Disables the internal caching that happens in autocomplete
|
||||
* @param {boolean=} ng-disabled Determines whether or not to disable the input field
|
||||
* @param {number=} md-min-length Specifies the minimum length of text before autocomplete will make suggestions
|
||||
* @param {number=} md-delay Specifies the amount of time (in milliseconds) to wait before looking for results
|
||||
* @param {boolean=} md-autofocus If true, will immediately focus the input element
|
||||
* @param {boolean=} md-autoselect If true, the first item will be selected by default
|
||||
* @param {string=} md-menu-class This will be applied to the dropdown menu for styling
|
||||
* @param {string=} md-floating-label This will add a floating label to autocomplete and wrap it in `md-input-container`
|
||||
*
|
||||
* @usage
|
||||
* ###Basic Example
|
||||
* <hljs lang="html">
|
||||
* <md-autocomplete
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-autocomplete>
|
||||
* </hljs>
|
||||
*
|
||||
* ###Example with "not found" message
|
||||
* <hljs lang="html">
|
||||
* <md-autocomplete
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <md-item-template>
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-item-template>
|
||||
* <md-not-found>
|
||||
* No matches found.
|
||||
* </md-not-found>
|
||||
* </md-autocomplete>
|
||||
* </hljs>
|
||||
*
|
||||
* In this example, our code utilizes `md-item-template` and `md-not-found` to specify the different
|
||||
* parts that make up our component.
|
||||
*
|
||||
* ### Example with validation
|
||||
* <hljs lang="html">
|
||||
* <form name="autocompleteForm">
|
||||
* <md-autocomplete
|
||||
* required
|
||||
* input-name="autocomplete"
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <md-item-template>
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-item-template>
|
||||
* <div ng-messages="autocompleteForm.autocomplete.$error">
|
||||
* <div ng-message="required">This field is required</div>
|
||||
* </div>
|
||||
* </md-autocomplete>
|
||||
* </form>
|
||||
* </hljs>
|
||||
*
|
||||
* In this example, our code utilizes `md-item-template` and `md-not-found` to specify the different
|
||||
* parts that make up our component.
|
||||
*/
|
||||
|
||||
function MdAutocomplete ($mdTheming, $mdUtil) {
|
||||
return {
|
||||
controller: 'MdAutocompleteCtrl',
|
||||
controllerAs: '$mdAutocompleteCtrl',
|
||||
scope: {
|
||||
inputName: '@mdInputName',
|
||||
inputMinlength: '@mdInputMinlength',
|
||||
inputMaxlength: '@mdInputMaxlength',
|
||||
searchText: '=?mdSearchText',
|
||||
selectedItem: '=?mdSelectedItem',
|
||||
itemsExpr: '@mdItems',
|
||||
itemText: '&mdItemText',
|
||||
placeholder: '@placeholder',
|
||||
noCache: '=?mdNoCache',
|
||||
itemChange: '&?mdSelectedItemChange',
|
||||
textChange: '&?mdSearchTextChange',
|
||||
minLength: '=?mdMinLength',
|
||||
delay: '=?mdDelay',
|
||||
autofocus: '=?mdAutofocus',
|
||||
floatingLabel: '@?mdFloatingLabel',
|
||||
autoselect: '=?mdAutoselect',
|
||||
menuClass: '@?mdMenuClass'
|
||||
},
|
||||
template: function (element, attr) {
|
||||
var noItemsTemplate = getNoItemsTemplate(),
|
||||
itemTemplate = getItemTemplate(),
|
||||
leftover = element.html();
|
||||
return '\
|
||||
<md-autocomplete-wrap\
|
||||
layout="row"\
|
||||
ng-class="{ \'md-whiteframe-z1\': !floatingLabel }"\
|
||||
role="listbox">\
|
||||
' + getInputElement() + '\
|
||||
<md-progress-linear\
|
||||
ng-if="$mdAutocompleteCtrl.loading"\
|
||||
md-mode="indeterminate"></md-progress-linear>\
|
||||
<ul role="presentation"\
|
||||
class="md-autocomplete-suggestions md-whiteframe-z1 {{menuClass || \'\'}}"\
|
||||
id="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
ng-hide="$mdAutocompleteCtrl.hidden"\
|
||||
ng-mouseenter="$mdAutocompleteCtrl.listEnter()"\
|
||||
ng-mouseleave="$mdAutocompleteCtrl.listLeave()"\
|
||||
ng-mouseup="$mdAutocompleteCtrl.mouseUp()">\
|
||||
<li ng-repeat="(index, item) in $mdAutocompleteCtrl.matches"\
|
||||
ng-class="{ selected: index === $mdAutocompleteCtrl.index }"\
|
||||
ng-click="$mdAutocompleteCtrl.select(index)"\
|
||||
md-autocomplete-list-item="$mdAutocompleteCtrl.itemName">\
|
||||
' + itemTemplate + '\
|
||||
</li>\
|
||||
' + noItemsTemplate + '\
|
||||
</ul>\
|
||||
</md-autocomplete-wrap>\
|
||||
<aria-status\
|
||||
class="md-visually-hidden"\
|
||||
role="status"\
|
||||
aria-live="assertive">\
|
||||
<p ng-repeat="message in $mdAutocompleteCtrl.messages" ng-if="message">{{message}}</p>\
|
||||
</aria-status>';
|
||||
|
||||
function getItemTemplate() {
|
||||
var templateTag = element.find('md-item-template').remove(),
|
||||
html = templateTag.length ? templateTag.html() : element.html();
|
||||
if (!templateTag.length) element.empty();
|
||||
return html;
|
||||
}
|
||||
|
||||
function getNoItemsTemplate() {
|
||||
var templateTag = element.find('md-not-found').remove(),
|
||||
template = templateTag.length ? templateTag.html() : '';
|
||||
return template
|
||||
? '<li ng-if="!$mdAutocompleteCtrl.matches.length && !$mdAutocompleteCtrl.loading\
|
||||
&& !$mdAutocompleteCtrl.hidden"\
|
||||
ng-hide="$mdAutocompleteCtrl.hidden"\
|
||||
md-autocomplete-parent-scope>' + template + '</li>'
|
||||
: '';
|
||||
|
||||
}
|
||||
|
||||
function getInputElement() {
|
||||
if (attr.mdFloatingLabel) {
|
||||
return '\
|
||||
<md-input-container flex ng-if="floatingLabel">\
|
||||
<label>{{floatingLabel}}</label>\
|
||||
<input type="search"\
|
||||
id="fl-input-{{$mdAutocompleteCtrl.id}}"\
|
||||
name="{{inputName}}"\
|
||||
autocomplete="off"\
|
||||
ng-required="isRequired"\
|
||||
ng-minlength="inputMinlength"\
|
||||
ng-maxlength="inputMaxlength"\
|
||||
ng-disabled="$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-model="$mdAutocompleteCtrl.scope.searchText"\
|
||||
ng-keydown="$mdAutocompleteCtrl.keydown($event)"\
|
||||
ng-blur="$mdAutocompleteCtrl.blur()"\
|
||||
ng-focus="$mdAutocompleteCtrl.focus()"\
|
||||
aria-owns="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
aria-label="{{floatingLabel}}"\
|
||||
aria-autocomplete="list"\
|
||||
aria-haspopup="true"\
|
||||
aria-activedescendant=""\
|
||||
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
|
||||
<div md-autocomplete-parent-scope md-autocomplete-replace>' + leftover + '</div>\
|
||||
</md-input-container>';
|
||||
} else {
|
||||
return '\
|
||||
<input flex type="search"\
|
||||
id="input-{{$mdAutocompleteCtrl.id}}"\
|
||||
name="{{inputName}}"\
|
||||
ng-if="!floatingLabel"\
|
||||
autocomplete="off"\
|
||||
ng-required="isRequired"\
|
||||
ng-disabled="$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-model="$mdAutocompleteCtrl.scope.searchText"\
|
||||
ng-keydown="$mdAutocompleteCtrl.keydown($event)"\
|
||||
ng-blur="$mdAutocompleteCtrl.blur()"\
|
||||
ng-focus="$mdAutocompleteCtrl.focus()"\
|
||||
placeholder="{{placeholder}}"\
|
||||
aria-owns="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
aria-label="{{placeholder}}"\
|
||||
aria-autocomplete="list"\
|
||||
aria-haspopup="true"\
|
||||
aria-activedescendant=""\
|
||||
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
|
||||
<button\
|
||||
type="button"\
|
||||
tabindex="-1"\
|
||||
ng-if="$mdAutocompleteCtrl.scope.searchText && !$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-click="$mdAutocompleteCtrl.clear()">\
|
||||
<md-icon md-svg-icon="md-close"></md-icon>\
|
||||
<span class="md-visually-hidden">Clear</span>\
|
||||
</button>\
|
||||
';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
MdAutocomplete.$inject = ["$mdTheming", "$mdUtil"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.controller('MdHighlightCtrl', MdHighlightCtrl);
|
||||
|
||||
function MdHighlightCtrl ($scope, $element, $interpolate) {
|
||||
this.init = init;
|
||||
|
||||
return init();
|
||||
|
||||
function init (term) {
|
||||
var unsafeText = $interpolate($element.html())($scope),
|
||||
text = angular.element('<div>').text(unsafeText).html(),
|
||||
flags = $element.attr('md-highlight-flags') || '',
|
||||
watcher = $scope.$watch(term, function (term) {
|
||||
var regex = getRegExp(term, flags),
|
||||
html = text.replace(regex, '<span class="highlight">$&</span>');
|
||||
$element.html(html);
|
||||
});
|
||||
$element.on('$destroy', function () { watcher(); });
|
||||
}
|
||||
|
||||
function sanitize (term) {
|
||||
if (!term) return term;
|
||||
return term.replace(/[\\\^\$\*\+\?\.\(\)\|\{\}\[\]]/g, '\\$&');
|
||||
}
|
||||
|
||||
function getRegExp (text, flags) {
|
||||
var str = '';
|
||||
if (flags.indexOf('^') >= 1) str += '^';
|
||||
str += text;
|
||||
if (flags.indexOf('$') >= 1) str += '$';
|
||||
return new RegExp(sanitize(str), flags.replace(/[\$\^]/g, ''));
|
||||
}
|
||||
}
|
||||
MdHighlightCtrl.$inject = ["$scope", "$element", "$interpolate"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdHighlightText', MdHighlight);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdHighlightText
|
||||
* @module material.components.autocomplete
|
||||
*
|
||||
* @description
|
||||
* The `md-highlight-text` directive allows you to specify text that should be highlighted within
|
||||
* an element. Highlighted text will be wrapped in `<span class="highlight"></span>` which can
|
||||
* be styled through CSS. Please note that child elements may not be used with this directive.
|
||||
*
|
||||
* @param {string} md-highlight-text A model to be searched for
|
||||
* @param {string=} md-highlight-flags A list of flags (loosely based on JavaScript RexExp flags).
|
||||
* #### **Supported flags**:
|
||||
* - `g`: Find all matches within the provided text
|
||||
* - `i`: Ignore case when searching for matches
|
||||
* - `$`: Only match if the text ends with the search term
|
||||
* - `^`: Only match if the text begins with the search term
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <input placeholder="Enter a search term..." ng-model="searchTerm" type="text" />
|
||||
* <ul>
|
||||
* <li ng-repeat="result in results" md-highlight-text="searchTerm">
|
||||
* {{result.text}}
|
||||
* </li>
|
||||
* </ul>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
function MdHighlight () {
|
||||
return {
|
||||
terminal: true,
|
||||
scope: false,
|
||||
controller: 'MdHighlightCtrl',
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
ctrl.init(attr.mdHighlightText);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocompleteListItem', MdAutocompleteListItem);
|
||||
|
||||
function MdAutocompleteListItem ($compile, $mdUtil) {
|
||||
return {
|
||||
terminal: true,
|
||||
link: postLink,
|
||||
scope: false
|
||||
};
|
||||
function postLink (scope, element, attr) {
|
||||
var ctrl = scope.$parent.$mdAutocompleteCtrl,
|
||||
newScope = ctrl.parent.$new(false, ctrl.parent),
|
||||
itemName = ctrl.scope.$eval(attr.mdAutocompleteListItem);
|
||||
newScope[itemName] = scope.item;
|
||||
$compile(element.contents())(newScope);
|
||||
element.attr({
|
||||
role: 'option',
|
||||
id: 'item_' + $mdUtil.nextUid()
|
||||
});
|
||||
}
|
||||
}
|
||||
MdAutocompleteListItem.$inject = ["$compile", "$mdUtil"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocompleteParentScope', MdAutocompleteParentScope);
|
||||
|
||||
function MdAutocompleteParentScope ($compile, $mdUtil) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
terminal: true,
|
||||
link: postLink,
|
||||
scope: false
|
||||
};
|
||||
function postLink (scope, element, attr) {
|
||||
var ctrl = scope.$parent.$mdAutocompleteCtrl;
|
||||
$compile(element.contents())(ctrl.parent);
|
||||
if (attr.hasOwnProperty('mdAutocompleteReplace')) {
|
||||
element.after(element.contents());
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
MdAutocompleteParentScope.$inject = ["$compile", "$mdUtil"];
|
||||
|
||||
ng.material.components.autocomplete = angular.module("material.components.autocomplete");
|
||||
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-backdrop.md-opaque.md-THEME_NAME-theme {
|
||||
background-color: '{{foreground-4-0.5}}'; }
|
||||
@@ -0,0 +1,59 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-backdrop {
|
||||
z-index: 50;
|
||||
background-color: transparent;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
left: 0;
|
||||
right: 0; }
|
||||
md-backdrop.md-select-backdrop {
|
||||
z-index: 81; }
|
||||
md-backdrop.md-dialog-backdrop {
|
||||
z-index: 79; }
|
||||
md-backdrop.md-bottom-sheet-backdrop {
|
||||
z-index: 69; }
|
||||
md-backdrop.md-sidenav-backdrop {
|
||||
z-index: 59; }
|
||||
md-backdrop.md-click-catcher {
|
||||
top: 0;
|
||||
position: fixed; }
|
||||
md-backdrop.ng-enter {
|
||||
-webkit-animation: cubic-bezier(0.25, 0.8, 0.25, 1) mdBackdropFadeIn 0.5s both;
|
||||
animation: cubic-bezier(0.25, 0.8, 0.25, 1) mdBackdropFadeIn 0.5s both; }
|
||||
md-backdrop.ng-leave {
|
||||
-webkit-animation: cubic-bezier(0.55, 0, 0.55, 0.2) mdBackdropFadeOut 0.2s both;
|
||||
animation: cubic-bezier(0.55, 0, 0.55, 0.2) mdBackdropFadeOut 0.2s both; }
|
||||
|
||||
@-webkit-keyframes mdBackdropFadeIn {
|
||||
from {
|
||||
opacity: 0; }
|
||||
|
||||
to {
|
||||
opacity: 1; } }
|
||||
|
||||
@keyframes mdBackdropFadeIn {
|
||||
from {
|
||||
opacity: 0; }
|
||||
|
||||
to {
|
||||
opacity: 1; } }
|
||||
|
||||
@-webkit-keyframes mdBackdropFadeOut {
|
||||
from {
|
||||
opacity: 1; }
|
||||
|
||||
to {
|
||||
opacity: 0; } }
|
||||
|
||||
@keyframes mdBackdropFadeOut {
|
||||
from {
|
||||
opacity: 1; }
|
||||
|
||||
to {
|
||||
opacity: 0; } }
|
||||
38
www/lib/angular-material/modules/closure/backdrop/backdrop.js
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.backdrop');
|
||||
goog.require('ng.material.core');
|
||||
/*
|
||||
* @ngdoc module
|
||||
* @name material.components.backdrop
|
||||
* @description Backdrop
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdBackdrop
|
||||
* @module material.components.backdrop
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* `<md-backdrop>` is a backdrop element used by other components, such as dialog and bottom sheet.
|
||||
* Apply class `opaque` to make the backdrop use the theme backdrop color.
|
||||
*
|
||||
*/
|
||||
|
||||
angular.module('material.components.backdrop', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdBackdrop', BackdropDirective);
|
||||
|
||||
function BackdropDirective($mdTheming) {
|
||||
return $mdTheming;
|
||||
}
|
||||
BackdropDirective.$inject = ["$mdTheming"];
|
||||
|
||||
ng.material.components.backdrop = angular.module("material.components.backdrop");
|
||||
@@ -0,0 +1,16 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-bottom-sheet.md-THEME_NAME-theme {
|
||||
background-color: '{{background-50}}';
|
||||
border-top-color: '{{background-300}}'; }
|
||||
md-bottom-sheet.md-THEME_NAME-theme.md-list md-list-item {
|
||||
color: '{{foreground-1}}'; }
|
||||
md-bottom-sheet.md-THEME_NAME-theme .md-subheader {
|
||||
background-color: '{{background-50}}'; }
|
||||
md-bottom-sheet.md-THEME_NAME-theme .md-subheader {
|
||||
color: '{{foreground-1}}'; }
|
||||
@@ -0,0 +1,170 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-bottom-sheet {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
padding: 8px 16px 88px 16px;
|
||||
z-index: 70;
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
-webkit-transform: translate3d(0, 80px, 0);
|
||||
transform: translate3d(0, 80px, 0);
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transition-property: -webkit-transform;
|
||||
transition-property: transform; }
|
||||
md-bottom-sheet.md-has-header {
|
||||
padding-top: 0; }
|
||||
md-bottom-sheet.ng-enter {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 100%, 0);
|
||||
transform: translate3d(0, 100%, 0); }
|
||||
md-bottom-sheet.ng-enter-active {
|
||||
opacity: 1;
|
||||
display: block;
|
||||
-webkit-transform: translate3d(0, 80px, 0) !important;
|
||||
transform: translate3d(0, 80px, 0) !important; }
|
||||
md-bottom-sheet.ng-leave-active {
|
||||
-webkit-transform: translate3d(0, 100%, 0) !important;
|
||||
transform: translate3d(0, 100%, 0) !important;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-bottom-sheet .md-subheader {
|
||||
background-color: transparent;
|
||||
font-family: RobotoDraft, Roboto, 'Helvetica Neue', sans-serif;
|
||||
line-height: 56px;
|
||||
padding: 0;
|
||||
white-space: nowrap; }
|
||||
md-bottom-sheet md-inline-icon {
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
fill: #444; }
|
||||
md-bottom-sheet md-list-item {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
outline: none; }
|
||||
md-bottom-sheet md-list-item:hover {
|
||||
cursor: pointer; }
|
||||
md-bottom-sheet.md-list md-list-item {
|
||||
padding: 0;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
height: 48px; }
|
||||
md-bottom-sheet.md-list md-list-item div.md-icon-container {
|
||||
display: inline-block;
|
||||
height: 24px;
|
||||
margin-right: 32px; }
|
||||
md-bottom-sheet.md-grid {
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
padding-top: 0; }
|
||||
md-bottom-sheet.md-grid md-list {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-flex-wrap: wrap;
|
||||
-ms-flex-wrap: wrap;
|
||||
flex-wrap: wrap;
|
||||
transition: all 0.5s;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center; }
|
||||
md-bottom-sheet.md-grid md-list-item {
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
transition: all 0.5s;
|
||||
height: 96px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
/* Mixin for how many grid items to show per row */ }
|
||||
@media screen and (max-width: 600px) {
|
||||
md-bottom-sheet.md-grid md-list-item {
|
||||
-webkit-flex: 1 1 33.33333%;
|
||||
-ms-flex: 1 1 33.33333%;
|
||||
flex: 1 1 33.33333%;
|
||||
max-width: 33.33333%; }
|
||||
md-bottom-sheet.md-grid md-list-item:nth-of-type(3n+1) {
|
||||
-webkit-align-items: flex-start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start; }
|
||||
md-bottom-sheet.md-grid md-list-item:nth-of-type(3n) {
|
||||
-webkit-align-items: flex-end;
|
||||
-ms-flex-align: end;
|
||||
align-items: flex-end; } }
|
||||
@media screen and (min-width: 600px) and (max-width: 960px) {
|
||||
md-bottom-sheet.md-grid md-list-item {
|
||||
-webkit-flex: 1 1 25%;
|
||||
-ms-flex: 1 1 25%;
|
||||
flex: 1 1 25%;
|
||||
max-width: 25%; } }
|
||||
@media screen and (min-width: 960px) and (max-width: 1200px) {
|
||||
md-bottom-sheet.md-grid md-list-item {
|
||||
-webkit-flex: 1 1 16.66667%;
|
||||
-ms-flex: 1 1 16.66667%;
|
||||
flex: 1 1 16.66667%;
|
||||
max-width: 16.66667%; } }
|
||||
@media screen and (min-width: 1200px) {
|
||||
md-bottom-sheet.md-grid md-list-item {
|
||||
-webkit-flex: 1 1 14.28571%;
|
||||
-ms-flex: 1 1 14.28571%;
|
||||
flex: 1 1 14.28571%;
|
||||
max-width: 14.28571%; } }
|
||||
md-bottom-sheet.md-grid md-list-item .md-list-item-content {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: 48px;
|
||||
padding-bottom: 16px; }
|
||||
md-bottom-sheet.md-grid md-list-item .md-grid-item-content {
|
||||
border: 1px solid transparent;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: 80px; }
|
||||
md-bottom-sheet.md-grid md-list-item .md-icon-container {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
height: 48px;
|
||||
width: 48px;
|
||||
margin: 0 0; }
|
||||
md-bottom-sheet.md-grid md-list-item .md-grid-text {
|
||||
font-weight: 400;
|
||||
line-height: 16px;
|
||||
font-size: 13px;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
width: 64px;
|
||||
text-align: center;
|
||||
text-transform: none;
|
||||
padding-top: 8px; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-bottom-sheet {
|
||||
border: 1px solid #fff; } }
|
||||
267
www/lib/angular-material/modules/closure/bottomSheet/bottomSheet.js
vendored
Normal file
@@ -0,0 +1,267 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.bottomSheet');
|
||||
goog.require('ng.material.components.backdrop');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.bottomSheet
|
||||
* @description
|
||||
* BottomSheet
|
||||
*/
|
||||
angular.module('material.components.bottomSheet', [
|
||||
'material.core',
|
||||
'material.components.backdrop'
|
||||
])
|
||||
.directive('mdBottomSheet', MdBottomSheetDirective)
|
||||
.provider('$mdBottomSheet', MdBottomSheetProvider);
|
||||
|
||||
function MdBottomSheetDirective() {
|
||||
return {
|
||||
restrict: 'E'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $mdBottomSheet
|
||||
* @module material.components.bottomSheet
|
||||
*
|
||||
* @description
|
||||
* `$mdBottomSheet` opens a bottom sheet over the app and provides a simple promise API.
|
||||
*
|
||||
* ## Restrictions
|
||||
*
|
||||
* - The bottom sheet's template must have an outer `<md-bottom-sheet>` element.
|
||||
* - Add the `md-grid` class to the bottom sheet for a grid layout.
|
||||
* - Add the `md-list` class to the bottom sheet for a list layout.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div ng-controller="MyController">
|
||||
* <md-button ng-click="openBottomSheet()">
|
||||
* Open a Bottom Sheet!
|
||||
* </md-button>
|
||||
* </div>
|
||||
* </hljs>
|
||||
* <hljs lang="js">
|
||||
* var app = angular.module('app', ['ngMaterial']);
|
||||
* app.controller('MyController', function($scope, $mdBottomSheet) {
|
||||
* $scope.openBottomSheet = function() {
|
||||
* $mdBottomSheet.show({
|
||||
* template: '<md-bottom-sheet>Hello!</md-bottom-sheet>'
|
||||
* });
|
||||
* };
|
||||
* });
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdBottomSheet#show
|
||||
*
|
||||
* @description
|
||||
* Show a bottom sheet with the specified options.
|
||||
*
|
||||
* @param {object} options An options object, with the following properties:
|
||||
*
|
||||
* - `templateUrl` - `{string=}`: The url of an html template file that will
|
||||
* be used as the content of the bottom sheet. Restrictions: the template must
|
||||
* have an outer `md-bottom-sheet` element.
|
||||
* - `template` - `{string=}`: Same as templateUrl, except this is an actual
|
||||
* template string.
|
||||
* - `scope` - `{object=}`: the scope to link the template / controller to. If none is specified, it will create a new child scope.
|
||||
* This scope will be destroyed when the bottom sheet is removed unless `preserveScope` is set to true.
|
||||
* - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed. Default is false
|
||||
* - `controller` - `{string=}`: The controller to associate with this bottom sheet.
|
||||
* - `locals` - `{string=}`: An object containing key/value pairs. The keys will
|
||||
* be used as names of values to inject into the controller. For example,
|
||||
* `locals: {three: 3}` would inject `three` into the controller with the value
|
||||
* of 3.
|
||||
* - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,
|
||||
* the location of the click will be used as the starting point for the opening animation
|
||||
* of the the dialog.
|
||||
* - `resolve` - `{object=}`: Similar to locals, except it takes promises as values
|
||||
* and the bottom sheet will not open until the promises resolve.
|
||||
* - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
|
||||
* - `parent` - `{element=}`: The element to append the bottom sheet to. The `parent` may be a `function`, `string`,
|
||||
* `object`, or null. Defaults to appending to the body of the root element (or the root element) of the application.
|
||||
* e.g. angular.element(document.getElementById('content')) or "#content"
|
||||
* - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the bottom sheet is open.
|
||||
* Default true.
|
||||
*
|
||||
* @returns {promise} A promise that can be resolved with `$mdBottomSheet.hide()` or
|
||||
* rejected with `$mdBottomSheet.cancel()`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdBottomSheet#hide
|
||||
*
|
||||
* @description
|
||||
* Hide the existing bottom sheet and resolve the promise returned from
|
||||
* `$mdBottomSheet.show()`. This call will close the most recently opened/current bottomsheet (if any).
|
||||
*
|
||||
* @param {*=} response An argument for the resolved promise.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdBottomSheet#cancel
|
||||
*
|
||||
* @description
|
||||
* Hide the existing bottom sheet and reject the promise returned from
|
||||
* `$mdBottomSheet.show()`.
|
||||
*
|
||||
* @param {*=} response An argument for the rejected promise.
|
||||
*
|
||||
*/
|
||||
|
||||
function MdBottomSheetProvider($$interimElementProvider) {
|
||||
// how fast we need to flick down to close the sheet, pixels/ms
|
||||
var CLOSING_VELOCITY = 0.5;
|
||||
var PADDING = 80; // same as css
|
||||
|
||||
bottomSheetDefaults.$inject = ["$animate", "$mdConstant", "$mdUtil", "$timeout", "$compile", "$mdTheming", "$mdBottomSheet", "$rootElement", "$mdGesture"];
|
||||
return $$interimElementProvider('$mdBottomSheet')
|
||||
.setDefaults({
|
||||
methods: ['disableParentScroll', 'escapeToClose', 'targetEvent'],
|
||||
options: bottomSheetDefaults
|
||||
});
|
||||
|
||||
/* ngInject */
|
||||
function bottomSheetDefaults($animate, $mdConstant, $mdUtil, $timeout, $compile, $mdTheming, $mdBottomSheet, $rootElement, $mdGesture) {
|
||||
var backdrop;
|
||||
|
||||
return {
|
||||
themable: true,
|
||||
targetEvent: null,
|
||||
onShow: onShow,
|
||||
onRemove: onRemove,
|
||||
escapeToClose: true,
|
||||
disableParentScroll: true
|
||||
};
|
||||
|
||||
|
||||
function onShow(scope, element, options) {
|
||||
|
||||
element = $mdUtil.extractElementByName(element, 'md-bottom-sheet');
|
||||
|
||||
// Add a backdrop that will close on click
|
||||
backdrop = $compile('<md-backdrop class="md-opaque md-bottom-sheet-backdrop">')(scope);
|
||||
backdrop.on('click', function() {
|
||||
$timeout($mdBottomSheet.cancel);
|
||||
});
|
||||
$mdTheming.inherit(backdrop, options.parent);
|
||||
|
||||
$animate.enter(backdrop, options.parent, null);
|
||||
|
||||
var bottomSheet = new BottomSheet(element, options.parent);
|
||||
options.bottomSheet = bottomSheet;
|
||||
|
||||
// Give up focus on calling item
|
||||
options.targetEvent && angular.element(options.targetEvent.target).blur();
|
||||
$mdTheming.inherit(bottomSheet.element, options.parent);
|
||||
|
||||
if (options.disableParentScroll) {
|
||||
options.lastOverflow = options.parent.css('overflow');
|
||||
options.parent.css('overflow', 'hidden');
|
||||
}
|
||||
|
||||
return $animate.enter(bottomSheet.element, options.parent)
|
||||
.then(function() {
|
||||
var focusable = angular.element(
|
||||
element[0].querySelector('button') ||
|
||||
element[0].querySelector('a') ||
|
||||
element[0].querySelector('[ng-click]')
|
||||
);
|
||||
focusable.focus();
|
||||
|
||||
if (options.escapeToClose) {
|
||||
options.rootElementKeyupCallback = function(e) {
|
||||
if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
|
||||
$timeout($mdBottomSheet.cancel);
|
||||
}
|
||||
};
|
||||
$rootElement.on('keyup', options.rootElementKeyupCallback);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function onRemove(scope, element, options) {
|
||||
|
||||
var bottomSheet = options.bottomSheet;
|
||||
|
||||
$animate.leave(backdrop);
|
||||
return $animate.leave(bottomSheet.element).then(function() {
|
||||
if (options.disableParentScroll) {
|
||||
options.parent.css('overflow', options.lastOverflow);
|
||||
delete options.lastOverflow;
|
||||
}
|
||||
|
||||
bottomSheet.cleanup();
|
||||
|
||||
// Restore focus
|
||||
options.targetEvent && angular.element(options.targetEvent.target).focus();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* BottomSheet class to apply bottom-sheet behavior to an element
|
||||
*/
|
||||
function BottomSheet(element, parent) {
|
||||
var deregister = $mdGesture.register(parent, 'drag', { horizontal: false });
|
||||
parent.on('$md.dragstart', onDragStart)
|
||||
.on('$md.drag', onDrag)
|
||||
.on('$md.dragend', onDragEnd);
|
||||
|
||||
return {
|
||||
element: element,
|
||||
cleanup: function cleanup() {
|
||||
deregister();
|
||||
parent.off('$md.dragstart', onDragStart)
|
||||
.off('$md.drag', onDrag)
|
||||
.off('$md.dragend', onDragEnd);
|
||||
}
|
||||
};
|
||||
|
||||
function onDragStart(ev) {
|
||||
// Disable transitions on transform so that it feels fast
|
||||
element.css($mdConstant.CSS.TRANSITION_DURATION, '0ms');
|
||||
}
|
||||
|
||||
function onDrag(ev) {
|
||||
var transform = ev.pointer.distanceY;
|
||||
if (transform < 5) {
|
||||
// Slow down drag when trying to drag up, and stop after PADDING
|
||||
transform = Math.max(-PADDING, transform / 2);
|
||||
}
|
||||
element.css($mdConstant.CSS.TRANSFORM, 'translate3d(0,' + (PADDING + transform) + 'px,0)');
|
||||
}
|
||||
|
||||
function onDragEnd(ev) {
|
||||
if (ev.pointer.distanceY > 0 &&
|
||||
(ev.pointer.distanceY > 20 || Math.abs(ev.pointer.velocityY) > CLOSING_VELOCITY)) {
|
||||
var distanceRemaining = element.prop('offsetHeight') - ev.pointer.distanceY;
|
||||
var transitionDuration = Math.min(distanceRemaining / ev.pointer.velocityY * 0.75, 500);
|
||||
element.css($mdConstant.CSS.TRANSITION_DURATION, transitionDuration + 'ms');
|
||||
$timeout($mdBottomSheet.cancel);
|
||||
} else {
|
||||
element.css($mdConstant.CSS.TRANSITION_DURATION, '');
|
||||
element.css($mdConstant.CSS.TRANSFORM, '');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
MdBottomSheetProvider.$inject = ["$$interimElementProvider"];
|
||||
|
||||
ng.material.components.bottomSheet = angular.module("material.components.bottomSheet");
|
||||
@@ -0,0 +1,94 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
a.md-button.md-THEME_NAME-theme, .md-button.md-THEME_NAME-theme {
|
||||
border-radius: 3px; }
|
||||
a.md-button.md-THEME_NAME-theme:not([disabled]):hover, .md-button.md-THEME_NAME-theme:not([disabled]):hover {
|
||||
background-color: '{{background-500-0.2}}'; }
|
||||
a.md-button.md-THEME_NAME-theme:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme:not([disabled]).md-focused {
|
||||
background-color: '{{background-500-0.2}}'; }
|
||||
a.md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover, .md-button.md-THEME_NAME-theme:not([disabled]).md-icon-button:hover {
|
||||
background-color: transparent; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab, .md-button.md-THEME_NAME-theme.md-fab {
|
||||
border-radius: 50%;
|
||||
background-color: '{{accent-color}}';
|
||||
color: '{{accent-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab md-icon, .md-button.md-THEME_NAME-theme.md-fab md-icon {
|
||||
color: '{{accent-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover {
|
||||
background-color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused {
|
||||
background-color: '{{accent-A700}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-icon-button, .md-button.md-THEME_NAME-theme.md-icon-button {
|
||||
border-radius: 50%; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary, .md-button.md-THEME_NAME-theme.md-primary {
|
||||
color: '{{primary-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary.md-raised, a.md-button.md-THEME_NAME-theme.md-primary.md-fab, .md-button.md-THEME_NAME-theme.md-primary.md-raised, .md-button.md-THEME_NAME-theme.md-primary.md-fab {
|
||||
color: '{{primary-contrast}}';
|
||||
background-color: '{{primary-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]) md-icon {
|
||||
color: '{{primary-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]):hover {
|
||||
background-color: '{{primary-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-primary.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-primary.md-fab:not([disabled]).md-focused {
|
||||
background-color: '{{primary-600}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-primary:not([disabled]) md-icon {
|
||||
color: '{{primary-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab, .md-button.md-THEME_NAME-theme.md-fab {
|
||||
border-radius: 50%;
|
||||
background-color: '{{accent-color}}';
|
||||
color: '{{accent-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]) .md-icon, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]) .md-icon {
|
||||
color: '{{accent-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]):hover {
|
||||
background-color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-fab:not([disabled]).md-focused {
|
||||
background-color: '{{accent-A700}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-raised, .md-button.md-THEME_NAME-theme.md-raised {
|
||||
color: '{{background-contrast}}';
|
||||
background-color: '{{background-50}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]) .md-icon, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]) .md-icon {
|
||||
color: '{{background-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]):hover {
|
||||
background-color: '{{background-50}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-raised:not([disabled]).md-focused {
|
||||
background-color: '{{background-200}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn, .md-button.md-THEME_NAME-theme.md-warn {
|
||||
color: '{{warn-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn.md-raised, a.md-button.md-THEME_NAME-theme.md-warn.md-fab, .md-button.md-THEME_NAME-theme.md-warn.md-raised, .md-button.md-THEME_NAME-theme.md-warn.md-fab {
|
||||
color: '{{warn-contrast}}';
|
||||
background-color: '{{warn-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]) md-icon {
|
||||
color: '{{warn-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]):hover {
|
||||
background-color: '{{warn-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-warn.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-warn.md-fab:not([disabled]).md-focused {
|
||||
background-color: '{{warn-700}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-warn:not([disabled]) md-icon {
|
||||
color: '{{warn-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent, .md-button.md-THEME_NAME-theme.md-accent {
|
||||
color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent.md-raised, a.md-button.md-THEME_NAME-theme.md-accent.md-fab, .md-button.md-THEME_NAME-theme.md-accent.md-raised, .md-button.md-THEME_NAME-theme.md-accent.md-fab {
|
||||
color: '{{accent-contrast}}';
|
||||
background-color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]) md-icon {
|
||||
color: '{{accent-contrast}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]):hover, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]):hover {
|
||||
background-color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused, a.md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-accent.md-raised:not([disabled]).md-focused, .md-button.md-THEME_NAME-theme.md-accent.md-fab:not([disabled]).md-focused {
|
||||
background-color: '{{accent-700}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon, .md-button.md-THEME_NAME-theme.md-accent:not([disabled]) md-icon {
|
||||
color: '{{accent-color}}'; }
|
||||
a.md-button.md-THEME_NAME-theme[disabled], a.md-button.md-THEME_NAME-theme.md-raised[disabled], a.md-button.md-THEME_NAME-theme.md-fab[disabled], a.md-button.md-THEME_NAME-theme.md-accent[disabled], a.md-button.md-THEME_NAME-theme.md-warn[disabled], .md-button.md-THEME_NAME-theme[disabled], .md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled], .md-button.md-THEME_NAME-theme.md-accent[disabled], .md-button.md-THEME_NAME-theme.md-warn[disabled] {
|
||||
color: '{{foreground-3}}';
|
||||
cursor: not-allowed; }
|
||||
a.md-button.md-THEME_NAME-theme[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon, a.md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon, .md-button.md-THEME_NAME-theme[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-raised[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-fab[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-accent[disabled] md-icon, .md-button.md-THEME_NAME-theme.md-warn[disabled] md-icon {
|
||||
color: '{{foreground-3}}'; }
|
||||
a.md-button.md-THEME_NAME-theme.md-raised[disabled], a.md-button.md-THEME_NAME-theme.md-fab[disabled], .md-button.md-THEME_NAME-theme.md-raised[disabled], .md-button.md-THEME_NAME-theme.md-fab[disabled] {
|
||||
background-color: '{{foreground-4}}'; }
|
||||
a.md-button.md-THEME_NAME-theme[disabled], .md-button.md-THEME_NAME-theme[disabled] {
|
||||
background-color: transparent; }
|
||||
158
www/lib/angular-material/modules/closure/button/button.css
Normal file
@@ -0,0 +1,158 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
/**
|
||||
* Position a FAB button.
|
||||
*/
|
||||
.md-button {
|
||||
box-sizing: border-box;
|
||||
color: currentColor;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
position: relative;
|
||||
outline: none;
|
||||
border: 0;
|
||||
display: inline-table;
|
||||
padding: 0 6px;
|
||||
margin: 6px 8px;
|
||||
line-height: 36px;
|
||||
min-height: 36px;
|
||||
background: transparent;
|
||||
white-space: nowrap;
|
||||
min-width: 88px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-weight: 500;
|
||||
font-size: 14px;
|
||||
font-style: inherit;
|
||||
font-variant: inherit;
|
||||
font-family: inherit;
|
||||
text-decoration: none;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
transition: box-shadow 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), background-color 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
.md-button *, .md-button *:before, .md-button *:after {
|
||||
box-sizing: border-box; }
|
||||
.md-button:focus {
|
||||
outline: none; }
|
||||
.md-button:hover, .md-button:focus {
|
||||
text-decoration: none; }
|
||||
.md-button.ng-hide, .md-button.ng-leave {
|
||||
transition: none; }
|
||||
.md-button.md-cornered {
|
||||
border-radius: 0; }
|
||||
.md-button.md-icon {
|
||||
padding: 0;
|
||||
background: none; }
|
||||
.md-button.md-icon-button {
|
||||
margin: 0 6px;
|
||||
height: 48px;
|
||||
min-width: 0;
|
||||
line-height: 48px;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
width: 48px;
|
||||
border-radius: 50%; }
|
||||
.md-button.md-icon-button .md-ripple-container {
|
||||
border-radius: 50%;
|
||||
background-clip: padding-box;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC'); }
|
||||
.md-button.md-fab {
|
||||
z-index: 20;
|
||||
line-height: 56px;
|
||||
min-width: 0;
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
vertical-align: middle;
|
||||
border-radius: 50%;
|
||||
background-clip: padding-box;
|
||||
overflow: hidden;
|
||||
transition: 0.2s linear;
|
||||
transition-property: background-color, box-shadow; }
|
||||
.md-button.md-fab.md-fab-bottom-right {
|
||||
top: auto;
|
||||
right: 20px;
|
||||
bottom: 20px;
|
||||
left: auto;
|
||||
position: absolute; }
|
||||
.md-button.md-fab.md-fab-bottom-left {
|
||||
top: auto;
|
||||
right: auto;
|
||||
bottom: 20px;
|
||||
left: 20px;
|
||||
position: absolute; }
|
||||
.md-button.md-fab.md-fab-top-right {
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
bottom: auto;
|
||||
left: auto;
|
||||
position: absolute; }
|
||||
.md-button.md-fab.md-fab-top-left {
|
||||
top: 20px;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
left: 20px;
|
||||
position: absolute; }
|
||||
.md-button.md-fab .md-ripple-container {
|
||||
border-radius: 50%;
|
||||
background-clip: padding-box;
|
||||
overflow: hidden;
|
||||
-webkit-mask-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAIAAACQd1PeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAA5JREFUeNpiYGBgAAgwAAAEAAGbA+oJAAAAAElFTkSuQmCC'); }
|
||||
.md-button.md-fab md-icon {
|
||||
margin-top: 0; }
|
||||
.md-button.md-fab.md-mini {
|
||||
line-height: 40px;
|
||||
width: 40px;
|
||||
height: 40px; }
|
||||
|
||||
.md-toast-open-top .md-button.md-fab-top-left, .md-toast-open-top .md-button.md-fab-top-right {
|
||||
-webkit-transform: translate3d(0, 42px, 0);
|
||||
transform: translate3d(0, 42px, 0); }
|
||||
.md-toast-open-top .md-button.md-fab-top-left:not([disabled]).md-focused, .md-toast-open-top .md-button.md-fab-top-left:not([disabled]):hover, .md-toast-open-top .md-button.md-fab-top-right:not([disabled]).md-focused, .md-toast-open-top .md-button.md-fab-top-right:not([disabled]):hover {
|
||||
-webkit-transform: translate3d(0, 41px, 0);
|
||||
transform: translate3d(0, 41px, 0); }
|
||||
|
||||
.md-toast-open-bottom .md-button.md-fab-bottom-left, .md-toast-open-bottom .md-button.md-fab-bottom-right {
|
||||
-webkit-transform: translate3d(0, -42px, 0);
|
||||
transform: translate3d(0, -42px, 0); }
|
||||
.md-toast-open-bottom .md-button.md-fab-bottom-left:not([disabled]).md-focused, .md-toast-open-bottom .md-button.md-fab-bottom-left:not([disabled]):hover, .md-toast-open-bottom .md-button.md-fab-bottom-right:not([disabled]).md-focused, .md-toast-open-bottom .md-button.md-fab-bottom-right:not([disabled]):hover {
|
||||
-webkit-transform: translate3d(0, -43px, 0);
|
||||
transform: translate3d(0, -43px, 0); }
|
||||
|
||||
.md-button-group {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
width: 100%; }
|
||||
|
||||
.md-button-group > .md-button {
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
width: 0;
|
||||
border-width: 1px 0px 1px 1px;
|
||||
border-radius: 0;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap; }
|
||||
.md-button-group > .md-button:first-child {
|
||||
border-radius: 2px 0px 0px 2px; }
|
||||
.md-button-group > .md-button:last-child {
|
||||
border-right-width: 1px;
|
||||
border-radius: 0px 2px 2px 0px; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
.md-button.md-raised, .md-button.md-fab {
|
||||
border: 1px solid #fff; } }
|
||||
135
www/lib/angular-material/modules/closure/button/button.js
vendored
Normal file
@@ -0,0 +1,135 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.button');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.button
|
||||
* @description
|
||||
*
|
||||
* Button
|
||||
*/
|
||||
angular
|
||||
.module('material.components.button', [ 'material.core' ])
|
||||
.directive('mdButton', MdButtonDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdButton
|
||||
* @module material.components.button
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* `<md-button>` is a button directive with optional ink ripples (default enabled).
|
||||
*
|
||||
* If you supply a `href` or `ng-href` attribute, it will become an `<a>` element. Otherwise, it will
|
||||
* become a `<button>` element. As per the [Material Design specifications](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
|
||||
* the FAB button background is filled with the accent color [by default]. The primary color palette may be used with
|
||||
* the `md-primary` class.
|
||||
*
|
||||
* @param {boolean=} md-no-ink If present, disable ripple ink effects.
|
||||
* @param {expression=} ng-disabled En/Disable based on the expression
|
||||
* @param {string=} md-ripple-size Overrides the default ripple size logic. Options: `full`, `partial`, `auto`
|
||||
* @param {string=} aria-label Adds alternative text to button for accessibility, useful for icon buttons.
|
||||
* If no default text is found, a warning will be logged.
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* Regular buttons:
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-button> Flat Button </md-button>
|
||||
* <md-button href="http://google.com"> Flat link </md-button>
|
||||
* <md-button class="md-raised"> Raised Button </md-button>
|
||||
* <md-button ng-disabled="true"> Disabled Button </md-button>
|
||||
* <md-button>
|
||||
* <md-icon md-svg-src="your/icon.svg"></md-icon>
|
||||
* Register Now
|
||||
* </md-button>
|
||||
* </hljs>
|
||||
*
|
||||
* FAB buttons:
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-button class="md-fab" aria-label="FAB">
|
||||
* <md-icon md-svg-src="your/icon.svg"></md-icon>
|
||||
* </md-button>
|
||||
* <!-- mini-FAB -->
|
||||
* <md-button class="md-fab md-mini" aria-label="Mini FAB">
|
||||
* <md-icon md-svg-src="your/icon.svg"></md-icon>
|
||||
* </md-button>
|
||||
* <!-- Button with SVG Icon -->
|
||||
* <md-button class="md-icon-button" aria-label="Custom Icon Button">
|
||||
* <md-icon md-svg-icon="path/to/your.svg"></md-icon>
|
||||
* </md-button>
|
||||
* </hljs>
|
||||
*/
|
||||
function MdButtonDirective($mdButtonInkRipple, $mdTheming, $mdAria, $timeout) {
|
||||
|
||||
return {
|
||||
restrict: 'EA',
|
||||
replace: true,
|
||||
transclude: true,
|
||||
template: getTemplate,
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function isAnchor(attr) {
|
||||
return angular.isDefined(attr.href) || angular.isDefined(attr.ngHref) || angular.isDefined(attr.ngLink) || angular.isDefined(attr.uiSref);
|
||||
}
|
||||
|
||||
function getTemplate(element, attr) {
|
||||
return isAnchor(attr) ?
|
||||
'<a class="md-button" ng-transclude></a>' :
|
||||
'<button class="md-button" ng-transclude></button>';
|
||||
}
|
||||
|
||||
function postLink(scope, element, attr) {
|
||||
var node = element[0];
|
||||
$mdTheming(element);
|
||||
$mdButtonInkRipple.attach(scope, element);
|
||||
|
||||
var elementHasText = node.textContent.trim();
|
||||
if (!elementHasText) {
|
||||
$mdAria.expect(element, 'aria-label');
|
||||
}
|
||||
|
||||
// For anchor elements, we have to set tabindex manually when the
|
||||
// element is disabled
|
||||
if (isAnchor(attr) && angular.isDefined(attr.ngDisabled) ) {
|
||||
scope.$watch(attr.ngDisabled, function(isDisabled) {
|
||||
element.attr('tabindex', isDisabled ? -1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
// disabling click event when disabled is true
|
||||
element.on('click', function(e){
|
||||
if (attr.disabled === true) {
|
||||
e.preventDefault();
|
||||
e.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
|
||||
// restrict focus styles to the keyboard
|
||||
scope.mouseActive = false;
|
||||
element.on('mousedown', function() {
|
||||
scope.mouseActive = true;
|
||||
$timeout(function(){
|
||||
scope.mouseActive = false;
|
||||
}, 100);
|
||||
})
|
||||
.on('focus', function() {
|
||||
if(scope.mouseActive === false) { element.addClass('md-focused'); }
|
||||
})
|
||||
.on('blur', function() { element.removeClass('md-focused'); });
|
||||
}
|
||||
|
||||
}
|
||||
MdButtonDirective.$inject = ["$mdButtonInkRipple", "$mdTheming", "$mdAria", "$timeout"];
|
||||
|
||||
ng.material.components.button = angular.module("material.components.button");
|
||||
@@ -0,0 +1,12 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-card.md-THEME_NAME-theme {
|
||||
background-color: '{{background-color}}';
|
||||
border-radius: 2px; }
|
||||
md-card.md-THEME_NAME-theme .md-card-image {
|
||||
border-radius: 2px 2px 0 0; }
|
||||
34
www/lib/angular-material/modules/closure/card/card.css
Normal file
@@ -0,0 +1,34 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-card {
|
||||
box-sizing: border-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
margin: 8px;
|
||||
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.14), 0px 2px 2px 0px rgba(0, 0, 0, 0.098), 0px 1px 5px 0px rgba(0, 0, 0, 0.084); }
|
||||
md-card > img, md-card > :not(md-card-content) img {
|
||||
width: 100%; }
|
||||
md-card md-card-content {
|
||||
padding: 16px; }
|
||||
md-card .md-actions {
|
||||
margin: 0; }
|
||||
md-card .md-actions .md-button {
|
||||
margin-bottom: 8px;
|
||||
margin-top: 8px;
|
||||
margin-right: 4px;
|
||||
margin-left: 4px; }
|
||||
md-card md-card-footer {
|
||||
padding: 16px; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-card {
|
||||
border: 1px solid #fff; } }
|
||||
84
www/lib/angular-material/modules/closure/card/card.js
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.card');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.card
|
||||
*
|
||||
* @description
|
||||
* Card components.
|
||||
*/
|
||||
angular.module('material.components.card', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdCard', mdCardDirective);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdCard
|
||||
* @module material.components.card
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-card>` directive is a container element used within `<md-content>` containers.
|
||||
*
|
||||
* An image included as a direct descendant will fill the card's width, while the `<md-card-content>`
|
||||
* container will wrap text content and provide padding. An `<md-card-footer>` element can be
|
||||
* optionally included to put content flush against the bottom edge of the card.
|
||||
*
|
||||
* Action buttons can be included in an element with the `.md-actions` class, also used in `md-dialog`.
|
||||
* You can then position buttons using layout attributes.
|
||||
*
|
||||
* Cards have constant width and variable heights; where the maximum height is limited to what can
|
||||
* fit within a single view on a platform, but it can temporarily expand as needed.
|
||||
*
|
||||
* @usage
|
||||
* ###Card with optional footer
|
||||
* <hljs lang="html">
|
||||
* <md-card>
|
||||
* <img src="card-image.png" class="md-card-image" alt="image caption">
|
||||
* <md-card-content>
|
||||
* <h2>Card headline</h2>
|
||||
* <p>Card content</p>
|
||||
* </md-card-content>
|
||||
* <md-card-footer>
|
||||
* Card footer
|
||||
* </md-card-footer>
|
||||
* </md-card>
|
||||
* </hljs>
|
||||
*
|
||||
* ###Card with actions
|
||||
* <hljs lang="html">
|
||||
* <md-card>
|
||||
* <img src="card-image.png" class="md-card-image" alt="image caption">
|
||||
* <md-card-content>
|
||||
* <h2>Card headline</h2>
|
||||
* <p>Card content</p>
|
||||
* </md-card-content>
|
||||
* <div class="md-actions" layout="row" layout-align="end center">
|
||||
* <md-button>Action 1</md-button>
|
||||
* <md-button>Action 2</md-button>
|
||||
* </div>
|
||||
* </md-card>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function mdCardDirective($mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function($scope, $element, $attr) {
|
||||
$mdTheming($element);
|
||||
}
|
||||
};
|
||||
}
|
||||
mdCardDirective.$inject = ["$mdTheming"];
|
||||
|
||||
ng.material.components.card = angular.module("material.components.card");
|
||||
@@ -0,0 +1,47 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-checkbox.md-THEME_NAME-theme .md-ripple {
|
||||
color: '{{accent-600}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme.md-checked .md-ripple {
|
||||
color: '{{background-600}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme.md-checked.md-focused .md-container:before {
|
||||
background-color: '{{accent-color-0.26}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme .md-icon {
|
||||
border-color: '{{foreground-2}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme.md-checked .md-icon {
|
||||
background-color: '{{accent-color-0.87}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme.md-checked .md-icon:after {
|
||||
border-color: '{{background-200}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-ripple {
|
||||
color: '{{primary-600}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ripple {
|
||||
color: '{{background-600}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary .md-icon {
|
||||
border-color: '{{foreground-2}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon {
|
||||
background-color: '{{primary-color-0.87}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked.md-focused .md-container:before {
|
||||
background-color: '{{primary-color-0.26}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-icon:after {
|
||||
border-color: '{{background-200}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-ripple {
|
||||
color: '{{warn-600}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn .md-icon {
|
||||
border-color: '{{foreground-2}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon {
|
||||
background-color: '{{warn-color-0.87}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked.md-focused:not([disabled]) .md-container:before {
|
||||
background-color: '{{warn-color-0.26}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-icon:after {
|
||||
border-color: '{{background-200}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme[disabled] .md-icon {
|
||||
border-color: '{{foreground-3}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme[disabled].md-checked .md-icon {
|
||||
background-color: '{{foreground-3}}'; }
|
||||
md-checkbox.md-THEME_NAME-theme[disabled] .md-label {
|
||||
color: '{{foreground-3}}'; }
|
||||
124
www/lib/angular-material/modules/closure/checkbox/checkbox.css
Normal file
@@ -0,0 +1,124 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-checkbox {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 8px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
padding-left: 18px;
|
||||
padding-right: 0;
|
||||
position: relative;
|
||||
line-height: 26px;
|
||||
min-width: 18px;
|
||||
min-height: 18px; }
|
||||
html[dir=rtl] md-checkbox {
|
||||
padding-left: 0; }
|
||||
html[dir=rtl] md-checkbox {
|
||||
padding-right: 18px; }
|
||||
md-checkbox *, md-checkbox *:before, md-checkbox *:after {
|
||||
box-sizing: border-box; }
|
||||
md-checkbox.md-focused:not([disabled]) .md-container:before {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
bottom: -8px; }
|
||||
md-checkbox.md-focused:not([disabled]):not(.md-checked) .md-container:before {
|
||||
background-color: rgba(0, 0, 0, 0.12); }
|
||||
md-checkbox .md-container {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
display: inline-block;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
left: 0;
|
||||
right: auto; }
|
||||
html[dir=rtl] md-checkbox .md-container {
|
||||
left: auto; }
|
||||
html[dir=rtl] md-checkbox .md-container {
|
||||
right: 0; }
|
||||
md-checkbox .md-container:before {
|
||||
background-color: transparent;
|
||||
border-radius: 50%;
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: auto;
|
||||
left: 0;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
transition: all 0.5s;
|
||||
width: auto; }
|
||||
md-checkbox .md-container:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -10px;
|
||||
right: -10px;
|
||||
bottom: -10px;
|
||||
left: -10px; }
|
||||
md-checkbox .md-container .md-ripple-container {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: auto;
|
||||
height: auto;
|
||||
left: -15px;
|
||||
top: -15px;
|
||||
right: -15px;
|
||||
bottom: -15px; }
|
||||
md-checkbox .md-icon {
|
||||
transition: 240ms;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-radius: 2px; }
|
||||
md-checkbox.md-checked .md-icon {
|
||||
border: none; }
|
||||
md-checkbox[disabled] {
|
||||
cursor: no-drop; }
|
||||
md-checkbox.md-checked .md-icon:after {
|
||||
-webkit-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
position: absolute;
|
||||
left: 6px;
|
||||
top: 2px;
|
||||
display: table;
|
||||
width: 6px;
|
||||
height: 12px;
|
||||
border-width: 2px;
|
||||
border-style: solid;
|
||||
border-top: 0;
|
||||
border-left: 0;
|
||||
content: ''; }
|
||||
md-checkbox .md-label {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
white-space: normal;
|
||||
-webkit-user-select: text;
|
||||
-moz-user-select: text;
|
||||
-ms-user-select: text;
|
||||
user-select: text; }
|
||||
md-checkbox .md-label span {
|
||||
margin-left: 10px;
|
||||
margin-right: 0; }
|
||||
html[dir=rtl] md-checkbox .md-label span {
|
||||
margin-left: 0; }
|
||||
html[dir=rtl] md-checkbox .md-label span {
|
||||
margin-right: 10px; }
|
||||
166
www/lib/angular-material/modules/closure/checkbox/checkbox.js
vendored
Normal file
@@ -0,0 +1,166 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.checkbox');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.checkbox
|
||||
* @description Checkbox module!
|
||||
*/
|
||||
angular
|
||||
.module('material.components.checkbox', ['material.core'])
|
||||
.directive('mdCheckbox', MdCheckboxDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdCheckbox
|
||||
* @module material.components.checkbox
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The checkbox directive is used like the normal [angular checkbox](https://docs.angularjs.org/api/ng/input/input%5Bcheckbox%5D).
|
||||
*
|
||||
* As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
|
||||
* the checkbox is in the accent color by default. The primary color palette may be used with
|
||||
* the `md-primary` class.
|
||||
*
|
||||
* @param {string} ng-model Assignable angular expression to data-bind to.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {expression=} ng-true-value The value to which the expression should be set when selected.
|
||||
* @param {expression=} ng-false-value The value to which the expression should be set when not selected.
|
||||
* @param {string=} ng-change Angular expression to be executed when input changes due to user interaction with the input element.
|
||||
* @param {boolean=} md-no-ink Use of attribute indicates use of ripple ink effects
|
||||
* @param {string=} aria-label Adds label to checkbox for accessibility.
|
||||
* Defaults to checkbox's text. If no default text is found, a warning will be logged.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-checkbox ng-model="isChecked" aria-label="Finished?">
|
||||
* Finished ?
|
||||
* </md-checkbox>
|
||||
*
|
||||
* <md-checkbox md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
|
||||
* No Ink Effects
|
||||
* </md-checkbox>
|
||||
*
|
||||
* <md-checkbox ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
|
||||
* Disabled
|
||||
* </md-checkbox>
|
||||
*
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function MdCheckboxDirective(inputDirective, $mdInkRipple, $mdAria, $mdConstant, $mdTheming, $mdUtil, $timeout) {
|
||||
inputDirective = inputDirective[0];
|
||||
var CHECKED_CSS = 'md-checked';
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
require: '?ngModel',
|
||||
priority:210, // Run before ngAria
|
||||
template:
|
||||
'<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
|
||||
'<div class="md-icon"></div>' +
|
||||
'</div>' +
|
||||
'<div ng-transclude class="md-label"></div>',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
// **********************************************************
|
||||
// Private Methods
|
||||
// **********************************************************
|
||||
|
||||
function compile (tElement, tAttrs) {
|
||||
|
||||
tAttrs.type = 'checkbox';
|
||||
tAttrs.tabindex = tAttrs.tabindex || '0';
|
||||
tElement.attr('role', tAttrs.type);
|
||||
|
||||
return function postLink(scope, element, attr, ngModelCtrl) {
|
||||
ngModelCtrl = ngModelCtrl || $mdUtil.fakeNgModel();
|
||||
$mdTheming(element);
|
||||
|
||||
if (attr.ngChecked) {
|
||||
scope.$watch(
|
||||
scope.$eval.bind(scope, attr.ngChecked),
|
||||
ngModelCtrl.$setViewValue.bind(ngModelCtrl)
|
||||
);
|
||||
}
|
||||
$$watchExpr('ngDisabled', 'tabindex', {
|
||||
true: '-1',
|
||||
false: attr.tabindex
|
||||
});
|
||||
$mdAria.expectWithText(element, 'aria-label');
|
||||
|
||||
// Reuse the original input[type=checkbox] directive from Angular core.
|
||||
// This is a bit hacky as we need our own event listener and own render
|
||||
// function.
|
||||
inputDirective.link.pre(scope, {
|
||||
on: angular.noop,
|
||||
0: {}
|
||||
}, attr, [ngModelCtrl]);
|
||||
|
||||
scope.mouseActive = false;
|
||||
element.on('click', listener)
|
||||
.on('keypress', keypressHandler)
|
||||
.on('mousedown', function() {
|
||||
scope.mouseActive = true;
|
||||
$timeout(function(){
|
||||
scope.mouseActive = false;
|
||||
}, 100);
|
||||
})
|
||||
.on('focus', function() {
|
||||
if(scope.mouseActive === false) { element.addClass('md-focused'); }
|
||||
})
|
||||
.on('blur', function() { element.removeClass('md-focused'); });
|
||||
|
||||
ngModelCtrl.$render = render;
|
||||
|
||||
function $$watchExpr(expr, htmlAttr, valueOpts) {
|
||||
if (attr[expr]) {
|
||||
scope.$watch(attr[expr], function(val) {
|
||||
if (valueOpts[val]) {
|
||||
element.attr(htmlAttr, valueOpts[val]);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function keypressHandler(ev) {
|
||||
var keyCode = ev.which || ev.keyCode;
|
||||
if (keyCode === $mdConstant.KEY_CODE.SPACE || keyCode === $mdConstant.KEY_CODE.ENTER) {
|
||||
ev.preventDefault();
|
||||
if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
|
||||
listener(ev);
|
||||
}
|
||||
}
|
||||
function listener(ev) {
|
||||
if (element[0].hasAttribute('disabled')) return;
|
||||
|
||||
scope.$apply(function() {
|
||||
// Toggle the checkbox value...
|
||||
var viewValue = attr.ngChecked ? attr.checked : !ngModelCtrl.$viewValue;
|
||||
|
||||
ngModelCtrl.$setViewValue( viewValue, ev && ev.type);
|
||||
ngModelCtrl.$render();
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
if(ngModelCtrl.$viewValue) {
|
||||
element.addClass(CHECKED_CSS);
|
||||
} else {
|
||||
element.removeClass(CHECKED_CSS);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
MdCheckboxDirective.$inject = ["inputDirective", "$mdInkRipple", "$mdAria", "$mdConstant", "$mdTheming", "$mdUtil", "$timeout"];
|
||||
|
||||
ng.material.components.checkbox = angular.module("material.components.checkbox");
|
||||
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-chips.md-THEME_NAME-theme .md-chips {
|
||||
box-shadow: 0 1px '{{background-300}}'; }
|
||||
md-chips.md-THEME_NAME-theme .md-chips.md-focused {
|
||||
box-shadow: 0 2px '{{primary-color}}'; }
|
||||
md-chips.md-THEME_NAME-theme .md-chip {
|
||||
background: '{{background-300}}';
|
||||
color: '{{background-800}}'; }
|
||||
md-chips.md-THEME_NAME-theme .md-chip.md-focused {
|
||||
background: '{{primary-color}}';
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-chips.md-THEME_NAME-theme .md-chip.md-focused md-icon {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-chips.md-THEME_NAME-theme md-chip-remove .md-button md-icon path {
|
||||
fill: '{{background-500}}'; }
|
||||
|
||||
.md-contact-suggestion span.md-contact-email {
|
||||
color: '{{background-400}}'; }
|
||||
131
www/lib/angular-material/modules/closure/chips/chips.css
Normal file
@@ -0,0 +1,131 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
.md-contact-chips .md-chips .md-chip {
|
||||
padding: 0 8px 0 0; }
|
||||
.md-contact-chips .md-chips .md-chip .md-contact-avatar {
|
||||
float: left; }
|
||||
.md-contact-chips .md-chips .md-chip .md-contact-avatar img {
|
||||
height: 32px;
|
||||
border-radius: 16px; }
|
||||
.md-contact-chips .md-chips .md-chip .md-contact-name {
|
||||
display: inline-block;
|
||||
height: 32px;
|
||||
margin-left: 8px; }
|
||||
|
||||
.md-contact-suggestion {
|
||||
height: 56px; }
|
||||
.md-contact-suggestion img {
|
||||
height: 40px;
|
||||
border-radius: 20px;
|
||||
margin-top: 8px; }
|
||||
.md-contact-suggestion .md-contact-name {
|
||||
margin-left: 8px;
|
||||
width: 120px; }
|
||||
.md-contact-suggestion .md-contact-name, .md-contact-suggestion .md-contact-email {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis; }
|
||||
|
||||
.md-contact-chips-suggestions li {
|
||||
height: 100%; }
|
||||
|
||||
.md-chips {
|
||||
display: block;
|
||||
font-family: RobotoDraft, Roboto, 'Helvetica Neue', sans-serif;
|
||||
font-size: 13px;
|
||||
padding: 0 0 8px 0;
|
||||
vertical-align: middle;
|
||||
cursor: text; }
|
||||
.md-chips:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both; }
|
||||
.md-chips .md-chip {
|
||||
cursor: default;
|
||||
border-radius: 16px;
|
||||
display: block;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 8px 8px 0 0;
|
||||
padding: 0 8px 0 12px;
|
||||
float: left; }
|
||||
.md-chips .md-chip .md-chip-content {
|
||||
display: block;
|
||||
padding-right: 4px;
|
||||
float: left;
|
||||
white-space: nowrap; }
|
||||
.md-chips .md-chip .md-chip-content:focus {
|
||||
outline: none; }
|
||||
.md-chips .md-chip .md-chip-remove-container {
|
||||
display: inline-block;
|
||||
margin-right: -5px; }
|
||||
.md-chips .md-chip .md-chip-remove {
|
||||
text-align: center;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
min-width: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
margin: 0;
|
||||
position: relative; }
|
||||
.md-chips .md-chip .md-chip-remove md-icon {
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||
transform: translate3d(-50%, -50%, 0); }
|
||||
.md-chips .md-chip-input-container {
|
||||
display: block;
|
||||
line-height: 32px;
|
||||
margin: 8px 8px 0 0;
|
||||
padding: 0 8px 0 12px;
|
||||
float: left; }
|
||||
.md-chips .md-chip-input-container input:not([type]), .md-chips .md-chip-input-container input[type="email"], .md-chips .md-chip-input-container input[type="number"], .md-chips .md-chip-input-container input[type="tel"], .md-chips .md-chip-input-container input[type="url"], .md-chips .md-chip-input-container input[type="text"] {
|
||||
border: 0;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0; }
|
||||
.md-chips .md-chip-input-container input:not([type]):focus, .md-chips .md-chip-input-container input[type="email"]:focus, .md-chips .md-chip-input-container input[type="number"]:focus, .md-chips .md-chip-input-container input[type="tel"]:focus, .md-chips .md-chip-input-container input[type="url"]:focus, .md-chips .md-chip-input-container input[type="text"]:focus {
|
||||
outline: none; }
|
||||
.md-chips .md-chip-input-container md-autocomplete, .md-chips .md-chip-input-container md-autocomplete-wrap {
|
||||
background: transparent;
|
||||
height: 32px; }
|
||||
.md-chips .md-chip-input-container md-autocomplete md-autocomplete-wrap {
|
||||
box-shadow: none; }
|
||||
.md-chips .md-chip-input-container md-autocomplete input {
|
||||
position: relative; }
|
||||
.md-chips .md-chip-input-container input {
|
||||
border: 0;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding: 0; }
|
||||
.md-chips .md-chip-input-container input:focus {
|
||||
outline: none; }
|
||||
.md-chips .md-chip-input-container md-autocomplete, .md-chips .md-chip-input-container md-autocomplete-wrap {
|
||||
height: 32px; }
|
||||
.md-chips .md-chip-input-container md-autocomplete {
|
||||
box-shadow: none; }
|
||||
.md-chips .md-chip-input-container md-autocomplete input {
|
||||
position: relative; }
|
||||
.md-chips .md-chip-input-container:not(:first-child) {
|
||||
margin: 8px 8px 0 0; }
|
||||
.md-chips .md-chip-input-container input {
|
||||
background: transparent;
|
||||
border-width: 0; }
|
||||
.md-chips md-autocomplete button {
|
||||
display: none; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
.md-chip-input-container, md-chip {
|
||||
border: 1px solid #fff; }
|
||||
.md-chip-input-container md-autocomplete {
|
||||
border: none; } }
|
||||
949
www/lib/angular-material/modules/closure/chips/chips.js
vendored
Normal file
@@ -0,0 +1,949 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.chips');
|
||||
goog.require('ng.material.components.autocomplete');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.chips
|
||||
*/
|
||||
/*
|
||||
* @see js folder for chips implementation
|
||||
*/
|
||||
angular.module('material.components.chips', [
|
||||
'material.core',
|
||||
'material.components.autocomplete'
|
||||
]);
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.directive('mdChip', MdChip);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdChip
|
||||
* @module material.components.chips
|
||||
*
|
||||
* @description
|
||||
* `<md-chip>` is a component used within `<md-chips>` and is responsible for rendering individual
|
||||
* chips.
|
||||
*
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-chip>{{$chip}}</md-chip>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
// This hint text is hidden within a chip but used by screen readers to
|
||||
// inform the user how they can interact with a chip.
|
||||
var DELETE_HINT_TEMPLATE = '\
|
||||
<span ng-if="!$mdChipsCtrl.readonly" class="md-visually-hidden">\
|
||||
{{$mdChipsCtrl.deleteHint}}\
|
||||
</span>';
|
||||
|
||||
/**
|
||||
* MDChip Directive Definition
|
||||
*
|
||||
* @param $mdTheming
|
||||
* @param $mdInkRipple
|
||||
* ngInject
|
||||
*/
|
||||
function MdChip($mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '^?mdChips',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(element, attr) {
|
||||
element.append(DELETE_HINT_TEMPLATE);
|
||||
return function postLink(scope, element, attr, ctrl) {
|
||||
element.addClass('md-chip');
|
||||
$mdTheming(element);
|
||||
|
||||
if (ctrl) angular.element(element[0].querySelector('.md-chip-content'))
|
||||
.on('blur', function () {
|
||||
ctrl.selectedChip = -1;
|
||||
});
|
||||
};
|
||||
}
|
||||
}
|
||||
MdChip.$inject = ["$mdTheming"];
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.directive('mdChipRemove', MdChipRemove);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdChipRemove
|
||||
* @module material.components.chips
|
||||
*
|
||||
* @description
|
||||
* `<md-chip-remove>`
|
||||
* Designates an element to be used as the delete button for a chip. This
|
||||
* element is passed as a child of the `md-chips` element.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-chips><button md-chip-remove>DEL</button></md-chips>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* MdChipRemove Directive Definition.
|
||||
*
|
||||
* @param $compile
|
||||
* @param $timeout
|
||||
* @returns {{restrict: string, require: string[], link: Function, scope: boolean}}
|
||||
* @constructor
|
||||
*/
|
||||
function MdChipRemove ($timeout) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '^mdChips',
|
||||
scope: false,
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr, ctrl) {
|
||||
element.on('click', function(event) {
|
||||
scope.$apply(function() {
|
||||
ctrl.removeChip(scope.$$replacedScope.$index);
|
||||
});
|
||||
});
|
||||
|
||||
// Child elements aren't available until after a $timeout tick as they are hidden by an
|
||||
// `ng-if`. see http://goo.gl/zIWfuw
|
||||
$timeout(function() {
|
||||
element.attr({ tabindex: -1, ariaHidden: true });
|
||||
element.find('button').attr('tabindex', '-1');
|
||||
});
|
||||
}
|
||||
}
|
||||
MdChipRemove.$inject = ["$timeout"];
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.directive('mdChipTransclude', MdChipTransclude);
|
||||
|
||||
function MdChipTransclude ($compile, $mdUtil) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
terminal: true,
|
||||
link: link,
|
||||
scope: false
|
||||
};
|
||||
function link (scope, element, attr) {
|
||||
var ctrl = scope.$parent.$mdChipsCtrl,
|
||||
newScope = ctrl.parent.$new(false, ctrl.parent);
|
||||
newScope.$$replacedScope = scope;
|
||||
newScope.$chip = scope.$chip;
|
||||
newScope.$mdChipsCtrl = ctrl;
|
||||
element.html(ctrl.$scope.$eval(attr.mdChipTransclude));
|
||||
$compile(element.contents())(newScope);
|
||||
}
|
||||
}
|
||||
MdChipTransclude.$inject = ["$compile", "$mdUtil"];
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.controller('MdChipsCtrl', MdChipsCtrl);
|
||||
|
||||
/**
|
||||
* Controller for the MdChips component. Responsible for adding to and
|
||||
* removing from the list of chips, marking chips as selected, and binding to
|
||||
* the models of various input components.
|
||||
*
|
||||
* @param $scope
|
||||
* @param $mdConstant
|
||||
* @param $log
|
||||
* @param $element
|
||||
* @constructor
|
||||
*/
|
||||
function MdChipsCtrl ($scope, $mdConstant, $log, $element, $timeout) {
|
||||
/** @type {$timeout} **/
|
||||
this.$timeout = $timeout;
|
||||
|
||||
/** @type {Object} */
|
||||
this.$mdConstant = $mdConstant;
|
||||
|
||||
/** @type {angular.$scope} */
|
||||
this.$scope = $scope;
|
||||
|
||||
/** @type {angular.$scope} */
|
||||
this.parent = $scope.$parent;
|
||||
|
||||
/** @type {$log} */
|
||||
this.$log = $log;
|
||||
|
||||
/** @type {$element} */
|
||||
this.$element = $element;
|
||||
|
||||
/** @type {angular.NgModelController} */
|
||||
this.ngModelCtrl = null;
|
||||
|
||||
/** @type {angular.NgModelController} */
|
||||
this.userInputNgModelCtrl = null;
|
||||
|
||||
/** @type {Element} */
|
||||
this.userInputElement = null;
|
||||
|
||||
/** @type {Array.<Object>} */
|
||||
this.items = [];
|
||||
|
||||
/** @type {number} */
|
||||
this.selectedChip = -1;
|
||||
|
||||
|
||||
/**
|
||||
* Hidden hint text for how to delete a chip. Used to give context to screen readers.
|
||||
* @type {string}
|
||||
*/
|
||||
this.deleteHint = 'Press delete to remove this chip.';
|
||||
|
||||
/**
|
||||
* Hidden label for the delete button. Used to give context to screen readers.
|
||||
* @type {string}
|
||||
*/
|
||||
this.deleteButtonLabel = 'Remove';
|
||||
|
||||
/**
|
||||
* Model used by the input element.
|
||||
* @type {string}
|
||||
*/
|
||||
this.chipBuffer = '';
|
||||
|
||||
/**
|
||||
* Whether to use the mdOnAppend expression to transform the chip buffer
|
||||
* before appending it to the list.
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.useMdOnAppend = false;
|
||||
}
|
||||
MdChipsCtrl.$inject = ["$scope", "$mdConstant", "$log", "$element", "$timeout"];
|
||||
|
||||
/**
|
||||
* Handles the keydown event on the input element: <enter> appends the
|
||||
* buffer to the chip list, while backspace removes the last chip in the list
|
||||
* if the current buffer is empty.
|
||||
* @param event
|
||||
*/
|
||||
MdChipsCtrl.prototype.inputKeydown = function(event) {
|
||||
var chipBuffer = this.getChipBuffer();
|
||||
switch (event.keyCode) {
|
||||
case this.$mdConstant.KEY_CODE.ENTER:
|
||||
if (this.$scope.requireMatch || !chipBuffer) break;
|
||||
event.preventDefault();
|
||||
this.appendChip(chipBuffer);
|
||||
this.resetChipBuffer();
|
||||
break;
|
||||
case this.$mdConstant.KEY_CODE.BACKSPACE:
|
||||
if (chipBuffer) break;
|
||||
event.stopPropagation();
|
||||
if (this.items.length) this.selectAndFocusChipSafe(this.items.length - 1);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles the keydown event on the chip elements: backspace removes the selected chip, arrow
|
||||
* keys switch which chips is active
|
||||
* @param event
|
||||
*/
|
||||
MdChipsCtrl.prototype.chipKeydown = function (event) {
|
||||
if (this.getChipBuffer()) return;
|
||||
switch (event.keyCode) {
|
||||
case this.$mdConstant.KEY_CODE.BACKSPACE:
|
||||
case this.$mdConstant.KEY_CODE.DELETE:
|
||||
if (this.selectedChip < 0) return;
|
||||
event.preventDefault();
|
||||
this.removeAndSelectAdjacentChip(this.selectedChip);
|
||||
break;
|
||||
case this.$mdConstant.KEY_CODE.LEFT_ARROW:
|
||||
event.preventDefault();
|
||||
if (this.selectedChip < 0) this.selectedChip = this.items.length;
|
||||
if (this.items.length) this.selectAndFocusChipSafe(this.selectedChip - 1);
|
||||
break;
|
||||
case this.$mdConstant.KEY_CODE.RIGHT_ARROW:
|
||||
event.preventDefault();
|
||||
this.selectAndFocusChipSafe(this.selectedChip + 1);
|
||||
break;
|
||||
case this.$mdConstant.KEY_CODE.ESCAPE:
|
||||
case this.$mdConstant.KEY_CODE.TAB:
|
||||
if (this.selectedChip < 0) return;
|
||||
event.preventDefault();
|
||||
this.onFocus();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the input's placeholder - uses `placeholder` when list is empty and `secondary-placeholder`
|
||||
* when the list is non-empty. If `secondary-placeholder` is not provided, `placeholder` is used
|
||||
* always.
|
||||
*/
|
||||
MdChipsCtrl.prototype.getPlaceholder = function() {
|
||||
// Allow `secondary-placeholder` to be blank.
|
||||
var useSecondary = (this.items.length &&
|
||||
(this.secondaryPlaceholder == '' || this.secondaryPlaceholder));
|
||||
return useSecondary ? this.placeholder : this.secondaryPlaceholder;
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes chip at {@code index} and selects the adjacent chip.
|
||||
* @param index
|
||||
*/
|
||||
MdChipsCtrl.prototype.removeAndSelectAdjacentChip = function(index) {
|
||||
var selIndex = this.getAdjacentChipIndex(index);
|
||||
this.removeChip(index);
|
||||
this.$timeout(angular.bind(this, function () {
|
||||
this.selectAndFocusChipSafe(selIndex);
|
||||
}));
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the selected chip index to -1.
|
||||
*/
|
||||
MdChipsCtrl.prototype.resetSelectedChip = function() {
|
||||
this.selectedChip = -1;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the index of an adjacent chip to select after deletion. Adjacency is
|
||||
* determined as the next chip in the list, unless the target chip is the
|
||||
* last in the list, then it is the chip immediately preceding the target. If
|
||||
* there is only one item in the list, -1 is returned (select none).
|
||||
* The number returned is the index to select AFTER the target has been
|
||||
* removed.
|
||||
* If the current chip is not selected, then -1 is returned to select none.
|
||||
*/
|
||||
MdChipsCtrl.prototype.getAdjacentChipIndex = function(index) {
|
||||
var len = this.items.length - 1;
|
||||
return (len == 0) ? -1 :
|
||||
(index == len) ? index -1 : index;
|
||||
};
|
||||
|
||||
/**
|
||||
* Append the contents of the buffer to the chip list. This method will first
|
||||
* call out to the md-on-append method, if provided
|
||||
* @param newChip
|
||||
*/
|
||||
MdChipsCtrl.prototype.appendChip = function(newChip) {
|
||||
if (this.items.indexOf(newChip) + 1) return;
|
||||
if (this.useMdOnAppend && this.mdOnAppend) {
|
||||
newChip = this.mdOnAppend({'$chip': newChip});
|
||||
}
|
||||
this.items.push(newChip);
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets whether to use the md-on-append expression. This expression is
|
||||
* bound to scope and controller in {@code MdChipsDirective} as
|
||||
* {@code mdOnAppend}. Due to the nature of directive scope bindings, the
|
||||
* controller cannot know on its own/from the scope whether an expression was
|
||||
* actually provided.
|
||||
*/
|
||||
MdChipsCtrl.prototype.useMdOnAppendExpression = function() {
|
||||
this.useMdOnAppend = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the input buffer. The input buffer can be the model bound to the
|
||||
* default input item {@code this.chipBuffer}, the {@code selectedItem}
|
||||
* model of an {@code md-autocomplete}, or, through some magic, the model
|
||||
* bound to any inpput or text area element found within a
|
||||
* {@code md-input-container} element.
|
||||
* @return {Object|string}
|
||||
*/
|
||||
MdChipsCtrl.prototype.getChipBuffer = function() {
|
||||
return !this.userInputElement ? this.chipBuffer :
|
||||
this.userInputNgModelCtrl ? this.userInputNgModelCtrl.$viewValue :
|
||||
this.userInputElement[0].value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Resets the input buffer for either the internal input or user provided input element.
|
||||
*/
|
||||
MdChipsCtrl.prototype.resetChipBuffer = function() {
|
||||
if (this.userInputElement) {
|
||||
if (this.userInputNgModelCtrl) {
|
||||
this.userInputNgModelCtrl.$setViewValue('');
|
||||
this.userInputNgModelCtrl.$render();
|
||||
} else {
|
||||
this.userInputElement[0].value = '';
|
||||
}
|
||||
} else {
|
||||
this.chipBuffer = '';
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Removes the chip at the given index.
|
||||
* @param index
|
||||
*/
|
||||
MdChipsCtrl.prototype.removeChip = function(index) {
|
||||
this.items.splice(index, 1);
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.removeChipAndFocusInput = function (index) {
|
||||
this.removeChip(index);
|
||||
this.onFocus();
|
||||
};
|
||||
/**
|
||||
* Selects the chip at `index`,
|
||||
* @param index
|
||||
*/
|
||||
MdChipsCtrl.prototype.selectAndFocusChipSafe = function(index) {
|
||||
if (!this.items.length) {
|
||||
this.selectChip(-1);
|
||||
this.onFocus();
|
||||
return;
|
||||
}
|
||||
if (index === this.items.length) return this.onFocus();
|
||||
index = Math.max(index, 0);
|
||||
index = Math.min(index, this.items.length - 1);
|
||||
this.selectChip(index);
|
||||
this.focusChip(index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Marks the chip at the given index as selected.
|
||||
* @param index
|
||||
*/
|
||||
MdChipsCtrl.prototype.selectChip = function(index) {
|
||||
if (index >= -1 && index <= this.items.length) {
|
||||
this.selectedChip = index;
|
||||
} else {
|
||||
this.$log.warn('Selected Chip index out of bounds; ignoring.');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Selects the chip at `index` and gives it focus.
|
||||
* @param index
|
||||
*/
|
||||
MdChipsCtrl.prototype.selectAndFocusChip = function(index) {
|
||||
this.selectChip(index);
|
||||
if (index != -1) {
|
||||
this.focusChip(index);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Call `focus()` on the chip at `index`
|
||||
*/
|
||||
MdChipsCtrl.prototype.focusChip = function(index) {
|
||||
this.$element[0].querySelector('md-chip[index="' + index + '"] .md-chip-content').focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Configures the required interactions with the ngModel Controller.
|
||||
* Specifically, set {@code this.items} to the {@code NgModelCtrl#$viewVale}.
|
||||
* @param ngModelCtrl
|
||||
*/
|
||||
MdChipsCtrl.prototype.configureNgModel = function(ngModelCtrl) {
|
||||
this.ngModelCtrl = ngModelCtrl;
|
||||
|
||||
var self = this;
|
||||
ngModelCtrl.$render = function() {
|
||||
// model is updated. do something.
|
||||
self.items = self.ngModelCtrl.$viewValue;
|
||||
};
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.onFocus = function () {
|
||||
var input = this.$element[0].querySelector('input');
|
||||
input && input.focus();
|
||||
this.resetSelectedChip();
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.onInputFocus = function () {
|
||||
this.inputHasFocus = true;
|
||||
this.resetSelectedChip();
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.onInputBlur = function () {
|
||||
this.inputHasFocus = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Configure event bindings on a user-provided input element.
|
||||
* @param inputElement
|
||||
*/
|
||||
MdChipsCtrl.prototype.configureUserInput = function(inputElement) {
|
||||
this.userInputElement = inputElement;
|
||||
|
||||
// Find the NgModelCtrl for the input element
|
||||
var ngModelCtrl = inputElement.controller('ngModel');
|
||||
// `.controller` will look in the parent as well.
|
||||
if (ngModelCtrl != this.ngModelCtrl) {
|
||||
this.userInputNgModelCtrl = ngModelCtrl;
|
||||
}
|
||||
|
||||
// Bind to keydown and focus events of input
|
||||
var scope = this.$scope;
|
||||
var ctrl = this;
|
||||
inputElement
|
||||
.attr({ tabindex: 0 })
|
||||
.on('keydown', function(event) { scope.$apply( angular.bind(ctrl, function() { ctrl.inputKeydown(event); })) })
|
||||
.on('focus', angular.bind(ctrl, ctrl.onInputFocus))
|
||||
.on('blur', angular.bind(ctrl, ctrl.onInputBlur));
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.configureAutocomplete = function(ctrl) {
|
||||
|
||||
ctrl.registerSelectedItemWatcher(angular.bind(this, function (item) {
|
||||
if (item) {
|
||||
this.appendChip(item);
|
||||
this.resetChipBuffer();
|
||||
}
|
||||
}));
|
||||
|
||||
this.$element.find('input')
|
||||
.on('focus',angular.bind(this, this.onInputFocus) )
|
||||
.on('blur', angular.bind(this, this.onInputBlur) );
|
||||
};
|
||||
|
||||
MdChipsCtrl.prototype.hasFocus = function () {
|
||||
return this.inputHasFocus || this.selectedChip >= 0;
|
||||
};
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.directive('mdChips', MdChips);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdChips
|
||||
* @module material.components.chips
|
||||
*
|
||||
* @description
|
||||
* `<md-chips>` is an input component for building lists of strings or objects. The list items are
|
||||
* displayed as 'chips'. This component can make use of an `<input>` element or an
|
||||
* `<md-autocomplete>` element.
|
||||
*
|
||||
* <strong>Custom `<md-chip-template>` template</strong>
|
||||
* A custom template may be provided to render the content of each chip. This is achieved by
|
||||
* specifying an `<md-chip-template>` element as a child of `<md-chips>`. Note: Any attributes on
|
||||
* `<md-chip-template>` will be dropped as only the innerHTML is used for the chip template. The
|
||||
* variables `$chip` and `$index` are available in the scope of `<md-chip-template>`, representing
|
||||
* the chip object and its index in the list of chips, respectively.
|
||||
* To override the chip delete control, include an element (ideally a button) with the attribute
|
||||
* `md-chip-remove`. A click listener to remove the chip will be added automatically. The element
|
||||
* is also placed as a sibling to the chip content (on which there are also click listeners) to
|
||||
* avoid a nested ng-click situation.
|
||||
*
|
||||
* <h3> Pending Features </h3>
|
||||
* <ul style="padding-left:20px;">
|
||||
*
|
||||
* <ul>Style
|
||||
* <li>Colours for hover, press states (ripple?).</li>
|
||||
* </ul>
|
||||
*
|
||||
* <ul>List Manipulation
|
||||
* <li>delete item via DEL or backspace keys when selected</li>
|
||||
* </ul>
|
||||
*
|
||||
* <ul>Validation
|
||||
* <li>de-dupe values (or support duplicates, but fix the ng-repeat duplicate key issue)</li>
|
||||
* <li>allow a validation callback</li>
|
||||
* <li>hilighting style for invalid chips</li>
|
||||
* </ul>
|
||||
*
|
||||
* <ul>Item mutation
|
||||
* <li>Support `
|
||||
* <md-chip-edit>` template, show/hide the edit element on tap/click? double tap/double
|
||||
* click?
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* <ul>Truncation and Disambiguation (?)
|
||||
* <li>Truncate chip text where possible, but do not truncate entries such that two are
|
||||
* indistinguishable.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <ul>Drag and Drop
|
||||
* <li>Drag and drop chips between related `<md-chips>` elements.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </ul>
|
||||
*
|
||||
* <span style="font-size:.8em;text-align:center">
|
||||
* Warning: This component is a WORK IN PROGRESS. If you use it now,
|
||||
* it will probably break on you in the future.
|
||||
* </span>
|
||||
*
|
||||
* @param {string=|object=} ng-model A model to bind the list of items to
|
||||
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
|
||||
* @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,
|
||||
* displayed when there is at least on item in the list
|
||||
* @param {boolean=} readonly Disables list manipulation (deleting or adding list items), hiding
|
||||
* the input and delete buttons
|
||||
* @param {expression} md-on-append An expression expected to convert the input string into an
|
||||
* object when adding a chip.
|
||||
* @param {string=} delete-hint A string read by screen readers instructing users that pressing
|
||||
* the delete key will remove the chip.
|
||||
* @param {string=} delete-button-label A label for the delete button. Also hidden and read by
|
||||
* screen readers.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-chips
|
||||
* ng-model="myItems"
|
||||
* placeholder="Add an item"
|
||||
* readonly="isReadOnly">
|
||||
* </md-chips>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
var MD_CHIPS_TEMPLATE = '\
|
||||
<md-chips-wrap\
|
||||
ng-if="!$mdChipsCtrl.readonly || $mdChipsCtrl.items.length > 0"\
|
||||
ng-keydown="$mdChipsCtrl.chipKeydown($event)"\
|
||||
ng-class="{ \'md-focused\': $mdChipsCtrl.hasFocus() }"\
|
||||
class="md-chips">\
|
||||
<md-chip ng-repeat="$chip in $mdChipsCtrl.items"\
|
||||
index="{{$index}}"\
|
||||
ng-class="{\'md-focused\': $mdChipsCtrl.selectedChip == $index}">\
|
||||
<div class="md-chip-content"\
|
||||
tabindex="-1"\
|
||||
aria-hidden="true"\
|
||||
ng-focus="!$mdChipsCtrl.readonly && $mdChipsCtrl.selectChip($index)"\
|
||||
md-chip-transclude="$mdChipsCtrl.chipContentsTemplate"></div>\
|
||||
<div class="md-chip-remove-container"\
|
||||
md-chip-transclude="$mdChipsCtrl.chipRemoveTemplate"></div>\
|
||||
</md-chip>\
|
||||
<div ng-if="!$mdChipsCtrl.readonly && $mdChipsCtrl.ngModelCtrl"\
|
||||
class="md-chip-input-container"\
|
||||
md-chip-transclude="$mdChipsCtrl.chipInputTemplate"></div>\
|
||||
</div>\
|
||||
</md-chips-wrap>';
|
||||
|
||||
var CHIP_INPUT_TEMPLATE = '\
|
||||
<input\
|
||||
tabindex="0"\
|
||||
placeholder="{{$mdChipsCtrl.getPlaceholder()}}"\
|
||||
aria-label="{{$mdChipsCtrl.getPlaceholder()}}"\
|
||||
ng-model="$mdChipsCtrl.chipBuffer"\
|
||||
ng-focus="$mdChipsCtrl.onInputFocus()"\
|
||||
ng-blur="$mdChipsCtrl.onInputBlur()"\
|
||||
ng-keydown="$mdChipsCtrl.inputKeydown($event)">';
|
||||
|
||||
var CHIP_DEFAULT_TEMPLATE = '\
|
||||
<span>{{$chip}}</span>';
|
||||
|
||||
var CHIP_REMOVE_TEMPLATE = '\
|
||||
<button\
|
||||
class="md-chip-remove"\
|
||||
ng-if="!$mdChipsCtrl.readonly"\
|
||||
ng-click="$mdChipsCtrl.removeChipAndFocusInput($$replacedScope.$index)"\
|
||||
type="button"\
|
||||
aria-hidden="true"\
|
||||
tabindex="-1">\
|
||||
<md-icon md-svg-icon="md-close"></md-icon>\
|
||||
<span class="md-visually-hidden">\
|
||||
{{$mdChipsCtrl.deleteButtonLabel}}\
|
||||
</span>\
|
||||
</button>';
|
||||
|
||||
/**
|
||||
* MDChips Directive Definition
|
||||
*/
|
||||
function MdChips ($mdTheming, $mdUtil, $compile, $log, $timeout) {
|
||||
return {
|
||||
template: function(element, attrs) {
|
||||
// Clone the element into an attribute. By prepending the attribute
|
||||
// name with '$', Angular won't write it into the DOM. The cloned
|
||||
// element propagates to the link function via the attrs argument,
|
||||
// where various contained-elements can be consumed.
|
||||
var content = attrs['$mdUserTemplate'] = element.clone();
|
||||
return MD_CHIPS_TEMPLATE;
|
||||
},
|
||||
require: ['mdChips'],
|
||||
restrict: 'E',
|
||||
controller: 'MdChipsCtrl',
|
||||
controllerAs: '$mdChipsCtrl',
|
||||
bindToController: true,
|
||||
compile: compile,
|
||||
scope: {
|
||||
readonly: '=readonly',
|
||||
placeholder: '@',
|
||||
secondaryPlaceholder: '@',
|
||||
mdOnAppend: '&',
|
||||
deleteHint: '@',
|
||||
deleteButtonLabel: '@',
|
||||
requireMatch: '=?mdRequireMatch'
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Builds the final template for `md-chips` and returns the postLink function.
|
||||
*
|
||||
* Building the template involves 3 key components:
|
||||
* static chips
|
||||
* chip template
|
||||
* input control
|
||||
*
|
||||
* If no `ng-model` is provided, only the static chip work needs to be done.
|
||||
*
|
||||
* If no user-passed `md-chip-template` exists, the default template is used. This resulting
|
||||
* template is appended to the chip content element.
|
||||
*
|
||||
* The remove button may be overridden by passing an element with an md-chip-remove attribute.
|
||||
*
|
||||
* If an `input` or `md-autocomplete` element is provided by the caller, it is set aside for
|
||||
* transclusion later. The transclusion happens in `postLink` as the parent scope is required.
|
||||
* If no user input is provided, a default one is appended to the input container node in the
|
||||
* template.
|
||||
*
|
||||
* Static Chips (i.e. `md-chip` elements passed from the caller) are gathered and set aside for
|
||||
* transclusion in the `postLink` function.
|
||||
*
|
||||
*
|
||||
* @param element
|
||||
* @param attr
|
||||
* @returns {Function}
|
||||
*/
|
||||
function compile(element, attr) {
|
||||
// Grab the user template from attr and reset the attribute to null.
|
||||
var userTemplate = attr['$mdUserTemplate'];
|
||||
attr['$mdUserTemplate'] = null;
|
||||
|
||||
// Set the chip remove, chip contents and chip input templates. The link function will put
|
||||
// them on the scope for transclusion later.
|
||||
var chipRemoveTemplate = getTemplateByQuery('md-chips>*[md-chip-remove]') || CHIP_REMOVE_TEMPLATE,
|
||||
chipContentsTemplate = getTemplateByQuery('md-chips>md-chip-template') || CHIP_DEFAULT_TEMPLATE,
|
||||
chipInputTemplate = getTemplateByQuery('md-chips>md-autocomplete')
|
||||
|| getTemplateByQuery('md-chips>input')
|
||||
|| CHIP_INPUT_TEMPLATE,
|
||||
staticChips = userTemplate.find('md-chip');
|
||||
|
||||
// Warn of malformed template. See #2545
|
||||
if (userTemplate[0].querySelector('md-chip-template>*[md-chip-remove]')) {
|
||||
$log.warn('invalid placement of md-chip-remove within md-chip-template.');
|
||||
}
|
||||
|
||||
function getTemplateByQuery (query) {
|
||||
if (!attr.ngModel) return;
|
||||
var element = userTemplate[0].querySelector(query);
|
||||
return element && element.outerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures controller and transcludes.
|
||||
*/
|
||||
return function postLink(scope, element, attrs, controllers) {
|
||||
|
||||
$mdUtil.initOptionalProperties(scope, attr);
|
||||
|
||||
$mdTheming(element);
|
||||
var mdChipsCtrl = controllers[0];
|
||||
mdChipsCtrl.chipContentsTemplate = chipContentsTemplate;
|
||||
mdChipsCtrl.chipRemoveTemplate = chipRemoveTemplate;
|
||||
mdChipsCtrl.chipInputTemplate = chipInputTemplate;
|
||||
|
||||
element
|
||||
.attr({ ariaHidden: true, tabindex: -1 })
|
||||
.on('focus', function () { mdChipsCtrl.onFocus(); });
|
||||
|
||||
if (attr.ngModel) {
|
||||
mdChipsCtrl.configureNgModel(element.controller('ngModel'));
|
||||
|
||||
// If an `md-on-append` attribute was set, tell the controller to use the expression
|
||||
// when appending chips.
|
||||
if (attrs.mdOnAppend) mdChipsCtrl.useMdOnAppendExpression();
|
||||
|
||||
// The md-autocomplete and input elements won't be compiled until after this directive
|
||||
// is complete (due to their nested nature). Wait a tick before looking for them to
|
||||
// configure the controller.
|
||||
if (chipInputTemplate != CHIP_INPUT_TEMPLATE) {
|
||||
$timeout(function() {
|
||||
if (chipInputTemplate.indexOf('<md-autocomplete') === 0)
|
||||
mdChipsCtrl
|
||||
.configureAutocomplete(element.find('md-autocomplete')
|
||||
.controller('mdAutocomplete'));
|
||||
mdChipsCtrl.configureUserInput(element.find('input'));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Compile with the parent's scope and prepend any static chips to the wrapper.
|
||||
if (staticChips.length > 0) {
|
||||
var compiledStaticChips = $compile(staticChips)(scope.$parent);
|
||||
$timeout(function() { element.find('md-chips-wrap').prepend(compiledStaticChips); });
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
MdChips.$inject = ["$mdTheming", "$mdUtil", "$compile", "$log", "$timeout"];
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.controller('MdContactChipsCtrl', MdContactChipsCtrl);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Controller for the MdContactChips component
|
||||
* @constructor
|
||||
*/
|
||||
function MdContactChipsCtrl () {
|
||||
/** @type {Object} */
|
||||
this.selectedItem = null;
|
||||
|
||||
/** @type {string} */
|
||||
this.searchText = '';
|
||||
}
|
||||
|
||||
|
||||
MdContactChipsCtrl.prototype.queryContact = function(searchText) {
|
||||
var results = this.contactQuery({'$query': searchText});
|
||||
return this.filterSelected ?
|
||||
results.filter(angular.bind(this, this.filterSelectedContacts)) : results;
|
||||
};
|
||||
|
||||
|
||||
MdContactChipsCtrl.prototype.filterSelectedContacts = function(contact) {
|
||||
return this.contacts.indexOf(contact) == -1;
|
||||
};
|
||||
|
||||
angular
|
||||
.module('material.components.chips')
|
||||
.directive('mdContactChips', MdContactChips);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdContactChips
|
||||
* @module material.components.chips
|
||||
*
|
||||
* @description
|
||||
* `<md-contact-chips>` is an input component based on `md-chips` and makes use of an
|
||||
* `md-autocomplete` element. The component allows the caller to supply a query expression
|
||||
* which returns a list of possible contacts. The user can select one of these and add it to
|
||||
* the list of chips.
|
||||
*
|
||||
* @param {string=|object=} ng-model A model to bind the list of items to
|
||||
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
|
||||
* @param {string=} secondary-placeholder Placeholder text that will be forwarded to the input,
|
||||
* displayed when there is at least on item in the list
|
||||
* @param {expression} md-contacts An expression expected to return contacts matching the search
|
||||
* test, `$query`.
|
||||
* @param {string} md-contact-name The field name of the contact object representing the
|
||||
* contact's name.
|
||||
* @param {string} md-contact-email The field name of the contact object representing the
|
||||
* contact's email address.
|
||||
* @param {string} md-contact-image The field name of the contact object representing the
|
||||
* contact's image.
|
||||
*
|
||||
*
|
||||
* // The following attribute has been removed but may come back.
|
||||
* @param {expression=} filter-selected Whether to filter selected contacts from the list of
|
||||
* suggestions shown in the autocomplete.
|
||||
*
|
||||
*
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-contact-chips
|
||||
* ng-model="ctrl.contacts"
|
||||
* md-contacts="ctrl.querySearch($query)"
|
||||
* md-contact-name="name"
|
||||
* md-contact-image="image"
|
||||
* md-contact-email="email"
|
||||
* placeholder="To">
|
||||
* </md-contact-chips>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
var MD_CONTACT_CHIPS_TEMPLATE = '\
|
||||
<md-chips class="md-contact-chips"\
|
||||
ng-model="$mdContactChipsCtrl.contacts"\
|
||||
md-require-match="$mdContactChipsCtrl.requireMatch"\
|
||||
md-autocomplete-snap>\
|
||||
<md-autocomplete\
|
||||
md-menu-class="md-contact-chips-suggestions"\
|
||||
md-selected-item="$mdContactChipsCtrl.selectedItem"\
|
||||
md-search-text="$mdContactChipsCtrl.searchText"\
|
||||
md-items="item in $mdContactChipsCtrl.queryContact($mdContactChipsCtrl.searchText)"\
|
||||
md-item-text="$mdContactChipsCtrl.mdContactName"\
|
||||
md-no-cache="true"\
|
||||
md-autoselect\
|
||||
placeholder="{{$mdContactChipsCtrl.contacts.length == 0 ?\
|
||||
$mdContactChipsCtrl.placeholder : $mdContactChipsCtrl.secondaryPlaceholder}}">\
|
||||
<div class="md-contact-suggestion">\
|
||||
<img \
|
||||
ng-src="{{item[$mdContactChipsCtrl.contactImage]}}"\
|
||||
alt="{{item[$mdContactChipsCtrl.contactName]}}" />\
|
||||
<span class="md-contact-name" md-highlight-text="$mdContactChipsCtrl.searchText">\
|
||||
{{item[$mdContactChipsCtrl.contactName]}}\
|
||||
</span>\
|
||||
<span class="md-contact-email" >{{item[$mdContactChipsCtrl.contactEmail]}}</span>\
|
||||
</div>\
|
||||
</md-autocomplete>\
|
||||
<md-chip-template>\
|
||||
<div class="md-contact-avatar">\
|
||||
<img \
|
||||
ng-src="{{$chip[$mdContactChipsCtrl.contactImage]}}"\
|
||||
alt="{{$chip[$mdContactChipsCtrl.contactName]}}" />\
|
||||
</div>\
|
||||
<div class="md-contact-name">\
|
||||
{{$chip[$mdContactChipsCtrl.contactName]}}\
|
||||
</div>\
|
||||
</md-chip-template>\
|
||||
</md-chips>';
|
||||
|
||||
|
||||
/**
|
||||
* MDContactChips Directive Definition
|
||||
*
|
||||
* @param $mdTheming
|
||||
* @returns {*}
|
||||
* ngInject
|
||||
*/
|
||||
function MdContactChips ($mdTheming, $mdUtil) {
|
||||
return {
|
||||
template: function(element, attrs) {
|
||||
return MD_CONTACT_CHIPS_TEMPLATE;
|
||||
},
|
||||
restrict: 'E',
|
||||
controller: 'MdContactChipsCtrl',
|
||||
controllerAs: '$mdContactChipsCtrl',
|
||||
bindToController: true,
|
||||
compile: compile,
|
||||
scope: {
|
||||
contactQuery: '&mdContacts',
|
||||
placeholder: '@',
|
||||
secondaryPlaceholder: '@',
|
||||
contactName: '@mdContactName',
|
||||
contactImage: '@mdContactImage',
|
||||
contactEmail: '@mdContactEmail',
|
||||
contacts: '=ngModel',
|
||||
requireMatch: '=?mdRequireMatch'
|
||||
}
|
||||
};
|
||||
|
||||
function compile(element, attr) {
|
||||
return function postLink(scope, element, attrs, controllers) {
|
||||
|
||||
$mdUtil.initOptionalProperties(scope, attr);
|
||||
$mdTheming(element);
|
||||
|
||||
element.attr('tabindex', '-1');
|
||||
};
|
||||
}
|
||||
}
|
||||
MdContactChips.$inject = ["$mdTheming", "$mdUtil"];
|
||||
|
||||
ng.material.components.chips = angular.module("material.components.chips");
|
||||
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-content.md-THEME_NAME-theme {
|
||||
background-color: '{{background-color}}'; }
|
||||
20
www/lib/angular-material/modules/closure/content/content.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-content {
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch; }
|
||||
md-content[md-scroll-y] {
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden; }
|
||||
md-content[md-scroll-x] {
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden; }
|
||||
md-content.autoScroll {
|
||||
-webkit-overflow-scrolling: auto; }
|
||||
84
www/lib/angular-material/modules/closure/content/content.js
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.content');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.content
|
||||
*
|
||||
* @description
|
||||
* Scrollable content
|
||||
*/
|
||||
angular.module('material.components.content', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdContent', mdContentDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdContent
|
||||
* @module material.components.content
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-content>` directive is a container element useful for scrollable content
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* - Add the `[layout-padding]` attribute to make the content padded.
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-content layout-padding>
|
||||
* Lorem ipsum dolor sit amet, ne quod novum mei.
|
||||
* </md-content>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
function mdContentDirective($mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: ['$scope', '$element', ContentController],
|
||||
link: function(scope, element, attr) {
|
||||
var node = element[0];
|
||||
|
||||
$mdTheming(element);
|
||||
scope.$broadcast('$mdContentLoaded', element);
|
||||
|
||||
iosScrollFix(element[0]);
|
||||
}
|
||||
};
|
||||
|
||||
function ContentController($scope, $element) {
|
||||
this.$scope = $scope;
|
||||
this.$element = $element;
|
||||
}
|
||||
}
|
||||
mdContentDirective.$inject = ["$mdTheming"];
|
||||
|
||||
function iosScrollFix(node) {
|
||||
// IOS FIX:
|
||||
// If we scroll where there is no more room for the webview to scroll,
|
||||
// by default the webview itself will scroll up and down, this looks really
|
||||
// bad. So if we are scrolling to the very top or bottom, add/subtract one
|
||||
angular.element(node).on('$md.pressdown', function(ev) {
|
||||
// Only touch events
|
||||
if (ev.pointer.type !== 't') return;
|
||||
// Don't let a child content's touchstart ruin it for us.
|
||||
if (ev.$materialScrollFixed) return;
|
||||
ev.$materialScrollFixed = true;
|
||||
|
||||
if (node.scrollTop === 0) {
|
||||
node.scrollTop = 1;
|
||||
} else if (node.scrollHeight === node.scrollTop + node.offsetHeight) {
|
||||
node.scrollTop -= 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ng.material.components.content = angular.module("material.components.content");
|
||||
2594
www/lib/angular-material/modules/closure/core/core.css
Normal file
3772
www/lib/angular-material/modules/closure/core/core.js
vendored
Normal file
4
www/lib/angular-material/modules/closure/core/default-theme.js
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-dialog.md-THEME_NAME-theme {
|
||||
border-radius: 4px;
|
||||
background-color: '{{background-color}}'; }
|
||||
md-dialog.md-THEME_NAME-theme.md-content-overflow .md-actions {
|
||||
border-top-color: '{{foreground-4}}'; }
|
||||
111
www/lib/angular-material/modules/closure/dialog/dialog.css
Normal file
@@ -0,0 +1,111 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
.md-dialog-is-showing {
|
||||
max-height: 100%; }
|
||||
|
||||
.md-dialog-container {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 80; }
|
||||
|
||||
md-dialog {
|
||||
opacity: 0;
|
||||
min-width: 240px;
|
||||
max-width: 80%;
|
||||
max-height: 80%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
box-shadow: 0px 8px 10px -5px rgba(0, 0, 0, 0.14), 0px 16px 24px 2px rgba(0, 0, 0, 0.098), 0px 6px 30px 5px rgba(0, 0, 0, 0.084);
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column; }
|
||||
md-dialog.transition-in {
|
||||
opacity: 1;
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
-webkit-transform: translate3d(0, 0, 0) scale(1);
|
||||
transform: translate3d(0, 0, 0) scale(1); }
|
||||
md-dialog.transition-out {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
-webkit-transform: translate3d(0, 100%, 0) scale(0.2);
|
||||
transform: translate3d(0, 100%, 0) scale(0.2); }
|
||||
md-dialog > form {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
overflow: auto; }
|
||||
md-dialog md-dialog-content {
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding: 24px;
|
||||
overflow: auto;
|
||||
-webkit-overflow-scrolling: touch; }
|
||||
md-dialog md-dialog-content:not([layout=row]) > *:first-child:not(.md-subheader) {
|
||||
margin-top: 0; }
|
||||
md-dialog md-dialog-content:focus {
|
||||
outline: none; }
|
||||
md-dialog md-dialog-content .md-subheader {
|
||||
margin: 0; }
|
||||
md-dialog md-dialog-content .md-subheader.sticky-clone {
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.16); }
|
||||
md-dialog md-dialog-content.sticky-container {
|
||||
padding: 0; }
|
||||
md-dialog md-dialog-content.sticky-container > div {
|
||||
padding: 24px;
|
||||
padding-top: 0; }
|
||||
md-dialog .md-actions {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2;
|
||||
box-sizing: border-box;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-justify-content: flex-end;
|
||||
-ms-flex-pack: end;
|
||||
justify-content: flex-end;
|
||||
margin-bottom: 0;
|
||||
padding-right: 8px;
|
||||
padding-left: 16px;
|
||||
min-height: 52px; }
|
||||
md-dialog .md-actions .md-button {
|
||||
margin-bottom: 8px;
|
||||
margin-left: 8px;
|
||||
margin-right: 0;
|
||||
margin-top: 8px; }
|
||||
md-dialog.md-content-overflow .md-actions {
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-dialog {
|
||||
border: 1px solid #fff; } }
|
||||
713
www/lib/angular-material/modules/closure/dialog/dialog.js
vendored
Normal file
@@ -0,0 +1,713 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.dialog');
|
||||
goog.require('ng.material.components.backdrop');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.dialog
|
||||
*/
|
||||
angular.module('material.components.dialog', [
|
||||
'material.core',
|
||||
'material.components.backdrop'
|
||||
])
|
||||
.directive('mdDialog', MdDialogDirective)
|
||||
.provider('$mdDialog', MdDialogProvider);
|
||||
|
||||
function MdDialogDirective($$rAF, $mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
$$rAF(function() {
|
||||
var content = element[0].querySelector('md-dialog-content');
|
||||
if (content && content.scrollHeight > content.clientHeight) {
|
||||
element.addClass('md-content-overflow');
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
MdDialogDirective.$inject = ["$$rAF", "$mdTheming"];
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $mdDialog
|
||||
* @module material.components.dialog
|
||||
*
|
||||
* @description
|
||||
* `$mdDialog` opens a dialog over the app to inform users about critical information or require
|
||||
* them to make decisions. There are two approaches for setup: a simple promise API
|
||||
* and regular object syntax.
|
||||
*
|
||||
* ## Restrictions
|
||||
*
|
||||
* - The dialog is always given an isolate scope.
|
||||
* - The dialog's template must have an outer `<md-dialog>` element.
|
||||
* Inside, use an `<md-dialog-content>` element for the dialog's content, and use
|
||||
* an element with class `md-actions` for the dialog's actions.
|
||||
* - Dialogs must cover the entire application to keep interactions inside of them.
|
||||
* Use the `parent` option to change where dialogs are appended.
|
||||
*
|
||||
* ## Sizing
|
||||
* - Complex dialogs can be sized with `flex="percentage"`, i.e. `flex="66"`.
|
||||
* - Default max-width is 80% of the `rootElement` or `parent`.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div ng-app="demoApp" ng-controller="EmployeeController">
|
||||
* <div>
|
||||
* <md-button ng-click="showAlert()" class="md-raised md-warn">
|
||||
* Employee Alert!
|
||||
* </md-button>
|
||||
* </div>
|
||||
* <div>
|
||||
* <md-button ng-click="showDialog($event)" class="md-raised">
|
||||
* Custom Dialog
|
||||
* </md-button>
|
||||
* </div>
|
||||
* <div>
|
||||
* <md-button ng-click="closeAlert()" ng-disabled="!hasAlert()" class="md-raised">
|
||||
* Close Alert
|
||||
* </md-button>
|
||||
* </div>
|
||||
* <div>
|
||||
* <md-button ng-click="showGreeting($event)" class="md-raised md-primary" >
|
||||
* Greet Employee
|
||||
* </md-button>
|
||||
* </div>
|
||||
* </div>
|
||||
* </hljs>
|
||||
*
|
||||
* ### JavaScript: object syntax
|
||||
* <hljs lang="js">
|
||||
* (function(angular, undefined){
|
||||
* "use strict";
|
||||
*
|
||||
* angular
|
||||
* .module('demoApp', ['ngMaterial'])
|
||||
* .controller('AppCtrl', AppController);
|
||||
*
|
||||
* function AppController($scope, $mdDialog) {
|
||||
* var alert;
|
||||
* $scope.showAlert = showAlert;
|
||||
* $scope.showDialog = showDialog;
|
||||
* $scope.items = [1, 2, 3];
|
||||
*
|
||||
* // Internal method
|
||||
* function showAlert() {
|
||||
* alert = $mdDialog.alert({
|
||||
* title: 'Attention',
|
||||
* content: 'This is an example of how easy dialogs can be!',
|
||||
* ok: 'Close'
|
||||
* });
|
||||
*
|
||||
* $mdDialog
|
||||
* .show( alert )
|
||||
* .finally(function() {
|
||||
* alert = undefined;
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* function showDialog($event) {
|
||||
* var parentEl = angular.element(document.body);
|
||||
* $mdDialog.show({
|
||||
* parent: parentEl,
|
||||
* targetEvent: $event,
|
||||
* template:
|
||||
* '<md-dialog aria-label="List dialog">' +
|
||||
* ' <md-dialog-content>'+
|
||||
* ' <md-list>'+
|
||||
* ' <md-list-item ng-repeat="item in items">'+
|
||||
* ' <p>Number {{item}}</p>' +
|
||||
* ' </md-item>'+
|
||||
* ' </md-list>'+
|
||||
* ' </md-dialog-content>' +
|
||||
* ' <div class="md-actions">' +
|
||||
* ' <md-button ng-click="closeDialog()" class="md-primary">' +
|
||||
* ' Close Dialog' +
|
||||
* ' </md-button>' +
|
||||
* ' </div>' +
|
||||
* '</md-dialog>',
|
||||
* locals: {
|
||||
* items: $scope.items
|
||||
* },
|
||||
* controller: DialogController
|
||||
* });
|
||||
* function DialogController($scope, $mdDialog, items) {
|
||||
* $scope.items = items;
|
||||
* $scope.closeDialog = function() {
|
||||
* $mdDialog.hide();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* })(angular);
|
||||
* </hljs>
|
||||
*
|
||||
* ### JavaScript: promise API syntax, custom dialog template
|
||||
* <hljs lang="js">
|
||||
* (function(angular, undefined){
|
||||
* "use strict";
|
||||
*
|
||||
* angular
|
||||
* .module('demoApp', ['ngMaterial'])
|
||||
* .controller('EmployeeController', EmployeeEditor)
|
||||
* .controller('GreetingController', GreetingController);
|
||||
*
|
||||
* // Fictitious Employee Editor to show how to use simple and complex dialogs.
|
||||
*
|
||||
* function EmployeeEditor($scope, $mdDialog) {
|
||||
* var alert;
|
||||
*
|
||||
* $scope.showAlert = showAlert;
|
||||
* $scope.closeAlert = closeAlert;
|
||||
* $scope.showGreeting = showCustomGreeting;
|
||||
*
|
||||
* $scope.hasAlert = function() { return !!alert };
|
||||
* $scope.userName = $scope.userName || 'Bobby';
|
||||
*
|
||||
* // Dialog #1 - Show simple alert dialog and cache
|
||||
* // reference to dialog instance
|
||||
*
|
||||
* function showAlert() {
|
||||
* alert = $mdDialog.alert()
|
||||
* .title('Attention, ' + $scope.userName)
|
||||
* .content('This is an example of how easy dialogs can be!')
|
||||
* .ok('Close');
|
||||
*
|
||||
* $mdDialog
|
||||
* .show( alert )
|
||||
* .finally(function() {
|
||||
* alert = undefined;
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* // Close the specified dialog instance and resolve with 'finished' flag
|
||||
* // Normally this is not needed, just use '$mdDialog.hide()' to close
|
||||
* // the most recent dialog popup.
|
||||
*
|
||||
* function closeAlert() {
|
||||
* $mdDialog.hide( alert, "finished" );
|
||||
* alert = undefined;
|
||||
* }
|
||||
*
|
||||
* // Dialog #2 - Demonstrate more complex dialogs construction and popup.
|
||||
*
|
||||
* function showCustomGreeting($event) {
|
||||
* $mdDialog.show({
|
||||
* targetEvent: $event,
|
||||
* template:
|
||||
* '<md-dialog>' +
|
||||
*
|
||||
* ' <md-dialog-content>Hello {{ employee }}!</md-dialog-content>' +
|
||||
*
|
||||
* ' <div class="md-actions">' +
|
||||
* ' <md-button ng-click="closeDialog()" class="md-primary">' +
|
||||
* ' Close Greeting' +
|
||||
* ' </md-button>' +
|
||||
* ' </div>' +
|
||||
* '</md-dialog>',
|
||||
* controller: 'GreetingController',
|
||||
* onComplete: afterShowAnimation,
|
||||
* locals: { employee: $scope.userName }
|
||||
* });
|
||||
*
|
||||
* // When the 'enter' animation finishes...
|
||||
*
|
||||
* function afterShowAnimation(scope, element, options) {
|
||||
* // post-show code here: DOM element focus, etc.
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* // Dialog #3 - Demonstrate use of ControllerAs and passing $scope to dialog
|
||||
* // Here we used ng-controller="GreetingController as vm" and
|
||||
* // $scope.vm === <controller instance>
|
||||
*
|
||||
* function showCustomGreeting() {
|
||||
*
|
||||
* $mdDialog.show({
|
||||
* clickOutsideToClose: true,
|
||||
*
|
||||
* scope: $scope, // use parent scope in template
|
||||
* preserveScope: true, // do not forget this if use parent scope
|
||||
|
||||
* // Since GreetingController is instantiated with ControllerAs syntax
|
||||
* // AND we are passing the parent '$scope' to the dialog, we MUST
|
||||
* // use 'vm.<xxx>' in the template markup
|
||||
*
|
||||
* template: '<md-dialog>' +
|
||||
* ' <md-dialog-content>' +
|
||||
* ' Hi There {{vm.employee}}' +
|
||||
* ' </md-dialog-content>' +
|
||||
* '</md-dialog>',
|
||||
*
|
||||
* controller: function DialogController($scope, $mdDialog) {
|
||||
* $scope.closeDialog = function() {
|
||||
* $mdDialog.hide();
|
||||
* }
|
||||
* }
|
||||
* });
|
||||
* }
|
||||
*
|
||||
* }
|
||||
*
|
||||
* // Greeting controller used with the more complex 'showCustomGreeting()' custom dialog
|
||||
*
|
||||
* function GreetingController($scope, $mdDialog, employee) {
|
||||
* // Assigned from construction <code>locals</code> options...
|
||||
* $scope.employee = employee;
|
||||
*
|
||||
* $scope.closeDialog = function() {
|
||||
* // Easily hides most recent dialog shown...
|
||||
* // no specific instance reference is needed.
|
||||
* $mdDialog.hide();
|
||||
* };
|
||||
* }
|
||||
*
|
||||
* })(angular);
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdDialog#alert
|
||||
*
|
||||
* @description
|
||||
* Builds a preconfigured dialog with the specified message.
|
||||
*
|
||||
* @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
|
||||
*
|
||||
* - $mdDialogPreset#title(string) - sets title to string
|
||||
* - $mdDialogPreset#content(string) - sets content / message to string
|
||||
* - $mdDialogPreset#ok(string) - sets okay button text to string
|
||||
* - $mdDialogPreset#theme(string) - sets the theme of the dialog
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdDialog#confirm
|
||||
*
|
||||
* @description
|
||||
* Builds a preconfigured dialog with the specified message. You can call show and the promise returned
|
||||
* will be resolved only if the user clicks the confirm action on the dialog.
|
||||
*
|
||||
* @returns {obj} an `$mdDialogPreset` with the chainable configuration methods:
|
||||
*
|
||||
* Additionally, it supports the following methods:
|
||||
*
|
||||
* - $mdDialogPreset#title(string) - sets title to string
|
||||
* - $mdDialogPreset#content(string) - sets content / message to string
|
||||
* - $mdDialogPreset#ok(string) - sets okay button text to string
|
||||
* - $mdDialogPreset#cancel(string) - sets cancel button text to string
|
||||
* - $mdDialogPreset#theme(string) - sets the theme of the dialog
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdDialog#show
|
||||
*
|
||||
* @description
|
||||
* Show a dialog with the specified options.
|
||||
*
|
||||
* @param {object} optionsOrPreset Either provide an `$mdDialogPreset` returned from `alert()`, and
|
||||
* `confirm()`, or an options object with the following properties:
|
||||
* - `templateUrl` - `{string=}`: The url of a template that will be used as the content
|
||||
* of the dialog.
|
||||
* - `template` - `{string=}`: Same as templateUrl, except this is an actual template string.
|
||||
* - `targetEvent` - `{DOMClickEvent=}`: A click's event object. When passed in as an option,
|
||||
* the location of the click will be used as the starting point for the opening animation
|
||||
* of the the dialog.
|
||||
* - `scope` - `{object=}`: the scope to link the template / controller to. If none is specified,
|
||||
* it will create a new isolate scope.
|
||||
* This scope will be destroyed when the dialog is removed unless `preserveScope` is set to true.
|
||||
* - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed. Default is false
|
||||
* - `disableParentScroll` - `{boolean=}`: Whether to disable scrolling while the dialog is open.
|
||||
* Default true.
|
||||
* - `hasBackdrop` - `{boolean=}`: Whether there should be an opaque backdrop behind the dialog.
|
||||
* Default true.
|
||||
* - `clickOutsideToClose` - `{boolean=}`: Whether the user can click outside the dialog to
|
||||
* close it. Default false.
|
||||
* - `escapeToClose` - `{boolean=}`: Whether the user can press escape to close the dialog.
|
||||
* Default true.
|
||||
* - `focusOnOpen` - `{boolean=}`: An option to override focus behavior on open. Only disable if
|
||||
* focusing some other way, as focus management is required for dialogs to be accessible.
|
||||
* Defaults to true.
|
||||
* - `controller` - `{string=}`: The controller to associate with the dialog. The controller
|
||||
* will be injected with the local `$mdDialog`, which passes along a scope for the dialog.
|
||||
* - `locals` - `{object=}`: An object containing key/value pairs. The keys will be used as names
|
||||
* of values to inject into the controller. For example, `locals: {three: 3}` would inject
|
||||
* `three` into the controller, with the value 3. If `bindToController` is true, they will be
|
||||
* copied to the controller instead.
|
||||
* - `bindToController` - `bool`: bind the locals to the controller, instead of passing them in.
|
||||
* These values will not be available until after initialization.
|
||||
* - `resolve` - `{object=}`: Similar to locals, except it takes promises as values, and the
|
||||
* dialog will not open until all of the promises resolve.
|
||||
* - `controllerAs` - `{string=}`: An alias to assign the controller to on the scope.
|
||||
* - `parent` - `{element=}`: The element to append the dialog to. Defaults to appending
|
||||
* to the root element of the application.
|
||||
* - `onComplete` `{function=}`: Callback function used to announce when the show() action is
|
||||
* finished.
|
||||
*
|
||||
* @returns {promise} A promise that can be resolved with `$mdDialog.hide()` or
|
||||
* rejected with `$mdDialog.cancel()`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdDialog#hide
|
||||
*
|
||||
* @description
|
||||
* Hide an existing dialog and resolve the promise returned from `$mdDialog.show()`.
|
||||
*
|
||||
* @param {*=} response An argument for the resolved promise.
|
||||
*
|
||||
* @returns {promise} A promise that is resolved when the dialog has been closed.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdDialog#cancel
|
||||
*
|
||||
* @description
|
||||
* Hide an existing dialog and reject the promise returned from `$mdDialog.show()`.
|
||||
*
|
||||
* @param {*=} response An argument for the rejected promise.
|
||||
*
|
||||
* @returns {promise} A promise that is resolved when the dialog has been closed.
|
||||
*/
|
||||
|
||||
function MdDialogProvider($$interimElementProvider) {
|
||||
|
||||
var alertDialogMethods = ['title', 'content', 'ariaLabel', 'ok'];
|
||||
|
||||
advancedDialogOptions.$inject = ["$mdDialog", "$mdTheming"];
|
||||
dialogDefaultOptions.$inject = ["$mdAria", "$document", "$mdUtil", "$mdConstant", "$mdTheming", "$mdDialog", "$timeout", "$rootElement", "$animate", "$$rAF", "$q"];
|
||||
return $$interimElementProvider('$mdDialog')
|
||||
.setDefaults({
|
||||
methods: ['disableParentScroll', 'hasBackdrop', 'clickOutsideToClose', 'escapeToClose', 'targetEvent', 'parent'],
|
||||
options: dialogDefaultOptions
|
||||
})
|
||||
.addPreset('alert', {
|
||||
methods: ['title', 'content', 'ariaLabel', 'ok', 'theme'],
|
||||
options: advancedDialogOptions
|
||||
})
|
||||
.addPreset('confirm', {
|
||||
methods: ['title', 'content', 'ariaLabel', 'ok', 'cancel', 'theme'],
|
||||
options: advancedDialogOptions
|
||||
});
|
||||
|
||||
/* ngInject */
|
||||
function advancedDialogOptions($mdDialog, $mdTheming) {
|
||||
return {
|
||||
template: [
|
||||
'<md-dialog md-theme="{{ dialog.theme }}" aria-label="{{ dialog.ariaLabel }}">',
|
||||
'<md-dialog-content role="document" tabIndex="-1">',
|
||||
'<h2 class="md-title">{{ dialog.title }}</h2>',
|
||||
'<p>{{ dialog.content }}</p>',
|
||||
'</md-dialog-content>',
|
||||
'<div class="md-actions">',
|
||||
'<md-button ng-if="dialog.$type == \'confirm\'"' +
|
||||
' ng-click="dialog.abort()" class="md-primary">',
|
||||
'{{ dialog.cancel }}',
|
||||
'</md-button>',
|
||||
'<md-button ng-click="dialog.hide()" class="md-primary">',
|
||||
'{{ dialog.ok }}',
|
||||
'</md-button>',
|
||||
'</div>',
|
||||
'</md-dialog>'
|
||||
].join(''),
|
||||
controller: function mdDialogCtrl() {
|
||||
this.hide = function() {
|
||||
$mdDialog.hide(true);
|
||||
};
|
||||
this.abort = function() {
|
||||
$mdDialog.cancel();
|
||||
};
|
||||
},
|
||||
controllerAs: 'dialog',
|
||||
bindToController: true,
|
||||
theme: $mdTheming.defaultTheme()
|
||||
};
|
||||
}
|
||||
|
||||
/* ngInject */
|
||||
function dialogDefaultOptions($mdAria, $document, $mdUtil, $mdConstant, $mdTheming, $mdDialog, $timeout, $rootElement, $animate, $$rAF, $q) {
|
||||
return {
|
||||
hasBackdrop: true,
|
||||
isolateScope: true,
|
||||
onShow: onShow,
|
||||
onRemove: onRemove,
|
||||
clickOutsideToClose: false,
|
||||
escapeToClose: true,
|
||||
targetEvent: null,
|
||||
focusOnOpen: true,
|
||||
disableParentScroll: true,
|
||||
transformTemplate: function(template) {
|
||||
return '<div class="md-dialog-container">' + template + '</div>';
|
||||
}
|
||||
};
|
||||
|
||||
function trapFocus(ev) {
|
||||
var dialog = document.querySelector('md-dialog');
|
||||
|
||||
if (dialog && !dialog.contains(ev.target)) {
|
||||
ev.stopImmediatePropagation();
|
||||
dialog.focus();
|
||||
}
|
||||
}
|
||||
|
||||
// On show method for dialogs
|
||||
function onShow(scope, element, options) {
|
||||
angular.element($document[0].body).addClass('md-dialog-is-showing');
|
||||
element = $mdUtil.extractElementByName(element, 'md-dialog');
|
||||
|
||||
// Incase the user provides a raw dom element, always wrap it in jqLite
|
||||
options.parent = angular.element(options.parent);
|
||||
|
||||
options.popInTarget = angular.element((options.targetEvent || {}).target);
|
||||
var closeButton = findCloseButton();
|
||||
|
||||
if (options.hasBackdrop) {
|
||||
// Fix for IE 10
|
||||
var computeFrom = (options.parent[0] == $document[0].body && $document[0].documentElement
|
||||
&& $document[0].documentElement.scrollTop) ? angular.element($document[0].documentElement) : options.parent;
|
||||
var parentOffset = computeFrom.prop('scrollTop');
|
||||
options.backdrop = angular.element('<md-backdrop class="md-dialog-backdrop md-opaque">');
|
||||
options.backdrop.css('top', parentOffset +'px');
|
||||
$mdTheming.inherit(options.backdrop, options.parent);
|
||||
$animate.enter(options.backdrop, options.parent);
|
||||
element.css('top', parentOffset +'px');
|
||||
}
|
||||
|
||||
var role = 'dialog',
|
||||
elementToFocus = closeButton;
|
||||
|
||||
if (options.$type === 'alert') {
|
||||
role = 'alertdialog';
|
||||
elementToFocus = element.find('md-dialog-content');
|
||||
}
|
||||
|
||||
configureAria(element.find('md-dialog'), role, options);
|
||||
|
||||
document.addEventListener('focus', trapFocus, true);
|
||||
|
||||
if (options.disableParentScroll) {
|
||||
options.lastOverflow = options.parent.css('overflow');
|
||||
options.parent.css('overflow', 'hidden');
|
||||
}
|
||||
|
||||
return dialogPopIn(
|
||||
element,
|
||||
options.parent,
|
||||
options.popInTarget && options.popInTarget.length && options.popInTarget
|
||||
)
|
||||
.then(function() {
|
||||
|
||||
applyAriaToSiblings(element, true);
|
||||
|
||||
if (options.escapeToClose) {
|
||||
options.rootElementKeyupCallback = function(e) {
|
||||
if (e.keyCode === $mdConstant.KEY_CODE.ESCAPE) {
|
||||
$timeout($mdDialog.cancel);
|
||||
}
|
||||
};
|
||||
$rootElement.on('keyup', options.rootElementKeyupCallback);
|
||||
}
|
||||
|
||||
if (options.clickOutsideToClose) {
|
||||
options.dialogClickOutsideCallback = function(ev) {
|
||||
// Only close if we click the flex container outside the backdrop
|
||||
if (ev.target === element[0]) {
|
||||
$timeout($mdDialog.cancel);
|
||||
}
|
||||
};
|
||||
element.on('click', options.dialogClickOutsideCallback);
|
||||
}
|
||||
|
||||
if (options.focusOnOpen) {
|
||||
elementToFocus.focus();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function findCloseButton() {
|
||||
//If no element with class dialog-close, try to find the last
|
||||
//button child in md-actions and assume it is a close button
|
||||
var closeButton = element[0].querySelector('.dialog-close');
|
||||
if (!closeButton) {
|
||||
var actionButtons = element[0].querySelectorAll('.md-actions button');
|
||||
closeButton = actionButtons[ actionButtons.length - 1 ];
|
||||
}
|
||||
return angular.element(closeButton);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// On remove function for all dialogs
|
||||
function onRemove(scope, element, options) {
|
||||
angular.element($document[0].body).removeClass('md-dialog-is-showing');
|
||||
|
||||
if (options.backdrop) {
|
||||
$animate.leave(options.backdrop);
|
||||
}
|
||||
if (options.disableParentScroll) {
|
||||
options.parent.css('overflow', options.lastOverflow);
|
||||
delete options.lastOverflow;
|
||||
}
|
||||
if (options.escapeToClose) {
|
||||
$rootElement.off('keyup', options.rootElementKeyupCallback);
|
||||
}
|
||||
if (options.clickOutsideToClose) {
|
||||
element.off('click', options.dialogClickOutsideCallback);
|
||||
}
|
||||
|
||||
applyAriaToSiblings(element, false);
|
||||
|
||||
document.removeEventListener('focus', trapFocus, true);
|
||||
|
||||
return dialogPopOut(
|
||||
element,
|
||||
options.parent,
|
||||
options.popInTarget && options.popInTarget.length && options.popInTarget
|
||||
).then(function() {
|
||||
element.remove();
|
||||
options.popInTarget && options.popInTarget.focus();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject ARIA-specific attributes appropriate for Dialogs
|
||||
*/
|
||||
function configureAria(element, role, options) {
|
||||
|
||||
element.attr({
|
||||
'role': role,
|
||||
'tabIndex': '-1'
|
||||
});
|
||||
|
||||
var dialogContent = element.find('md-dialog-content');
|
||||
if (dialogContent.length === 0){
|
||||
dialogContent = element;
|
||||
}
|
||||
|
||||
var dialogId = element.attr('id') || ('dialog_' + $mdUtil.nextUid());
|
||||
dialogContent.attr('id', dialogId);
|
||||
element.attr('aria-describedby', dialogId);
|
||||
|
||||
if (options.ariaLabel) {
|
||||
$mdAria.expect(element, 'aria-label', options.ariaLabel);
|
||||
}
|
||||
else {
|
||||
$mdAria.expectAsync(element, 'aria-label', function() {
|
||||
var words = dialogContent.text().split(/\s+/);
|
||||
if (words.length > 3) words = words.slice(0,3).concat('...');
|
||||
return words.join(' ');
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Utility function to filter out raw DOM nodes
|
||||
*/
|
||||
function isNodeOneOf(elem, nodeTypeArray) {
|
||||
if (nodeTypeArray.indexOf(elem.nodeName) !== -1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Walk DOM to apply or remove aria-hidden on sibling nodes
|
||||
* and parent sibling nodes
|
||||
*
|
||||
* Prevents screen reader interaction behind modal window
|
||||
* on swipe interfaces
|
||||
*/
|
||||
function applyAriaToSiblings(element, value) {
|
||||
var attribute = 'aria-hidden';
|
||||
|
||||
// get raw DOM node
|
||||
element = element[0];
|
||||
|
||||
function walkDOM(element) {
|
||||
while (element.parentNode) {
|
||||
if (element === document.body) {
|
||||
return;
|
||||
}
|
||||
var children = element.parentNode.children;
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
// skip over child if it is an ascendant of the dialog
|
||||
// or a script or style tag
|
||||
if (element !== children[i] && !isNodeOneOf(children[i], ['SCRIPT', 'STYLE'])) {
|
||||
children[i].setAttribute(attribute, value);
|
||||
}
|
||||
}
|
||||
|
||||
walkDOM(element = element.parentNode);
|
||||
}
|
||||
}
|
||||
walkDOM(element);
|
||||
}
|
||||
|
||||
function dialogPopIn(container, parentElement, clickElement) {
|
||||
var dialogEl = container.find('md-dialog');
|
||||
|
||||
parentElement.append(container);
|
||||
transformToClickElement(dialogEl, clickElement);
|
||||
|
||||
$$rAF(function() {
|
||||
dialogEl.addClass('transition-in')
|
||||
.css($mdConstant.CSS.TRANSFORM, '');
|
||||
});
|
||||
|
||||
return $mdUtil.transitionEndPromise(dialogEl);
|
||||
}
|
||||
|
||||
function dialogPopOut(container, parentElement, clickElement) {
|
||||
var dialogEl = container.find('md-dialog');
|
||||
|
||||
dialogEl.addClass('transition-out').removeClass('transition-in');
|
||||
transformToClickElement(dialogEl, clickElement);
|
||||
|
||||
return $mdUtil.transitionEndPromise(dialogEl);
|
||||
}
|
||||
|
||||
function transformToClickElement(dialogEl, clickElement) {
|
||||
if (clickElement) {
|
||||
var clickRect = clickElement[0].getBoundingClientRect();
|
||||
var dialogRect = dialogEl[0].getBoundingClientRect();
|
||||
|
||||
var scaleX = Math.min(0.5, clickRect.width / dialogRect.width);
|
||||
var scaleY = Math.min(0.5, clickRect.height / dialogRect.height);
|
||||
|
||||
dialogEl.css($mdConstant.CSS.TRANSFORM, 'translate3d(' +
|
||||
(-dialogRect.left + clickRect.left + clickRect.width/2 - dialogRect.width/2) + 'px,' +
|
||||
(-dialogRect.top + clickRect.top + clickRect.height/2 - dialogRect.height/2) + 'px,' +
|
||||
'0) scale(' + scaleX + ',' + scaleY + ')'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function dialogTransitionEnd(dialogEl) {
|
||||
var deferred = $q.defer();
|
||||
dialogEl.on($mdConstant.CSS.TRANSITIONEND, finished);
|
||||
function finished(ev) {
|
||||
//Make sure this transitionend didn't bubble up from a child
|
||||
if (ev.target === dialogEl[0]) {
|
||||
dialogEl.off($mdConstant.CSS.TRANSITIONEND, finished);
|
||||
deferred.resolve();
|
||||
}
|
||||
}
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
MdDialogProvider.$inject = ["$$interimElementProvider"];
|
||||
|
||||
ng.material.components.dialog = angular.module("material.components.dialog");
|
||||
@@ -0,0 +1,9 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-divider.md-THEME_NAME-theme {
|
||||
border-top-color: '{{foreground-4}}'; }
|
||||
14
www/lib/angular-material/modules/closure/divider/divider.css
Normal file
@@ -0,0 +1,14 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-divider {
|
||||
display: block;
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
margin: 0; }
|
||||
md-divider[md-inset] {
|
||||
margin-left: 80px; }
|
||||
45
www/lib/angular-material/modules/closure/divider/divider.js
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.divider');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.divider
|
||||
* @description Divider module!
|
||||
*/
|
||||
angular.module('material.components.divider', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdDivider', MdDividerDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdDivider
|
||||
* @module material.components.divider
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* Dividers group and separate content within lists and page layouts using strong visual and spatial distinctions. This divider is a thin rule, lightweight enough to not distract the user from content.
|
||||
*
|
||||
* @param {boolean=} md-inset Add this attribute to activate the inset divider style.
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-divider></md-divider>
|
||||
*
|
||||
* <md-divider md-inset></md-divider>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function MdDividerDirective($mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: $mdTheming
|
||||
};
|
||||
}
|
||||
MdDividerDirective.$inject = ["$mdTheming"];
|
||||
|
||||
ng.material.components.divider = angular.module("material.components.divider");
|
||||
57
www/lib/angular-material/modules/closure/fabActions/fabActions.js
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.fabActions');
|
||||
goog.require('ng.material.core');
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('material.components.fabActions', ['material.core'])
|
||||
.directive('mdFabActions', MdFabActionsDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdFabActions
|
||||
* @module material.components.fabSpeedDial
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-fab-actions>` directive is used inside of a `<md-fab-speed-dial>` or
|
||||
* `<md-fab-toolbar>` directive to mark the an element (or elements) as the actions and setup the
|
||||
* proper event listeners.
|
||||
*
|
||||
* @usage
|
||||
* See the `<md-fab-speed-dial>` or `<md-fab-toolbar>` directives for example usage.
|
||||
*/
|
||||
function MdFabActionsDirective() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
||||
require: ['^?mdFabSpeedDial', '^?mdFabToolbar'],
|
||||
|
||||
link: function(scope, element, attributes, controllers) {
|
||||
// Grab whichever parent controller is used
|
||||
var controller = controllers[0] || controllers[1];
|
||||
|
||||
// Make the children open/close their parent directive
|
||||
if (controller) {
|
||||
angular.forEach(element.children(), function(child) {
|
||||
angular.element(child).on('focus', controller.open);
|
||||
angular.element(child).on('blur', controller.close);
|
||||
});
|
||||
}
|
||||
|
||||
// After setting up the listeners, wrap every child in a new div and add a class that we can
|
||||
// scale/fling independently
|
||||
element.children().wrap('<div class="md-fab-action-item">');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
ng.material.components.fabActions = angular.module("material.components.fabActions");
|
||||
@@ -0,0 +1,100 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-fab-speed-dial {
|
||||
position: relative;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
/*
|
||||
* Handle the animations
|
||||
*/ }
|
||||
md-fab-speed-dial .md-css-variables {
|
||||
z-index: 20; }
|
||||
md-fab-speed-dial.md-is-open .md-fab-action-item {
|
||||
visibility: visible; }
|
||||
md-fab-speed-dial md-fab-actions {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
height: 100%; }
|
||||
md-fab-speed-dial md-fab-actions .md-fab-action-item {
|
||||
visibility: hidden;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-fab-speed-dial.md-down {
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column; }
|
||||
md-fab-speed-dial.md-down md-fab-trigger {
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1; }
|
||||
md-fab-speed-dial.md-down md-fab-actions {
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2; }
|
||||
md-fab-speed-dial.md-up {
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column; }
|
||||
md-fab-speed-dial.md-up md-fab-trigger {
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2; }
|
||||
md-fab-speed-dial.md-up md-fab-actions {
|
||||
-webkit-flex-direction: column-reverse;
|
||||
-ms-flex-direction: column-reverse;
|
||||
flex-direction: column-reverse;
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1; }
|
||||
md-fab-speed-dial.md-left {
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row; }
|
||||
md-fab-speed-dial.md-left md-fab-trigger {
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2; }
|
||||
md-fab-speed-dial.md-left md-fab-actions {
|
||||
-webkit-flex-direction: row-reverse;
|
||||
-ms-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse;
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1; }
|
||||
md-fab-speed-dial.md-left md-fab-actions .md-fab-action-item {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-fab-speed-dial.md-right {
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row; }
|
||||
md-fab-speed-dial.md-right md-fab-trigger {
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1; }
|
||||
md-fab-speed-dial.md-right md-fab-actions {
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2; }
|
||||
md-fab-speed-dial.md-right md-fab-actions .md-fab-action-item {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-fab-speed-dial.md-scale .md-fab-action-item {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 0.14286s; }
|
||||
236
www/lib/angular-material/modules/closure/fabSpeedDial/fabSpeedDial.js
vendored
Normal file
@@ -0,0 +1,236 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.fabSpeedDial');
|
||||
goog.require('ng.material.components.fabActions');
|
||||
goog.require('ng.material.components.fabTrigger');
|
||||
goog.require('ng.material.core');
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('material.components.fabSpeedDial', [
|
||||
'material.core',
|
||||
'material.components.fabTrigger',
|
||||
'material.components.fabActions'
|
||||
])
|
||||
.directive('mdFabSpeedDial', MdFabSpeedDialDirective)
|
||||
.animation('.md-fling', MdFabSpeedDialFlingAnimation)
|
||||
.animation('.md-scale', MdFabSpeedDialScaleAnimation);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdFabSpeedDial
|
||||
* @module material.components.fabSpeedDial
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-fab-speed-dial>` directive is used to present a series of popup elements (usually
|
||||
* `<md-button>`s) for quick access to common actions.
|
||||
*
|
||||
* There are currently two animations available by applying one of the following classes to
|
||||
* the component:
|
||||
*
|
||||
* - `md-fling` - The speed dial items appear from underneath the trigger and move into their
|
||||
* appropriate positions.
|
||||
* - `md-scale` - The speed dial items appear in their proper places by scaling from 0% to 100%.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-fab-speed-dial direction="up" class="md-fling">
|
||||
* <md-fab-trigger>
|
||||
* <md-button aria-label="Add..."><md-icon icon="/img/icons/plus.svg"></md-icon></md-button>
|
||||
* </md-fab-trigger>
|
||||
*
|
||||
* <md-fab-actions>
|
||||
* <md-button aria-label="Add User">
|
||||
* <md-icon icon="/img/icons/user.svg"></md-icon>
|
||||
* </md-button>
|
||||
*
|
||||
* <md-button aria-label="Add Group">
|
||||
* <md-icon icon="/img/icons/group.svg"></md-icon>
|
||||
* </md-button>
|
||||
* </md-fab-actions>
|
||||
* </md-fab-speed-dial>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {string=} md-direction From which direction you would like the speed dial to appear
|
||||
* relative to the trigger element.
|
||||
* @param {expression=} md-open Programmatically control whether or not the speed-dial is visible.
|
||||
*/
|
||||
function MdFabSpeedDialDirective() {
|
||||
FabSpeedDialController.$inject = ["$scope", "$element", "$animate"];
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
||||
scope: {
|
||||
direction: '@?mdDirection',
|
||||
isOpen: '=?mdOpen'
|
||||
},
|
||||
|
||||
bindToController: true,
|
||||
controller: FabSpeedDialController,
|
||||
controllerAs: 'vm',
|
||||
|
||||
link: FabSpeedDialLink
|
||||
};
|
||||
|
||||
function FabSpeedDialLink(scope, element) {
|
||||
// Prepend an element to hold our CSS variables so we can use them in the animations below
|
||||
element.prepend('<div class="md-css-variables"></div>');
|
||||
}
|
||||
|
||||
function FabSpeedDialController($scope, $element, $animate) {
|
||||
var vm = this;
|
||||
|
||||
// Define our open/close functions
|
||||
// Note: Used by fabTrigger and fabActions directives
|
||||
vm.open = function() {
|
||||
$scope.$apply('vm.isOpen = true');
|
||||
};
|
||||
|
||||
vm.close = function() {
|
||||
$scope.$apply('vm.isOpen = false');
|
||||
};
|
||||
|
||||
setupDefaults();
|
||||
setupListeners();
|
||||
setupWatchers();
|
||||
|
||||
// Set our default variables
|
||||
function setupDefaults() {
|
||||
// Set the default direction to 'down' if none is specified
|
||||
vm.direction = vm.direction || 'down';
|
||||
|
||||
// Set the default to be closed
|
||||
vm.isOpen = vm.isOpen || false;
|
||||
}
|
||||
|
||||
// Setup our event listeners
|
||||
function setupListeners() {
|
||||
$element.on('mouseenter', vm.open);
|
||||
$element.on('mouseleave', vm.close);
|
||||
}
|
||||
|
||||
// Setup our watchers
|
||||
function setupWatchers() {
|
||||
// Watch for changes to the direction and update classes/attributes
|
||||
$scope.$watch('vm.direction', function(newDir, oldDir) {
|
||||
// Add the appropriate classes so we can target the direction in the CSS
|
||||
$animate.removeClass($element, 'md-' + oldDir);
|
||||
$animate.addClass($element, 'md-' + newDir);
|
||||
});
|
||||
|
||||
|
||||
// Watch for changes to md-open
|
||||
$scope.$watch('vm.isOpen', function(isOpen) {
|
||||
var toAdd = isOpen ? 'md-is-open' : '';
|
||||
var toRemove = isOpen ? '' : 'md-is-open';
|
||||
|
||||
$animate.setClass($element, toAdd, toRemove);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MdFabSpeedDialFlingAnimation() {
|
||||
function runAnimation(element) {
|
||||
var el = element[0];
|
||||
var ctrl = element.controller('mdFabSpeedDial');
|
||||
var items = el.querySelectorAll('.md-fab-action-item');
|
||||
|
||||
// Grab our element which stores CSS variables
|
||||
var variablesElement = el.querySelector('.md-css-variables');
|
||||
|
||||
// Setup JS variables based on our CSS variables
|
||||
var startZIndex = variablesElement.style.zIndex;
|
||||
|
||||
// Always reset the items to their natural position/state
|
||||
angular.forEach(items, function(item, index) {
|
||||
var styles = item.style;
|
||||
|
||||
styles.transform = '';
|
||||
styles.transitionDelay = '';
|
||||
styles.opacity = 1;
|
||||
|
||||
// Make the items closest to the trigger have the highest z-index
|
||||
item.style.zIndex = (items.length - index) + startZIndex;
|
||||
});
|
||||
|
||||
// If the control is closed, hide the items behind the trigger
|
||||
if (!ctrl.isOpen) {
|
||||
angular.forEach(items, function(item, index) {
|
||||
var newPosition, axis;
|
||||
|
||||
switch (ctrl.direction) {
|
||||
case 'up':
|
||||
newPosition = item.scrollHeight * (index + 1);
|
||||
axis = 'Y';
|
||||
break;
|
||||
case 'down':
|
||||
newPosition = -item.scrollHeight * (index + 1);
|
||||
axis = 'Y';
|
||||
break;
|
||||
case 'left':
|
||||
newPosition = item.scrollWidth * (index + 1);
|
||||
axis = 'X';
|
||||
break;
|
||||
case 'right':
|
||||
newPosition = -item.scrollWidth * (index + 1);
|
||||
axis = 'X';
|
||||
break;
|
||||
}
|
||||
|
||||
item.style.transform = 'translate' + axis + '(' + newPosition + 'px)';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
addClass: function(element, className, done) {
|
||||
if (element.hasClass('md-fling')) {
|
||||
runAnimation(element);
|
||||
}
|
||||
},
|
||||
removeClass: function(element, className, done) {
|
||||
runAnimation(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function MdFabSpeedDialScaleAnimation() {
|
||||
var delay = 65;
|
||||
|
||||
function runAnimation(element) {
|
||||
var el = element[0];
|
||||
var ctrl = element.controller('mdFabSpeedDial');
|
||||
var items = el.querySelectorAll('.md-fab-action-item');
|
||||
|
||||
// Always reset the items to their natural position/state
|
||||
angular.forEach(items, function(item, index) {
|
||||
var styles = item.style,
|
||||
offsetDelay = index * delay;
|
||||
|
||||
styles.opacity = ctrl.isOpen ? 1 : 0;
|
||||
styles.transform = ctrl.isOpen ? 'scale(1)' : 'scale(0)';
|
||||
styles.transitionDelay = (ctrl.isOpen ? offsetDelay : (items.length - offsetDelay)) + 'ms';
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
addClass: function(element, className, done) {
|
||||
runAnimation(element);
|
||||
},
|
||||
|
||||
removeClass: function(element, className, done) {
|
||||
runAnimation(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
ng.material.components.fabSpeedDial = angular.module("material.components.fabSpeedDial");
|
||||
@@ -0,0 +1,74 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-fab-toolbar {
|
||||
display: block;
|
||||
/*
|
||||
* Closed styling
|
||||
*/
|
||||
/*
|
||||
* Hover styling
|
||||
*/ }
|
||||
md-fab-toolbar .md-fab-toolbar-wrapper {
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
height: 6.8rem; }
|
||||
md-fab-toolbar md-fab-trigger {
|
||||
position: absolute;
|
||||
z-index: 20; }
|
||||
md-fab-toolbar md-fab-trigger button {
|
||||
overflow: visible !important; }
|
||||
md-fab-toolbar md-fab-trigger .md-fab-toolbar-background {
|
||||
display: block;
|
||||
position: absolute;
|
||||
z-index: 21;
|
||||
opacity: 1;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-fab-toolbar md-fab-trigger md-icon {
|
||||
position: relative;
|
||||
z-index: 22;
|
||||
opacity: 1;
|
||||
transition: all 200ms ease-in; }
|
||||
md-fab-toolbar.md-left md-fab-trigger {
|
||||
left: 0; }
|
||||
md-fab-toolbar.md-left .md-toolbar-tools {
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row; }
|
||||
md-fab-toolbar.md-right md-fab-trigger {
|
||||
right: 0; }
|
||||
md-fab-toolbar.md-right .md-toolbar-tools {
|
||||
-webkit-flex-direction: row-reverse;
|
||||
-ms-flex-direction: row-reverse;
|
||||
flex-direction: row-reverse; }
|
||||
md-fab-toolbar.md-right .md-toolbar-tools > .md-button:first-child {
|
||||
margin-left: 0.6rem; }
|
||||
md-fab-toolbar.md-right .md-toolbar-tools > .md-button:first-child {
|
||||
margin-right: -0.8rem; }
|
||||
md-fab-toolbar.md-right .md-toolbar-tools > .md-button:last-child {
|
||||
margin-right: 8px; }
|
||||
md-fab-toolbar md-toolbar {
|
||||
background-color: transparent !important;
|
||||
z-index: 23; }
|
||||
md-fab-toolbar md-toolbar .md-toolbar-tools {
|
||||
padding: 0 20px;
|
||||
margin-top: 3px; }
|
||||
md-fab-toolbar md-toolbar .md-fab-action-item {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 0.15s; }
|
||||
md-fab-toolbar.md-is-open md-fab-trigger > button {
|
||||
box-shadow: none; }
|
||||
md-fab-toolbar.md-is-open md-fab-trigger > button md-icon {
|
||||
opacity: 0; }
|
||||
md-fab-toolbar.md-is-open .md-fab-action-item {
|
||||
opacity: 1;
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
218
www/lib/angular-material/modules/closure/fabToolbar/fabToolbar.js
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.fabToolbar');
|
||||
goog.require('ng.material.components.fabActions');
|
||||
goog.require('ng.material.components.fabTrigger');
|
||||
goog.require('ng.material.core');
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('material.components.fabToolbar', [
|
||||
'material.core',
|
||||
'material.components.fabTrigger',
|
||||
'material.components.fabActions'
|
||||
])
|
||||
.directive('mdFabToolbar', MdFabToolbarDirective)
|
||||
.animation('.md-fab-toolbar', MdFabToolbarAnimation);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdFabToolbar
|
||||
* @module material.components.fabToolbar
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* The `<md-fab-toolbar>` directive is used present a toolbar of elements (usually `<md-button>`s)
|
||||
* for quick access to common actions when a floating action button is activated (via hover or
|
||||
* keyboard navigation).
|
||||
*
|
||||
* @usage
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-fab-toolbar>
|
||||
* <md-fab-trigger>
|
||||
* <md-button aria-label="Add..."><md-icon icon="/img/icons/plus.svg"></md-icon></md-button>
|
||||
* </md-fab-trigger>
|
||||
*
|
||||
* <md-fab-actions>
|
||||
* <md-button aria-label="Add User">
|
||||
* <md-icon icon="/img/icons/user.svg"></md-icon>
|
||||
* </md-button>
|
||||
*
|
||||
* <md-button aria-label="Add Group">
|
||||
* <md-icon icon="/img/icons/group.svg"></md-icon>
|
||||
* </md-button>
|
||||
* </md-fab-actions>
|
||||
* </md-fab-toolbar>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {expression=} md-open Programmatically control whether or not the toolbar is visible.
|
||||
*/
|
||||
function MdFabToolbarDirective() {
|
||||
FabToolbarController.$inject = ["$scope", "$element", "$animate"];
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
template:
|
||||
'<div class="md-fab-toolbar-wrapper">' +
|
||||
' <div class="md-fab-toolbar-content" ng-transclude></div>' +
|
||||
'</div>',
|
||||
|
||||
scope: {
|
||||
isOpen: '=?mdOpen'
|
||||
},
|
||||
|
||||
bindToController: true,
|
||||
controller: FabToolbarController,
|
||||
controllerAs: 'vm',
|
||||
|
||||
link: link
|
||||
};
|
||||
|
||||
function FabToolbarController($scope, $element, $animate) {
|
||||
var vm = this;
|
||||
|
||||
// Set the default to be closed
|
||||
vm.isOpen = vm.isOpen || false;
|
||||
|
||||
vm.open = function() {
|
||||
vm.isOpen = true;
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
vm.close = function() {
|
||||
vm.isOpen = false;
|
||||
$scope.$apply();
|
||||
};
|
||||
|
||||
// Add our class so we can trigger the animation on start
|
||||
$element.addClass('md-fab-toolbar');
|
||||
|
||||
// Setup some mouse events so the hover effect can be triggered
|
||||
// anywhere over the toolbar
|
||||
$element.on('mouseenter', vm.open);
|
||||
$element.on('mouseleave', vm.close);
|
||||
|
||||
// Watch for changes to md-open and toggle our class
|
||||
$scope.$watch('vm.isOpen', function(isOpen) {
|
||||
var toAdd = isOpen ? 'md-is-open' : '';
|
||||
var toRemove = isOpen ? '' : 'md-is-open';
|
||||
|
||||
$animate.setClass($element, toAdd, toRemove);
|
||||
});
|
||||
}
|
||||
|
||||
function link(scope, element, attributes) {
|
||||
// Don't allow focus on the trigger
|
||||
element.find('md-fab-trigger').find('button').attr('tabindex', '-1');
|
||||
|
||||
// Prepend the background element to the trigger's button
|
||||
element.find('md-fab-trigger').find('button')
|
||||
.prepend('<div class="md-fab-toolbar-background"></div>');
|
||||
}
|
||||
}
|
||||
|
||||
function MdFabToolbarAnimation() {
|
||||
var originalIconDelay;
|
||||
|
||||
function runAnimation(element, className, done) {
|
||||
var el = element[0];
|
||||
var ctrl = element.controller('mdFabToolbar');
|
||||
|
||||
// Grab the relevant child elements
|
||||
var backgroundElement = el.querySelector('.md-fab-toolbar-background');
|
||||
var triggerElement = el.querySelector('md-fab-trigger button');
|
||||
var iconElement = el.querySelector('md-fab-trigger button md-icon');
|
||||
var actions = element.find('md-fab-actions').children();
|
||||
|
||||
// If we have both elements, use them to position the new background
|
||||
if (triggerElement && backgroundElement) {
|
||||
// Get our variables
|
||||
var color = window.getComputedStyle(triggerElement).getPropertyValue('background-color');
|
||||
var width = el.offsetWidth;
|
||||
var height = el.offsetHeight;
|
||||
|
||||
// Make a square
|
||||
var scale = width * 2;
|
||||
|
||||
// Set some basic styles no matter what animation we're doing
|
||||
backgroundElement.style.backgroundColor = color;
|
||||
backgroundElement.style.borderRadius = width + 'px';
|
||||
|
||||
// If we're open
|
||||
if (ctrl.isOpen) {
|
||||
|
||||
// Set the width/height to take up the full toolbar width
|
||||
backgroundElement.style.width = scale + 'px';
|
||||
backgroundElement.style.height = scale + 'px';
|
||||
|
||||
// Set the top/left to move up/left (or right) by the scale width/height
|
||||
backgroundElement.style.top = -(scale / 2) + 'px';
|
||||
|
||||
if (element.hasClass('md-left')) {
|
||||
backgroundElement.style.left = -(scale / 2) + 'px';
|
||||
backgroundElement.style.right = null;
|
||||
}
|
||||
|
||||
if (element.hasClass('md-right')) {
|
||||
backgroundElement.style.right = -(scale / 2) + 'px';
|
||||
backgroundElement.style.left = null;
|
||||
}
|
||||
|
||||
// Set the next close animation to have the proper delays
|
||||
backgroundElement.style.transitionDelay = '0ms';
|
||||
iconElement.style.transitionDelay = '.3s';
|
||||
|
||||
// Apply a transition delay to actions
|
||||
angular.forEach(actions, function(action, index) {
|
||||
action.style.transitionDelay = (actions.length - index) * 25 + 'ms';
|
||||
});
|
||||
} else {
|
||||
// Otherwise, set the width/height to the trigger's width/height
|
||||
backgroundElement.style.width = triggerElement.offsetWidth + 'px';
|
||||
backgroundElement.style.height = triggerElement.offsetHeight + 'px';
|
||||
|
||||
// Reset the position
|
||||
backgroundElement.style.top = '0px';
|
||||
|
||||
if (element.hasClass('md-left')) {
|
||||
backgroundElement.style.left = '0px';
|
||||
backgroundElement.style.right = null;
|
||||
}
|
||||
|
||||
if (element.hasClass('md-right')) {
|
||||
backgroundElement.style.right = '0px';
|
||||
backgroundElement.style.left = null;
|
||||
}
|
||||
|
||||
// Set the next open animation to have the proper delays
|
||||
backgroundElement.style.transitionDelay = '200ms';
|
||||
iconElement.style.transitionDelay = '0ms';
|
||||
|
||||
// Apply a transition delay to actions
|
||||
angular.forEach(actions, function(action, index) {
|
||||
action.style.transitionDelay = (index * 25) + 'ms';
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
addClass: function(element, className, done) {
|
||||
runAnimation(element, className, done);
|
||||
},
|
||||
|
||||
removeClass: function(element, className, done) {
|
||||
runAnimation(element, className, done);
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
ng.material.components.fabToolbar = angular.module("material.components.fabToolbar");
|
||||
54
www/lib/angular-material/modules/closure/fabTrigger/fabTrigger.js
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.fabTrigger');
|
||||
goog.require('ng.material.core');
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('material.components.fabTrigger', [ 'material.core' ])
|
||||
.directive('mdFabTrigger', MdFabTriggerDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdFabTrigger
|
||||
* @module material.components.fabSpeedDial
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-fab-trigger>` directive is used inside of a `<md-fab-speed-dial>` or
|
||||
* `<md-fab-toolbar>` directive to mark the an element (or elements) as the trigger and setup the
|
||||
* proper event listeners.
|
||||
*
|
||||
* @usage
|
||||
* See the `<md-fab-speed-dial>` or `<md-fab-toolbar>` directives for example usage.
|
||||
*/
|
||||
function MdFabTriggerDirective() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
|
||||
require: ['^?mdFabSpeedDial', '^?mdFabToolbar'],
|
||||
|
||||
link: function(scope, element, attributes, controllers) {
|
||||
// Grab whichever parent controller is used
|
||||
var controller = controllers[0] || controllers[1];
|
||||
|
||||
// Make the children open/close their parent directive
|
||||
if (controller) {
|
||||
angular.forEach(element.children(), function(child) {
|
||||
angular.element(child).on('focus', controller.open);
|
||||
angular.element(child).on('blur', controller.close);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
ng.material.components.fabTrigger = angular.module("material.components.fabTrigger");
|
||||
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.8.0-rc1-master-91053dc
|
||||
*/
|
||||
@@ -0,0 +1,68 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-grid-list {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: relative; }
|
||||
md-grid-list *, md-grid-list *:before, md-grid-list *:after {
|
||||
box-sizing: border-box; }
|
||||
md-grid-list md-grid-tile {
|
||||
display: block;
|
||||
position: absolute; }
|
||||
md-grid-list md-grid-tile figure {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-justify-content: center;
|
||||
-ms-flex-pack: center;
|
||||
justify-content: center;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
padding: 0;
|
||||
margin: 0; }
|
||||
md-grid-list md-grid-tile md-grid-tile-header, md-grid-list md-grid-tile md-grid-tile-footer {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
height: 48px;
|
||||
color: #fff;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0; }
|
||||
md-grid-list md-grid-tile md-grid-tile-header h3, md-grid-list md-grid-tile md-grid-tile-header h4, md-grid-list md-grid-tile md-grid-tile-footer h3, md-grid-list md-grid-tile md-grid-tile-footer h4 {
|
||||
font-weight: 400;
|
||||
margin: 0 0 0 16px; }
|
||||
md-grid-list md-grid-tile md-grid-tile-header h3, md-grid-list md-grid-tile md-grid-tile-footer h3 {
|
||||
font-size: 14px; }
|
||||
md-grid-list md-grid-tile md-grid-tile-header h4, md-grid-list md-grid-tile md-grid-tile-footer h4 {
|
||||
font-size: 12px; }
|
||||
md-grid-list md-grid-tile md-grid-tile-header {
|
||||
top: 0; }
|
||||
md-grid-list md-grid-tile md-grid-tile-footer {
|
||||
bottom: 0; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-grid-tile {
|
||||
border: 1px solid #fff; }
|
||||
md-grid-tile-footer {
|
||||
border-top: 1px solid #fff; } }
|
||||
762
www/lib/angular-material/modules/closure/gridList/gridList.js
vendored
Normal file
@@ -0,0 +1,762 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.gridList');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.gridList
|
||||
*/
|
||||
angular.module('material.components.gridList', ['material.core'])
|
||||
.directive('mdGridList', GridListDirective)
|
||||
.directive('mdGridTile', GridTileDirective)
|
||||
.directive('mdGridTileFooter', GridTileCaptionDirective)
|
||||
.directive('mdGridTileHeader', GridTileCaptionDirective)
|
||||
.factory('$mdGridLayout', GridLayoutFactory);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdGridList
|
||||
* @module material.components.gridList
|
||||
* @restrict E
|
||||
* @description
|
||||
* Grid lists are an alternative to standard list views. Grid lists are distinct
|
||||
* from grids used for layouts and other visual presentations.
|
||||
*
|
||||
* A grid list is best suited to presenting a homogenous data type, typically
|
||||
* images, and is optimized for visual comprehension and differentiating between
|
||||
* like data types.
|
||||
*
|
||||
* A grid list is a continuous element consisting of tessellated, regular
|
||||
* subdivisions called cells that contain tiles (`md-grid-tile`).
|
||||
*
|
||||
* <img src="//material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7OVlEaXZ5YmU1Xzg/components_grids_usage2.png"
|
||||
* style="width: 300px; height: auto; margin-right: 16px;" alt="Concept of grid explained visually">
|
||||
* <img src="//material-design.storage.googleapis.com/publish/v_2/material_ext_publish/0Bx4BSt6jniD7VGhsOE5idWlJWXM/components_grids_usage3.png"
|
||||
* style="width: 300px; height: auto;" alt="Grid concepts legend">
|
||||
*
|
||||
* Cells are arrayed vertically and horizontally within the grid.
|
||||
*
|
||||
* Tiles hold content and can span one or more cells vertically or horizontally.
|
||||
*
|
||||
* ### Responsive Attributes
|
||||
*
|
||||
* The `md-grid-list` directive supports "responsive" attributes, which allow
|
||||
* different `md-cols`, `md-gutter` and `md-row-height` values depending on the
|
||||
* currently matching media query (as defined in `$mdConstant.MEDIA`).
|
||||
*
|
||||
* In order to set a responsive attribute, first define the fallback value with
|
||||
* the standard attribute name, then add additional attributes with the
|
||||
* following convention: `{base-attribute-name}-{media-query-name}="{value}"`
|
||||
* (ie. `md-cols-lg="8"`)
|
||||
*
|
||||
* @param {number} md-cols Number of columns in the grid.
|
||||
* @param {string} md-row-height One of
|
||||
* <ul>
|
||||
* <li>CSS length - Fixed height rows (eg. `8px` or `1rem`)</li>
|
||||
* <li>`{width}:{height}` - Ratio of width to height (eg.
|
||||
* `md-row-height="16:9"`)</li>
|
||||
* <li>`"fit"` - Height will be determined by subdividing the available
|
||||
* height by the number of rows</li>
|
||||
* </ul>
|
||||
* @param {string=} md-gutter The amount of space between tiles in CSS units
|
||||
* (default 1px)
|
||||
* @param {expression=} md-on-layout Expression to evaluate after layout. Event
|
||||
* object is available as `$event`, and contains performance information.
|
||||
*
|
||||
* @usage
|
||||
* Basic:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-list md-cols="5" md-gutter="1em" md-row-height="4:3">
|
||||
* <md-grid-tile></md-grid-tile>
|
||||
* </md-grid-list>
|
||||
* </hljs>
|
||||
*
|
||||
* Fixed-height rows:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-list md-cols="4" md-row-height="200px" ...>
|
||||
* <md-grid-tile></md-grid-tile>
|
||||
* </md-grid-list>
|
||||
* </hljs>
|
||||
*
|
||||
* Fit rows:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-list md-cols="4" md-row-height="fit" style="height: 400px;" ...>
|
||||
* <md-grid-tile></md-grid-tile>
|
||||
* </md-grid-list>
|
||||
* </hljs>
|
||||
*
|
||||
* Using responsive attributes:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-list
|
||||
* md-cols-sm="2"
|
||||
* md-cols-md="4"
|
||||
* md-cols-lg="8"
|
||||
* md-cols-gt-lg="12"
|
||||
* ...>
|
||||
* <md-grid-tile></md-grid-tile>
|
||||
* </md-grid-list>
|
||||
* </hljs>
|
||||
*/
|
||||
function GridListDirective($interpolate, $mdConstant, $mdGridLayout, $mdMedia) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: GridListController,
|
||||
scope: {
|
||||
mdOnLayout: '&'
|
||||
},
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attrs, ctrl) {
|
||||
// Apply semantics
|
||||
element.attr('role', 'list');
|
||||
|
||||
// Provide the controller with a way to trigger layouts.
|
||||
ctrl.layoutDelegate = layoutDelegate;
|
||||
|
||||
var invalidateLayout = angular.bind(ctrl, ctrl.invalidateLayout),
|
||||
unwatchAttrs = watchMedia();
|
||||
scope.$on('$destroy', unwatchMedia);
|
||||
|
||||
/**
|
||||
* Watches for changes in media, invalidating layout as necessary.
|
||||
*/
|
||||
function watchMedia() {
|
||||
for (var mediaName in $mdConstant.MEDIA) {
|
||||
$mdMedia(mediaName); // initialize
|
||||
$mdMedia.getQuery($mdConstant.MEDIA[mediaName])
|
||||
.addListener(invalidateLayout);
|
||||
}
|
||||
return $mdMedia.watchResponsiveAttributes(
|
||||
['md-cols', 'md-row-height'], attrs, layoutIfMediaMatch);
|
||||
}
|
||||
|
||||
function unwatchMedia() {
|
||||
ctrl.layoutDelegate = angular.noop;
|
||||
|
||||
unwatchAttrs();
|
||||
for (var mediaName in $mdConstant.MEDIA) {
|
||||
$mdMedia.getQuery($mdConstant.MEDIA[mediaName])
|
||||
.removeListener(invalidateLayout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs grid layout if the provided mediaName matches the currently
|
||||
* active media type.
|
||||
*/
|
||||
function layoutIfMediaMatch(mediaName) {
|
||||
if (mediaName == null) {
|
||||
// TODO(shyndman): It would be nice to only layout if we have
|
||||
// instances of attributes using this media type
|
||||
ctrl.invalidateLayout();
|
||||
} else if ($mdMedia(mediaName)) {
|
||||
ctrl.invalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
var lastLayoutProps;
|
||||
|
||||
/**
|
||||
* Invokes the layout engine, and uses its results to lay out our
|
||||
* tile elements.
|
||||
*
|
||||
* @param {boolean} tilesInvalidated Whether tiles have been
|
||||
* added/removed/moved since the last layout. This is to avoid situations
|
||||
* where tiles are replaced with properties identical to their removed
|
||||
* counterparts.
|
||||
*/
|
||||
function layoutDelegate(tilesInvalidated) {
|
||||
var tiles = getTileElements();
|
||||
var props = {
|
||||
tileSpans: getTileSpans(tiles),
|
||||
colCount: getColumnCount(),
|
||||
rowMode: getRowMode(),
|
||||
rowHeight: getRowHeight(),
|
||||
gutter: getGutter()
|
||||
};
|
||||
|
||||
if (!tilesInvalidated && angular.equals(props, lastLayoutProps)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var performance =
|
||||
$mdGridLayout(props.colCount, props.tileSpans, tiles)
|
||||
.map(function(tilePositions, rowCount) {
|
||||
return {
|
||||
grid: {
|
||||
element: element,
|
||||
style: getGridStyle(props.colCount, rowCount,
|
||||
props.gutter, props.rowMode, props.rowHeight)
|
||||
},
|
||||
tiles: tilePositions.map(function(ps, i) {
|
||||
return {
|
||||
element: angular.element(tiles[i]),
|
||||
style: getTileStyle(ps.position, ps.spans,
|
||||
props.colCount, props.rowCount,
|
||||
props.gutter, props.rowMode, props.rowHeight)
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
.reflow()
|
||||
.performance();
|
||||
|
||||
// Report layout
|
||||
scope.mdOnLayout({
|
||||
$event: {
|
||||
performance: performance
|
||||
}
|
||||
});
|
||||
|
||||
lastLayoutProps = props;
|
||||
}
|
||||
|
||||
// Use $interpolate to do some simple string interpolation as a convenience.
|
||||
|
||||
var startSymbol = $interpolate.startSymbol();
|
||||
var endSymbol = $interpolate.endSymbol();
|
||||
|
||||
// Returns an expression wrapped in the interpolator's start and end symbols.
|
||||
function expr(exprStr) {
|
||||
return startSymbol + exprStr + endSymbol;
|
||||
}
|
||||
|
||||
// The amount of space a single 1x1 tile would take up (either width or height), used as
|
||||
// a basis for other calculations. This consists of taking the base size percent (as would be
|
||||
// if evenly dividing the size between cells), and then subtracting the size of one gutter.
|
||||
// However, since there are no gutters on the edges, each tile only uses a fration
|
||||
// (gutterShare = numGutters / numCells) of the gutter size. (Imagine having one gutter per
|
||||
// tile, and then breaking up the extra gutter on the edge evenly among the cells).
|
||||
var UNIT = $interpolate(expr('share') + '% - (' + expr('gutter') + ' * ' + expr('gutterShare') + ')');
|
||||
|
||||
// The horizontal or vertical position of a tile, e.g., the 'top' or 'left' property value.
|
||||
// The position comes the size of a 1x1 tile plus gutter for each previous tile in the
|
||||
// row/column (offset).
|
||||
var POSITION = $interpolate('calc((' + expr('unit') + ' + ' + expr('gutter') + ') * ' + expr('offset') + ')');
|
||||
|
||||
// The actual size of a tile, e.g., width or height, taking rowSpan or colSpan into account.
|
||||
// This is computed by multiplying the base unit by the rowSpan/colSpan, and then adding back
|
||||
// in the space that the gutter would normally have used (which was already accounted for in
|
||||
// the base unit calculation).
|
||||
var DIMENSION = $interpolate('calc((' + expr('unit') + ') * ' + expr('span') + ' + (' + expr('span') + ' - 1) * ' + expr('gutter') + ')');
|
||||
|
||||
/**
|
||||
* Gets the styles applied to a tile element described by the given parameters.
|
||||
* @param {{row: number, col: number}} position The row and column indices of the tile.
|
||||
* @param {{row: number, col: number}} spans The rowSpan and colSpan of the tile.
|
||||
* @param {number} colCount The number of columns.
|
||||
* @param {number} rowCount The number of rows.
|
||||
* @param {string} gutter The amount of space between tiles. This will be something like
|
||||
* '5px' or '2em'.
|
||||
* @param {string} rowMode The row height mode. Can be one of:
|
||||
* 'fixed': all rows have a fixed size, given by rowHeight,
|
||||
* 'ratio': row height defined as a ratio to width, or
|
||||
* 'fit': fit to the grid-list element height, divinding evenly among rows.
|
||||
* @param {string|number} rowHeight The height of a row. This is only used for 'fixed' mode and
|
||||
* for 'ratio' mode. For 'ratio' mode, this is the *ratio* of width-to-height (e.g., 0.75).
|
||||
* @returns {Object} Map of CSS properties to be applied to the style element. Will define
|
||||
* values for top, left, width, height, marginTop, and paddingTop.
|
||||
*/
|
||||
function getTileStyle(position, spans, colCount, rowCount, gutter, rowMode, rowHeight) {
|
||||
// TODO(shyndman): There are style caching opportunities here.
|
||||
|
||||
// Percent of the available horizontal space that one column takes up.
|
||||
var hShare = (1 / colCount) * 100;
|
||||
|
||||
// Fraction of the gutter size that each column takes up.
|
||||
var hGutterShare = (colCount - 1) / colCount;
|
||||
|
||||
// Base horizontal size of a column.
|
||||
var hUnit = UNIT({share: hShare, gutterShare: hGutterShare, gutter: gutter});
|
||||
|
||||
// The width and horizontal position of each tile is always calculated the same way, but the
|
||||
// height and vertical position depends on the rowMode.
|
||||
var style = {
|
||||
left: POSITION({ unit: hUnit, offset: position.col, gutter: gutter }),
|
||||
width: DIMENSION({ unit: hUnit, span: spans.col, gutter: gutter }),
|
||||
// resets
|
||||
paddingTop: '',
|
||||
marginTop: '',
|
||||
top: '',
|
||||
height: ''
|
||||
};
|
||||
|
||||
switch (rowMode) {
|
||||
case 'fixed':
|
||||
// In fixed mode, simply use the given rowHeight.
|
||||
style.top = POSITION({ unit: rowHeight, offset: position.row, gutter: gutter });
|
||||
style.height = DIMENSION({ unit: rowHeight, span: spans.row, gutter: gutter });
|
||||
break;
|
||||
|
||||
case 'ratio':
|
||||
// Percent of the available vertical space that one row takes up. Here, rowHeight holds
|
||||
// the ratio value. For example, if the width:height ratio is 4:3, rowHeight = 1.333.
|
||||
var vShare = hShare / rowHeight;
|
||||
|
||||
// Base veritcal size of a row.
|
||||
var vUnit = UNIT({ share: vShare, gutterShare: hGutterShare, gutter: gutter });
|
||||
|
||||
// padidngTop and marginTop are used to maintain the given aspect ratio, as
|
||||
// a percentage-based value for these properties is applied to the *width* of the
|
||||
// containing block. See http://www.w3.org/TR/CSS2/box.html#margin-properties
|
||||
style.paddingTop = DIMENSION({ unit: vUnit, span: spans.row, gutter: gutter});
|
||||
style.marginTop = POSITION({ unit: vUnit, offset: position.row, gutter: gutter });
|
||||
break;
|
||||
|
||||
case 'fit':
|
||||
// Fraction of the gutter size that each column takes up.
|
||||
var vGutterShare = (rowCount - 1) / rowCount;
|
||||
|
||||
// Percent of the available vertical space that one row takes up.
|
||||
var vShare = (1 / rowCount) * 100;
|
||||
|
||||
// Base vertical size of a row.
|
||||
var vUnit = UNIT({share: vShare, gutterShare: vGutterShare, gutter: gutter});
|
||||
|
||||
style.top = POSITION({unit: vUnit, offset: position.row, gutter: gutter});
|
||||
style.height = DIMENSION({unit: vUnit, span: spans.row, gutter: gutter});
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
function getGridStyle(colCount, rowCount, gutter, rowMode, rowHeight) {
|
||||
var style = {
|
||||
height: '',
|
||||
paddingBottom: ''
|
||||
};
|
||||
|
||||
switch(rowMode) {
|
||||
case 'fixed':
|
||||
style.height = DIMENSION({ unit: rowHeight, span: rowCount, gutter: gutter });
|
||||
break;
|
||||
|
||||
case 'ratio':
|
||||
// rowHeight is width / height
|
||||
var hGutterShare = colCount === 1 ? 0 : (colCount - 1) / colCount,
|
||||
hShare = (1 / colCount) * 100,
|
||||
vShare = hShare * (1 / rowHeight),
|
||||
vUnit = UNIT({ share: vShare, gutterShare: hGutterShare, gutter: gutter });
|
||||
|
||||
style.paddingBottom = DIMENSION({ unit: vUnit, span: rowCount, gutter: gutter});
|
||||
break;
|
||||
|
||||
case 'fit':
|
||||
// noop, as the height is user set
|
||||
break;
|
||||
}
|
||||
|
||||
return style;
|
||||
}
|
||||
|
||||
function getTileElements() {
|
||||
return [].filter.call(element.children(), function(ele) {
|
||||
return ele.tagName == 'MD-GRID-TILE';
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of objects containing the rowspan and colspan for each tile.
|
||||
* @returns {Array<{row: number, col: number}>}
|
||||
*/
|
||||
function getTileSpans(tileElements) {
|
||||
return [].map.call(tileElements, function(ele) {
|
||||
var ctrl = angular.element(ele).controller('mdGridTile');
|
||||
return {
|
||||
row: parseInt(
|
||||
$mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-rowspan'), 10) || 1,
|
||||
col: parseInt(
|
||||
$mdMedia.getResponsiveAttribute(ctrl.$attrs, 'md-colspan'), 10) || 1
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
function getColumnCount() {
|
||||
var colCount = parseInt($mdMedia.getResponsiveAttribute(attrs, 'md-cols'), 10);
|
||||
if (isNaN(colCount)) {
|
||||
throw 'md-grid-list: md-cols attribute was not found, or contained a non-numeric value';
|
||||
}
|
||||
return colCount;
|
||||
}
|
||||
|
||||
function getGutter() {
|
||||
return applyDefaultUnit($mdMedia.getResponsiveAttribute(attrs, 'md-gutter') || 1);
|
||||
}
|
||||
|
||||
function getRowHeight() {
|
||||
var rowHeight = $mdMedia.getResponsiveAttribute(attrs, 'md-row-height');
|
||||
switch (getRowMode()) {
|
||||
case 'fixed':
|
||||
return applyDefaultUnit(rowHeight);
|
||||
case 'ratio':
|
||||
var whRatio = rowHeight.split(':');
|
||||
return parseFloat(whRatio[0]) / parseFloat(whRatio[1]);
|
||||
case 'fit':
|
||||
return 0; // N/A
|
||||
}
|
||||
}
|
||||
|
||||
function getRowMode() {
|
||||
var rowHeight = $mdMedia.getResponsiveAttribute(attrs, 'md-row-height');
|
||||
if (rowHeight == 'fit') {
|
||||
return 'fit';
|
||||
} else if (rowHeight.indexOf(':') !== -1) {
|
||||
return 'ratio';
|
||||
} else {
|
||||
return 'fixed';
|
||||
}
|
||||
}
|
||||
|
||||
function applyDefaultUnit(val) {
|
||||
return /\D$/.test(val) ? val : val + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
GridListDirective.$inject = ["$interpolate", "$mdConstant", "$mdGridLayout", "$mdMedia"];
|
||||
|
||||
/* ngInject */
|
||||
function GridListController($timeout) {
|
||||
this.layoutInvalidated = false;
|
||||
this.tilesInvalidated = false;
|
||||
this.$timeout_ = $timeout;
|
||||
this.layoutDelegate = angular.noop;
|
||||
}
|
||||
GridListController.$inject = ["$timeout"];
|
||||
|
||||
GridListController.prototype = {
|
||||
invalidateTiles: function() {
|
||||
this.tilesInvalidated = true;
|
||||
this.invalidateLayout();
|
||||
},
|
||||
|
||||
invalidateLayout: function() {
|
||||
if (this.layoutInvalidated) {
|
||||
return;
|
||||
}
|
||||
this.layoutInvalidated = true;
|
||||
this.$timeout_(angular.bind(this, this.layout));
|
||||
},
|
||||
|
||||
layout: function() {
|
||||
try {
|
||||
this.layoutDelegate(this.tilesInvalidated);
|
||||
} finally {
|
||||
this.layoutInvalidated = false;
|
||||
this.tilesInvalidated = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/* ngInject */
|
||||
function GridLayoutFactory($mdUtil) {
|
||||
var defaultAnimator = GridTileAnimator;
|
||||
|
||||
/**
|
||||
* Set the reflow animator callback
|
||||
*/
|
||||
GridLayout.animateWith = function(customAnimator) {
|
||||
defaultAnimator = !angular.isFunction(customAnimator) ? GridTileAnimator : customAnimator;
|
||||
};
|
||||
|
||||
return GridLayout;
|
||||
|
||||
/**
|
||||
* Publish layout function
|
||||
*/
|
||||
function GridLayout(colCount, tileSpans) {
|
||||
var self, layoutInfo, gridStyles, layoutTime, mapTime, reflowTime;
|
||||
|
||||
layoutTime = $mdUtil.time(function() {
|
||||
layoutInfo = calculateGridFor(colCount, tileSpans);
|
||||
});
|
||||
|
||||
return self = {
|
||||
|
||||
/**
|
||||
* An array of objects describing each tile's position in the grid.
|
||||
*/
|
||||
layoutInfo: function() {
|
||||
return layoutInfo;
|
||||
},
|
||||
|
||||
/**
|
||||
* Maps grid positioning to an element and a set of styles using the
|
||||
* provided updateFn.
|
||||
*/
|
||||
map: function(updateFn) {
|
||||
mapTime = $mdUtil.time(function() {
|
||||
var info = self.layoutInfo();
|
||||
gridStyles = updateFn(info.positioning, info.rowCount);
|
||||
});
|
||||
return self;
|
||||
},
|
||||
|
||||
/**
|
||||
* Default animator simply sets the element.css( <styles> ). An alternate
|
||||
* animator can be provided as an argument. The function has the following
|
||||
* signature:
|
||||
*
|
||||
* function({grid: {element: JQLite, style: Object}, tiles: Array<{element: JQLite, style: Object}>)
|
||||
*/
|
||||
reflow: function(animatorFn) {
|
||||
reflowTime = $mdUtil.time(function() {
|
||||
var animator = animatorFn || defaultAnimator;
|
||||
animator(gridStyles.grid, gridStyles.tiles);
|
||||
});
|
||||
return self;
|
||||
},
|
||||
|
||||
/**
|
||||
* Timing for the most recent layout run.
|
||||
*/
|
||||
performance: function() {
|
||||
return {
|
||||
tileCount: tileSpans.length,
|
||||
layoutTime: layoutTime,
|
||||
mapTime: mapTime,
|
||||
reflowTime: reflowTime,
|
||||
totalTime: layoutTime + mapTime + reflowTime
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Default Gridlist animator simple sets the css for each element;
|
||||
* NOTE: any transitions effects must be manually set in the CSS.
|
||||
* e.g.
|
||||
*
|
||||
* md-grid-tile {
|
||||
* transition: all 700ms ease-out 50ms;
|
||||
* }
|
||||
*
|
||||
*/
|
||||
function GridTileAnimator(grid, tiles) {
|
||||
grid.element.css(grid.style);
|
||||
tiles.forEach(function(t) {
|
||||
t.element.css(t.style);
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the positions of tiles.
|
||||
*
|
||||
* The algorithm works as follows:
|
||||
* An Array<Number> with length colCount (spaceTracker) keeps track of
|
||||
* available tiling positions, where elements of value 0 represents an
|
||||
* empty position. Space for a tile is reserved by finding a sequence of
|
||||
* 0s with length <= than the tile's colspan. When such a space has been
|
||||
* found, the occupied tile positions are incremented by the tile's
|
||||
* rowspan value, as these positions have become unavailable for that
|
||||
* many rows.
|
||||
*
|
||||
* If the end of a row has been reached without finding space for the
|
||||
* tile, spaceTracker's elements are each decremented by 1 to a minimum
|
||||
* of 0. Rows are searched in this fashion until space is found.
|
||||
*/
|
||||
function calculateGridFor(colCount, tileSpans) {
|
||||
var curCol = 0,
|
||||
curRow = 0,
|
||||
spaceTracker = newSpaceTracker();
|
||||
|
||||
return {
|
||||
positioning: tileSpans.map(function(spans, i) {
|
||||
return {
|
||||
spans: spans,
|
||||
position: reserveSpace(spans, i)
|
||||
};
|
||||
}),
|
||||
rowCount: curRow + Math.max.apply(Math, spaceTracker)
|
||||
};
|
||||
|
||||
function reserveSpace(spans, i) {
|
||||
if (spans.col > colCount) {
|
||||
throw 'md-grid-list: Tile at position ' + i + ' has a colspan ' +
|
||||
'(' + spans.col + ') that exceeds the column count ' +
|
||||
'(' + colCount + ')';
|
||||
}
|
||||
|
||||
var start = 0,
|
||||
end = 0;
|
||||
|
||||
// TODO(shyndman): This loop isn't strictly necessary if you can
|
||||
// determine the minimum number of rows before a space opens up. To do
|
||||
// this, recognize that you've iterated across an entire row looking for
|
||||
// space, and if so fast-forward by the minimum rowSpan count. Repeat
|
||||
// until the required space opens up.
|
||||
while (end - start < spans.col) {
|
||||
if (curCol >= colCount) {
|
||||
nextRow();
|
||||
continue;
|
||||
}
|
||||
|
||||
start = spaceTracker.indexOf(0, curCol);
|
||||
if (start === -1 || (end = findEnd(start + 1)) === -1) {
|
||||
start = end = 0;
|
||||
nextRow();
|
||||
continue;
|
||||
}
|
||||
|
||||
curCol = end + 1;
|
||||
}
|
||||
|
||||
adjustRow(start, spans.col, spans.row);
|
||||
curCol = start + spans.col;
|
||||
|
||||
return {
|
||||
col: start,
|
||||
row: curRow
|
||||
};
|
||||
}
|
||||
|
||||
function nextRow() {
|
||||
curCol = 0;
|
||||
curRow++;
|
||||
adjustRow(0, colCount, -1); // Decrement row spans by one
|
||||
}
|
||||
|
||||
function adjustRow(from, cols, by) {
|
||||
for (var i = from; i < from + cols; i++) {
|
||||
spaceTracker[i] = Math.max(spaceTracker[i] + by, 0);
|
||||
}
|
||||
}
|
||||
|
||||
function findEnd(start) {
|
||||
var i;
|
||||
for (i = start; i < spaceTracker.length; i++) {
|
||||
if (spaceTracker[i] !== 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
if (i === spaceTracker.length) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
function newSpaceTracker() {
|
||||
var tracker = [];
|
||||
for (var i = 0; i < colCount; i++) {
|
||||
tracker.push(0);
|
||||
}
|
||||
return tracker;
|
||||
}
|
||||
}
|
||||
}
|
||||
GridLayoutFactory.$inject = ["$mdUtil"];
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdGridTile
|
||||
* @module material.components.gridList
|
||||
* @restrict E
|
||||
* @description
|
||||
* Tiles contain the content of an `md-grid-list`. They span one or more grid
|
||||
* cells vertically or horizontally, and use `md-grid-tile-{footer,header}` to
|
||||
* display secondary content.
|
||||
*
|
||||
* ### Responsive Attributes
|
||||
*
|
||||
* The `md-grid-tile` directive supports "responsive" attributes, which allow
|
||||
* different `md-rowspan` and `md-colspan` values depending on the currently
|
||||
* matching media query (as defined in `$mdConstant.MEDIA`).
|
||||
*
|
||||
* In order to set a responsive attribute, first define the fallback value with
|
||||
* the standard attribute name, then add additional attributes with the
|
||||
* following convention: `{base-attribute-name}-{media-query-name}="{value}"`
|
||||
* (ie. `md-colspan-sm="4"`)
|
||||
*
|
||||
* @param {number=} md-colspan The number of columns to span (default 1). Cannot
|
||||
* exceed the number of columns in the grid. Supports interpolation.
|
||||
* @param {number=} md-rowspan The number of rows to span (default 1). Supports
|
||||
* interpolation.
|
||||
*
|
||||
* @usage
|
||||
* With header:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-tile>
|
||||
* <md-grid-tile-header>
|
||||
* <h3>This is a header</h3>
|
||||
* </md-grid-tile-header>
|
||||
* </md-grid-tile>
|
||||
* </hljs>
|
||||
*
|
||||
* With footer:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-tile>
|
||||
* <md-grid-tile-footer>
|
||||
* <h3>This is a footer</h3>
|
||||
* </md-grid-tile-footer>
|
||||
* </md-grid-tile>
|
||||
* </hljs>
|
||||
*
|
||||
* Spanning multiple rows/columns:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-tile md-colspan="2" md-rowspan="3">
|
||||
* </md-grid-tile>
|
||||
* </hljs>
|
||||
*
|
||||
* Responsive attributes:
|
||||
* <hljs lang="html">
|
||||
* <md-grid-tile md-colspan="1" md-colspan-sm="3" md-colspan-md="5">
|
||||
* </md-grid-tile>
|
||||
* </hljs>
|
||||
*/
|
||||
function GridTileDirective($mdMedia) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '^mdGridList',
|
||||
template: '<figure ng-transclude></figure>',
|
||||
transclude: true,
|
||||
scope: {},
|
||||
// Simple controller that exposes attributes to the grid directive
|
||||
controller: ["$attrs", function($attrs) {
|
||||
this.$attrs = $attrs;
|
||||
}],
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attrs, gridCtrl) {
|
||||
// Apply semantics
|
||||
element.attr('role', 'listitem');
|
||||
|
||||
// If our colspan or rowspan changes, trigger a layout
|
||||
var unwatchAttrs = $mdMedia.watchResponsiveAttributes(['md-colspan', 'md-rowspan'],
|
||||
attrs, angular.bind(gridCtrl, gridCtrl.invalidateLayout));
|
||||
|
||||
// Tile registration/deregistration
|
||||
gridCtrl.invalidateTiles();
|
||||
scope.$on('$destroy', function() {
|
||||
unwatchAttrs();
|
||||
gridCtrl.invalidateLayout();
|
||||
});
|
||||
|
||||
if (angular.isDefined(scope.$parent.$index)) {
|
||||
scope.$watch(function() { return scope.$parent.$index; },
|
||||
function indexChanged(newIdx, oldIdx) {
|
||||
if (newIdx === oldIdx) {
|
||||
return;
|
||||
}
|
||||
gridCtrl.invalidateTiles();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
GridTileDirective.$inject = ["$mdMedia"];
|
||||
|
||||
|
||||
function GridTileCaptionDirective() {
|
||||
return {
|
||||
template: '<figcaption ng-transclude></figcaption>',
|
||||
transclude: true
|
||||
};
|
||||
}
|
||||
|
||||
ng.material.components.gridList = angular.module("material.components.gridList");
|
||||
@@ -0,0 +1,15 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-icon.md-THEME_NAME-theme {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-icon.md-THEME_NAME-theme.md-primary {
|
||||
color: '{{primary-color}}'; }
|
||||
md-icon.md-THEME_NAME-theme.md-accent {
|
||||
color: '{{accent-color}}'; }
|
||||
md-icon.md-THEME_NAME-theme.md-warn {
|
||||
color: '{{warn-color}}'; }
|
||||
20
www/lib/angular-material/modules/closure/icon/icon.css
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-icon {
|
||||
margin: auto;
|
||||
background-repeat: no-repeat no-repeat;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
fill: currentColor;
|
||||
height: 24px;
|
||||
width: 24px; }
|
||||
md-icon svg {
|
||||
pointer-events: none; }
|
||||
md-icon[md-font-icon] {
|
||||
line-height: 1;
|
||||
width: auto; }
|
||||
783
www/lib/angular-material/modules/closure/icon/icon.js
vendored
Normal file
@@ -0,0 +1,783 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.icon');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.icon
|
||||
* @description
|
||||
* Icon
|
||||
*/
|
||||
angular.module('material.components.icon', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdIcon', mdIconDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdIcon
|
||||
* @module material.components.icon
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-icon>` directive is an markup element useful for showing an icon based on a font-icon
|
||||
* or a SVG. Icons are view-only elements that should not be used directly as buttons; instead nest a `<md-icon>`
|
||||
* inside a `md-button` to add hover and click features.
|
||||
*
|
||||
* When using SVGs, both external SVGs (via URLs) or sets of SVGs [from icon sets] can be
|
||||
* easily loaded and used.When use font-icons, developers must following three (3) simple steps:
|
||||
*
|
||||
* <ol>
|
||||
* <li>Load the font library. e.g.<br/>
|
||||
* <link href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||
* rel="stylesheet">
|
||||
* </li>
|
||||
* <li> Use either (a) font-icon class names or (b) font ligatures to render the font glyph by using its textual name</li>
|
||||
* <li> Use <md-icon md-font-icon="classname" /> or <br/>
|
||||
* use <md-icon md-font-set="font library classname or alias"> textual_name </md-icon> or <br/>
|
||||
* use <md-icon md-font-set="font library classname or alias"> numerical_character_reference </md-icon>
|
||||
* </li>
|
||||
* </ol>
|
||||
*
|
||||
* Full details for these steps can be found:
|
||||
*
|
||||
* <ul>
|
||||
* <li>http://google.github.io/material-design-icons/</li>
|
||||
* <li>http://google.github.io/material-design-icons/#icon-font-for-the-web</li>
|
||||
* </ul>
|
||||
*
|
||||
* The Material Design icon style <code>.material-icons</code> and the icon font references are published in
|
||||
* Material Design Icons:
|
||||
*
|
||||
* <ul>
|
||||
* <li>http://www.google.com/design/icons/</li>
|
||||
* <li>https://www.google.com/design/icons/#ic_accessibility</li>
|
||||
* </ul>
|
||||
*
|
||||
* <h2 id="material_design_icons">Material Design Icons</h2>
|
||||
* Using the Material Design Icon-Selector, developers can easily and quickly search for a Material Design font-icon and
|
||||
* determine its textual name and character reference code. Click on any icon to see the slide-up information
|
||||
* panel with details regarding a SVG download or information on the font-icon usage.
|
||||
*
|
||||
* <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank" style="border-bottom:none;">
|
||||
* <img src="https://cloud.githubusercontent.com/assets/210413/7902490/fe8dd14c-0780-11e5-98fb-c821cc6475e6.png"
|
||||
* aria-label="Material Design Icon-Selector" style="max-width:75%;padding-left:10%">
|
||||
* </a>
|
||||
*
|
||||
* <span class="image_caption">
|
||||
* Click on the image above to link to the
|
||||
* <a href="https://www.google.com/design/icons/#ic_accessibility" target="_blank">Material Design Icon-Selector</a>.
|
||||
* </span>
|
||||
*
|
||||
* @param {string} md-font-icon Name of CSS icon associated with the font-face will be used
|
||||
* to render the icon. Requires the fonts and the named CSS styles to be preloaded.
|
||||
* @param {string} md-font-set CSS style name associated with the font library; which will be assigned as
|
||||
* the class for the font-icon ligature. This value may also be an alias that is used to lookup the classname;
|
||||
* internally use `$mdIconProvider.fontSet(<alias>)` to determine the style name.
|
||||
* @param {string} md-svg-src URL [or expression ] used to load, cache, and display an external SVG.
|
||||
* @param {string} md-svg-icon Name used for lookup of the icon from the internal cache; interpolated strings or
|
||||
* expressions may also be used. Specific set names can be used with the syntax `<set name>:<icon name>`.<br/><br/>
|
||||
* To use icon sets, developers are required to pre-register the sets using the `$mdIconProvider` service.
|
||||
* @param {string=} aria-label Labels icon for accessibility. If an empty string is provided, icon
|
||||
* will be hidden from accessibility layer with `aria-hidden="true"`. If there's no aria-label on the icon
|
||||
* nor a label on the parent element, a warning will be logged to the console.
|
||||
*
|
||||
* @usage
|
||||
* When using SVGs:
|
||||
* <hljs lang="html">
|
||||
*
|
||||
* <!-- Icon ID; may contain optional icon set prefix; icons must registered using $mdIconProvider -->
|
||||
* <md-icon md-svg-icon="social:android" aria-label="android " ></md-icon>
|
||||
*
|
||||
* <!-- Icon urls; may be preloaded in templateCache -->
|
||||
* <md-icon md-svg-src="/android.svg" aria-label="android " ></md-icon>
|
||||
* <md-icon md-svg-src="{{ getAndroid() }}" aria-label="android " ></md-icon>
|
||||
*
|
||||
* </hljs>
|
||||
*
|
||||
* Use the <code>$mdIconProvider</code> to configure your application with
|
||||
* svg iconsets.
|
||||
*
|
||||
* <hljs lang="js">
|
||||
* angular.module('appSvgIconSets', ['ngMaterial'])
|
||||
* .controller('DemoCtrl', function($scope) {})
|
||||
* .config(function($mdIconProvider) {
|
||||
* $mdIconProvider
|
||||
* .iconSet('social', 'img/icons/sets/social-icons.svg', 24)
|
||||
* .defaultIconSet('img/icons/sets/core-icons.svg', 24);
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*
|
||||
* When using Font Icons with classnames:
|
||||
* <hljs lang="html">
|
||||
*
|
||||
* <md-icon md-font-icon="android" aria-label="android" ></md-icon>
|
||||
* <md-icon class="icon_home" aria-label="Home" ></md-icon>
|
||||
*
|
||||
* </hljs>
|
||||
*
|
||||
* When using Material Font Icons with ligatures:
|
||||
* <hljs lang="html">
|
||||
* <!-- For Material Design Icons -->
|
||||
* <!-- The class '.material-icons' is auto-added. -->
|
||||
* <md-icon> face </md-icon>
|
||||
* <md-icon class="md-light md-48"> face </md-icon>
|
||||
* <md-icon md-font-set="material-icons"> face </md-icon>
|
||||
* <md-icon> #xE87C; </md-icon>
|
||||
* </hljs>
|
||||
*
|
||||
* When using other Font-Icon libraries:
|
||||
*
|
||||
* <hljs lang="js">
|
||||
* // Specify a font-icon style alias
|
||||
* angular.config(function($mdIconProvider) {
|
||||
* $mdIconProvider.fontSet('fa', 'fontawesome');
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-icon md-font-set="fa">email</md-icon>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function mdIconDirective($mdIcon, $mdTheming, $mdAria, $interpolate ) {
|
||||
|
||||
return {
|
||||
scope: {
|
||||
fontSet : '@mdFontSet',
|
||||
fontIcon: '@mdFontIcon',
|
||||
svgIcon : '@mdSvgIcon',
|
||||
svgSrc : '@mdSvgSrc'
|
||||
},
|
||||
restrict: 'E',
|
||||
link : postLink
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Directive postLink
|
||||
* Supports embedded SVGs, font-icons, & external SVGs
|
||||
*/
|
||||
function postLink(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
|
||||
prepareForFontIcon();
|
||||
|
||||
// If using a font-icon, then the textual name of the icon itself
|
||||
// provides the aria-label.
|
||||
|
||||
var label = attr.alt || scope.fontIcon || scope.svgIcon || element.text();
|
||||
var attrName = attr.$normalize(attr.$attr.mdSvgIcon || attr.$attr.mdSvgSrc || '');
|
||||
|
||||
if ( !attr['aria-label'] ) {
|
||||
|
||||
if (label != '' && !parentsHaveText() ) {
|
||||
|
||||
$mdAria.expect(element, 'aria-label', label);
|
||||
$mdAria.expect(element, 'role', 'img');
|
||||
|
||||
} else if ( !element.text() ) {
|
||||
// If not a font-icon with ligature, then
|
||||
// hide from the accessibility layer.
|
||||
|
||||
$mdAria.expect(element, 'aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
if (attrName) {
|
||||
// Use either pre-configured SVG or URL source, respectively.
|
||||
attr.$observe(attrName, function(attrVal) {
|
||||
|
||||
element.empty();
|
||||
if (attrVal) {
|
||||
$mdIcon(attrVal).then(function(svg) {
|
||||
element.append(svg);
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function parentsHaveText() {
|
||||
var parent = element.parent();
|
||||
if (parent.attr('aria-label') || parent.text()) {
|
||||
return true;
|
||||
}
|
||||
else if(parent.parent().attr('aria-label') || parent.parent().text()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function prepareForFontIcon () {
|
||||
if (!scope.svgIcon && !scope.svgSrc) {
|
||||
if (scope.fontIcon) {
|
||||
element.addClass('md-font');
|
||||
element.addClass(scope.fontIcon);
|
||||
} else {
|
||||
element.addClass($mdIcon.fontSet(scope.fontSet));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
mdIconDirective.$inject = ["$mdIcon", "$mdTheming", "$mdAria", "$interpolate"];
|
||||
|
||||
angular
|
||||
.module('material.components.icon' )
|
||||
.provider('$mdIcon', MdIconProvider);
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $mdIconProvider
|
||||
* @module material.components.icon
|
||||
*
|
||||
* @description
|
||||
* `$mdIconProvider` is used only to register icon IDs with URLs. These configuration features allow
|
||||
* icons and icon sets to be pre-registered and associated with source URLs **before** the `<md-icon />`
|
||||
* directives are compiled.
|
||||
*
|
||||
* If using font-icons, the developer is repsonsible for loading the fonts.
|
||||
*
|
||||
* If using SVGs, loading of the actual svg files are deferred to on-demand requests and are loaded
|
||||
* internally by the `$mdIcon` service using the `$http` service. When an SVG is requested by name/ID,
|
||||
* the `$mdIcon` service searches its registry for the associated source URL;
|
||||
* that URL is used to on-demand load and parse the SVG dynamically.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Configure URLs for icons specified by [set:]id.
|
||||
*
|
||||
* $mdIconProvider
|
||||
* .defaultFontSet( 'fontawesome' )
|
||||
* .defaultIconSet('my/app/icons.svg') // Register a default set of SVG icons
|
||||
* .iconSet('social', 'my/app/social.svg') // Register a named icon set of SVGs
|
||||
* .icon('android', 'my/app/android.svg') // Register a specific icon (by name)
|
||||
* .icon('work:chair', 'my/app/chair.svg'); // Register icon in a specific set
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
* SVG icons and icon sets can be easily pre-loaded and cached using either (a) a build process or (b) a runtime
|
||||
* **startup** process (shown below):
|
||||
*
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Register a default set of SVG icon definitions
|
||||
* $mdIconProvider.defaultIconSet('my/app/icons.svg')
|
||||
*
|
||||
* })
|
||||
* .run(function($http, $templateCache){
|
||||
*
|
||||
* // Pre-fetch icons sources by URL and cache in the $templateCache...
|
||||
* // subsequent $http calls will look there first.
|
||||
*
|
||||
* var urls = [ 'imy/app/icons.svg', 'img/icons/android.svg'];
|
||||
*
|
||||
* angular.forEach(urls, function(url) {
|
||||
* $http.get(url, {cache: $templateCache});
|
||||
* });
|
||||
*
|
||||
* });
|
||||
*
|
||||
* </hljs>
|
||||
*
|
||||
* NOTE: the loaded SVG data is subsequently cached internally for future requests.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdIconProvider#icon
|
||||
*
|
||||
* @description
|
||||
* Register a source URL for a specific icon name; the name may include optional 'icon set' name prefix.
|
||||
* These icons will later be retrieved from the cache using `$mdIcon( <icon name> )`
|
||||
*
|
||||
* @param {string} id Icon name/id used to register the icon
|
||||
* @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
|
||||
* data or as part of the lookup in `$templateCache` if pre-loading was configured.
|
||||
* @param {number=} viewBoxSize Sets the width and height the icon's viewBox.
|
||||
* It is ignored for icons with an existing viewBox. Default size is 24.
|
||||
*
|
||||
* @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Configure URLs for icons specified by [set:]id.
|
||||
*
|
||||
* $mdIconProvider
|
||||
* .icon('android', 'my/app/android.svg') // Register a specific icon (by name)
|
||||
* .icon('work:chair', 'my/app/chair.svg'); // Register icon in a specific set
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdIconProvider#iconSet
|
||||
*
|
||||
* @description
|
||||
* Register a source URL for a 'named' set of icons; group of SVG definitions where each definition
|
||||
* has an icon id. Individual icons can be subsequently retrieved from this cached set using
|
||||
* `$mdIcon(<icon set name>:<icon name>)`
|
||||
*
|
||||
* @param {string} id Icon name/id used to register the iconset
|
||||
* @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
|
||||
* data or as part of the lookup in `$templateCache` if pre-loading was configured.
|
||||
* @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.
|
||||
* It is ignored for icons with an existing viewBox. All icons in the icon set should be the same size.
|
||||
* Default value is 24.
|
||||
*
|
||||
* @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
|
||||
*
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Configure URLs for icons specified by [set:]id.
|
||||
*
|
||||
* $mdIconProvider
|
||||
* .iconSet('social', 'my/app/social.svg') // Register a named icon set
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdIconProvider#defaultIconSet
|
||||
*
|
||||
* @description
|
||||
* Register a source URL for the default 'named' set of icons. Unless explicitly registered,
|
||||
* subsequent lookups of icons will failover to search this 'default' icon set.
|
||||
* Icon can be retrieved from this cached, default set using `$mdIcon(<name>)`
|
||||
*
|
||||
* @param {string} url specifies the external location for the data file. Used internally by `$http` to load the
|
||||
* data or as part of the lookup in `$templateCache` if pre-loading was configured.
|
||||
* @param {number=} viewBoxSize Sets the width and height of the viewBox of all icons in the set.
|
||||
* It is ignored for icons with an existing viewBox. All icons in the icon set should be the same size.
|
||||
* Default value is 24.
|
||||
*
|
||||
* @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Configure URLs for icons specified by [set:]id.
|
||||
*
|
||||
* $mdIconProvider
|
||||
* .defaultIconSet( 'my/app/social.svg' ) // Register a default icon set
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdIconProvider#defaultFontSet
|
||||
*
|
||||
* @description
|
||||
* When using Font-Icons, Angular Material assumes the the Material Design icons will be used and automatically
|
||||
* configures the default font-set == 'material-icons'. Note that the font-set references the font-icon library
|
||||
* class style that should be applied to the `<md-icon>`.
|
||||
*
|
||||
* Configuring the default means that the attributes
|
||||
* `md-font-set="material-icons"` or `class="material-icons"` do not need to be explicitly declared on the
|
||||
* `<md-icon>` markup. For example:
|
||||
*
|
||||
* `<md-icon> face </md-icon>`
|
||||
* will render as
|
||||
* `<span class="material-icons"> face </span>`, and
|
||||
*
|
||||
* `<md-icon md-font-set="fa"> face </md-icon>`
|
||||
* will render as
|
||||
* `<span class="fa"> face </span>`
|
||||
*
|
||||
* @param {string} name of the font-library style that should be applied to the md-icon DOM element
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
* $mdIconProvider.defaultFontSet( 'fontawesome' );
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdIconProvider#defaultViewBoxSize
|
||||
*
|
||||
* @description
|
||||
* While `<md-icon />` markup can also be style with sizing CSS, this method configures
|
||||
* the default width **and** height used for all icons; unless overridden by specific CSS.
|
||||
* The default sizing is (24px, 24px).
|
||||
* @param {number=} viewBoxSize Sets the width and height of the viewBox for an icon or an icon set.
|
||||
* All icons in a set should be the same size. The default value is 24.
|
||||
*
|
||||
* @returns {obj} an `$mdIconProvider` reference; used to support method call chains for the API
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* app.config(function($mdIconProvider) {
|
||||
*
|
||||
* // Configure URLs for icons specified by [set:]id.
|
||||
*
|
||||
* $mdIconProvider
|
||||
* .defaultViewBoxSize(36) // Register a default icon size (width == height)
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
|
||||
var config = {
|
||||
defaultViewBoxSize: 24,
|
||||
defaultFontSet: 'material-icons',
|
||||
fontSets : [ ]
|
||||
};
|
||||
|
||||
function MdIconProvider() { }
|
||||
|
||||
MdIconProvider.prototype = {
|
||||
icon : function (id, url, viewBoxSize) {
|
||||
if ( id.indexOf(':') == -1 ) id = '$default:' + id;
|
||||
|
||||
config[id] = new ConfigurationItem(url, viewBoxSize );
|
||||
return this;
|
||||
},
|
||||
|
||||
iconSet : function (id, url, viewBoxSize) {
|
||||
config[id] = new ConfigurationItem(url, viewBoxSize );
|
||||
return this;
|
||||
},
|
||||
|
||||
defaultIconSet : function (url, viewBoxSize) {
|
||||
var setName = '$default';
|
||||
|
||||
if ( !config[setName] ) {
|
||||
config[setName] = new ConfigurationItem(url, viewBoxSize );
|
||||
}
|
||||
|
||||
config[setName].viewBoxSize = viewBoxSize || config.defaultViewBoxSize;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
defaultViewBoxSize : function (viewBoxSize) {
|
||||
config.defaultViewBoxSize = viewBoxSize;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Register an alias name associated with a font-icon library style ;
|
||||
*/
|
||||
fontSet : function fontSet(alias, className) {
|
||||
config.fontSets.push({
|
||||
alias : alias,
|
||||
fontSet : className || alias
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Specify a default style name associated with a font-icon library
|
||||
* fallback to Material Icons.
|
||||
*
|
||||
*/
|
||||
defaultFontSet : function defaultFontSet(className) {
|
||||
config.defaultFontSet = !className ? '' : className;
|
||||
return this;
|
||||
},
|
||||
|
||||
defaultIconSize : function defaultIconSize(iconSize) {
|
||||
config.defaultIconSize = iconSize;
|
||||
return this;
|
||||
},
|
||||
|
||||
preloadIcons: function ($templateCache) {
|
||||
var iconProvider = this;
|
||||
var svgRegistry = [
|
||||
{
|
||||
id : 'md-tabs-arrow',
|
||||
url: 'md-tabs-arrow.svg',
|
||||
svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><polygon points="15.4,7.4 14,6 8,12 14,18 15.4,16.6 10.8,12 "/></g></svg>'
|
||||
},
|
||||
{
|
||||
id : 'md-close',
|
||||
url: 'md-close.svg',
|
||||
svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><path d="M19 6.41l-1.41-1.41-5.59 5.59-5.59-5.59-1.41 1.41 5.59 5.59-5.59 5.59 1.41 1.41 5.59-5.59 5.59 5.59 1.41-1.41-5.59-5.59z"/></g></svg>'
|
||||
},
|
||||
{
|
||||
id: 'md-cancel',
|
||||
url: 'md-cancel.svg',
|
||||
svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 24 24"><g><path d="M12 2c-5.53 0-10 4.47-10 10s4.47 10 10 10 10-4.47 10-10-4.47-10-10-10zm5 13.59l-1.41 1.41-3.59-3.59-3.59 3.59-1.41-1.41 3.59-3.59-3.59-3.59 1.41-1.41 3.59 3.59 3.59-3.59 1.41 1.41-3.59 3.59 3.59 3.59z"/></g></svg>'
|
||||
},
|
||||
{
|
||||
id: 'md-menu',
|
||||
url: 'md-menu.svg',
|
||||
svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 100 100"><path d="M 50 0 L 100 14 L 92 80 L 50 100 L 8 80 L 0 14 Z" fill="#b2b2b2"></path><path d="M 50 5 L 6 18 L 13.5 77 L 50 94 Z" fill="#E42939"></path><path d="M 50 5 L 94 18 L 86.5 77 L 50 94 Z" fill="#B72833"></path><path d="M 50 7 L 83 75 L 72 75 L 65 59 L 50 59 L 50 50 L 61 50 L 50 26 Z" fill="#b2b2b2"></path><path d="M 50 7 L 17 75 L 28 75 L 35 59 L 50 59 L 50 50 L 39 50 L 50 26 Z" fill="#fff"></path></svg>'
|
||||
},
|
||||
{
|
||||
id: 'md-toggle-arrow',
|
||||
url: 'md-toggle-arrow-svg',
|
||||
svg: '<svg version="1.1" x="0px" y="0px" viewBox="0 0 48 48"><path d="M24 16l-12 12 2.83 2.83 9.17-9.17 9.17 9.17 2.83-2.83z"/><path d="M0 0h48v48h-48z" fill="none"/></svg>'
|
||||
}
|
||||
];
|
||||
|
||||
svgRegistry.forEach(function(asset){
|
||||
iconProvider.icon(asset.id, asset.url);
|
||||
$templateCache.put(asset.url, asset.svg);
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
$get : ['$http', '$q', '$log', '$templateCache', function($http, $q, $log, $templateCache) {
|
||||
this.preloadIcons($templateCache);
|
||||
return MdIconService(config, $http, $q, $log, $templateCache);
|
||||
}]
|
||||
};
|
||||
|
||||
/**
|
||||
* Configuration item stored in the Icon registry; used for lookups
|
||||
* to load if not already cached in the `loaded` cache
|
||||
*/
|
||||
function ConfigurationItem(url, viewBoxSize) {
|
||||
this.url = url;
|
||||
this.viewBoxSize = viewBoxSize || config.defaultViewBoxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $mdIcon
|
||||
* @module material.components.icon
|
||||
*
|
||||
* @description
|
||||
* The `$mdIcon` service is a function used to lookup SVG icons.
|
||||
*
|
||||
* @param {string} id Query value for a unique Id or URL. If the argument is a URL, then the service will retrieve the icon element
|
||||
* from its internal cache or load the icon and cache it first. If the value is not a URL-type string, then an ID lookup is
|
||||
* performed. The Id may be a unique icon ID or may include an iconSet ID prefix.
|
||||
*
|
||||
* For the **id** query to work properly, this means that all id-to-URL mappings must have been previously configured
|
||||
* using the `$mdIconProvider`.
|
||||
*
|
||||
* @returns {obj} Clone of the initial SVG DOM element; which was created from the SVG markup in the SVG data file.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* function SomeDirective($mdIcon) {
|
||||
*
|
||||
* // See if the icon has already been loaded, if not
|
||||
* // then lookup the icon from the registry cache, load and cache
|
||||
* // it for future requests.
|
||||
* // NOTE: ID queries require configuration with $mdIconProvider
|
||||
*
|
||||
* $mdIcon('android').then(function(iconEl) { element.append(iconEl); });
|
||||
* $mdIcon('work:chair').then(function(iconEl) { element.append(iconEl); });
|
||||
*
|
||||
* // Load and cache the external SVG using a URL
|
||||
*
|
||||
* $mdIcon('img/icons/android.svg').then(function(iconEl) {
|
||||
* element.append(iconEl);
|
||||
* });
|
||||
* };
|
||||
* </hljs>
|
||||
*
|
||||
* NOTE: The `<md-icon /> ` directive internally uses the `$mdIcon` service to query, loaded, and instantiate
|
||||
* SVG DOM elements.
|
||||
*/
|
||||
function MdIconService(config, $http, $q, $log, $templateCache) {
|
||||
var iconCache = {};
|
||||
var urlRegex = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/i;
|
||||
|
||||
Icon.prototype = { clone : cloneSVG, prepare: prepareAndStyle };
|
||||
getIcon.fontSet = findRegisteredFontSet;
|
||||
|
||||
// Publish service...
|
||||
return getIcon;
|
||||
|
||||
/**
|
||||
* Actual $mdIcon service is essentially a lookup function
|
||||
*/
|
||||
function getIcon(id) {
|
||||
id = id || '';
|
||||
|
||||
// If already loaded and cached, use a clone of the cached icon.
|
||||
// Otherwise either load by URL, or lookup in the registry and then load by URL, and cache.
|
||||
|
||||
if ( iconCache[id] ) return $q.when( iconCache[id].clone() );
|
||||
if ( urlRegex.test(id) ) return loadByURL(id).then( cacheIcon(id) );
|
||||
if ( id.indexOf(':') == -1 ) id = '$default:' + id;
|
||||
|
||||
return loadByID(id)
|
||||
.catch(loadFromIconSet)
|
||||
.catch(announceIdNotFound)
|
||||
.catch(announceNotFound)
|
||||
.then( cacheIcon(id) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup registered fontSet style using its alias...
|
||||
* If not found,
|
||||
*/
|
||||
function findRegisteredFontSet(alias) {
|
||||
var useDefault = angular.isUndefined(alias) || !(alias && alias.length);
|
||||
if ( useDefault ) return config.defaultFontSet;
|
||||
|
||||
var result = alias;
|
||||
angular.forEach(config.fontSets, function(it){
|
||||
if ( it.alias == alias ) result = it.fontSet || result;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare and cache the loaded icon for the specified `id`
|
||||
*/
|
||||
function cacheIcon( id ) {
|
||||
|
||||
return function updateCache( icon ) {
|
||||
iconCache[id] = isIcon(icon) ? icon : new Icon(icon, config[id]);
|
||||
|
||||
return iconCache[id].clone();
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup the configuration in the registry, if !registered throw an error
|
||||
* otherwise load the icon [on-demand] using the registered URL.
|
||||
*
|
||||
*/
|
||||
function loadByID(id) {
|
||||
var iconConfig = config[id];
|
||||
|
||||
return !iconConfig ? $q.reject(id) : loadByURL(iconConfig.url).then(function(icon) {
|
||||
return new Icon(icon, iconConfig);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the file as XML and uses querySelector( <id> ) to find
|
||||
* the desired node...
|
||||
*/
|
||||
function loadFromIconSet(id) {
|
||||
var setName = id.substring(0, id.lastIndexOf(':')) || '$default';
|
||||
var iconSetConfig = config[setName];
|
||||
|
||||
return !iconSetConfig ? $q.reject(id) : loadByURL(iconSetConfig.url).then(extractFromSet);
|
||||
|
||||
function extractFromSet(set) {
|
||||
var iconName = id.slice(id.lastIndexOf(':') + 1);
|
||||
var icon = set.querySelector('#' + iconName);
|
||||
return !icon ? $q.reject(id) : new Icon(icon, iconSetConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the icon by URL (may use the $templateCache).
|
||||
* Extract the data for later conversion to Icon
|
||||
*/
|
||||
function loadByURL(url) {
|
||||
return $http
|
||||
.get(url, { cache: $templateCache })
|
||||
.then(function(response) {
|
||||
return angular.element('<div>').append(response.data).find('svg')[0];
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* User did not specify a URL and the ID has not been registered with the $mdIcon
|
||||
* registry
|
||||
*/
|
||||
function announceIdNotFound(id) {
|
||||
var msg;
|
||||
|
||||
if (angular.isString(id)) {
|
||||
msg = 'icon ' + id + ' not found';
|
||||
$log.warn(msg);
|
||||
}
|
||||
|
||||
return $q.reject(msg || id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Catch HTTP or generic errors not related to incorrect icon IDs.
|
||||
*/
|
||||
function announceNotFound(err) {
|
||||
var msg = angular.isString(err) ? err : (err.message || err.data || err.statusText);
|
||||
$log.warn(msg);
|
||||
|
||||
return $q.reject(msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check target signature to see if it is an Icon instance.
|
||||
*/
|
||||
function isIcon(target) {
|
||||
return angular.isDefined(target.element) && angular.isDefined(target.config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Define the Icon class
|
||||
*/
|
||||
function Icon(el, config) {
|
||||
if (el.tagName != 'svg') {
|
||||
el = angular.element('<svg xmlns="http://www.w3.org/2000/svg">').append(el)[0];
|
||||
}
|
||||
|
||||
// Inject the namespace if not available...
|
||||
if ( !el.getAttribute('xmlns') ) {
|
||||
el.setAttribute('xmlns', "http://www.w3.org/2000/svg");
|
||||
}
|
||||
|
||||
this.element = el;
|
||||
this.config = config;
|
||||
this.prepare();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the DOM element that will be cached in the
|
||||
* loaded iconCache store.
|
||||
*/
|
||||
function prepareAndStyle() {
|
||||
var viewBoxSize = this.config ? this.config.viewBoxSize : config.defaultViewBoxSize;
|
||||
angular.forEach({
|
||||
'fit' : '',
|
||||
'height': '100%',
|
||||
'width' : '100%',
|
||||
'preserveAspectRatio': 'xMidYMid meet',
|
||||
'viewBox' : this.element.getAttribute('viewBox') || ('0 0 ' + viewBoxSize + ' ' + viewBoxSize)
|
||||
}, function(val, attr) {
|
||||
this.element.setAttribute(attr, val);
|
||||
}, this);
|
||||
|
||||
angular.forEach({
|
||||
'pointer-events' : 'none',
|
||||
'display' : 'block'
|
||||
}, function(val, style) {
|
||||
this.element.style[style] = val;
|
||||
}, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the Icon DOM element.
|
||||
*/
|
||||
function cloneSVG(){
|
||||
return this.element.cloneNode(true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ng.material.components.icon = angular.module("material.components.icon");
|
||||
@@ -0,0 +1,46 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-input-container.md-THEME_NAME-theme .md-input {
|
||||
color: '{{foreground-1}}';
|
||||
border-color: '{{foreground-4}}';
|
||||
text-shadow: '{{foreground-shadow}}'; }
|
||||
md-input-container.md-THEME_NAME-theme .md-input::-webkit-input-placeholder, md-input-container.md-THEME_NAME-theme .md-input::-moz-placeholder, md-input-container.md-THEME_NAME-theme .md-input:-moz-placeholder, md-input-container.md-THEME_NAME-theme .md-input:-ms-input-placeholder {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-input-container.md-THEME_NAME-theme > md-icon {
|
||||
color: '{{foreground-1}}'; }
|
||||
md-input-container.md-THEME_NAME-theme label, md-input-container.md-THEME_NAME-theme .md-placeholder {
|
||||
text-shadow: '{{foreground-shadow}}';
|
||||
color: '{{foreground-3}}'; }
|
||||
md-input-container.md-THEME_NAME-theme ng-messages, md-input-container.md-THEME_NAME-theme [ng-message], md-input-container.md-THEME_NAME-theme [data-ng-message], md-input-container.md-THEME_NAME-theme [x-ng-message] {
|
||||
color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-has-value label {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused .md-input {
|
||||
border-color: '{{primary-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused label {
|
||||
color: '{{primary-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused md-icon {
|
||||
color: '{{primary-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent .md-input {
|
||||
border-color: '{{accent-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-accent label {
|
||||
color: '{{accent-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn .md-input {
|
||||
border-color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme:not(.md-input-invalid).md-input-focused.md-warn label {
|
||||
color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme.md-input-invalid .md-input {
|
||||
border-color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme.md-input-invalid.md-input-focused label {
|
||||
color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme.md-input-invalid ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid data-ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid x-ng-message, md-input-container.md-THEME_NAME-theme.md-input-invalid [ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid [data-ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid [x-ng-message], md-input-container.md-THEME_NAME-theme.md-input-invalid .md-char-counter {
|
||||
color: '{{warn-500}}'; }
|
||||
md-input-container.md-THEME_NAME-theme .md-input[disabled], [disabled] md-input-container.md-THEME_NAME-theme .md-input {
|
||||
border-bottom-color: transparent;
|
||||
color: '{{foreground-3}}';
|
||||
background-image: linear-gradient(to right, '{{foreground-3}}' 0%, '{{foreground-3}}' 33%, transparent 0%); }
|
||||
162
www/lib/angular-material/modules/closure/input/input.css
Normal file
@@ -0,0 +1,162 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-input-container {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
position: relative;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding: 2px;
|
||||
padding-bottom: 26px;
|
||||
/*
|
||||
* The .md-input class is added to the input/textarea
|
||||
*/ }
|
||||
md-input-container > md-icon {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 2px; }
|
||||
md-input-container > md-icon + input {
|
||||
margin-left: 36px; }
|
||||
md-input-container textarea, md-input-container input[type="text"], md-input-container input[type="password"], md-input-container input[type="datetime"], md-input-container input[type="datetime-local"], md-input-container input[type="date"], md-input-container input[type="month"], md-input-container input[type="time"], md-input-container input[type="week"], md-input-container input[type="number"], md-input-container input[type="email"], md-input-container input[type="url"], md-input-container input[type="search"], md-input-container input[type="tel"], md-input-container input[type="color"] {
|
||||
/* remove default appearance from all input/textarea */
|
||||
-moz-appearance: none;
|
||||
-webkit-appearance: none; }
|
||||
md-input-container input[type="date"], md-input-container input[type="datetime-local"], md-input-container input[type="month"], md-input-container input[type="time"], md-input-container input[type="week"] {
|
||||
min-height: 26px; }
|
||||
md-input-container textarea {
|
||||
resize: none;
|
||||
overflow: hidden; }
|
||||
md-input-container textarea.md-input {
|
||||
min-height: 56px;
|
||||
-ms-flex-preferred-size: auto; }
|
||||
md-input-container label {
|
||||
position: relative;
|
||||
top: -2px; }
|
||||
md-input-container label:not(.md-no-float), md-input-container .md-placeholder:not(.md-select-label) {
|
||||
-webkit-order: 1;
|
||||
-ms-flex-order: 1;
|
||||
order: 1;
|
||||
pointer-events: none;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
padding-left: 2px;
|
||||
z-index: 1;
|
||||
-webkit-transform: translate3d(0, 28px, 0) scale(1);
|
||||
transform: translate3d(0, 28px, 0) scale(1);
|
||||
transition: -webkit-transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.25s;
|
||||
transition: transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.25s;
|
||||
-webkit-transform-origin: left top;
|
||||
transform-origin: left top; }
|
||||
html[dir=rtl] md-input-container label:not(.md-no-float), html[dir=rtl] md-input-container .md-placeholder:not(.md-select-label) {
|
||||
-webkit-transform-origin: right top;
|
||||
transform-origin: right top; }
|
||||
md-input-container .md-placeholder:not(.md-select-label) {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
opacity: 0;
|
||||
transition-property: opacity, -webkit-transform;
|
||||
transition-property: opacity, transform;
|
||||
-webkit-transform: translate3d(0, 30px, 0);
|
||||
transform: translate3d(0, 30px, 0); }
|
||||
md-input-container.md-input-focused .md-placeholder {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 24px, 0);
|
||||
transform: translate3d(0, 24px, 0); }
|
||||
md-input-container.md-input-has-value .md-placeholder {
|
||||
transition: none;
|
||||
opacity: 0; }
|
||||
md-input-container:not(.md-input-has-value) input:not(:focus) {
|
||||
color: transparent; }
|
||||
md-input-container .md-input {
|
||||
-webkit-flex: 1 1 auto;
|
||||
-ms-flex: 1 1 auto;
|
||||
flex: 1 1 auto;
|
||||
-webkit-order: 2;
|
||||
-ms-flex-order: 2;
|
||||
order: 2;
|
||||
display: block;
|
||||
background: none;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 1px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
border-width: 0 0 1px 0;
|
||||
line-height: 26px;
|
||||
-ms-flex-preferred-size: 26px;
|
||||
border-radius: 0; }
|
||||
md-input-container .md-input:focus {
|
||||
outline: none; }
|
||||
md-input-container .md-input:invalid {
|
||||
outline: none;
|
||||
box-shadow: none; }
|
||||
md-input-container ng-messages, md-input-container data-ng-messages, md-input-container x-ng-messages, md-input-container [ng-messages], md-input-container [data-ng-messages], md-input-container [x-ng-messages] {
|
||||
-webkit-order: 3;
|
||||
-ms-flex-order: 3;
|
||||
order: 3;
|
||||
position: relative; }
|
||||
md-input-container ng-message, md-input-container data-ng-message, md-input-container x-ng-message, md-input-container [ng-message], md-input-container [data-ng-message], md-input-container [x-ng-message], md-input-container .md-char-counter {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
position: absolute;
|
||||
font-size: 12px;
|
||||
line-height: 24px; }
|
||||
md-input-container ng-message:not(.md-char-counter), md-input-container data-ng-message:not(.md-char-counter), md-input-container x-ng-message:not(.md-char-counter), md-input-container [ng-message]:not(.md-char-counter), md-input-container [data-ng-message]:not(.md-char-counter), md-input-container [x-ng-message]:not(.md-char-counter), md-input-container .md-char-counter:not(.md-char-counter) {
|
||||
padding-right: 30px; }
|
||||
md-input-container ng-message.ng-enter, md-input-container data-ng-message.ng-enter, md-input-container x-ng-message.ng-enter, md-input-container [ng-message].ng-enter, md-input-container [data-ng-message].ng-enter, md-input-container [x-ng-message].ng-enter, md-input-container .md-char-counter.ng-enter {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transition-delay: 0.2s; }
|
||||
md-input-container ng-message.ng-leave, md-input-container data-ng-message.ng-leave, md-input-container x-ng-message.ng-leave, md-input-container [ng-message].ng-leave, md-input-container [data-ng-message].ng-leave, md-input-container [x-ng-message].ng-leave, md-input-container .md-char-counter.ng-leave {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-input-container ng-message.ng-enter, md-input-container ng-message.ng-leave.ng-leave-active, md-input-container data-ng-message.ng-enter, md-input-container data-ng-message.ng-leave.ng-leave-active, md-input-container x-ng-message.ng-enter, md-input-container x-ng-message.ng-leave.ng-leave-active, md-input-container [ng-message].ng-enter, md-input-container [ng-message].ng-leave.ng-leave-active, md-input-container [data-ng-message].ng-enter, md-input-container [data-ng-message].ng-leave.ng-leave-active, md-input-container [x-ng-message].ng-enter, md-input-container [x-ng-message].ng-leave.ng-leave-active, md-input-container .md-char-counter.ng-enter, md-input-container .md-char-counter.ng-leave.ng-leave-active {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -20%, 0);
|
||||
transform: translate3d(0, -20%, 0); }
|
||||
md-input-container ng-message.ng-leave, md-input-container ng-message.ng-enter.ng-enter-active, md-input-container data-ng-message.ng-leave, md-input-container data-ng-message.ng-enter.ng-enter-active, md-input-container x-ng-message.ng-leave, md-input-container x-ng-message.ng-enter.ng-enter-active, md-input-container [ng-message].ng-leave, md-input-container [ng-message].ng-enter.ng-enter-active, md-input-container [data-ng-message].ng-leave, md-input-container [data-ng-message].ng-enter.ng-enter-active, md-input-container [x-ng-message].ng-leave, md-input-container [x-ng-message].ng-enter.ng-enter-active, md-input-container .md-char-counter.ng-leave, md-input-container .md-char-counter.ng-enter.ng-enter-active {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
md-input-container .md-char-counter {
|
||||
bottom: 2px;
|
||||
right: 2px; }
|
||||
md-input-container.md-input-focused label:not(.md-no-float), md-input-container.md-input-has-value label:not(.md-no-float) {
|
||||
-webkit-transform: translate3d(0, 6px, 0) scale(0.75);
|
||||
transform: translate3d(0, 6px, 0) scale(0.75); }
|
||||
md-input-container.md-input-focused .md-input, md-input-container .md-input.ng-invalid.ng-dirty {
|
||||
padding-bottom: 0;
|
||||
border-width: 0 0 2px 0; }
|
||||
md-input-container .md-input[disabled], [disabled] md-input-container .md-input {
|
||||
background-position: 0 bottom;
|
||||
background-size: 4px 1px;
|
||||
background-repeat: repeat-x;
|
||||
margin-bottom: -1px; }
|
||||
|
||||
md-input-container.md-icon-float {
|
||||
margin-top: -16px;
|
||||
transition: margin-top 0.5s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
md-input-container.md-icon-float > label {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
margin-left: 36px; }
|
||||
md-input-container.md-icon-float > md-icon {
|
||||
top: 26px;
|
||||
left: 2px; }
|
||||
md-input-container.md-icon-float > md-icon + input {
|
||||
margin-left: 36px; }
|
||||
md-input-container.md-icon-float > input {
|
||||
padding-top: 24px; }
|
||||
md-input-container.md-icon-float.md-input-focused, md-input-container.md-icon-float.md-input-has-value {
|
||||
margin-top: -8px; }
|
||||
md-input-container.md-icon-float.md-input-focused label, md-input-container.md-icon-float.md-input-has-value label {
|
||||
-webkit-transform: translate3d(0, 6px, 0) scale(0.75);
|
||||
transform: translate3d(0, 6px, 0) scale(0.75);
|
||||
transition: -webkit-transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.5s;
|
||||
transition: transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.5s; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-input-container.md-default-theme > md-icon {
|
||||
fill: #fff; } }
|
||||
371
www/lib/angular-material/modules/closure/input/input.js
vendored
Normal file
@@ -0,0 +1,371 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.input');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.input
|
||||
*/
|
||||
|
||||
angular.module('material.components.input', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdInputContainer', mdInputContainerDirective)
|
||||
.directive('label', labelDirective)
|
||||
.directive('input', inputTextareaDirective)
|
||||
.directive('textarea', inputTextareaDirective)
|
||||
.directive('mdMaxlength', mdMaxlengthDirective)
|
||||
.directive('placeholder', placeholderDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdInputContainer
|
||||
* @module material.components.input
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* `<md-input-container>` is the parent of any input or textarea element.
|
||||
*
|
||||
* Input and textarea elements will not behave properly unless the md-input-container
|
||||
* parent is provided.
|
||||
*
|
||||
* @param md-is-error {expression=} When the given expression evaluates to true, the input container will go into error state. Defaults to erroring if the input has been touched and is invalid.
|
||||
* @param md-no-float {boolean=} When present, placeholders will not be converted to floating labels
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
*
|
||||
* <md-input-container>
|
||||
* <label>Username</label>
|
||||
* <input type="text" ng-model="user.name">
|
||||
* </md-input-container>
|
||||
*
|
||||
* <md-input-container>
|
||||
* <label>Description</label>
|
||||
* <textarea ng-model="user.description"></textarea>
|
||||
* </md-input-container>
|
||||
*
|
||||
* </hljs>
|
||||
*/
|
||||
function mdInputContainerDirective($mdTheming, $parse) {
|
||||
ContainerCtrl.$inject = ["$scope", "$element", "$attrs"];
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: postLink,
|
||||
controller: ContainerCtrl
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
}
|
||||
function ContainerCtrl($scope, $element, $attrs) {
|
||||
var self = this;
|
||||
|
||||
self.isErrorGetter = $attrs.mdIsError && $parse($attrs.mdIsError);
|
||||
|
||||
self.delegateClick = function() {
|
||||
self.input.focus();
|
||||
};
|
||||
self.element = $element;
|
||||
self.setFocused = function(isFocused) {
|
||||
$element.toggleClass('md-input-focused', !!isFocused);
|
||||
};
|
||||
self.setHasValue = function(hasValue) {
|
||||
$element.toggleClass('md-input-has-value', !!hasValue);
|
||||
};
|
||||
self.setInvalid = function(isInvalid) {
|
||||
$element.toggleClass('md-input-invalid', !!isInvalid);
|
||||
};
|
||||
$scope.$watch(function() {
|
||||
return self.label && self.input;
|
||||
}, function(hasLabelAndInput) {
|
||||
if (hasLabelAndInput && !self.label.attr('for')) {
|
||||
self.label.attr('for', self.input.attr('id'));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
mdInputContainerDirective.$inject = ["$mdTheming", "$parse"];
|
||||
|
||||
function labelDirective() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '^?mdInputContainer',
|
||||
link: function(scope, element, attr, containerCtrl) {
|
||||
if (!containerCtrl || attr.mdNoFloat) return;
|
||||
|
||||
containerCtrl.label = element;
|
||||
scope.$on('$destroy', function() {
|
||||
containerCtrl.label = null;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdInput
|
||||
* @restrict E
|
||||
* @module material.components.input
|
||||
*
|
||||
* @description
|
||||
* Use the `<input>` or the `<textarea>` as a child of an `<md-input-container>`.
|
||||
*
|
||||
* @param {number=} md-maxlength The maximum number of characters allowed in this input. If this is specified, a character counter will be shown underneath the input.<br/><br/>
|
||||
* The purpose of **`md-maxlength`** is exactly to show the max length counter text. If you don't want the counter text and only need "plain" validation, you can use the "simple" `ng-maxlength` or maxlength attributes.
|
||||
* @param {string=} aria-label Aria-label is required when no label is present. A warning message will be logged in the console if not present.
|
||||
* @param {string=} placeholder An alternative approach to using aria-label when the label is not present. The placeholder text is copied to the aria-label attribute.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-input-container>
|
||||
* <label>Color</label>
|
||||
* <input type="text" ng-model="color" required md-maxlength="10">
|
||||
* </md-input-container>
|
||||
* </hljs>
|
||||
* <h3>With Errors</h3>
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <form name="userForm">
|
||||
* <md-input-container>
|
||||
* <label>Last Name</label>
|
||||
* <input name="lastName" ng-model="lastName" required md-maxlength="10" minlength="4">
|
||||
* <div ng-messages="userForm.lastName.$error" ng-show="userForm.lastName.$dirty">
|
||||
* <div ng-message="required">This is required!</div>
|
||||
* <div ng-message="md-maxlength">That's too long!</div>
|
||||
* <div ng-message="minlength">That's too short!</div>
|
||||
* </div>
|
||||
* </md-input-container>
|
||||
* <md-input-container>
|
||||
* <label>Biography</label>
|
||||
* <textarea name="bio" ng-model="biography" required md-maxlength="150"></textarea>
|
||||
* <div ng-messages="userForm.bio.$error" ng-show="userForm.bio.$dirty">
|
||||
* <div ng-message="required">This is required!</div>
|
||||
* <div ng-message="md-maxlength">That's too long!</div>
|
||||
* </div>
|
||||
* </md-input-container>
|
||||
* <md-input-container>
|
||||
* <input aria-label='title' ng-model='title'>
|
||||
* </md-input-container>
|
||||
* <md-input-container>
|
||||
* <input placeholder='title' ng-model='title'>
|
||||
* </md-input-container>
|
||||
* </form>
|
||||
* </hljs>
|
||||
*
|
||||
* Requires [ngMessages](https://docs.angularjs.org/api/ngMessages).
|
||||
* Behaves like the [AngularJS input directive](https://docs.angularjs.org/api/ng/directive/input).
|
||||
*
|
||||
*/
|
||||
|
||||
function inputTextareaDirective($mdUtil, $window, $mdAria) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: ['^?mdInputContainer', '?ngModel'],
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr, ctrls) {
|
||||
|
||||
var containerCtrl = ctrls[0];
|
||||
var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();
|
||||
var isReadonly = angular.isDefined(attr.readonly);
|
||||
|
||||
if ( !containerCtrl ) return;
|
||||
if (containerCtrl.input) {
|
||||
throw new Error("<md-input-container> can only have *one* <input> or <textarea> child element!");
|
||||
}
|
||||
containerCtrl.input = element;
|
||||
|
||||
if(!containerCtrl.label) {
|
||||
$mdAria.expect(element, 'aria-label', element.attr('placeholder'));
|
||||
}
|
||||
|
||||
element.addClass('md-input');
|
||||
if (!element.attr('id')) {
|
||||
element.attr('id', 'input_' + $mdUtil.nextUid());
|
||||
}
|
||||
|
||||
if (element[0].tagName.toLowerCase() === 'textarea') {
|
||||
setupTextarea();
|
||||
}
|
||||
|
||||
var isErrorGetter = containerCtrl.isErrorGetter || function() {
|
||||
return ngModelCtrl.$invalid && ngModelCtrl.$touched;
|
||||
};
|
||||
scope.$watch(isErrorGetter, containerCtrl.setInvalid);
|
||||
|
||||
ngModelCtrl.$parsers.push(ngModelPipelineCheckValue);
|
||||
ngModelCtrl.$formatters.push(ngModelPipelineCheckValue);
|
||||
|
||||
element.on('input', inputCheckValue);
|
||||
|
||||
if (!isReadonly) {
|
||||
element
|
||||
.on('focus', function(ev) {
|
||||
containerCtrl.setFocused(true);
|
||||
})
|
||||
.on('blur', function(ev) {
|
||||
containerCtrl.setFocused(false);
|
||||
inputCheckValue();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
//ngModelCtrl.$setTouched();
|
||||
//if( ngModelCtrl.$invalid ) containerCtrl.setInvalid();
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
containerCtrl.setFocused(false);
|
||||
containerCtrl.setHasValue(false);
|
||||
containerCtrl.input = null;
|
||||
});
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
function ngModelPipelineCheckValue(arg) {
|
||||
containerCtrl.setHasValue(!ngModelCtrl.$isEmpty(arg));
|
||||
return arg;
|
||||
}
|
||||
function inputCheckValue() {
|
||||
// An input's value counts if its length > 0,
|
||||
// or if the input's validity state says it has bad input (eg string in a number input)
|
||||
containerCtrl.setHasValue(element.val().length > 0 || (element[0].validity||{}).badInput);
|
||||
}
|
||||
|
||||
function setupTextarea() {
|
||||
var node = element[0];
|
||||
var onChangeTextarea = $mdUtil.debounce(growTextarea, 1);
|
||||
|
||||
function pipelineListener(value) {
|
||||
onChangeTextarea();
|
||||
return value;
|
||||
}
|
||||
|
||||
if (ngModelCtrl) {
|
||||
ngModelCtrl.$formatters.push(pipelineListener);
|
||||
ngModelCtrl.$viewChangeListeners.push(pipelineListener);
|
||||
} else {
|
||||
onChangeTextarea();
|
||||
}
|
||||
element.on('keydown input', onChangeTextarea);
|
||||
element.on('scroll', onScroll);
|
||||
angular.element($window).on('resize', onChangeTextarea);
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
angular.element($window).off('resize', onChangeTextarea);
|
||||
});
|
||||
|
||||
function growTextarea() {
|
||||
node.style.height = "auto";
|
||||
node.scrollTop = 0;
|
||||
var height = getHeight();
|
||||
if (height) node.style.height = height + 'px';
|
||||
}
|
||||
|
||||
function getHeight () {
|
||||
var line = node.scrollHeight - node.offsetHeight;
|
||||
return node.offsetHeight + (line > 0 ? line : 0);
|
||||
}
|
||||
|
||||
function onScroll(e) {
|
||||
node.scrollTop = 0;
|
||||
// for smooth new line adding
|
||||
var line = node.scrollHeight - node.offsetHeight;
|
||||
var height = node.offsetHeight + line;
|
||||
node.style.height = height + 'px';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
inputTextareaDirective.$inject = ["$mdUtil", "$window", "$mdAria"];
|
||||
|
||||
function mdMaxlengthDirective($animate) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: ['ngModel', '^mdInputContainer'],
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr, ctrls) {
|
||||
var maxlength;
|
||||
var ngModelCtrl = ctrls[0];
|
||||
var containerCtrl = ctrls[1];
|
||||
var charCountEl = angular.element('<div class="md-char-counter">');
|
||||
|
||||
// Stop model from trimming. This makes it so whitespace
|
||||
// over the maxlength still counts as invalid.
|
||||
attr.$set('ngTrim', 'false');
|
||||
containerCtrl.element.append(charCountEl);
|
||||
|
||||
ngModelCtrl.$formatters.push(renderCharCount);
|
||||
ngModelCtrl.$viewChangeListeners.push(renderCharCount);
|
||||
element.on('input keydown', function() {
|
||||
renderCharCount(); //make sure it's called with no args
|
||||
});
|
||||
|
||||
scope.$watch(attr.mdMaxlength, function(value) {
|
||||
maxlength = value;
|
||||
if (angular.isNumber(value) && value > 0) {
|
||||
if (!charCountEl.parent().length) {
|
||||
$animate.enter(charCountEl, containerCtrl.element,
|
||||
angular.element(containerCtrl.element[0].lastElementChild));
|
||||
}
|
||||
renderCharCount();
|
||||
} else {
|
||||
$animate.leave(charCountEl);
|
||||
}
|
||||
});
|
||||
|
||||
ngModelCtrl.$validators['md-maxlength'] = function(modelValue, viewValue) {
|
||||
if (!angular.isNumber(maxlength) || maxlength < 0) {
|
||||
return true;
|
||||
}
|
||||
return ( modelValue || element.val() || viewValue || '' ).length <= maxlength;
|
||||
};
|
||||
|
||||
function renderCharCount(value) {
|
||||
charCountEl.text( ( element.val() || value || '' ).length + '/' + maxlength );
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
mdMaxlengthDirective.$inject = ["$animate"];
|
||||
|
||||
function placeholderDirective($log) {
|
||||
var blackListElements = ['MD-SELECT'];
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '^^?mdInputContainer',
|
||||
priority: 200,
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr, inputContainer) {
|
||||
if (!inputContainer) return;
|
||||
if (blackListElements.indexOf(element[0].nodeName) != -1) return;
|
||||
if (angular.isDefined(inputContainer.element.attr('md-no-float'))) return;
|
||||
|
||||
var placeholderText = attr.placeholder;
|
||||
element.removeAttr('placeholder');
|
||||
|
||||
if ( inputContainer.element.find('label').length == 0 ) {
|
||||
var placeholder = '<label ng-click="delegateClick()">' + placeholderText + '</label>';
|
||||
|
||||
inputContainer.element.addClass('md-icon-float');
|
||||
inputContainer.element.prepend(placeholder);
|
||||
} else {
|
||||
$log.warn("The placeholder='" + placeholderText + "' will be ignored since this md-input-container has a child label element.");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
placeholderDirective.$inject = ["$log"];
|
||||
|
||||
ng.material.components.input = angular.module("material.components.input");
|
||||