Neues Initialrelease mit IonicMaterial
This commit is contained in:
@@ -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
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
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
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
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
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
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
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
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
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
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
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
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
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
2594
www/lib/angular-material/modules/closure/core/core.css
Normal file
File diff suppressed because it is too large
Load Diff
3772
www/lib/angular-material/modules/closure/core/core.js
vendored
Normal file
3772
www/lib/angular-material/modules/closure/core/core.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
www/lib/angular-material/modules/closure/core/default-theme.js
vendored
Normal file
4
www/lib/angular-material/modules/closure/core/default-theme.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -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
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
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
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
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
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
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
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
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
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
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
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
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
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");
|
||||
@@ -0,0 +1,23 @@
|
||||
/*!
|
||||
* 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-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h3, md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text h4, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h3, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text h4 {
|
||||
color: '{{foreground-1}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item.md-2-line .md-list-item-text p, md-list.md-THEME_NAME-theme md-list-item.md-3-line .md-list-item-text p {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-list.md-THEME_NAME-theme .md-proxy-focus.md-focused div.md-no-style {
|
||||
background-color: '{{background-100}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item > md-icon {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight {
|
||||
color: '{{primary-color}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item > md-icon.md-highlight.md-accent {
|
||||
color: '{{accent-color}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item button {
|
||||
background-color: '{{background-color}}'; }
|
||||
md-list.md-THEME_NAME-theme md-list-item button.md-button:not([disabled]):hover {
|
||||
background-color: '{{background-color}}'; }
|
||||
147
www/lib/angular-material/modules/closure/list/list.css
Normal file
147
www/lib/angular-material/modules/closure/list/list.css
Normal file
@@ -0,0 +1,147 @@
|
||||
/*!
|
||||
* 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-list {
|
||||
display: block;
|
||||
padding: 8px 0px 8px 0px; }
|
||||
md-list .md-subheader {
|
||||
line-height: 0.75em; }
|
||||
|
||||
md-list-item.md-proxy-focus.md-focused .md-no-style {
|
||||
transition: background-color 0.15s linear; }
|
||||
md-list-item.md-no-proxy, md-list-item .md-no-style {
|
||||
position: relative;
|
||||
padding: 0px 16px;
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1; }
|
||||
md-list-item.md-no-proxy.md-button, md-list-item .md-no-style.md-button {
|
||||
font-size: inherit;
|
||||
height: inherit;
|
||||
text-align: left;
|
||||
text-transform: none;
|
||||
width: 100%;
|
||||
white-space: normal; }
|
||||
md-list-item.md-no-proxy:focus, md-list-item .md-no-style:focus {
|
||||
outline: none; }
|
||||
md-list-item.md-with-secondary {
|
||||
position: relative; }
|
||||
md-list-item.md-clickable:hover {
|
||||
cursor: pointer; }
|
||||
md-list-item md-divider {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%; }
|
||||
md-list-item md-divider[md-inset] {
|
||||
left: 96px;
|
||||
width: calc(100% - 96px);
|
||||
margin: 0; }
|
||||
|
||||
md-list-item, md-list-item .md-list-item-inner {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
min-height: 48px; }
|
||||
md-list-item > div.md-primary > md-icon, md-list-item > div.md-secondary > md-icon, md-list-item > md-icon:first-child, md-list-item > md-icon.md-secondary, md-list-item .md-list-item-inner > div.md-primary > md-icon, md-list-item .md-list-item-inner > div.md-secondary > md-icon, md-list-item .md-list-item-inner > md-icon:first-child, md-list-item .md-list-item-inner > md-icon.md-secondary {
|
||||
width: 24px;
|
||||
margin-top: 16px;
|
||||
margin-bottom: 12px;
|
||||
box-sizing: content-box; }
|
||||
md-list-item > div.md-primary > md-checkbox, md-list-item > div.md-secondary > md-checkbox, md-list-item > md-checkbox:first-child, md-list-item md-checkbox.md-secondary, md-list-item .md-list-item-inner > div.md-primary > md-checkbox, md-list-item .md-list-item-inner > div.md-secondary > md-checkbox, md-list-item .md-list-item-inner > md-checkbox:first-child, md-list-item .md-list-item-inner md-checkbox.md-secondary {
|
||||
-webkit-align-self: center;
|
||||
-ms-flex-item-align: center;
|
||||
align-self: center; }
|
||||
md-list-item > div.md-primary > md-checkbox .md-label, md-list-item > div.md-secondary > md-checkbox .md-label, md-list-item > md-checkbox:first-child .md-label, md-list-item md-checkbox.md-secondary .md-label, md-list-item .md-list-item-inner > div.md-primary > md-checkbox .md-label, md-list-item .md-list-item-inner > div.md-secondary > md-checkbox .md-label, md-list-item .md-list-item-inner > md-checkbox:first-child .md-label, md-list-item .md-list-item-inner md-checkbox.md-secondary .md-label {
|
||||
display: none; }
|
||||
md-list-item > md-icon:first-child, md-list-item .md-list-item-inner > md-icon:first-child {
|
||||
margin-right: 32px; }
|
||||
md-list-item > md-checkbox:first-child, md-list-item .md-list-item-inner > md-checkbox:first-child {
|
||||
width: 24px;
|
||||
margin-left: 3px;
|
||||
margin-right: 29px; }
|
||||
md-list-item > .md-avatar:first-child, md-list-item .md-list-item-inner > .md-avatar:first-child {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin-top: 8px;
|
||||
margin-bottom: 8px;
|
||||
margin-right: 16px;
|
||||
border-radius: 50%;
|
||||
box-sizing: content-box; }
|
||||
md-list-item md-checkbox.md-secondary, md-list-item md-switch.md-secondary, md-list-item .md-list-item-inner md-checkbox.md-secondary, md-list-item .md-list-item-inner md-switch.md-secondary {
|
||||
margin-right: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0; }
|
||||
md-list-item button.md-button.md-secondary-container, md-list-item .md-list-item-inner button.md-button.md-secondary-container {
|
||||
background-color: transparent;
|
||||
-webkit-align-self: center;
|
||||
-ms-flex-item-align: center;
|
||||
align-self: center;
|
||||
border-radius: 50%;
|
||||
margin: 0px;
|
||||
min-width: 0px; }
|
||||
md-list-item button.md-button.md-secondary-container .md-ripple, md-list-item button.md-button.md-secondary-container .md-ripple-container, md-list-item .md-list-item-inner button.md-button.md-secondary-container .md-ripple, md-list-item .md-list-item-inner button.md-button.md-secondary-container .md-ripple-container {
|
||||
border-radius: 50%; }
|
||||
md-list-item .md-secondary-container, md-list-item .md-secondary, md-list-item .md-list-item-inner .md-secondary-container, md-list-item .md-list-item-inner .md-secondary {
|
||||
margin-left: 16px;
|
||||
position: absolute;
|
||||
right: 16px;
|
||||
top: 50%;
|
||||
-webkit-transform: translate3d(0, -50%, 0);
|
||||
transform: translate3d(0, -50%, 0); }
|
||||
md-list-item > .md-button.md-secondary-container > .md-secondary, md-list-item .md-list-item-inner > .md-button.md-secondary-container > .md-secondary {
|
||||
margin-left: 0px;
|
||||
position: static; }
|
||||
md-list-item > p, md-list-item > .md-list-item-inner > p, md-list-item .md-list-item-inner > p, md-list-item .md-list-item-inner > .md-list-item-inner > p {
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
margin: 0; }
|
||||
|
||||
md-list-item.md-2-line, md-list-item.md-2-line > .md-no-style, md-list-item.md-3-line, md-list-item.md-3-line > .md-no-style {
|
||||
-webkit-align-items: flex-start;
|
||||
-ms-flex-align: start;
|
||||
align-items: flex-start; }
|
||||
md-list-item.md-2-line .md-list-item-text, md-list-item.md-2-line > .md-no-style .md-list-item-text, md-list-item.md-3-line .md-list-item-text, md-list-item.md-3-line > .md-no-style .md-list-item-text {
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
padding: 16px 0;
|
||||
text-overflow: ellipsis; }
|
||||
md-list-item.md-2-line .md-list-item-text.md-offset, md-list-item.md-2-line > .md-no-style .md-list-item-text.md-offset, md-list-item.md-3-line .md-list-item-text.md-offset, md-list-item.md-3-line > .md-no-style .md-list-item-text.md-offset {
|
||||
margin-left: 56px; }
|
||||
md-list-item.md-2-line .md-list-item-text h3, md-list-item.md-2-line > .md-no-style .md-list-item-text h3, md-list-item.md-3-line .md-list-item-text h3, md-list-item.md-3-line > .md-no-style .md-list-item-text h3 {
|
||||
margin: 0 0 6px 0;
|
||||
line-height: 0.75em; }
|
||||
md-list-item.md-2-line .md-list-item-text h4, md-list-item.md-2-line > .md-no-style .md-list-item-text h4, md-list-item.md-3-line .md-list-item-text h4, md-list-item.md-3-line > .md-no-style .md-list-item-text h4 {
|
||||
font-weight: 400;
|
||||
margin: 10px 0 5px 0;
|
||||
line-height: 0.75em; }
|
||||
md-list-item.md-2-line .md-list-item-text p, md-list-item.md-2-line > .md-no-style .md-list-item-text p, md-list-item.md-3-line .md-list-item-text p, md-list-item.md-3-line > .md-no-style .md-list-item-text p {
|
||||
margin: 0 0 0px 0;
|
||||
line-height: 1.6em; }
|
||||
|
||||
md-list-item.md-2-line > .md-avatar:first-child, md-list-item.md-2-line > .md-no-style > .md-avatar:first-child {
|
||||
margin-top: 12px; }
|
||||
md-list-item.md-2-line > md-icon:first-child, md-list-item.md-2-line > .md-no-style > md-icon:first-child {
|
||||
-webkit-align-self: flex-start;
|
||||
-ms-flex-item-align: start;
|
||||
align-self: flex-start; }
|
||||
md-list-item.md-2-line .md-list-item-text, md-list-item.md-2-line > .md-no-style .md-list-item-text {
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
padding-top: 19px; }
|
||||
|
||||
md-list-item.md-3-line > md-icon:first-child, md-list-item.md-3-line > .md-avatar:first-child, md-list-item.md-3-line > .md-no-style > md-icon:first-child, md-list-item.md-3-line > .md-no-style > .md-avatar:first-child {
|
||||
margin-top: 16px; }
|
||||
273
www/lib/angular-material/modules/closure/list/list.js
vendored
Normal file
273
www/lib/angular-material/modules/closure/list/list.js
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.list');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.list
|
||||
* @description
|
||||
* List module
|
||||
*/
|
||||
angular.module('material.components.list', [
|
||||
'material.core'
|
||||
])
|
||||
.controller('MdListController', MdListController)
|
||||
.directive('mdList', mdListDirective)
|
||||
.directive('mdListItem', mdListItemDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdList
|
||||
* @module material.components.list
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-list>` directive is a list container for 1..n `<md-list-item>` tags.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-list>
|
||||
* <md-list-item class="md-2-line" ng-repeat="item in todos">
|
||||
* <md-checkbox ng-model="item.done"></md-checkbox>
|
||||
* <div class="md-list-item-text">
|
||||
* <h3>{{item.title}}</h3>
|
||||
* <p>{{item.description}}</p>
|
||||
* </div>
|
||||
* </md-list-item>
|
||||
* </md-list>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
function mdListDirective($mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
compile: function(tEl) {
|
||||
tEl[0].setAttribute('role', 'list');
|
||||
return $mdTheming;
|
||||
}
|
||||
};
|
||||
}
|
||||
mdListDirective.$inject = ["$mdTheming"];
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdListItem
|
||||
* @module material.components.list
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-list-item>` directive is a container intended for row items in a `<md-list>` container.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-list>
|
||||
* <md-list-item>
|
||||
* Item content in list
|
||||
* </md-list-item>
|
||||
* </md-list>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function mdListItemDirective($mdAria, $mdConstant, $timeout) {
|
||||
var proxiedTypes = ['md-checkbox', 'md-switch'];
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: 'MdListController',
|
||||
compile: function(tEl, tAttrs) {
|
||||
// Check for proxy controls (no ng-click on parent, and a control inside)
|
||||
var secondaryItem = tEl[0].querySelector('.md-secondary');
|
||||
var hasProxiedElement;
|
||||
var proxyElement;
|
||||
|
||||
tEl[0].setAttribute('role', 'listitem');
|
||||
|
||||
if (!tAttrs.ngClick) {
|
||||
for (var i = 0, type; type = proxiedTypes[i]; ++i) {
|
||||
if (proxyElement = tEl[0].querySelector(type)) {
|
||||
hasProxiedElement = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasProxiedElement) {
|
||||
wrapIn('div');
|
||||
} else if (!tEl[0].querySelector('md-button')) {
|
||||
tEl.addClass('md-no-proxy');
|
||||
}
|
||||
} else {
|
||||
wrapIn('button');
|
||||
}
|
||||
setupToggleAria();
|
||||
|
||||
|
||||
function setupToggleAria() {
|
||||
var toggleTypes = ['md-switch', 'md-checkbox'];
|
||||
var toggle;
|
||||
|
||||
for (var i = 0, toggleType; toggleType = toggleTypes[i]; ++i) {
|
||||
if (toggle = tEl.find(toggleType)[0]) {
|
||||
if (!toggle.hasAttribute('aria-label')) {
|
||||
var p = tEl.find('p')[0];
|
||||
if (!p) return;
|
||||
toggle.setAttribute('aria-label', 'Toggle ' + p.textContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function wrapIn(type) {
|
||||
var container;
|
||||
if (type == 'div') {
|
||||
container = angular.element('<div class="md-no-style md-list-item-inner">');
|
||||
container.append(tEl.contents());
|
||||
tEl.addClass('md-proxy-focus');
|
||||
} else {
|
||||
container = angular.element('<md-button class="md-no-style"><div class="md-list-item-inner"></div></md-button>');
|
||||
var copiedAttrs = ['ng-click', 'aria-label', 'ng-disabled'];
|
||||
angular.forEach(copiedAttrs, function(attr) {
|
||||
if (tEl[0].hasAttribute(attr)) {
|
||||
container[0].setAttribute(attr, tEl[0].getAttribute(attr));
|
||||
tEl[0].removeAttribute(attr);
|
||||
}
|
||||
});
|
||||
container.children().eq(0).append(tEl.contents());
|
||||
}
|
||||
|
||||
tEl[0].setAttribute('tabindex', '-1');
|
||||
tEl.append(container);
|
||||
|
||||
if (secondaryItem && secondaryItem.hasAttribute('ng-click')) {
|
||||
$mdAria.expect(secondaryItem, 'aria-label');
|
||||
var buttonWrapper = angular.element('<md-button class="md-secondary-container md-icon-button">');
|
||||
buttonWrapper.attr('ng-click', secondaryItem.getAttribute('ng-click'));
|
||||
secondaryItem.removeAttribute('ng-click');
|
||||
secondaryItem.setAttribute('tabindex', '-1');
|
||||
secondaryItem.classList.remove('md-secondary');
|
||||
buttonWrapper.append(secondaryItem);
|
||||
secondaryItem = buttonWrapper[0];
|
||||
}
|
||||
|
||||
// Check for a secondary item and move it outside
|
||||
if ( secondaryItem && (
|
||||
secondaryItem.hasAttribute('ng-click') ||
|
||||
( tAttrs.ngClick &&
|
||||
isProxiedElement(secondaryItem) )
|
||||
)) {
|
||||
tEl.addClass('md-with-secondary');
|
||||
tEl.append(secondaryItem);
|
||||
}
|
||||
}
|
||||
|
||||
function isProxiedElement(el) {
|
||||
return proxiedTypes.indexOf(el.nodeName.toLowerCase()) != -1;
|
||||
}
|
||||
|
||||
return postLink;
|
||||
|
||||
function postLink($scope, $element, $attr, ctrl) {
|
||||
|
||||
var proxies = [],
|
||||
firstChild = $element[0].firstElementChild,
|
||||
hasClick = firstChild && firstChild.hasAttribute('ng-click');
|
||||
|
||||
computeProxies();
|
||||
computeClickable();
|
||||
|
||||
if ($element.hasClass('md-proxy-focus') && proxies.length) {
|
||||
angular.forEach(proxies, function(proxy) {
|
||||
proxy = angular.element(proxy);
|
||||
|
||||
$scope.mouseActive = false;
|
||||
proxy.on('mousedown', function() {
|
||||
$scope.mouseActive = true;
|
||||
$timeout(function(){
|
||||
$scope.mouseActive = false;
|
||||
}, 100);
|
||||
})
|
||||
.on('focus', function() {
|
||||
if ($scope.mouseActive === false) { $element.addClass('md-focused'); }
|
||||
proxy.on('blur', function proxyOnBlur() {
|
||||
$element.removeClass('md-focused');
|
||||
proxy.off('blur', proxyOnBlur);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function computeProxies() {
|
||||
var children = $element.children();
|
||||
if (children.length && !children[0].hasAttribute('ng-click')) {
|
||||
angular.forEach(proxiedTypes, function(type) {
|
||||
angular.forEach(firstChild.querySelectorAll(type), function(child) {
|
||||
proxies.push(child);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
function computeClickable() {
|
||||
if (proxies.length || hasClick) {
|
||||
$element.addClass('md-clickable');
|
||||
|
||||
ctrl.attachRipple($scope, angular.element($element[0].querySelector('.md-no-style')));
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasClick && !proxies.length) {
|
||||
firstChild && firstChild.addEventListener('keypress', function(e) {
|
||||
if (e.target.nodeName != 'INPUT' && e.target.nodeName != 'TEXTAREA') {
|
||||
var keyCode = e.which || e.keyCode;
|
||||
if (keyCode == $mdConstant.KEY_CODE.SPACE) {
|
||||
if (firstChild) {
|
||||
firstChild.click();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$element.off('click');
|
||||
$element.off('keypress');
|
||||
|
||||
if (proxies.length && firstChild) {
|
||||
$element.children().eq(0).on('click', function(e) {
|
||||
if (firstChild.contains(e.target)) {
|
||||
angular.forEach(proxies, function(proxy) {
|
||||
if (e.target !== proxy && !proxy.contains(e.target)) {
|
||||
angular.element(proxy).triggerHandler('click');
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
mdListItemDirective.$inject = ["$mdAria", "$mdConstant", "$timeout"];
|
||||
|
||||
/*
|
||||
* @private
|
||||
* @ngdoc controller
|
||||
* @name MdListController
|
||||
* @module material.components.list
|
||||
*
|
||||
*/
|
||||
function MdListController($scope, $element, $mdListInkRipple) {
|
||||
var ctrl = this;
|
||||
ctrl.attachRipple = attachRipple;
|
||||
|
||||
function attachRipple (scope, element) {
|
||||
var options = {};
|
||||
$mdListInkRipple.attach(scope, element, options);
|
||||
}
|
||||
}
|
||||
MdListController.$inject = ["$scope", "$element", "$mdListInkRipple"];
|
||||
|
||||
|
||||
ng.material.components.list = angular.module("material.components.list");
|
||||
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* 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-menu-content.md-THEME_NAME-theme {
|
||||
background-color: '{{background-color}}'; }
|
||||
md-menu-content.md-THEME_NAME-theme md-menu-divider {
|
||||
background-color: '{{foreground-4}}'; }
|
||||
121
www/lib/angular-material/modules/closure/menu/menu.css
Normal file
121
www/lib/angular-material/modules/closure/menu/menu.css
Normal file
@@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* 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-open-menu-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
opacity: 0; }
|
||||
.md-open-menu-container md-menu-divider {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
height: 1px;
|
||||
width: 100%; }
|
||||
.md-open-menu-container md-menu-content > * {
|
||||
opacity: 0; }
|
||||
.md-open-menu-container:not(.md-clickable) {
|
||||
pointer-events: none; }
|
||||
.md-open-menu-container.md-active {
|
||||
opacity: 1;
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transition-duration: 200ms; }
|
||||
.md-open-menu-container.md-active > md-menu-content > * {
|
||||
opacity: 1;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 200ms;
|
||||
transition-delay: 100ms; }
|
||||
.md-open-menu-container.md-leave {
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 250ms; }
|
||||
|
||||
md-menu-content {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
padding: 8px 0; }
|
||||
md-menu-content.md-dense md-menu-item {
|
||||
height: 32px; }
|
||||
|
||||
md-menu-item {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
height: 48px;
|
||||
-webkit-align-content: center;
|
||||
-ms-flex-line-pack: center;
|
||||
align-content: center;
|
||||
-webkit-justify-content: flex-start;
|
||||
-ms-flex-pack: start;
|
||||
justify-content: flex-start; }
|
||||
md-menu-item > * {
|
||||
width: 100%;
|
||||
margin: auto 0;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px; }
|
||||
md-menu-item > .md-button {
|
||||
border-radius: 0;
|
||||
margin: auto 0;
|
||||
font-size: 15px;
|
||||
text-transform: none;
|
||||
font-weight: 400;
|
||||
text-align: start;
|
||||
height: 100%;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex; }
|
||||
md-menu-item > .md-button md-icon {
|
||||
margin: auto 16px auto 0; }
|
||||
md-menu-item > .md-button p {
|
||||
margin: auto;
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1; }
|
||||
|
||||
.md-menu {
|
||||
padding: 8px 0; }
|
||||
|
||||
md-toolbar .md-menu {
|
||||
height: auto;
|
||||
margin: auto; }
|
||||
|
||||
@media (max-width: 599px) {
|
||||
md-menu-content {
|
||||
min-width: 112px; }
|
||||
md-menu-content[width="3"] {
|
||||
min-width: 168px; }
|
||||
md-menu-content[width="4"] {
|
||||
min-width: 224px; }
|
||||
md-menu-content[width="5"] {
|
||||
min-width: 280px; }
|
||||
md-menu-content[width="6"] {
|
||||
min-width: 336px; }
|
||||
md-menu-content[width="7"] {
|
||||
min-width: 392px; } }
|
||||
|
||||
@media (min-width: 600px) {
|
||||
md-menu-content {
|
||||
min-width: 96px; }
|
||||
md-menu-content[width="3"] {
|
||||
min-width: 192px; }
|
||||
md-menu-content[width="4"] {
|
||||
min-width: 256px; }
|
||||
md-menu-content[width="5"] {
|
||||
min-width: 320px; }
|
||||
md-menu-content[width="6"] {
|
||||
min-width: 384px; }
|
||||
md-menu-content[width="7"] {
|
||||
min-width: 448px; } }
|
||||
620
www/lib/angular-material/modules/closure/menu/menu.js
vendored
Normal file
620
www/lib/angular-material/modules/closure/menu/menu.js
vendored
Normal file
@@ -0,0 +1,620 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.menu');
|
||||
goog.require('ng.material.components.backdrop');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.menu
|
||||
*/
|
||||
|
||||
angular.module('material.components.menu', [
|
||||
'material.core',
|
||||
'material.components.backdrop'
|
||||
])
|
||||
.directive('mdMenu', MenuDirective)
|
||||
.controller('mdMenuCtrl', MenuController);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdMenu
|
||||
* @module material.components.menu
|
||||
* @restrict E
|
||||
* @description
|
||||
*
|
||||
* Menus are elements that open when clicked. They are useful for displaying
|
||||
* additional options within the context of an action.
|
||||
*
|
||||
* Every `md-menu` must specify exactly two child elements. The first element is what is
|
||||
* left in the DOM and is used to open the menu. This element is called the trigger element.
|
||||
* The trigger element's scope has access to `$mdOpenMenu()`
|
||||
* which it may call to open the menu.
|
||||
*
|
||||
* The second element is the `md-menu-content` element which represents the
|
||||
* contents of the menu when it is open. Typically this will contain `md-menu-item`s,
|
||||
* but you can do custom content as well.
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-menu>
|
||||
* <!-- Trigger element is a md-button with an icon -->
|
||||
* <md-button ng-click="$mdOpenMenu()" class="md-icon-button" aria-label="Open sample menu">
|
||||
* <md-icon md-svg-icon="call:phone"></md-icon>
|
||||
* </md-button>
|
||||
* <md-menu-content>
|
||||
* <md-menu-item><md-button ng-click="doSomething()">Do Something</md-button></md-menu-item>
|
||||
* </md-menu-content>
|
||||
* </md-menu>
|
||||
* </hljs>
|
||||
|
||||
* ## Sizing Menus
|
||||
*
|
||||
* The width of the menu when it is open may be specified by specifying a `width`
|
||||
* attribute on the `md-menu-content` element.
|
||||
* See the [Material Design Spec](http://www.google.com/design/spec/components/menus.html#menus-specs)
|
||||
* for more information.
|
||||
*
|
||||
*
|
||||
* ## Aligning Menus
|
||||
*
|
||||
* When a menu opens, it is important that the content aligns with the trigger element.
|
||||
* Failure to align menus can result in jarring experiences for users as content
|
||||
* suddenly shifts. To help with this, `md-menu` provides serveral APIs to help
|
||||
* with alignment.
|
||||
*
|
||||
* ### Target Mode
|
||||
*
|
||||
* By default, `md-menu` will attempt to align the `md-menu-content` by aligning
|
||||
* designated child elements in both the trigger and the menu content.
|
||||
*
|
||||
* To specify the alignment element in the `trigger` you can use the `md-menu-origin`
|
||||
* attribute on a child element. If no `md-menu-origin` is specified, the `md-menu`
|
||||
* will be used as the origin element.
|
||||
*
|
||||
* Similarly, the `md-menu-content` may specify a `md-menu-align-target` for a
|
||||
* `md-menu-item` to specify the node that it should try and align with.
|
||||
*
|
||||
* In this example code, we specify an icon to be our origin element, and an
|
||||
* icon in our menu content to be our alignment target. This ensures that both
|
||||
* icons are aligned when the menu opens.
|
||||
*
|
||||
* <hljs lang="html">
|
||||
* <md-menu>
|
||||
* <md-button ng-click="$mdOpenMenu()" class="md-icon-button" aria-label="Open some menu">
|
||||
* <md-icon md-menu-origin md-svg-icon="call:phone"></md-icon>
|
||||
* </md-button>
|
||||
* <md-menu-content>
|
||||
* <md-menu-item>
|
||||
* <md-button ng-click="doSomething()" aria-label="Do something">
|
||||
* <md-icon md-menu-align-target md-svg-icon="call:phone"></md-icon>
|
||||
* Do Something
|
||||
* </md-button>
|
||||
* </md-menu-item>
|
||||
* </md-menu-content>
|
||||
* </md-menu>
|
||||
* </hljs>
|
||||
*
|
||||
* Sometimes we want to specify alignment on the right side of an element, for example
|
||||
* if we have a menu on the right side a toolbar, we want to right align our menu content.
|
||||
*
|
||||
* We can specify the origin by using the `md-position-mode` attribute on both
|
||||
* the `x` and `y` axis. Right now only the `x-axis` has more than one option.
|
||||
* You may specify the default mode of `target target` or
|
||||
* `target-right target` to specify a right-oriented alignment target. See the
|
||||
* position section of the demos for more examples.
|
||||
*
|
||||
* ### Menu Offsets
|
||||
*
|
||||
* It is sometimes unavoidable to need to have a deeper level of control for
|
||||
* the positioning of a menu to ensure perfect alignment. `md-menu` provides
|
||||
* the `md-offset` attribute to allow pixel level specificty of adjusting the
|
||||
* exact positioning.
|
||||
*
|
||||
* This offset is provided in the format of `x y` or `n` where `n` will be used
|
||||
* in both the `x` and `y` axis.
|
||||
*
|
||||
* For example, to move a menu by `2px` from the top, we can use:
|
||||
* <hljs lang="html">
|
||||
* <md-menu md-offset="2 0">
|
||||
* <!-- menu-content -->
|
||||
* </md-menu>
|
||||
* </hljs>
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-menu>
|
||||
* <md-button ng-click="$mdOpenMenu()" class="md-icon-button">
|
||||
* <md-icon md-svg-icon="call:phone"></md-icon>
|
||||
* </md-button>
|
||||
* <md-menu-content>
|
||||
* <md-menu-item><md-button ng-click="doSomething()">Do Something</md-button></md-menu-item>
|
||||
* </md-menu-content>
|
||||
* </md-menu>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {string} md-position-mode The position mode in the form of
|
||||
`x`, `y`. Default value is `target`,`target`. Right now the `x` axis
|
||||
also suppports `target-right`.
|
||||
* @param {string} md-offset An offset to apply to the dropdown after positioning
|
||||
`x`, `y`. Default value is `0`,`0`.
|
||||
*
|
||||
*/
|
||||
|
||||
function MenuDirective($mdMenu) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: 'mdMenu',
|
||||
controller: 'mdMenuCtrl', // empty function to be built by link
|
||||
scope: true,
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(templateElement) {
|
||||
templateElement.addClass('md-menu');
|
||||
var triggerElement = templateElement.children()[0];
|
||||
if (!triggerElement.hasAttribute('ng-click')) {
|
||||
triggerElement = triggerElement.querySelector('[ng-click]');
|
||||
}
|
||||
triggerElement && triggerElement.setAttribute('aria-haspopup', 'true');
|
||||
if (templateElement.children().length != 2) {
|
||||
throw Error('Invalid HTML for md-menu. Expected two children elements.');
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
||||
function link(scope, element, attrs, mdMenuCtrl) {
|
||||
|
||||
// Move everything into a md-menu-container and pass it to the controller
|
||||
var menuContainer = angular.element(
|
||||
'<div class="md-open-menu-container md-whiteframe-z2"></div>'
|
||||
);
|
||||
var menuContents = element.children()[1];
|
||||
menuContainer.append(menuContents);
|
||||
mdMenuCtrl.init(menuContainer);
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
if (mdMenuCtrl.isOpen) {
|
||||
menuContainer.remove();
|
||||
mdMenuCtrl.close();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
MenuDirective.$inject = ["$mdMenu"];
|
||||
|
||||
function MenuController($mdMenu, $attrs, $element, $scope) {
|
||||
|
||||
var menuContainer;
|
||||
var ctrl = this;
|
||||
var triggerElement;
|
||||
|
||||
// Called by our linking fn to provide access to the menu-content
|
||||
// element removed during link
|
||||
this.init = function(setMenuContainer) {
|
||||
menuContainer = setMenuContainer;
|
||||
triggerElement = $element[0].querySelector('[ng-click]');
|
||||
};
|
||||
|
||||
// Uses the $mdMenu interim element service to open the menu contents
|
||||
this.open = function openMenu() {
|
||||
ctrl.isOpen = true;
|
||||
triggerElement.setAttribute('aria-expanded', 'true');
|
||||
$mdMenu.show({
|
||||
mdMenuCtrl: ctrl,
|
||||
element: menuContainer,
|
||||
target: $element[0]
|
||||
});
|
||||
};
|
||||
// Expose a open function to the child scope for html to use
|
||||
$scope.$mdOpenMenu = this.open;
|
||||
|
||||
// Use the $mdMenu interim element service to close the menu contents
|
||||
this.close = function closeMenu(skipFocus) {
|
||||
ctrl.isOpen = false;
|
||||
triggerElement.setAttribute('aria-expanded', 'false');
|
||||
$mdMenu.hide();
|
||||
|
||||
if (!skipFocus) {
|
||||
$element.children()[0].focus();
|
||||
}
|
||||
};
|
||||
|
||||
// Build a nice object out of our string attribute which specifies the
|
||||
// target mode for left and top positioning
|
||||
this.positionMode = function() {
|
||||
var attachment = ($attrs.mdPositionMode || 'target').split(' ');
|
||||
|
||||
// If attachment is a single item, duplicate it for our second value.
|
||||
// ie. 'target' -> 'target target'
|
||||
if (attachment.length == 1) {
|
||||
attachment.push(attachment[0]);
|
||||
}
|
||||
|
||||
return {
|
||||
left: attachment[0],
|
||||
top: attachment[1]
|
||||
};
|
||||
};
|
||||
|
||||
// Build a nice object out of our string attribute which specifies
|
||||
// the offset of top and left in pixels.
|
||||
this.offsets = function() {
|
||||
var offsets = ($attrs.mdOffset || '0 0').split(' ').map(parseFloat);
|
||||
if (offsets.length == 2) {
|
||||
return {
|
||||
left: offsets[0],
|
||||
top: offsets[1]
|
||||
};
|
||||
} else if (offsets.length == 1) {
|
||||
return {
|
||||
top: offsets[0],
|
||||
left: offsets[0]
|
||||
};
|
||||
} else {
|
||||
throw Error('Invalid offsets specified. Please follow format <x, y> or <n>');
|
||||
}
|
||||
};
|
||||
}
|
||||
MenuController.$inject = ["$mdMenu", "$attrs", "$element", "$scope"];
|
||||
|
||||
angular.module('material.components.menu')
|
||||
.provider('$mdMenu', MenuProvider);
|
||||
|
||||
/*
|
||||
* Interim element provider for the menu.
|
||||
* Handles behavior for a menu while it is open, including:
|
||||
* - handling animating the menu opening/closing
|
||||
* - handling key/mouse events on the menu element
|
||||
* - handling enabling/disabling scroll while the menu is open
|
||||
* - handling redrawing during resizes and orientation changes
|
||||
*
|
||||
*/
|
||||
|
||||
function MenuProvider($$interimElementProvider) {
|
||||
var MENU_EDGE_MARGIN = 8;
|
||||
|
||||
menuDefaultOptions.$inject = ["$$rAF", "$window", "$mdUtil", "$mdTheming", "$timeout", "$mdConstant", "$document"];
|
||||
return $$interimElementProvider('$mdMenu')
|
||||
.setDefaults({
|
||||
methods: ['target'],
|
||||
options: menuDefaultOptions
|
||||
});
|
||||
|
||||
/* ngInject */
|
||||
function menuDefaultOptions($$rAF, $window, $mdUtil, $mdTheming, $timeout, $mdConstant, $document) {
|
||||
return {
|
||||
parent: 'body',
|
||||
onShow: onShow,
|
||||
onRemove: onRemove,
|
||||
hasBackdrop: true,
|
||||
disableParentScroll: true,
|
||||
skipCompile: true,
|
||||
themable: true
|
||||
};
|
||||
|
||||
/**
|
||||
* Boilerplate interimElement onShow function
|
||||
* Handles inserting the menu into the DOM, positioning it, and wiring up
|
||||
* various interaction events
|
||||
*/
|
||||
function onShow(scope, element, opts) {
|
||||
|
||||
// Sanitize and set defaults on opts
|
||||
buildOpts(opts);
|
||||
|
||||
// Wire up theming on our menu element
|
||||
$mdTheming.inherit(opts.menuContentEl, opts.target);
|
||||
|
||||
// Register various listeners to move menu on resize/orientation change
|
||||
handleResizing();
|
||||
|
||||
// Disable scrolling
|
||||
if (opts.disableParentScroll) {
|
||||
opts.restoreScroll = $mdUtil.disableScrollAround(opts.element);
|
||||
}
|
||||
|
||||
// Only activate click listeners after a short time to stop accidental double taps/clicks
|
||||
// from clicking the wrong item
|
||||
$timeout(activateInteraction, 75, false);
|
||||
|
||||
if (opts.backdrop) {
|
||||
$mdTheming.inherit(opts.backdrop, opts.parent);
|
||||
opts.parent.append(opts.backdrop);
|
||||
}
|
||||
showMenu();
|
||||
|
||||
// Return the promise for when our menu is done animating in
|
||||
return $mdUtil.transitionEndPromise(element, {timeout: 350});
|
||||
|
||||
/** Check for valid opts and set some sane defaults */
|
||||
function buildOpts() {
|
||||
if (!opts.target) {
|
||||
throw Error(
|
||||
'$mdMenu.show() expected a target to animate from in options.target'
|
||||
);
|
||||
}
|
||||
angular.extend(opts, {
|
||||
alreadyOpen: false,
|
||||
isRemoved: false,
|
||||
target: angular.element(opts.target), //make sure it's not a naked dom node
|
||||
parent: angular.element(opts.parent),
|
||||
menuContentEl: angular.element(element[0].querySelector('md-menu-content')),
|
||||
backdrop: opts.hasBackdrop && angular.element('<md-backdrop class="md-menu-backdrop md-click-catcher">')
|
||||
});
|
||||
}
|
||||
|
||||
/** Wireup various resize listeners for screen changes */
|
||||
function handleResizing() {
|
||||
opts.resizeFn = function() {
|
||||
positionMenu(element, opts);
|
||||
};
|
||||
angular.element($window).on('resize', opts.resizeFn);
|
||||
angular.element($window).on('orientationchange', opts.resizeFn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Place the menu into the DOM and call positioning related functions
|
||||
*/
|
||||
function showMenu() {
|
||||
opts.parent.append(element);
|
||||
|
||||
element.removeClass('md-leave');
|
||||
// Kick off our animation/positioning but first, wait a few frames
|
||||
// so all of our computed positions/sizes are accurate
|
||||
$$rAF(function() {
|
||||
$$rAF(function() {
|
||||
positionMenu(element, opts);
|
||||
// Wait a frame before fading in menu (md-active) so that we don't trigger
|
||||
// transitions on the menu position changing
|
||||
$$rAF(function() {
|
||||
element.addClass('md-active');
|
||||
opts.alreadyOpen = true;
|
||||
element[0].style[$mdConstant.CSS.TRANSFORM] = '';
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Activate interaction on the menu. Wire up keyboard listerns for
|
||||
* clicks, keypresses, backdrop closing, etc.
|
||||
*/
|
||||
function activateInteraction() {
|
||||
element.addClass('md-clickable');
|
||||
|
||||
// close on backdrop click
|
||||
opts.backdrop && opts.backdrop.on('click', function(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
opts.mdMenuCtrl.close(true);
|
||||
});
|
||||
|
||||
// Wire up keyboard listeners.
|
||||
// Close on escape, focus next item on down arrow, focus prev item on up
|
||||
opts.menuContentEl.on('keydown', function(ev) {
|
||||
scope.$apply(function() {
|
||||
switch (ev.keyCode) {
|
||||
case $mdConstant.KEY_CODE.ESCAPE: opts.mdMenuCtrl.close(); break;
|
||||
case $mdConstant.KEY_CODE.UP_ARROW: focusMenuItem(ev, opts.menuContentEl, opts, -1); break;
|
||||
case $mdConstant.KEY_CODE.DOWN_ARROW: focusMenuItem(ev, opts.menuContentEl, opts, 1); break;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Close menu on menu item click, if said menu-item is not disabled
|
||||
opts.menuContentEl.on('click', function(e) {
|
||||
var target = e.target;
|
||||
// Traverse up the event until we get to the menuContentEl to see if
|
||||
// there is an ng-click and that the ng-click is not disabled
|
||||
do {
|
||||
if (target && target.hasAttribute('ng-click')) {
|
||||
if (!target.hasAttribute('disabled')) {
|
||||
close();
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while ((target = target.parentNode) && target != opts.menuContentEl)
|
||||
|
||||
function close() {
|
||||
scope.$apply(function() {
|
||||
opts.mdMenuCtrl.close();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// kick off initial focus in the menu on the first element
|
||||
var focusTarget = opts.menuContentEl[0].querySelector('[md-menu-focus-target]');
|
||||
if (!focusTarget) focusTarget = opts.menuContentEl[0].firstElementChild.firstElementChild;
|
||||
focusTarget.focus();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes a keypress event and focuses the next/previous menu
|
||||
* item from the emitting element
|
||||
* @param {event} e - The origin keypress event
|
||||
* @param {angular.element} menuEl - The menu element
|
||||
* @param {object} opts - The interim element options for the mdMenu
|
||||
* @param {number} direction - The direction to move in (+1 = next, -1 = prev)
|
||||
*/
|
||||
function focusMenuItem(e, menuEl, opts, direction) {
|
||||
var currentItem = $mdUtil.getClosest(e.target, 'MD-MENU-ITEM');
|
||||
|
||||
var items = $mdUtil.nodesToArray(menuEl[0].children);
|
||||
var currentIndex = items.indexOf(currentItem);
|
||||
|
||||
// Traverse through our elements in the specified direction (+/-1) and try to
|
||||
// focus them until we find one that accepts focus
|
||||
for (var i = currentIndex + direction; i >= 0 && i < items.length; i = i + direction) {
|
||||
var focusTarget = items[i].firstElementChild || items[i];
|
||||
var didFocus = attemptFocus(focusTarget);
|
||||
if (didFocus) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to focus an element. Checks whether that element is the currently
|
||||
* focused element after attempting.
|
||||
* @param {HTMLElement} el - the element to attempt focus on
|
||||
* @returns {bool} - whether the element was successfully focused
|
||||
*/
|
||||
function attemptFocus(el) {
|
||||
if (el && el.getAttribute('tabindex') != -1) {
|
||||
el.focus();
|
||||
if ($document[0].activeElement == el) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Boilerplate interimElement onRemove function
|
||||
* Handles removing the menu from the DOM, cleaning up the element
|
||||
* and removing various listeners
|
||||
*/
|
||||
function onRemove(scope, element, opts) {
|
||||
opts.isRemoved = true;
|
||||
element.addClass('md-leave')
|
||||
.removeClass('md-clickable');
|
||||
|
||||
// Disable resizing handlers
|
||||
angular.element($window).off('resize', opts.resizeFn);
|
||||
angular.element($window).off('orientationchange', opts.resizeFn);
|
||||
opts.resizeFn = undefined;
|
||||
|
||||
// Wait for animate out, then remove from the DOM
|
||||
return $mdUtil.transitionEndPromise(element, { timeout: 350 }).then(function() {
|
||||
element.removeClass('md-active');
|
||||
opts.backdrop && opts.backdrop.remove();
|
||||
if (element[0].parentNode === opts.parent[0]) {
|
||||
opts.parent[0].removeChild(element[0]);
|
||||
}
|
||||
opts.restoreScroll && opts.restoreScroll();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes menu position and sets the style on the menu container
|
||||
* @param {HTMLElement} el - the menu container element
|
||||
* @param {object} opts - the interim element options object
|
||||
*/
|
||||
function positionMenu(el, opts) {
|
||||
if (opts.isRemoved) return;
|
||||
|
||||
var containerNode = el[0],
|
||||
openMenuNode = el[0].firstElementChild,
|
||||
openMenuNodeRect = openMenuNode.getBoundingClientRect(),
|
||||
boundryNode = opts.parent[0],
|
||||
boundryNodeRect = boundryNode.getBoundingClientRect();
|
||||
|
||||
var originNode = opts.target[0].querySelector('[md-menu-origin]') || opts.target[0],
|
||||
originNodeRect = originNode.getBoundingClientRect();
|
||||
|
||||
|
||||
var bounds = {
|
||||
left: boundryNodeRect.left + MENU_EDGE_MARGIN,
|
||||
top: boundryNodeRect.top + MENU_EDGE_MARGIN,
|
||||
bottom: boundryNodeRect.bottom - MENU_EDGE_MARGIN,
|
||||
right: boundryNodeRect.right - MENU_EDGE_MARGIN
|
||||
};
|
||||
|
||||
|
||||
var alignTarget, alignTargetRect, existingOffsets;
|
||||
var positionMode = opts.mdMenuCtrl.positionMode();
|
||||
|
||||
if (positionMode.top == 'target' || positionMode.left == 'target' || positionMode.left == 'target-right') {
|
||||
// TODO: Allow centering on an arbitrary node, for now center on first menu-item's child
|
||||
alignTarget = openMenuNode.firstElementChild.firstElementChild || openMenuNode.firstElementChild;
|
||||
alignTarget = alignTarget.querySelector('[md-menu-align-target]') || alignTarget;
|
||||
alignTargetRect = alignTarget.getBoundingClientRect();
|
||||
|
||||
existingOffsets = {
|
||||
top: parseFloat(containerNode.style.top || 0),
|
||||
left: parseFloat(containerNode.style.left || 0)
|
||||
};
|
||||
}
|
||||
|
||||
var position = { };
|
||||
var transformOrigin = 'top ';
|
||||
|
||||
switch (positionMode.top) {
|
||||
case 'target':
|
||||
position.top = existingOffsets.top + originNodeRect.top - alignTargetRect.top;
|
||||
break;
|
||||
// Future support for mdMenuBar
|
||||
// case 'top':
|
||||
// position.top = originNodeRect.top;
|
||||
// break;
|
||||
// case 'bottom':
|
||||
// position.top = originNodeRect.top + originNodeRect.height;
|
||||
// break;
|
||||
default:
|
||||
throw new Error('Invalid target mode "' + positionMode.top + '" specified for md-menu on Y axis.');
|
||||
}
|
||||
|
||||
switch (positionMode.left) {
|
||||
case 'target':
|
||||
position.left = existingOffsets.left + originNodeRect.left - alignTargetRect.left;
|
||||
transformOrigin += 'left';
|
||||
break;
|
||||
case 'target-right':
|
||||
position.left = originNodeRect.right - openMenuNodeRect.width + (openMenuNodeRect.right - alignTargetRect.right);
|
||||
transformOrigin += 'right';
|
||||
break;
|
||||
// Future support for mdMenuBar
|
||||
// case 'left':
|
||||
// position.left = originNodeRect.left;
|
||||
// transformOrigin += 'left';
|
||||
// break;
|
||||
// case 'right':
|
||||
// position.left = originNodeRect.right - containerNode.offsetWidth;
|
||||
// transformOrigin += 'right';
|
||||
// break;
|
||||
default:
|
||||
throw new Error('Invalid target mode "' + positionMode.left + '" specified for md-menu on X axis.');
|
||||
}
|
||||
|
||||
var offsets = opts.mdMenuCtrl.offsets();
|
||||
position.top += offsets.top;
|
||||
position.left += offsets.left;
|
||||
|
||||
clamp(position);
|
||||
|
||||
el.css({
|
||||
top: position.top + 'px',
|
||||
left: position.left + 'px'
|
||||
});
|
||||
|
||||
containerNode.style[$mdConstant.CSS.TRANSFORM_ORIGIN] = transformOrigin;
|
||||
|
||||
// Animate a scale out if we aren't just repositioning
|
||||
if (!opts.alreadyOpen) {
|
||||
containerNode.style[$mdConstant.CSS.TRANSFORM] = 'scale(' +
|
||||
Math.min(originNodeRect.width / containerNode.offsetWidth, 1.0) + ',' +
|
||||
Math.min(originNodeRect.height / containerNode.offsetHeight, 1.0) +
|
||||
')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the repositioning of the menu within the confines of
|
||||
* bounding element (often the screen/body)
|
||||
*/
|
||||
function clamp(pos) {
|
||||
pos.top = Math.max(Math.min(pos.top, bounds.bottom - containerNode.offsetHeight), bounds.top);
|
||||
pos.left = Math.max(Math.min(pos.left, bounds.right - containerNode.offsetWidth), bounds.left);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
MenuProvider.$inject = ["$$interimElementProvider"];
|
||||
|
||||
ng.material.components.menu = angular.module("material.components.menu");
|
||||
@@ -0,0 +1,36 @@
|
||||
/*!
|
||||
* 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-progress-circular.md-THEME_NAME-theme {
|
||||
background-color: transparent; }
|
||||
md-progress-circular.md-THEME_NAME-theme .md-inner .md-gap {
|
||||
border-top-color: '{{primary-color}}';
|
||||
border-bottom-color: '{{primary-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme .md-inner .md-right .md-half-circle {
|
||||
border-top-color: '{{primary-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme .md-inner .md-right .md-half-circle {
|
||||
border-right-color: '{{primary-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme .md-inner .md-left .md-half-circle {
|
||||
border-left-color: '{{primary-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-gap {
|
||||
border-top-color: '{{warn-color}}';
|
||||
border-bottom-color: '{{warn-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-right .md-half-circle {
|
||||
border-top-color: '{{warn-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-right .md-half-circle {
|
||||
border-right-color: '{{warn-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-warn .md-inner .md-left .md-half-circle {
|
||||
border-left-color: '{{warn-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-gap {
|
||||
border-top-color: '{{accent-color}}';
|
||||
border-bottom-color: '{{accent-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-left .md-half-circle, md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-right .md-half-circle {
|
||||
border-top-color: '{{accent-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-right .md-half-circle {
|
||||
border-right-color: '{{accent-color}}'; }
|
||||
md-progress-circular.md-THEME_NAME-theme.md-accent .md-inner .md-left .md-half-circle {
|
||||
border-left-color: '{{accent-color}}'; }
|
||||
File diff suppressed because it is too large
Load Diff
109
www/lib/angular-material/modules/closure/progressCircular/progressCircular.js
vendored
Normal file
109
www/lib/angular-material/modules/closure/progressCircular/progressCircular.js
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.progressCircular');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.progressCircular
|
||||
* @description Circular Progress module!
|
||||
*/
|
||||
angular.module('material.components.progressCircular', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdProgressCircular', MdProgressCircularDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdProgressCircular
|
||||
* @module material.components.progressCircular
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The circular progress directive is used to make loading content in your app as delightful and
|
||||
* painless as possible by minimizing the amount of visual change a user sees before they can view
|
||||
* and interact with content.
|
||||
*
|
||||
* For operations where the percentage of the operation completed can be determined, use a
|
||||
* determinate indicator. They give users a quick sense of how long an operation will take.
|
||||
*
|
||||
* For operations where the user is asked to wait a moment while something finishes up, and it’s
|
||||
* not necessary to expose what's happening behind the scenes and how long it will take, use an
|
||||
* indeterminate indicator.
|
||||
*
|
||||
* @param {string} md-mode Select from one of two modes: determinate and indeterminate.
|
||||
* @param {number=} value In determinate mode, this number represents the percentage of the
|
||||
* circular progress. Default: 0
|
||||
* @param {number=} md-diameter This specifies the diamter of the circular progress. Default: 48
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-progress-circular md-mode="determinate" value="..."></md-progress-circular>
|
||||
*
|
||||
* <md-progress-circular md-mode="determinate" ng-value="..."></md-progress-circular>
|
||||
*
|
||||
* <md-progress-circular md-mode="determinate" value="..." md-diameter="100"></md-progress-circular>
|
||||
*
|
||||
* <md-progress-circular md-mode="indeterminate"></md-progress-circular>
|
||||
* </hljs>
|
||||
*/
|
||||
function MdProgressCircularDirective($mdConstant, $mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
template:
|
||||
// The progress 'circle' is composed of two half-circles: the left side and the right
|
||||
// side. Each side has CSS applied to 'fill-in' the half-circle to the appropriate progress.
|
||||
'<div class="md-spinner-wrapper">' +
|
||||
'<div class="md-inner">' +
|
||||
'<div class="md-gap"></div>' +
|
||||
'<div class="md-left">' +
|
||||
'<div class="md-half-circle"></div>' +
|
||||
'</div>' +
|
||||
'<div class="md-right">' +
|
||||
'<div class="md-half-circle"></div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(tElement) {
|
||||
// The javascript in this file is mainly responsible for setting the correct aria attributes.
|
||||
// The animation of the progress spinner is done entirely with just CSS.
|
||||
tElement.attr('aria-valuemin', 0);
|
||||
tElement.attr('aria-valuemax', 100);
|
||||
tElement.attr('role', 'progressbar');
|
||||
|
||||
return postLink;
|
||||
}
|
||||
|
||||
function postLink(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
var circle = element[0];
|
||||
|
||||
// Scale the progress circle based on the default diameter.
|
||||
var diameter = attr.mdDiameter || 48;
|
||||
var scale = diameter / 48;
|
||||
circle.style[$mdConstant.CSS.TRANSFORM] = 'scale(' + scale + ')';
|
||||
|
||||
attr.$observe('value', function(value) {
|
||||
var percentValue = clamp(value);
|
||||
element.attr('aria-valuenow', percentValue);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the value to be between 0 and 100.
|
||||
* @param {number} value The value to clamp.
|
||||
* @returns {number}
|
||||
*/
|
||||
function clamp(value) {
|
||||
return Math.max(0, Math.min(value || 0, 100));
|
||||
}
|
||||
}
|
||||
MdProgressCircularDirective.$inject = ["$mdConstant", "$mdTheming"];
|
||||
|
||||
ng.material.components.progressCircular = angular.module("material.components.progressCircular");
|
||||
@@ -0,0 +1,27 @@
|
||||
/*!
|
||||
* 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-progress-linear.md-THEME_NAME-theme .md-container {
|
||||
background-color: '{{primary-100}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme .md-bar {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme.md-warn .md-container {
|
||||
background-color: '{{warn-100}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme.md-warn .md-bar {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme.md-accent .md-container {
|
||||
background-color: '{{accent-100}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme.md-accent .md-bar {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-bar1 {
|
||||
background-color: '{{warn-100}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-warn .md-dashed:before {
|
||||
background: radial-gradient('{{warn-100}}' 0%, '{{warn-100}}' 16%, transparent 42%); }
|
||||
md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-bar1 {
|
||||
background-color: '{{accent-100}}'; }
|
||||
md-progress-linear.md-THEME_NAME-theme[md-mode=buffer].md-accent .md-dashed:before {
|
||||
background: radial-gradient('{{accent-100}}' 0%, '{{accent-100}}' 16%, transparent 42%); }
|
||||
@@ -0,0 +1,287 @@
|
||||
/*!
|
||||
* 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-progress-linear:not([md-mode="indeterminate"]) {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 5px; }
|
||||
md-progress-linear:not([md-mode="indeterminate"]) .md-container {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 5px;
|
||||
top: 5px;
|
||||
-webkit-transform: translate(0, 5px) scale(1, 0);
|
||||
transform: translate(0, 5px) scale(1, 0);
|
||||
transition: all .3s linear; }
|
||||
md-progress-linear:not([md-mode="indeterminate"]) .md-container.md-ready {
|
||||
-webkit-transform: translate(0, 0) scale(1, 1);
|
||||
transform: translate(0, 0) scale(1, 1); }
|
||||
md-progress-linear:not([md-mode="indeterminate"]) .md-bar {
|
||||
height: 5px;
|
||||
position: absolute;
|
||||
width: 100%; }
|
||||
md-progress-linear:not([md-mode="indeterminate"]) .md-bar1, md-progress-linear:not([md-mode="indeterminate"]) .md-bar2 {
|
||||
transition: all 0.2s linear; }
|
||||
md-progress-linear:not([md-mode="indeterminate"])[md-mode=determinate] .md-bar1 {
|
||||
display: none; }
|
||||
md-progress-linear:not([md-mode="indeterminate"])[md-mode=buffer] .md-container {
|
||||
background-color: transparent !important; }
|
||||
md-progress-linear:not([md-mode="indeterminate"])[md-mode=buffer] .md-dashed:before {
|
||||
content: "";
|
||||
display: block;
|
||||
height: 5px;
|
||||
width: 100%;
|
||||
margin-top: 0;
|
||||
position: absolute;
|
||||
background-color: transparent;
|
||||
background-size: 10px 10px !important;
|
||||
background-position: 0px -23px;
|
||||
-webkit-animation: buffer 3s infinite linear;
|
||||
animation: buffer 3s infinite linear; }
|
||||
md-progress-linear:not([md-mode="indeterminate"])[md-mode=query] .md-bar2 {
|
||||
-webkit-animation: query .8s infinite cubic-bezier(0.39, 0.575, 0.565, 1);
|
||||
animation: query .8s infinite cubic-bezier(0.39, 0.575, 0.565, 1); }
|
||||
|
||||
md-progress-linear[md-mode="indeterminate"] {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 5px;
|
||||
position: relative; }
|
||||
md-progress-linear[md-mode="indeterminate"] .md-container {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
height: 5px;
|
||||
top: 5px;
|
||||
transition: all .3s linear; }
|
||||
md-progress-linear[md-mode="indeterminate"] .md-container .md-bar {
|
||||
height: 5px;
|
||||
left: 0;
|
||||
width: 80%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0; }
|
||||
md-progress-linear[md-mode="indeterminate"] .md-container .md-bar1 {
|
||||
-webkit-animation: md-progress-linear-indeterminate-scale-1 4s infinite, md-progress-linear-indeterminate-1 4s infinite;
|
||||
animation: md-progress-linear-indeterminate-scale-1 4s infinite, md-progress-linear-indeterminate-1 4s infinite; }
|
||||
md-progress-linear[md-mode="indeterminate"] .md-container .md-bar2 {
|
||||
-webkit-animation: md-progress-linear-indeterminate-scale-2 4s infinite, md-progress-linear-indeterminate-2 4s infinite;
|
||||
animation: md-progress-linear-indeterminate-scale-2 4s infinite, md-progress-linear-indeterminate-2 4s infinite; }
|
||||
|
||||
@-webkit-keyframes query {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateX(35%) scale(.3, 1);
|
||||
transform: translateX(35%) scale(.3, 1); }
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(-50%) scale(0, 1);
|
||||
transform: translateX(-50%) scale(0, 1); } }
|
||||
|
||||
@keyframes query {
|
||||
0% {
|
||||
opacity: 1;
|
||||
-webkit-transform: translateX(35%) scale(.3, 1);
|
||||
transform: translateX(35%) scale(.3, 1); }
|
||||
|
||||
100% {
|
||||
opacity: 0;
|
||||
-webkit-transform: translateX(-50%) scale(0, 1);
|
||||
transform: translateX(-50%) scale(0, 1); } }
|
||||
|
||||
@-webkit-keyframes buffer {
|
||||
0% {
|
||||
opacity: 1;
|
||||
background-position: 0px -23px; }
|
||||
|
||||
50% {
|
||||
opacity: 0; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
background-position: -200px -23px; } }
|
||||
|
||||
@keyframes buffer {
|
||||
0% {
|
||||
opacity: 1;
|
||||
background-position: 0px -23px; }
|
||||
|
||||
50% {
|
||||
opacity: 0; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
background-position: -200px -23px; } }
|
||||
|
||||
@-webkit-keyframes md-progress-linear-indeterminate-scale-1 {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
36.6% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.33473, 0.12482, 0.78584, 1);
|
||||
animation-timing-function: cubic-bezier(0.33473, 0.12482, 0.78584, 1); }
|
||||
|
||||
69.15% {
|
||||
-webkit-transform: scaleX(0.83);
|
||||
transform: scaleX(0.83);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.22573, 0, 0.23365, 1.37098);
|
||||
animation-timing-function: cubic-bezier(0.22573, 0, 0.23365, 1.37098); }
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1); } }
|
||||
|
||||
@keyframes md-progress-linear-indeterminate-scale-1 {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
36.6% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.33473, 0.12482, 0.78584, 1);
|
||||
animation-timing-function: cubic-bezier(0.33473, 0.12482, 0.78584, 1); }
|
||||
|
||||
69.15% {
|
||||
-webkit-transform: scaleX(0.83);
|
||||
transform: scaleX(0.83);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.22573, 0, 0.23365, 1.37098);
|
||||
animation-timing-function: cubic-bezier(0.22573, 0, 0.23365, 1.37098); }
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1); } }
|
||||
|
||||
@-webkit-keyframes md-progress-linear-indeterminate-1 {
|
||||
0% {
|
||||
left: -105.16667%;
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
20% {
|
||||
left: -105.16667%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.70173, 0.49582);
|
||||
animation-timing-function: cubic-bezier(0.5, 0, 0.70173, 0.49582); }
|
||||
|
||||
69.15% {
|
||||
left: 21.5%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.30244, 0.38135, 0.55, 0.95635);
|
||||
animation-timing-function: cubic-bezier(0.30244, 0.38135, 0.55, 0.95635); }
|
||||
|
||||
100% {
|
||||
left: 95.44444%; } }
|
||||
|
||||
@keyframes md-progress-linear-indeterminate-1 {
|
||||
0% {
|
||||
left: -105.16667%;
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
20% {
|
||||
left: -105.16667%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.5, 0, 0.70173, 0.49582);
|
||||
animation-timing-function: cubic-bezier(0.5, 0, 0.70173, 0.49582); }
|
||||
|
||||
69.15% {
|
||||
left: 21.5%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.30244, 0.38135, 0.55, 0.95635);
|
||||
animation-timing-function: cubic-bezier(0.30244, 0.38135, 0.55, 0.95635); }
|
||||
|
||||
100% {
|
||||
left: 95.44444%; } }
|
||||
|
||||
@-webkit-keyframes md-progress-linear-indeterminate-scale-2 {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.20503, 0.05705, 0.57661, 0.45397);
|
||||
animation-timing-function: cubic-bezier(0.20503, 0.05705, 0.57661, 0.45397); }
|
||||
|
||||
19.15% {
|
||||
-webkit-transform: scaleX(0.57);
|
||||
transform: scaleX(0.57);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.15231, 0.19643, 0.64837, 1.00432);
|
||||
animation-timing-function: cubic-bezier(0.15231, 0.19643, 0.64837, 1.00432); }
|
||||
|
||||
44.15% {
|
||||
-webkit-transform: scaleX(0.91);
|
||||
transform: scaleX(0.91);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.25776, -0.00316, 0.21176, 1.38179);
|
||||
animation-timing-function: cubic-bezier(0.25776, -0.00316, 0.21176, 1.38179); }
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1); } }
|
||||
|
||||
@keyframes md-progress-linear-indeterminate-scale-2 {
|
||||
0% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.20503, 0.05705, 0.57661, 0.45397);
|
||||
animation-timing-function: cubic-bezier(0.20503, 0.05705, 0.57661, 0.45397); }
|
||||
|
||||
19.15% {
|
||||
-webkit-transform: scaleX(0.57);
|
||||
transform: scaleX(0.57);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.15231, 0.19643, 0.64837, 1.00432);
|
||||
animation-timing-function: cubic-bezier(0.15231, 0.19643, 0.64837, 1.00432); }
|
||||
|
||||
44.15% {
|
||||
-webkit-transform: scaleX(0.91);
|
||||
transform: scaleX(0.91);
|
||||
-webkit-animation-timing-function: cubic-bezier(0.25776, -0.00316, 0.21176, 1.38179);
|
||||
animation-timing-function: cubic-bezier(0.25776, -0.00316, 0.21176, 1.38179); }
|
||||
|
||||
100% {
|
||||
-webkit-transform: scaleX(0.1);
|
||||
transform: scaleX(0.1); } }
|
||||
|
||||
@-webkit-keyframes md-progress-linear-indeterminate-2 {
|
||||
0% {
|
||||
left: -54.88889%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.51506, 0.40968);
|
||||
animation-timing-function: cubic-bezier(0.15, 0, 0.51506, 0.40968); }
|
||||
|
||||
25% {
|
||||
left: -17.25%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.31033, 0.28406, 0.8, 0.73372);
|
||||
animation-timing-function: cubic-bezier(0.31033, 0.28406, 0.8, 0.73372); }
|
||||
|
||||
48.35% {
|
||||
left: 29.5%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.4, 0.62703, 0.6, 0.90203);
|
||||
animation-timing-function: cubic-bezier(0.4, 0.62703, 0.6, 0.90203); }
|
||||
|
||||
100% {
|
||||
left: 117.38889%; } }
|
||||
|
||||
@keyframes md-progress-linear-indeterminate-2 {
|
||||
0% {
|
||||
left: -54.88889%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.15, 0, 0.51506, 0.40968);
|
||||
animation-timing-function: cubic-bezier(0.15, 0, 0.51506, 0.40968); }
|
||||
|
||||
25% {
|
||||
left: -17.25%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.31033, 0.28406, 0.8, 0.73372);
|
||||
animation-timing-function: cubic-bezier(0.31033, 0.28406, 0.8, 0.73372); }
|
||||
|
||||
48.35% {
|
||||
left: 29.5%;
|
||||
-webkit-animation-timing-function: cubic-bezier(0.4, 0.62703, 0.6, 0.90203);
|
||||
animation-timing-function: cubic-bezier(0.4, 0.62703, 0.6, 0.90203); }
|
||||
|
||||
100% {
|
||||
left: 117.38889%; } }
|
||||
126
www/lib/angular-material/modules/closure/progressLinear/progressLinear.js
vendored
Normal file
126
www/lib/angular-material/modules/closure/progressLinear/progressLinear.js
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.progressLinear');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.progressLinear
|
||||
* @description Linear Progress module!
|
||||
*/
|
||||
angular.module('material.components.progressLinear', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdProgressLinear', MdProgressLinearDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdProgressLinear
|
||||
* @module material.components.progressLinear
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The linear progress directive is used to make loading content in your app as delightful and painless as possible by minimizing the amount of visual change a user sees before they can view and interact with content. Each operation should only be represented by one activity indicator—for example, one refresh operation should not display both a refresh bar and an activity circle.
|
||||
*
|
||||
* For operations where the percentage of the operation completed can be determined, use a determinate indicator. They give users a quick sense of how long an operation will take.
|
||||
*
|
||||
* For operations where the user is asked to wait a moment while something finishes up, and it’s not necessary to expose what's happening behind the scenes and how long it will take, use an indeterminate indicator.
|
||||
*
|
||||
* @param {string} md-mode Select from one of four modes: determinate, indeterminate, buffer or query.
|
||||
* @param {number=} value In determinate and buffer modes, this number represents the percentage of the primary progress bar. Default: 0
|
||||
* @param {number=} md-buffer-value In the buffer mode, this number represents the precentage of the secondary progress bar. Default: 0
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-progress-linear md-mode="determinate" value="..."></md-progress-linear>
|
||||
*
|
||||
* <md-progress-linear md-mode="determinate" ng-value="..."></md-progress-linear>
|
||||
*
|
||||
* <md-progress-linear md-mode="indeterminate"></md-progress-linear>
|
||||
*
|
||||
* <md-progress-linear md-mode="buffer" value="..." md-buffer-value="..."></md-progress-linear>
|
||||
*
|
||||
* <md-progress-linear md-mode="query"></md-progress-linear>
|
||||
* </hljs>
|
||||
*/
|
||||
function MdProgressLinearDirective($$rAF, $mdConstant, $mdTheming) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: '<div class="md-container">' +
|
||||
'<div class="md-dashed"></div>' +
|
||||
'<div class="md-bar md-bar1"></div>' +
|
||||
'<div class="md-bar md-bar2"></div>' +
|
||||
'</div>',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(tElement, tAttrs, transclude) {
|
||||
tElement.attr('aria-valuemin', 0);
|
||||
tElement.attr('aria-valuemax', 100);
|
||||
tElement.attr('role', 'progressbar');
|
||||
|
||||
return postLink;
|
||||
}
|
||||
function postLink(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
var bar1Style = element[0].querySelector('.md-bar1').style,
|
||||
bar2Style = element[0].querySelector('.md-bar2').style,
|
||||
container = angular.element(element[0].querySelector('.md-container'));
|
||||
|
||||
attr.$observe('value', function(value) {
|
||||
if (attr.mdMode == 'query') {
|
||||
return;
|
||||
}
|
||||
|
||||
var clamped = clamp(value);
|
||||
element.attr('aria-valuenow', clamped);
|
||||
bar2Style[$mdConstant.CSS.TRANSFORM] = transforms[clamped];
|
||||
});
|
||||
|
||||
attr.$observe('mdBufferValue', function(value) {
|
||||
bar1Style[$mdConstant.CSS.TRANSFORM] = transforms[clamp(value)];
|
||||
});
|
||||
|
||||
$$rAF(function() {
|
||||
container.addClass('md-ready');
|
||||
});
|
||||
}
|
||||
|
||||
function clamp(value) {
|
||||
if (value > 100) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.ceil(value || 0);
|
||||
}
|
||||
}
|
||||
MdProgressLinearDirective.$inject = ["$$rAF", "$mdConstant", "$mdTheming"];
|
||||
|
||||
|
||||
// **********************************************************
|
||||
// Private Methods
|
||||
// **********************************************************
|
||||
var transforms = (function() {
|
||||
var values = new Array(101);
|
||||
for(var i = 0; i < 101; i++){
|
||||
values[i] = makeTransform(i);
|
||||
}
|
||||
|
||||
return values;
|
||||
|
||||
function makeTransform(value){
|
||||
var scale = value/100;
|
||||
var translateX = (value-100)/2;
|
||||
return 'translateX(' + translateX.toString() + '%) scale(' + scale.toString() + ', 1)';
|
||||
}
|
||||
})();
|
||||
|
||||
ng.material.components.progressLinear = angular.module("material.components.progressLinear");
|
||||
@@ -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-radio-button.md-THEME_NAME-theme .md-off {
|
||||
border-color: '{{foreground-2}}'; }
|
||||
md-radio-button.md-THEME_NAME-theme .md-on {
|
||||
background-color: '{{accent-color-0.87}}'; }
|
||||
md-radio-button.md-THEME_NAME-theme.md-checked .md-off {
|
||||
border-color: '{{accent-color-0.87}}'; }
|
||||
md-radio-button.md-THEME_NAME-theme.md-checked .md-ink-ripple {
|
||||
color: '{{accent-color-0.87}}'; }
|
||||
md-radio-button.md-THEME_NAME-theme .md-container .md-ripple {
|
||||
color: '{{accent-600}}'; }
|
||||
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-on {
|
||||
background-color: '{{primary-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-off {
|
||||
border-color: '{{primary-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary.md-checked .md-ink-ripple {
|
||||
color: '{{primary-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-primary .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-primary .md-container .md-ripple {
|
||||
color: '{{primary-600}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-on, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-on {
|
||||
background-color: '{{warn-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-off, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-off {
|
||||
border-color: '{{warn-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn.md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-checked .md-ink-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn.md-checked .md-ink-ripple {
|
||||
color: '{{warn-color-0.87}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple, md-radio-group.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]) .md-warn .md-container .md-ripple, md-radio-button.md-THEME_NAME-theme:not([disabled]).md-warn .md-container .md-ripple {
|
||||
color: '{{warn-600}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme[disabled], md-radio-button.md-THEME_NAME-theme[disabled] {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-off, md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-off {
|
||||
border-color: '{{foreground-3}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme[disabled] .md-container .md-on, md-radio-button.md-THEME_NAME-theme[disabled] .md-container .md-on {
|
||||
border-color: '{{foreground-3}}'; }
|
||||
|
||||
md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked .md-container:before {
|
||||
background-color: '{{accent-color-0.26}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked:not([disabled]).md-primary .md-container:before {
|
||||
background-color: '{{primary-color-0.26}}'; }
|
||||
md-radio-group.md-THEME_NAME-theme.md-focused:not(:empty) .md-checked.md-primary .md-container:before {
|
||||
background-color: '{{warn-color-0.26}}'; }
|
||||
@@ -0,0 +1,91 @@
|
||||
/*!
|
||||
* 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-radio-button, .md-switch-thumb {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
margin: 15px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer; }
|
||||
md-radio-button *, md-radio-button *:before, md-radio-button *:after, .md-switch-thumb *, .md-switch-thumb *:before, .md-switch-thumb *:after {
|
||||
box-sizing: border-box; }
|
||||
md-radio-button input, .md-switch-thumb input {
|
||||
display: none; }
|
||||
md-radio-button .md-container, .md-switch-thumb .md-container {
|
||||
position: relative;
|
||||
top: 4px;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
cursor: pointer; }
|
||||
md-radio-button .md-container .md-ripple-container, .md-switch-thumb .md-container .md-ripple-container {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
left: -16px;
|
||||
top: -16px; }
|
||||
md-radio-button .md-container:before, .md-switch-thumb .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-radio-button .md-off, .md-switch-thumb .md-off {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-radius: 50%;
|
||||
transition: border-color ease 0.28s; }
|
||||
md-radio-button .md-on, .md-switch-thumb .md-on {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
transition: -webkit-transform ease 0.28s;
|
||||
transition: transform ease 0.28s;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0); }
|
||||
md-radio-button.md-checked .md-on, .md-switch-thumb.md-checked .md-on {
|
||||
-webkit-transform: scale(0.5);
|
||||
transform: scale(0.5); }
|
||||
md-radio-button .md-label, .md-switch-thumb .md-label {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
vertical-align: middle;
|
||||
white-space: normal;
|
||||
pointer-events: none;
|
||||
width: auto; }
|
||||
md-radio-button .circle, .md-switch-thumb .circle {
|
||||
border-radius: 50%; }
|
||||
|
||||
md-radio-group:focus {
|
||||
outline: none; }
|
||||
md-radio-group.md-focused .md-checked .md-container:before {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
bottom: -8px; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-radio-button.md-default-theme .md-on {
|
||||
background-color: #fff; } }
|
||||
312
www/lib/angular-material/modules/closure/radioButton/radioButton.js
vendored
Normal file
312
www/lib/angular-material/modules/closure/radioButton/radioButton.js
vendored
Normal file
@@ -0,0 +1,312 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.radioButton');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.radioButton
|
||||
* @description radioButton module!
|
||||
*/
|
||||
angular.module('material.components.radioButton', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdRadioGroup', mdRadioGroupDirective)
|
||||
.directive('mdRadioButton', mdRadioButtonDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module material.components.radioButton
|
||||
* @name mdRadioGroup
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-radio-group>` directive identifies a grouping
|
||||
* container for the 1..n grouped radio buttons; specified using nested
|
||||
* `<md-radio-button>` tags.
|
||||
*
|
||||
* As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
|
||||
* the radio button is in the accent color by default. The primary color palette may be used with
|
||||
* the `md-primary` class.
|
||||
*
|
||||
* Note: `<md-radio-group>` and `<md-radio-button>` handle tabindex differently
|
||||
* than the native `<input type='radio'>` controls. Whereas the native controls
|
||||
* force the user to tab through all the radio buttons, `<md-radio-group>`
|
||||
* is focusable, and by default the `<md-radio-button>`s are not.
|
||||
*
|
||||
* @param {string} ng-model Assignable angular expression to data-bind to.
|
||||
* @param {boolean=} md-no-ink Use of attribute indicates flag to disable ink ripple effects.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-radio-group ng-model="selected">
|
||||
*
|
||||
* <md-radio-button
|
||||
* ng-repeat="d in colorOptions"
|
||||
* ng-value="d.value" aria-label="{{ d.label }}">
|
||||
*
|
||||
* {{ d.label }}
|
||||
*
|
||||
* </md-radio-button>
|
||||
*
|
||||
* </md-radio-group>
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function mdRadioGroupDirective($mdUtil, $mdConstant, $mdTheming, $timeout) {
|
||||
RadioGroupController.prototype = createRadioGroupControllerProto();
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: ['$element', RadioGroupController],
|
||||
require: ['mdRadioGroup', '?ngModel'],
|
||||
link: { pre: linkRadioGroup }
|
||||
};
|
||||
|
||||
function linkRadioGroup(scope, element, attr, ctrls) {
|
||||
$mdTheming(element);
|
||||
var rgCtrl = ctrls[0];
|
||||
var ngModelCtrl = ctrls[1] || $mdUtil.fakeNgModel();
|
||||
|
||||
function setFocus() {
|
||||
if (!element.hasClass('md-focused')) { element.addClass('md-focused'); }
|
||||
}
|
||||
|
||||
function keydownListener(ev) {
|
||||
var keyCode = ev.which || ev.keyCode;
|
||||
switch(keyCode) {
|
||||
case $mdConstant.KEY_CODE.LEFT_ARROW:
|
||||
case $mdConstant.KEY_CODE.UP_ARROW:
|
||||
ev.preventDefault();
|
||||
rgCtrl.selectPrevious();
|
||||
setFocus();
|
||||
break;
|
||||
|
||||
case $mdConstant.KEY_CODE.RIGHT_ARROW:
|
||||
case $mdConstant.KEY_CODE.DOWN_ARROW:
|
||||
ev.preventDefault();
|
||||
rgCtrl.selectNext();
|
||||
setFocus();
|
||||
break;
|
||||
|
||||
case $mdConstant.KEY_CODE.ENTER:
|
||||
var form = angular.element($mdUtil.getClosest(element[0], 'form'));
|
||||
if (form.length > 0) {
|
||||
form.triggerHandler('submit');
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
rgCtrl.init(ngModelCtrl);
|
||||
|
||||
scope.mouseActive = false;
|
||||
element.attr({
|
||||
'role': 'radiogroup',
|
||||
'tabIndex': element.attr('tabindex') || '0'
|
||||
})
|
||||
.on('keydown', keydownListener)
|
||||
.on('mousedown', function(event) {
|
||||
scope.mouseActive = true;
|
||||
$timeout(function() {
|
||||
scope.mouseActive = false;
|
||||
}, 100);
|
||||
})
|
||||
.on('focus', function() {
|
||||
if(scope.mouseActive === false) { rgCtrl.$element.addClass('md-focused'); }
|
||||
})
|
||||
.on('blur', function() { rgCtrl.$element.removeClass('md-focused'); });
|
||||
}
|
||||
|
||||
function RadioGroupController($element) {
|
||||
this._radioButtonRenderFns = [];
|
||||
this.$element = $element;
|
||||
}
|
||||
|
||||
function createRadioGroupControllerProto() {
|
||||
return {
|
||||
init: function(ngModelCtrl) {
|
||||
this._ngModelCtrl = ngModelCtrl;
|
||||
this._ngModelCtrl.$render = angular.bind(this, this.render);
|
||||
},
|
||||
add: function(rbRender) {
|
||||
this._radioButtonRenderFns.push(rbRender);
|
||||
},
|
||||
remove: function(rbRender) {
|
||||
var index = this._radioButtonRenderFns.indexOf(rbRender);
|
||||
if (index !== -1) {
|
||||
this._radioButtonRenderFns.splice(index, 1);
|
||||
}
|
||||
},
|
||||
render: function() {
|
||||
this._radioButtonRenderFns.forEach(function(rbRender) {
|
||||
rbRender();
|
||||
});
|
||||
},
|
||||
setViewValue: function(value, eventType) {
|
||||
this._ngModelCtrl.$setViewValue(value, eventType);
|
||||
// update the other radio buttons as well
|
||||
this.render();
|
||||
},
|
||||
getViewValue: function() {
|
||||
return this._ngModelCtrl.$viewValue;
|
||||
},
|
||||
selectNext: function() {
|
||||
return changeSelectedButton(this.$element, 1);
|
||||
},
|
||||
selectPrevious: function() {
|
||||
return changeSelectedButton(this.$element, -1);
|
||||
},
|
||||
setActiveDescendant: function (radioId) {
|
||||
this.$element.attr('aria-activedescendant', radioId);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Change the radio group's selected button by a given increment.
|
||||
* If no button is selected, select the first button.
|
||||
*/
|
||||
function changeSelectedButton(parent, increment) {
|
||||
// Coerce all child radio buttons into an array, then wrap then in an iterator
|
||||
var buttons = $mdUtil.iterator(parent[0].querySelectorAll('md-radio-button'), true);
|
||||
|
||||
if (buttons.count()) {
|
||||
var validate = function (button) {
|
||||
// If disabled, then NOT valid
|
||||
return !angular.element(button).attr("disabled");
|
||||
};
|
||||
var selected = parent[0].querySelector('md-radio-button.md-checked');
|
||||
var target = buttons[increment < 0 ? 'previous' : 'next'](selected, validate) || buttons.first();
|
||||
// Activate radioButton's click listener (triggerHandler won't create a real click event)
|
||||
angular.element(target).triggerHandler('click');
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
mdRadioGroupDirective.$inject = ["$mdUtil", "$mdConstant", "$mdTheming", "$timeout"];
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module material.components.radioButton
|
||||
* @name mdRadioButton
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-radio-button>`directive is the child directive required to be used within `<md-radio-group>` elements.
|
||||
*
|
||||
* While similar to the `<input type="radio" ng-model="" value="">` directive,
|
||||
* the `<md-radio-button>` directive provides ink effects, ARIA support, and
|
||||
* supports use within named radio groups.
|
||||
*
|
||||
* @param {string} ngModel Assignable angular expression to data-bind to.
|
||||
* @param {string=} ngChange Angular expression to be executed when input changes due to user
|
||||
* interaction with the input element.
|
||||
* @param {string} ngValue Angular expression which sets the value to which the expression should
|
||||
* be set when selected.*
|
||||
* @param {string} value The value to which the expression should be set when selected.
|
||||
* @param {string=} name Property name of the form under which the control is published.
|
||||
* @param {string=} aria-label Adds label to radio button for accessibility.
|
||||
* Defaults to radio button's text. If no text content is available, a warning will be logged.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
*
|
||||
* <md-radio-button value="1" aria-label="Label 1">
|
||||
* Label 1
|
||||
* </md-radio-button>
|
||||
*
|
||||
* <md-radio-button ng-model="color" ng-value="specialValue" aria-label="Green">
|
||||
* Green
|
||||
* </md-radio-button>
|
||||
*
|
||||
* </hljs>
|
||||
*
|
||||
*/
|
||||
function mdRadioButtonDirective($mdAria, $mdUtil, $mdTheming) {
|
||||
|
||||
var CHECKED_CSS = 'md-checked';
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
require: '^mdRadioGroup',
|
||||
transclude: true,
|
||||
template: '<div class="md-container" md-ink-ripple md-ink-ripple-checkbox>' +
|
||||
'<div class="md-off"></div>' +
|
||||
'<div class="md-on"></div>' +
|
||||
'</div>' +
|
||||
'<div ng-transclude class="md-label"></div>',
|
||||
link: link
|
||||
};
|
||||
|
||||
function link(scope, element, attr, rgCtrl) {
|
||||
var lastChecked;
|
||||
|
||||
$mdTheming(element);
|
||||
configureAria(element, scope);
|
||||
|
||||
rgCtrl.add(render);
|
||||
attr.$observe('value', render);
|
||||
|
||||
element
|
||||
.on('click', listener)
|
||||
.on('$destroy', function() {
|
||||
rgCtrl.remove(render);
|
||||
});
|
||||
|
||||
function listener(ev) {
|
||||
if (element[0].hasAttribute('disabled')) return;
|
||||
|
||||
scope.$apply(function() {
|
||||
rgCtrl.setViewValue(attr.value, ev && ev.type);
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
var checked = (rgCtrl.getViewValue() == attr.value);
|
||||
if (checked === lastChecked) {
|
||||
return;
|
||||
}
|
||||
lastChecked = checked;
|
||||
element.attr('aria-checked', checked);
|
||||
if (checked) {
|
||||
element.addClass(CHECKED_CSS);
|
||||
rgCtrl.setActiveDescendant(element.attr('id'));
|
||||
} else {
|
||||
element.removeClass(CHECKED_CSS);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Inject ARIA-specific attributes appropriate for each radio button
|
||||
*/
|
||||
function configureAria( element, scope ){
|
||||
scope.ariaId = buildAriaID();
|
||||
|
||||
element.attr({
|
||||
'id' : scope.ariaId,
|
||||
'role' : 'radio',
|
||||
'aria-checked' : 'false'
|
||||
});
|
||||
|
||||
$mdAria.expectWithText(element, 'aria-label');
|
||||
|
||||
/**
|
||||
* Build a unique ID for each radio button that will be used with aria-activedescendant.
|
||||
* Preserve existing ID if already specified.
|
||||
* @returns {*|string}
|
||||
*/
|
||||
function buildAriaID() {
|
||||
return attr.id || ( 'radio' + "_" + $mdUtil.nextUid() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
mdRadioButtonDirective.$inject = ["$mdAria", "$mdUtil", "$mdTheming"];
|
||||
|
||||
ng.material.components.radioButton = angular.module("material.components.radioButton");
|
||||
@@ -0,0 +1,42 @@
|
||||
/*!
|
||||
* 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-select.md-THEME_NAME-theme.ng-invalid.ng-dirty .md-select-label {
|
||||
color: '{{warn-500}}' !important;
|
||||
border-bottom-color: '{{warn-500}}' !important; }
|
||||
md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-label {
|
||||
border-bottom-color: '{{primary-color}}';
|
||||
color: '{{ foreground-1 }}'; }
|
||||
md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-label.md-placeholder {
|
||||
color: '{{ foreground-1 }}'; }
|
||||
md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-label {
|
||||
border-bottom-color: '{{accent-color}}'; }
|
||||
md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-label {
|
||||
border-bottom-color: '{{warn-color}}'; }
|
||||
md-select.md-THEME_NAME-theme[disabled] .md-select-label {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-select.md-THEME_NAME-theme[disabled] .md-select-label.md-placeholder {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-select.md-THEME_NAME-theme .md-select-label {
|
||||
border-bottom-color: '{{foreground-4}}'; }
|
||||
md-select.md-THEME_NAME-theme .md-select-label.md-placeholder {
|
||||
color: '{{foreground-2}}'; }
|
||||
|
||||
md-select-menu.md-THEME_NAME-theme md-optgroup {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-optgroup md-option {
|
||||
color: '{{foreground-1}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-option[selected] {
|
||||
color: '{{primary-500}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-option[selected]:focus {
|
||||
color: '{{primary-600}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-option[selected].md-accent {
|
||||
color: '{{accent-500}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-option[selected].md-accent:focus {
|
||||
color: '{{accent-600}}'; }
|
||||
md-select-menu.md-THEME_NAME-theme md-option:focus:not([selected]) {
|
||||
background: '{{background-200}}'; }
|
||||
170
www/lib/angular-material/modules/closure/select/select.css
Normal file
170
www/lib/angular-material/modules/closure/select/select.css
Normal file
@@ -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-select-menu-container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
top: 0;
|
||||
z-index: 99;
|
||||
opacity: 0; }
|
||||
.md-select-menu-container:not(.md-clickable) {
|
||||
pointer-events: none; }
|
||||
.md-select-menu-container md-progress-circular {
|
||||
display: table;
|
||||
margin: 24px auto !important; }
|
||||
.md-select-menu-container.md-active {
|
||||
opacity: 1; }
|
||||
.md-select-menu-container.md-active md-select-menu {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
transition-duration: 200ms; }
|
||||
.md-select-menu-container.md-active md-select-menu > * {
|
||||
opacity: 1;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 200ms;
|
||||
transition-delay: 100ms; }
|
||||
.md-select-menu-container.md-leave {
|
||||
opacity: 0;
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
transition-duration: 250ms; }
|
||||
|
||||
md-input-container > md-select {
|
||||
margin: 0;
|
||||
margin-top: 3px; }
|
||||
|
||||
md-select {
|
||||
padding: 24px 2px 26px;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex; }
|
||||
md-select:focus {
|
||||
outline: none; }
|
||||
md-select[disabled]:hover {
|
||||
cursor: default; }
|
||||
md-select:not([disabled]):hover {
|
||||
cursor: pointer; }
|
||||
md-select:not([disabled]).ng-invalid.ng-dirty .md-select-label {
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-style: solid;
|
||||
padding-bottom: 0; }
|
||||
md-select:not([disabled]):focus .md-select-label {
|
||||
border-bottom-width: 2px;
|
||||
border-bottom-style: solid;
|
||||
padding-bottom: 0; }
|
||||
|
||||
.md-select-label {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
padding: 2px 2px 1px;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-style: solid;
|
||||
position: relative;
|
||||
box-sizing: content-box;
|
||||
min-width: 64px;
|
||||
min-height: 26px; }
|
||||
.md-select-label *:first-child {
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
max-width: calc(100% - 2*8px);
|
||||
-webkit-transform: translate3d(0, 2px, 0);
|
||||
transform: translate3d(0, 2px, 0); }
|
||||
.md-select-label .md-select-icon {
|
||||
-webkit-align-items: flex-end;
|
||||
-ms-flex-align: end;
|
||||
align-items: flex-end;
|
||||
text-align: end;
|
||||
width: 24px;
|
||||
margin: 0 4px;
|
||||
-webkit-transform: translate3d(0, 1px, 0);
|
||||
transform: translate3d(0, 1px, 0); }
|
||||
.md-select-label .md-select-icon:after {
|
||||
display: block;
|
||||
content: '\25BC';
|
||||
position: relative;
|
||||
top: 2px;
|
||||
speak: none;
|
||||
-webkit-transform: scaleY(0.6) scaleX(1);
|
||||
transform: scaleY(0.6) scaleX(1); }
|
||||
|
||||
md-select-menu {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
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);
|
||||
max-height: 256px;
|
||||
min-height: 48px;
|
||||
overflow-y: hidden;
|
||||
-webkit-transform-origin: left top;
|
||||
transform-origin: left top;
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
md-select-menu.md-reverse {
|
||||
-webkit-flex-direction: column-reverse;
|
||||
-ms-flex-direction: column-reverse;
|
||||
flex-direction: column-reverse; }
|
||||
md-select-menu:not(.md-overflow) md-content {
|
||||
padding-top: 8px;
|
||||
padding-bottom: 8px; }
|
||||
html[dir=rtl] md-select-menu {
|
||||
-webkit-transform-origin: right top;
|
||||
transform-origin: right top; }
|
||||
md-select-menu md-content {
|
||||
min-width: 136px;
|
||||
min-height: 48px;
|
||||
max-height: 256px;
|
||||
overflow-y: auto; }
|
||||
md-select-menu > * {
|
||||
opacity: 0; }
|
||||
|
||||
md-option {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: auto;
|
||||
padding: 0 16px 0 16px;
|
||||
height: 48px; }
|
||||
md-option:focus {
|
||||
outline: none; }
|
||||
md-option .md-text {
|
||||
width: auto;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-size: 16px; }
|
||||
|
||||
md-optgroup {
|
||||
display: block; }
|
||||
md-optgroup label {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
text-transform: uppercase;
|
||||
padding: 16px;
|
||||
font-weight: 500; }
|
||||
md-optgroup md-option {
|
||||
padding-left: 32px;
|
||||
padding-right: 32px; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
.md-select-backdrop {
|
||||
background-color: transparent; }
|
||||
md-select-menu {
|
||||
border: 1px solid #fff; } }
|
||||
1055
www/lib/angular-material/modules/closure/select/select.js
vendored
Normal file
1055
www/lib/angular-material/modules/closure/select/select.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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-sidenav.md-THEME_NAME-theme {
|
||||
background-color: '{{background-color}}'; }
|
||||
99
www/lib/angular-material/modules/closure/sidenav/sidenav.css
Normal file
99
www/lib/angular-material/modules/closure/sidenav/sidenav.css
Normal file
@@ -0,0 +1,99 @@
|
||||
/*!
|
||||
* 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-sidenav {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
width: 304px;
|
||||
min-width: 304px;
|
||||
max-width: 304px;
|
||||
bottom: 0;
|
||||
z-index: 60;
|
||||
background-color: white;
|
||||
overflow: auto;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column; }
|
||||
md-sidenav *, md-sidenav *:before, md-sidenav *:after {
|
||||
box-sizing: border-box; }
|
||||
md-sidenav ul {
|
||||
list-style: none; }
|
||||
md-sidenav.md-closed {
|
||||
display: none; }
|
||||
md-sidenav.md-closed-add, md-sidenav.md-closed-remove {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
/* this is required as of 1.3x to properly
|
||||
apply all styling in a show/hide animation */
|
||||
transition: 0s all; }
|
||||
md-sidenav.md-closed-add.md-closed-add-active, md-sidenav.md-closed-remove.md-closed-remove-active {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
md-sidenav.md-locked-open-add, md-sidenav.md-locked-open-remove {
|
||||
position: static;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
md-sidenav.md-locked-open {
|
||||
width: 304px;
|
||||
min-width: 304px;
|
||||
max-width: 304px; }
|
||||
md-sidenav.md-locked-open, md-sidenav.md-locked-open.md-closed, md-sidenav.md-locked-open.md-closed.md-sidenav-left, md-sidenav.md-locked-open.md-closed, md-sidenav.md-locked-open.md-closed.md-sidenav-right, md-sidenav.md-locked-open-remove.md-closed {
|
||||
position: static;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
md-sidenav.md-locked-open-remove-active {
|
||||
transition: width 0.3s cubic-bezier(0.55, 0, 0.55, 0.2), min-width 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
width: 0;
|
||||
min-width: 0; }
|
||||
md-sidenav.md-closed.md-locked-open-add {
|
||||
width: 0;
|
||||
min-width: 0;
|
||||
-webkit-transform: translate3d(0%, 0, 0);
|
||||
transform: translate3d(0%, 0, 0); }
|
||||
md-sidenav.md-closed.md-locked-open-add-active {
|
||||
transition: width 0.3s cubic-bezier(0.55, 0, 0.55, 0.2), min-width 0.3s cubic-bezier(0.55, 0, 0.55, 0.2);
|
||||
width: 304px;
|
||||
min-width: 304px;
|
||||
-webkit-transform: translate3d(0%, 0, 0);
|
||||
transform: translate3d(0%, 0, 0); }
|
||||
|
||||
.md-sidenav-backdrop.md-locked-open {
|
||||
display: none; }
|
||||
|
||||
.md-sidenav-left, md-sidenav {
|
||||
left: 0;
|
||||
top: 0;
|
||||
-webkit-transform: translate3d(0%, 0, 0);
|
||||
transform: translate3d(0%, 0, 0); }
|
||||
.md-sidenav-left.md-closed, md-sidenav.md-closed {
|
||||
-webkit-transform: translate3d(-100%, 0, 0);
|
||||
transform: translate3d(-100%, 0, 0); }
|
||||
|
||||
.md-sidenav-right {
|
||||
left: 100%;
|
||||
top: 0;
|
||||
-webkit-transform: translate3d(-100%, 0, 0);
|
||||
transform: translate3d(-100%, 0, 0); }
|
||||
.md-sidenav-right.md-closed {
|
||||
-webkit-transform: translate3d(0%, 0, 0);
|
||||
transform: translate3d(0%, 0, 0); }
|
||||
|
||||
@media (max-width: 360px) {
|
||||
md-sidenav {
|
||||
width: 85%; } }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
.md-sidenav-left, md-sidenav {
|
||||
border-right: 1px solid #fff; }
|
||||
.md-sidenav-right {
|
||||
border-left: 1px solid #fff; } }
|
||||
424
www/lib/angular-material/modules/closure/sidenav/sidenav.js
vendored
Normal file
424
www/lib/angular-material/modules/closure/sidenav/sidenav.js
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.sidenav');
|
||||
goog.require('ng.material.components.backdrop');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.sidenav
|
||||
*
|
||||
* @description
|
||||
* A Sidenav QP component.
|
||||
*/
|
||||
angular.module('material.components.sidenav', [
|
||||
'material.core',
|
||||
'material.components.backdrop'
|
||||
])
|
||||
.factory('$mdSidenav', SidenavService )
|
||||
.directive('mdSidenav', SidenavDirective)
|
||||
.directive('mdSidenavFocus', SidenavFocusDirective)
|
||||
.controller('$mdSidenavController', SidenavController);
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @ngdoc service
|
||||
* @name $mdSidenav
|
||||
* @module material.components.sidenav
|
||||
*
|
||||
* @description
|
||||
* `$mdSidenav` makes it easy to interact with multiple sidenavs
|
||||
* in an app.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="js">
|
||||
* // Async lookup for sidenav instance; will resolve when the instance is available
|
||||
* $mdSidenav(componentId).then(function(instance) {
|
||||
* $log.debug( componentId + "is now ready" );
|
||||
* });
|
||||
* // Async toggle the given sidenav;
|
||||
* // when instance is known ready and lazy lookup is not needed.
|
||||
* $mdSidenav(componentId)
|
||||
* .toggle()
|
||||
* .then(function(){
|
||||
* $log.debug('toggled');
|
||||
* });
|
||||
* // Async open the given sidenav
|
||||
* $mdSidenav(componentId)
|
||||
* .open()
|
||||
* .then(function(){
|
||||
* $log.debug('opened');
|
||||
* });
|
||||
* // Async close the given sidenav
|
||||
* $mdSidenav(componentId)
|
||||
* .close()
|
||||
* .then(function(){
|
||||
* $log.debug('closed');
|
||||
* });
|
||||
* // Sync check to see if the specified sidenav is set to be open
|
||||
* $mdSidenav(componentId).isOpen();
|
||||
* // Sync check to whether given sidenav is locked open
|
||||
* // If this is true, the sidenav will be open regardless of close()
|
||||
* $mdSidenav(componentId).isLockedOpen();
|
||||
* </hljs>
|
||||
*/
|
||||
function SidenavService($mdComponentRegistry, $q) {
|
||||
return function(handle) {
|
||||
|
||||
// Lookup the controller instance for the specified sidNav instance
|
||||
var self;
|
||||
var errorMsg = "SideNav '" + handle + "' is not available!";
|
||||
var instance = $mdComponentRegistry.get(handle);
|
||||
|
||||
if(!instance) {
|
||||
$mdComponentRegistry.notFoundError(handle);
|
||||
}
|
||||
|
||||
return self = {
|
||||
// -----------------
|
||||
// Sync methods
|
||||
// -----------------
|
||||
isOpen: function() {
|
||||
return instance && instance.isOpen();
|
||||
},
|
||||
isLockedOpen: function() {
|
||||
return instance && instance.isLockedOpen();
|
||||
},
|
||||
// -----------------
|
||||
// Async methods
|
||||
// -----------------
|
||||
toggle: function() {
|
||||
return instance ? instance.toggle() : $q.reject(errorMsg);
|
||||
},
|
||||
open: function() {
|
||||
return instance ? instance.open() : $q.reject(errorMsg);
|
||||
},
|
||||
close: function() {
|
||||
return instance ? instance.close() : $q.reject(errorMsg);
|
||||
},
|
||||
then : function( callbackFn ) {
|
||||
var promise = instance ? $q.when(instance) : waitForInstance();
|
||||
return promise.then( callbackFn || angular.noop );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Deferred lookup of component instance using $component registry
|
||||
*/
|
||||
function waitForInstance() {
|
||||
return $mdComponentRegistry
|
||||
.when(handle)
|
||||
.then(function( it ){
|
||||
instance = it;
|
||||
return it;
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
SidenavService.$inject = ["$mdComponentRegistry", "$q"];
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdSidenavFocus
|
||||
* @module material.components.sidenav
|
||||
*
|
||||
* @restrict A
|
||||
*
|
||||
* @description
|
||||
* `$mdSidenavFocus` provides a way to specify the focused element when a sidenav opens.
|
||||
* This is completely optional, as the sidenav itself is focused by default.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-sidenav>
|
||||
* <form>
|
||||
* <md-input-container>
|
||||
* <label for="testInput">Label</label>
|
||||
* <input id="testInput" type="text" md-sidenav-focus>
|
||||
* </md-input-container>
|
||||
* </form>
|
||||
* </md-sidenav>
|
||||
* </hljs>
|
||||
**/
|
||||
function SidenavFocusDirective() {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: '^mdSidenav',
|
||||
link: function(scope, element, attr, sidenavCtrl) {
|
||||
sidenavCtrl.focusElement(element);
|
||||
}
|
||||
};
|
||||
}
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdSidenav
|
||||
* @module material.components.sidenav
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
*
|
||||
* A Sidenav component that can be opened and closed programatically.
|
||||
*
|
||||
* By default, upon opening it will slide out on top of the main content area.
|
||||
*
|
||||
* For keyboard and screen reader accessibility, focus is sent to the sidenav wrapper by default.
|
||||
* It can be overridden with the `md-sidenav-focus` directive on the child element you want focused.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div layout="row" ng-controller="MyController">
|
||||
* <md-sidenav md-component-id="left" class="md-sidenav-left">
|
||||
* Left Nav!
|
||||
* </md-sidenav>
|
||||
*
|
||||
* <md-content>
|
||||
* Center Content
|
||||
* <md-button ng-click="openLeftMenu()">
|
||||
* Open Left Menu
|
||||
* </md-button>
|
||||
* </md-content>
|
||||
*
|
||||
* <md-sidenav md-component-id="right"
|
||||
* md-is-locked-open="$mdMedia('min-width: 333px')"
|
||||
* class="md-sidenav-right">
|
||||
* <form>
|
||||
* <md-input-container>
|
||||
* <label for="testInput">Test input</label>
|
||||
* <input id="testInput" type="text"
|
||||
* ng-model="data" md-sidenav-focus>
|
||||
* </md-input-container>
|
||||
* </form>
|
||||
* </md-sidenav>
|
||||
* </div>
|
||||
* </hljs>
|
||||
*
|
||||
* <hljs lang="js">
|
||||
* var app = angular.module('myApp', ['ngMaterial']);
|
||||
* app.controller('MyController', function($scope, $mdSidenav) {
|
||||
* $scope.openLeftMenu = function() {
|
||||
* $mdSidenav('left').toggle();
|
||||
* };
|
||||
* });
|
||||
* </hljs>
|
||||
*
|
||||
* @param {expression=} md-is-open A model bound to whether the sidenav is opened.
|
||||
* @param {string=} md-component-id componentId to use with $mdSidenav service.
|
||||
* @param {expression=} md-is-locked-open When this expression evalutes to true,
|
||||
* the sidenav 'locks open': it falls into the content's flow instead
|
||||
* of appearing over it. This overrides the `is-open` attribute.
|
||||
*
|
||||
* The $mdMedia() service is exposed to the is-locked-open attribute, which
|
||||
* can be given a media query or one of the `sm`, `gt-sm`, `md`, `gt-md`, `lg` or `gt-lg` presets.
|
||||
* Examples:
|
||||
*
|
||||
* - `<md-sidenav md-is-locked-open="shouldLockOpen"></md-sidenav>`
|
||||
* - `<md-sidenav md-is-locked-open="$mdMedia('min-width: 1000px')"></md-sidenav>`
|
||||
* - `<md-sidenav md-is-locked-open="$mdMedia('sm')"></md-sidenav>` (locks open on small screens)
|
||||
*/
|
||||
function SidenavDirective($timeout, $animate, $parse, $log, $mdMedia, $mdConstant, $compile, $mdTheming, $q, $document) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
scope: {
|
||||
isOpen: '=?mdIsOpen'
|
||||
},
|
||||
controller: '$mdSidenavController',
|
||||
compile: function(element) {
|
||||
element.addClass('md-closed');
|
||||
element.attr('tabIndex', '-1');
|
||||
return postLink;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Directive Post Link function...
|
||||
*/
|
||||
function postLink(scope, element, attr, sidenavCtrl) {
|
||||
var lastParentOverFlow;
|
||||
var triggeringElement = null;
|
||||
var promise = $q.when(true);
|
||||
|
||||
var isLockedOpenParsed = $parse(attr.mdIsLockedOpen);
|
||||
var isLocked = function() {
|
||||
return isLockedOpenParsed(scope.$parent, {
|
||||
$media: function(arg) {
|
||||
$log.warn("$media is deprecated for is-locked-open. Use $mdMedia instead.");
|
||||
return $mdMedia(arg);
|
||||
},
|
||||
$mdMedia: $mdMedia
|
||||
});
|
||||
};
|
||||
var backdrop = $compile(
|
||||
'<md-backdrop class="md-sidenav-backdrop md-opaque ng-enter">'
|
||||
)(scope);
|
||||
|
||||
element.on('$destroy', sidenavCtrl.destroy);
|
||||
$mdTheming.inherit(backdrop, element);
|
||||
|
||||
scope.$watch(isLocked, updateIsLocked);
|
||||
scope.$watch('isOpen', updateIsOpen);
|
||||
|
||||
|
||||
// Publish special accessor for the Controller instance
|
||||
sidenavCtrl.$toggleOpen = toggleOpen;
|
||||
sidenavCtrl.focusElement( sidenavCtrl.focusElement() || element );
|
||||
|
||||
/**
|
||||
* Toggle the DOM classes to indicate `locked`
|
||||
* @param isLocked
|
||||
*/
|
||||
function updateIsLocked(isLocked, oldValue) {
|
||||
scope.isLockedOpen = isLocked;
|
||||
if (isLocked === oldValue) {
|
||||
element.toggleClass('md-locked-open', !!isLocked);
|
||||
} else {
|
||||
$animate[isLocked ? 'addClass' : 'removeClass'](element, 'md-locked-open');
|
||||
}
|
||||
backdrop.toggleClass('md-locked-open', !!isLocked);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the SideNav view and attach/detach listeners
|
||||
* @param isOpen
|
||||
*/
|
||||
function updateIsOpen(isOpen) {
|
||||
var parent = element.parent();
|
||||
|
||||
parent[isOpen ? 'on' : 'off']('keydown', onKeyDown);
|
||||
backdrop[isOpen ? 'on' : 'off']('click', close);
|
||||
|
||||
if ( isOpen ) {
|
||||
// Capture upon opening..
|
||||
triggeringElement = $document[0].activeElement;
|
||||
}
|
||||
var focusEl = sidenavCtrl.focusElement();
|
||||
|
||||
disableParentScroll(isOpen);
|
||||
|
||||
return promise = $q.all([
|
||||
isOpen ? $animate.enter(backdrop, parent) : $animate.leave(backdrop),
|
||||
$animate[isOpen ? 'removeClass' : 'addClass'](element, 'md-closed')
|
||||
])
|
||||
.then(function() {
|
||||
// Perform focus when animations are ALL done...
|
||||
if (scope.isOpen) {
|
||||
focusEl && focusEl.focus();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent parent scrolling (when the SideNav is open)
|
||||
*/
|
||||
function disableParentScroll(disabled) {
|
||||
var parent = element.parent();
|
||||
if ( disabled ) {
|
||||
lastParentOverFlow = parent.css('overflow');
|
||||
parent.css('overflow', 'hidden');
|
||||
} else if (angular.isDefined(lastParentOverFlow)) {
|
||||
parent.css('overflow', lastParentOverFlow);
|
||||
lastParentOverFlow = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the sideNav view and publish a promise to be resolved when
|
||||
* the view animation finishes.
|
||||
*
|
||||
* @param isOpen
|
||||
* @returns {*}
|
||||
*/
|
||||
function toggleOpen( isOpen ) {
|
||||
if (scope.isOpen == isOpen ) {
|
||||
|
||||
return $q.when(true);
|
||||
|
||||
} else {
|
||||
var deferred = $q.defer();
|
||||
|
||||
// Toggle value to force an async `updateIsOpen()` to run
|
||||
scope.isOpen = isOpen;
|
||||
|
||||
$timeout(function() {
|
||||
|
||||
// When the current `updateIsOpen()` animation finishes
|
||||
promise.then(function(result) {
|
||||
|
||||
if ( !scope.isOpen ) {
|
||||
// reset focus to originating element (if available) upon close
|
||||
triggeringElement && triggeringElement.focus();
|
||||
triggeringElement = null;
|
||||
}
|
||||
|
||||
deferred.resolve(result);
|
||||
});
|
||||
|
||||
},0,false);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Auto-close sideNav when the `escape` key is pressed.
|
||||
* @param evt
|
||||
*/
|
||||
function onKeyDown(ev) {
|
||||
var isEscape = (ev.keyCode === $mdConstant.KEY_CODE.ESCAPE);
|
||||
return isEscape ? close(ev) : $q.when(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* With backdrop `clicks` or `escape` key-press, immediately
|
||||
* apply the CSS close transition... Then notify the controller
|
||||
* to close() and perform its own actions.
|
||||
*/
|
||||
function close(ev) {
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
|
||||
return sidenavCtrl.close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
SidenavDirective.$inject = ["$timeout", "$animate", "$parse", "$log", "$mdMedia", "$mdConstant", "$compile", "$mdTheming", "$q", "$document"];
|
||||
|
||||
/*
|
||||
* @private
|
||||
* @ngdoc controller
|
||||
* @name SidenavController
|
||||
* @module material.components.sidenav
|
||||
*
|
||||
*/
|
||||
function SidenavController($scope, $element, $attrs, $mdComponentRegistry, $q) {
|
||||
|
||||
var self = this,
|
||||
focusElement;
|
||||
|
||||
// Use Default internal method until overridden by directive postLink
|
||||
|
||||
// Synchronous getters
|
||||
self.isOpen = function() { return !!$scope.isOpen; };
|
||||
self.isLockedOpen = function() { return !!$scope.isLockedOpen; };
|
||||
|
||||
// Async actions
|
||||
self.open = function() { return self.$toggleOpen( true ); };
|
||||
self.close = function() { return self.$toggleOpen( false ); };
|
||||
self.toggle = function() { return self.$toggleOpen( !$scope.isOpen ); };
|
||||
self.focusElement = function(el) {
|
||||
if ( angular.isDefined(el) ) {
|
||||
focusElement = el;
|
||||
}
|
||||
return focusElement;
|
||||
};
|
||||
|
||||
self.$toggleOpen = function() { return $q.when($scope.isOpen); };
|
||||
|
||||
self.destroy = $mdComponentRegistry.register(self, $attrs.mdComponentId);
|
||||
}
|
||||
SidenavController.$inject = ["$scope", "$element", "$attrs", "$mdComponentRegistry", "$q"];
|
||||
|
||||
ng.material.components.sidenav = angular.module("material.components.sidenav");
|
||||
@@ -0,0 +1,56 @@
|
||||
/*!
|
||||
* 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-slider.md-THEME_NAME-theme .md-track {
|
||||
background-color: '{{foreground-3}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-track-ticks {
|
||||
background-color: '{{foreground-4}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-focus-thumb {
|
||||
background-color: '{{foreground-2}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-focus-ring {
|
||||
border-color: '{{foreground-4}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-disabled-thumb {
|
||||
border-color: '{{background-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-min .md-thumb:after {
|
||||
background-color: '{{background-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-track.md-track-fill {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-thumb:after {
|
||||
border-color: '{{accent-color}}';
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-sign {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-sign:after {
|
||||
border-top-color: '{{accent-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme .md-thumb-text {
|
||||
color: '{{accent-contrast}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-warn .md-track.md-track-fill {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-warn .md-thumb:after {
|
||||
border-color: '{{warn-color}}';
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-warn .md-sign {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-warn .md-sign:after {
|
||||
border-top-color: '{{warn-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-warn .md-thumb-text {
|
||||
color: '{{warn-contrast}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-primary .md-track.md-track-fill {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-primary .md-thumb:after {
|
||||
border-color: '{{primary-color}}';
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-primary .md-sign {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-primary .md-sign:after {
|
||||
border-top-color: '{{primary-color}}'; }
|
||||
md-slider.md-THEME_NAME-theme.md-primary .md-thumb-text {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-slider.md-THEME_NAME-theme[disabled] .md-thumb:after {
|
||||
border-color: '{{foreground-3}}'; }
|
||||
md-slider.md-THEME_NAME-theme[disabled]:not(.md-min) .md-thumb:after {
|
||||
background-color: '{{foreground-3}}'; }
|
||||
220
www/lib/angular-material/modules/closure/slider/slider.css
Normal file
220
www/lib/angular-material/modules/closure/slider/slider.css
Normal file
@@ -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 sliderFocusThumb {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0); }
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1; }
|
||||
|
||||
100% {
|
||||
opacity: 0; } }
|
||||
@keyframes sliderFocusThumb {
|
||||
0% {
|
||||
opacity: 0;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0); }
|
||||
|
||||
50% {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1; }
|
||||
|
||||
100% {
|
||||
opacity: 0; } }
|
||||
|
||||
md-slider {
|
||||
height: 48px;
|
||||
position: relative;
|
||||
display: block;
|
||||
margin-left: 4px;
|
||||
margin-right: 4px;
|
||||
padding: 0;
|
||||
/**
|
||||
* Track
|
||||
*/
|
||||
/**
|
||||
* Slider thumb
|
||||
*/
|
||||
/* The sign that's focused in discrete mode */
|
||||
/**
|
||||
* The border/background that comes in when focused in non-discrete mode
|
||||
*/
|
||||
/* Don't animate left/right while panning */ }
|
||||
md-slider *, md-slider *:after {
|
||||
box-sizing: border-box; }
|
||||
md-slider .md-slider-wrapper {
|
||||
position: relative; }
|
||||
md-slider .md-track-container {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
top: 23px;
|
||||
height: 2px; }
|
||||
md-slider .md-track {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%; }
|
||||
md-slider .md-track-fill {
|
||||
transition: width 0.05s linear; }
|
||||
md-slider .md-track-ticks {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 100%; }
|
||||
md-slider .md-thumb-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||
transform: translate3d(-50%, -50%, 0);
|
||||
transition: left 0.1s linear; }
|
||||
md-slider .md-thumb {
|
||||
z-index: 1;
|
||||
position: absolute;
|
||||
left: -19px;
|
||||
top: 5px;
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border-radius: 38px;
|
||||
-webkit-transform: scale(0.5);
|
||||
transform: scale(0.5);
|
||||
transition: all 0.1s linear; }
|
||||
md-slider .md-thumb:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
top: 3px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 32px;
|
||||
border-width: 3px;
|
||||
border-style: solid; }
|
||||
md-slider .md-sign {
|
||||
/* Center the children (slider-thumb-text) */
|
||||
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;
|
||||
position: absolute;
|
||||
left: -14px;
|
||||
top: -20px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
border-radius: 28px;
|
||||
-webkit-transform: scale(0.4) translate3d(0, 70px, 0);
|
||||
transform: scale(0.4) translate3d(0, 70px, 0);
|
||||
transition: all 0.2s ease-in-out;
|
||||
/* The arrow pointing down under the sign */ }
|
||||
md-slider .md-sign:after {
|
||||
position: absolute;
|
||||
content: '';
|
||||
left: 0px;
|
||||
border-radius: 16px;
|
||||
top: 19px;
|
||||
border-left: 14px solid transparent;
|
||||
border-right: 14px solid transparent;
|
||||
border-top-width: 16px;
|
||||
border-top-style: solid;
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, -8px, 0);
|
||||
transform: translate3d(0, -8px, 0);
|
||||
transition: all 0.2s ease-in-out; }
|
||||
md-slider .md-sign .md-thumb-text {
|
||||
z-index: 1;
|
||||
font-size: 12px;
|
||||
font-weight: bold; }
|
||||
md-slider .md-focus-thumb {
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: 0px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 48px;
|
||||
display: none;
|
||||
opacity: 0;
|
||||
background-color: #C0C0C0;
|
||||
-webkit-animation: sliderFocusThumb 0.4s linear;
|
||||
animation: sliderFocusThumb 0.4s linear; }
|
||||
md-slider .md-focus-ring {
|
||||
position: absolute;
|
||||
left: -24px;
|
||||
top: 0px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
border-radius: 48px;
|
||||
border: 2px solid #D6D6D6;
|
||||
background-color: transparent;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
transition: all 0.2s linear; }
|
||||
md-slider .md-disabled-thumb {
|
||||
position: absolute;
|
||||
left: -22px;
|
||||
top: 2px;
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
border-radius: 44px;
|
||||
-webkit-transform: scale(0.35);
|
||||
transform: scale(0.35);
|
||||
border-width: 6px;
|
||||
border-style: solid;
|
||||
display: none; }
|
||||
md-slider.md-min .md-thumb:after {
|
||||
background-color: white; }
|
||||
md-slider.md-min .md-sign {
|
||||
opacity: 0; }
|
||||
md-slider:focus {
|
||||
outline: none; }
|
||||
md-slider.dragging .md-thumb-container, md-slider.dragging .md-track-fill {
|
||||
transition: none; }
|
||||
md-slider:not([md-discrete]) {
|
||||
/* Hide the sign and ticks in non-discrete mode */ }
|
||||
md-slider:not([md-discrete]) .md-track-ticks, md-slider:not([md-discrete]) .md-sign {
|
||||
display: none; }
|
||||
md-slider:not([md-discrete]):not([disabled]):hover .md-thumb {
|
||||
-webkit-transform: scale(0.6);
|
||||
transform: scale(0.6); }
|
||||
md-slider:not([md-discrete]):not([disabled]):focus .md-focus-thumb, md-slider:not([md-discrete]):not([disabled]).active .md-focus-thumb {
|
||||
display: block; }
|
||||
md-slider:not([md-discrete]):not([disabled]):focus .md-focus-ring, md-slider:not([md-discrete]):not([disabled]).active .md-focus-ring {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
md-slider:not([md-discrete]):not([disabled]):focus .md-thumb, md-slider:not([md-discrete]):not([disabled]).active .md-thumb {
|
||||
-webkit-transform: scale(0.85);
|
||||
transform: scale(0.85); }
|
||||
md-slider[md-discrete] {
|
||||
/* Hide the focus thumb in discrete mode */ }
|
||||
md-slider[md-discrete] .md-focus-thumb, md-slider[md-discrete] .md-focus-ring {
|
||||
display: none; }
|
||||
md-slider[md-discrete]:not([disabled]):focus .md-sign, md-slider[md-discrete]:not([disabled]):focus .md-sign:after, md-slider[md-discrete]:not([disabled]).active .md-sign, md-slider[md-discrete]:not([disabled]).active .md-sign:after {
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0) scale(1);
|
||||
transform: translate3d(0, 0, 0) scale(1); }
|
||||
md-slider[disabled] .md-track-fill {
|
||||
display: none; }
|
||||
md-slider[disabled] .md-sign {
|
||||
display: none; }
|
||||
md-slider[disabled] .md-thumb {
|
||||
-webkit-transform: scale(0.35);
|
||||
transform: scale(0.35); }
|
||||
md-slider[disabled] .md-disabled-thumb {
|
||||
display: block; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-slider.md-default-theme .md-track {
|
||||
border-bottom: 1px solid #fff; } }
|
||||
403
www/lib/angular-material/modules/closure/slider/slider.js
vendored
Normal file
403
www/lib/angular-material/modules/closure/slider/slider.js
vendored
Normal file
@@ -0,0 +1,403 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.slider');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.slider
|
||||
*/
|
||||
angular.module('material.components.slider', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdSlider', SliderDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdSlider
|
||||
* @module material.components.slider
|
||||
* @restrict E
|
||||
* @description
|
||||
* The `<md-slider>` component allows the user to choose from a range of
|
||||
* values.
|
||||
*
|
||||
* As per the [material design spec](http://www.google.com/design/spec/style/color.html#color-ui-color-application)
|
||||
* the slider is in the accent color by default. The primary color palette may be used with
|
||||
* the `md-primary` class.
|
||||
*
|
||||
* It has two modes: 'normal' mode, where the user slides between a wide range
|
||||
* of values, and 'discrete' mode, where the user slides between only a few
|
||||
* select values.
|
||||
*
|
||||
* To enable discrete mode, add the `md-discrete` attribute to a slider,
|
||||
* and use the `step` attribute to change the distance between
|
||||
* values the user is allowed to pick.
|
||||
*
|
||||
* @usage
|
||||
* <h4>Normal Mode</h4>
|
||||
* <hljs lang="html">
|
||||
* <md-slider ng-model="myValue" min="5" max="500">
|
||||
* </md-slider>
|
||||
* </hljs>
|
||||
* <h4>Discrete Mode</h4>
|
||||
* <hljs lang="html">
|
||||
* <md-slider md-discrete ng-model="myDiscreteValue" step="10" min="10" max="130">
|
||||
* </md-slider>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {boolean=} md-discrete Whether to enable discrete mode.
|
||||
* @param {number=} step The distance between values the user is allowed to pick. Default 1.
|
||||
* @param {number=} min The minimum value the user is allowed to pick. Default 0.
|
||||
* @param {number=} max The maximum value the user is allowed to pick. Default 100.
|
||||
*/
|
||||
function SliderDirective($$rAF, $window, $mdAria, $mdUtil, $mdConstant, $mdTheming, $mdGesture, $parse) {
|
||||
return {
|
||||
scope: {},
|
||||
require: '?ngModel',
|
||||
template:
|
||||
'<div class="md-slider-wrapper">\
|
||||
<div class="md-track-container">\
|
||||
<div class="md-track"></div>\
|
||||
<div class="md-track md-track-fill"></div>\
|
||||
<div class="md-track-ticks"></div>\
|
||||
</div>\
|
||||
<div class="md-thumb-container">\
|
||||
<div class="md-thumb"></div>\
|
||||
<div class="md-focus-thumb"></div>\
|
||||
<div class="md-focus-ring"></div>\
|
||||
<div class="md-sign">\
|
||||
<span class="md-thumb-text"></span>\
|
||||
</div>\
|
||||
<div class="md-disabled-thumb"></div>\
|
||||
</div>\
|
||||
</div>',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
// **********************************************************
|
||||
// Private Methods
|
||||
// **********************************************************
|
||||
|
||||
function compile (tElement, tAttrs) {
|
||||
tElement.attr({
|
||||
tabIndex: 0,
|
||||
role: 'slider'
|
||||
});
|
||||
|
||||
$mdAria.expect(tElement, 'aria-label');
|
||||
|
||||
return postLink;
|
||||
}
|
||||
|
||||
function postLink(scope, element, attr, ngModelCtrl) {
|
||||
$mdTheming(element);
|
||||
ngModelCtrl = ngModelCtrl || {
|
||||
// Mock ngModelController if it doesn't exist to give us
|
||||
// the minimum functionality needed
|
||||
$setViewValue: function(val) {
|
||||
this.$viewValue = val;
|
||||
this.$viewChangeListeners.forEach(function(cb) { cb(); });
|
||||
},
|
||||
$parsers: [],
|
||||
$formatters: [],
|
||||
$viewChangeListeners: []
|
||||
};
|
||||
|
||||
var isDisabledParsed = attr.ngDisabled && $parse(attr.ngDisabled);
|
||||
var isDisabledGetter = isDisabledParsed ?
|
||||
function() { return isDisabledParsed(scope.$parent); } :
|
||||
angular.noop;
|
||||
var thumb = angular.element(element[0].querySelector('.md-thumb'));
|
||||
var thumbText = angular.element(element[0].querySelector('.md-thumb-text'));
|
||||
var thumbContainer = thumb.parent();
|
||||
var trackContainer = angular.element(element[0].querySelector('.md-track-container'));
|
||||
var activeTrack = angular.element(element[0].querySelector('.md-track-fill'));
|
||||
var tickContainer = angular.element(element[0].querySelector('.md-track-ticks'));
|
||||
var throttledRefreshDimensions = $mdUtil.throttle(refreshSliderDimensions, 5000);
|
||||
|
||||
// Default values, overridable by attrs
|
||||
angular.isDefined(attr.min) ? attr.$observe('min', updateMin) : updateMin(0);
|
||||
angular.isDefined(attr.max) ? attr.$observe('max', updateMax) : updateMax(100);
|
||||
angular.isDefined(attr.step)? attr.$observe('step', updateStep) : updateStep(1);
|
||||
|
||||
// We have to manually stop the $watch on ngDisabled because it exists
|
||||
// on the parent scope, and won't be automatically destroyed when
|
||||
// the component is destroyed.
|
||||
var stopDisabledWatch = angular.noop;
|
||||
if (attr.ngDisabled) {
|
||||
stopDisabledWatch = scope.$parent.$watch(attr.ngDisabled, updateAriaDisabled);
|
||||
}
|
||||
|
||||
$mdGesture.register(element, 'drag');
|
||||
|
||||
element
|
||||
.on('keydown', keydownListener)
|
||||
.on('$md.pressdown', onPressDown)
|
||||
.on('$md.pressup', onPressUp)
|
||||
.on('$md.dragstart', onDragStart)
|
||||
.on('$md.drag', onDrag)
|
||||
.on('$md.dragend', onDragEnd);
|
||||
|
||||
// On resize, recalculate the slider's dimensions and re-render
|
||||
function updateAll() {
|
||||
refreshSliderDimensions();
|
||||
ngModelRender();
|
||||
redrawTicks();
|
||||
}
|
||||
setTimeout(updateAll);
|
||||
|
||||
var debouncedUpdateAll = $$rAF.throttle(updateAll);
|
||||
angular.element($window).on('resize', debouncedUpdateAll);
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
angular.element($window).off('resize', debouncedUpdateAll);
|
||||
stopDisabledWatch();
|
||||
});
|
||||
|
||||
ngModelCtrl.$render = ngModelRender;
|
||||
ngModelCtrl.$viewChangeListeners.push(ngModelRender);
|
||||
ngModelCtrl.$formatters.push(minMaxValidator);
|
||||
ngModelCtrl.$formatters.push(stepValidator);
|
||||
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
var min;
|
||||
var max;
|
||||
var step;
|
||||
function updateMin(value) {
|
||||
min = parseFloat(value);
|
||||
element.attr('aria-valuemin', value);
|
||||
updateAll();
|
||||
}
|
||||
function updateMax(value) {
|
||||
max = parseFloat(value);
|
||||
element.attr('aria-valuemax', value);
|
||||
updateAll();
|
||||
}
|
||||
function updateStep(value) {
|
||||
step = parseFloat(value);
|
||||
redrawTicks();
|
||||
}
|
||||
function updateAriaDisabled(isDisabled) {
|
||||
element.attr('aria-disabled', !!isDisabled);
|
||||
}
|
||||
|
||||
// Draw the ticks with canvas.
|
||||
// The alternative to drawing ticks with canvas is to draw one element for each tick,
|
||||
// which could quickly become a performance bottleneck.
|
||||
var tickCanvas, tickCtx;
|
||||
function redrawTicks() {
|
||||
if (!angular.isDefined(attr.mdDiscrete)) return;
|
||||
|
||||
var numSteps = Math.floor( (max - min) / step );
|
||||
if (!tickCanvas) {
|
||||
var trackTicksStyle = $window.getComputedStyle(tickContainer[0]);
|
||||
tickCanvas = angular.element('<canvas style="position:absolute;">');
|
||||
tickCtx = tickCanvas[0].getContext('2d');
|
||||
tickCtx.fillStyle = trackTicksStyle.backgroundColor || 'black';
|
||||
tickContainer.append(tickCanvas);
|
||||
}
|
||||
var dimensions = getSliderDimensions();
|
||||
tickCanvas[0].width = dimensions.width;
|
||||
tickCanvas[0].height = dimensions.height;
|
||||
|
||||
var distance;
|
||||
for (var i = 0; i <= numSteps; i++) {
|
||||
distance = Math.floor(dimensions.width * (i / numSteps));
|
||||
tickCtx.fillRect(distance - 1, 0, 2, dimensions.height);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Refreshing Dimensions
|
||||
*/
|
||||
var sliderDimensions = {};
|
||||
refreshSliderDimensions();
|
||||
function refreshSliderDimensions() {
|
||||
sliderDimensions = trackContainer[0].getBoundingClientRect();
|
||||
}
|
||||
function getSliderDimensions() {
|
||||
throttledRefreshDimensions();
|
||||
return sliderDimensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* left/right arrow listener
|
||||
*/
|
||||
function keydownListener(ev) {
|
||||
if(element[0].hasAttribute('disabled')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var changeAmount;
|
||||
if (ev.keyCode === $mdConstant.KEY_CODE.LEFT_ARROW) {
|
||||
changeAmount = -step;
|
||||
} else if (ev.keyCode === $mdConstant.KEY_CODE.RIGHT_ARROW) {
|
||||
changeAmount = step;
|
||||
}
|
||||
if (changeAmount) {
|
||||
if (ev.metaKey || ev.ctrlKey || ev.altKey) {
|
||||
changeAmount *= 4;
|
||||
}
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
scope.$evalAsync(function() {
|
||||
setModelValue(ngModelCtrl.$viewValue + changeAmount);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ngModel setters and validators
|
||||
*/
|
||||
function setModelValue(value) {
|
||||
ngModelCtrl.$setViewValue( minMaxValidator(stepValidator(value)) );
|
||||
}
|
||||
function ngModelRender() {
|
||||
if (isNaN(ngModelCtrl.$viewValue)) {
|
||||
ngModelCtrl.$viewValue = ngModelCtrl.$modelValue;
|
||||
}
|
||||
|
||||
var percent = (ngModelCtrl.$viewValue - min) / (max - min);
|
||||
scope.modelValue = ngModelCtrl.$viewValue;
|
||||
element.attr('aria-valuenow', ngModelCtrl.$viewValue);
|
||||
setSliderPercent(percent);
|
||||
thumbText.text( ngModelCtrl.$viewValue );
|
||||
}
|
||||
|
||||
function minMaxValidator(value) {
|
||||
if (angular.isNumber(value)) {
|
||||
return Math.max(min, Math.min(max, value));
|
||||
}
|
||||
}
|
||||
function stepValidator(value) {
|
||||
if (angular.isNumber(value)) {
|
||||
var formattedValue = (Math.round(value / step) * step);
|
||||
// Format to 3 digits after the decimal point - fixes #2015.
|
||||
return (Math.round(formattedValue * 1000) / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param percent 0-1
|
||||
*/
|
||||
function setSliderPercent(percent) {
|
||||
activeTrack.css('width', (percent * 100) + '%');
|
||||
thumbContainer.css(
|
||||
'left',
|
||||
(percent * 100) + '%'
|
||||
);
|
||||
element.toggleClass('md-min', percent === 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Slide listeners
|
||||
*/
|
||||
var isDragging = false;
|
||||
var isDiscrete = angular.isDefined(attr.mdDiscrete);
|
||||
|
||||
function onPressDown(ev) {
|
||||
if (isDisabledGetter()) return;
|
||||
|
||||
element.addClass('active');
|
||||
element[0].focus();
|
||||
refreshSliderDimensions();
|
||||
|
||||
var exactVal = percentToValue( positionToPercent( ev.pointer.x ));
|
||||
var closestVal = minMaxValidator( stepValidator(exactVal) );
|
||||
scope.$apply(function() {
|
||||
setModelValue( closestVal );
|
||||
setSliderPercent( valueToPercent(closestVal));
|
||||
});
|
||||
}
|
||||
function onPressUp(ev) {
|
||||
if (isDisabledGetter()) return;
|
||||
|
||||
element.removeClass('dragging active');
|
||||
|
||||
var exactVal = percentToValue( positionToPercent( ev.pointer.x ));
|
||||
var closestVal = minMaxValidator( stepValidator(exactVal) );
|
||||
scope.$apply(function() {
|
||||
setModelValue(closestVal);
|
||||
ngModelRender();
|
||||
});
|
||||
}
|
||||
function onDragStart(ev) {
|
||||
if (isDisabledGetter()) return;
|
||||
isDragging = true;
|
||||
ev.stopPropagation();
|
||||
|
||||
element.addClass('dragging');
|
||||
setSliderFromEvent(ev);
|
||||
}
|
||||
function onDrag(ev) {
|
||||
if (!isDragging) return;
|
||||
ev.stopPropagation();
|
||||
setSliderFromEvent(ev);
|
||||
}
|
||||
function onDragEnd(ev) {
|
||||
if (!isDragging) return;
|
||||
ev.stopPropagation();
|
||||
isDragging = false;
|
||||
}
|
||||
|
||||
function setSliderFromEvent(ev) {
|
||||
// While panning discrete, update only the
|
||||
// visual positioning but not the model value.
|
||||
if ( isDiscrete ) adjustThumbPosition( ev.pointer.x );
|
||||
else doSlide( ev.pointer.x );
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide the UI by changing the model value
|
||||
* @param x
|
||||
*/
|
||||
function doSlide( x ) {
|
||||
scope.$evalAsync( function() {
|
||||
setModelValue( percentToValue( positionToPercent(x) ));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Slide the UI without changing the model (while dragging/panning)
|
||||
* @param x
|
||||
*/
|
||||
function adjustThumbPosition( x ) {
|
||||
var exactVal = percentToValue( positionToPercent( x ));
|
||||
var closestVal = minMaxValidator( stepValidator(exactVal) );
|
||||
setSliderPercent( positionToPercent(x) );
|
||||
thumbText.text( closestVal );
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert horizontal position on slider to percentage value of offset from beginning...
|
||||
* @param x
|
||||
* @returns {number}
|
||||
*/
|
||||
function positionToPercent( x ) {
|
||||
return Math.max(0, Math.min(1, (x - sliderDimensions.left) / (sliderDimensions.width)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert percentage offset on slide to equivalent model value
|
||||
* @param percent
|
||||
* @returns {*}
|
||||
*/
|
||||
function percentToValue( percent ) {
|
||||
return (min + percent * (max - min));
|
||||
}
|
||||
|
||||
function valueToPercent( val ) {
|
||||
return (val - min)/(max - min);
|
||||
}
|
||||
}
|
||||
}
|
||||
SliderDirective.$inject = ["$$rAF", "$window", "$mdAria", "$mdUtil", "$mdConstant", "$mdTheming", "$mdGesture", "$parse"];
|
||||
|
||||
ng.material.components.slider = angular.module("material.components.slider");
|
||||
21
www/lib/angular-material/modules/closure/sticky/sticky.css
Normal file
21
www/lib/angular-material/modules/closure/sticky/sticky.css
Normal file
@@ -0,0 +1,21 @@
|
||||
/*!
|
||||
* 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-sticky-clone {
|
||||
z-index: 2;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
position: absolute !important;
|
||||
-webkit-transform: translate3d(-9999px, -9999px, 0);
|
||||
transform: translate3d(-9999px, -9999px, 0); }
|
||||
.md-sticky-clone[sticky-state="active"] {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
.md-sticky-clone[sticky-state="active"]:not(.md-sticky-no-effect) .md-subheader-inner {
|
||||
-webkit-animation: subheaderStickyHoverIn 0.3s ease-out both;
|
||||
animation: subheaderStickyHoverIn 0.3s ease-out both; }
|
||||
315
www/lib/angular-material/modules/closure/sticky/sticky.js
vendored
Normal file
315
www/lib/angular-material/modules/closure/sticky/sticky.js
vendored
Normal file
@@ -0,0 +1,315 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.sticky');
|
||||
goog.require('ng.material.components.content');
|
||||
goog.require('ng.material.core');
|
||||
/*
|
||||
* @ngdoc module
|
||||
* @name material.components.sticky
|
||||
* @description
|
||||
*
|
||||
* Sticky effects for md
|
||||
*/
|
||||
|
||||
angular.module('material.components.sticky', [
|
||||
'material.core',
|
||||
'material.components.content'
|
||||
])
|
||||
.factory('$mdSticky', MdSticky);
|
||||
|
||||
/*
|
||||
* @ngdoc service
|
||||
* @name $mdSticky
|
||||
* @module material.components.sticky
|
||||
*
|
||||
* @description
|
||||
* The `$mdSticky`service provides a mixin to make elements sticky.
|
||||
*
|
||||
* @returns A `$mdSticky` function that takes three arguments:
|
||||
* - `scope`
|
||||
* - `element`: The element that will be 'sticky'
|
||||
* - `elementClone`: A clone of the element, that will be shown
|
||||
* when the user starts scrolling past the original element.
|
||||
* If not provided, it will use the result of `element.clone()`.
|
||||
*/
|
||||
|
||||
function MdSticky($document, $mdConstant, $compile, $$rAF, $mdUtil) {
|
||||
|
||||
var browserStickySupport = checkStickySupport();
|
||||
|
||||
/**
|
||||
* Registers an element as sticky, used internally by directives to register themselves
|
||||
*/
|
||||
return function registerStickyElement(scope, element, stickyClone) {
|
||||
var contentCtrl = element.controller('mdContent');
|
||||
if (!contentCtrl) return;
|
||||
|
||||
if (browserStickySupport) {
|
||||
element.css({
|
||||
position: browserStickySupport,
|
||||
top: 0,
|
||||
'z-index': 2
|
||||
});
|
||||
} else {
|
||||
var $$sticky = contentCtrl.$element.data('$$sticky');
|
||||
if (!$$sticky) {
|
||||
$$sticky = setupSticky(contentCtrl);
|
||||
contentCtrl.$element.data('$$sticky', $$sticky);
|
||||
}
|
||||
|
||||
var deregister = $$sticky.add(element, stickyClone || element.clone());
|
||||
scope.$on('$destroy', deregister);
|
||||
}
|
||||
};
|
||||
|
||||
function setupSticky(contentCtrl) {
|
||||
var contentEl = contentCtrl.$element;
|
||||
|
||||
// Refresh elements is very expensive, so we use the debounced
|
||||
// version when possible.
|
||||
var debouncedRefreshElements = $$rAF.throttle(refreshElements);
|
||||
|
||||
// setupAugmentedScrollEvents gives us `$scrollstart` and `$scroll`,
|
||||
// more reliable than `scroll` on android.
|
||||
setupAugmentedScrollEvents(contentEl);
|
||||
contentEl.on('$scrollstart', debouncedRefreshElements);
|
||||
contentEl.on('$scroll', onScroll);
|
||||
|
||||
var self;
|
||||
var stickyBaseoffset = contentEl.prop('offsetTop');
|
||||
return self = {
|
||||
prev: null,
|
||||
current: null, //the currently stickied item
|
||||
next: null,
|
||||
items: [],
|
||||
add: add,
|
||||
refreshElements: refreshElements
|
||||
};
|
||||
|
||||
/***************
|
||||
* Public
|
||||
***************/
|
||||
// Add an element and its sticky clone to this content's sticky collection
|
||||
function add(element, stickyClone) {
|
||||
stickyClone.addClass('md-sticky-clone');
|
||||
stickyClone.css('top', stickyBaseoffset + 'px');
|
||||
|
||||
var item = {
|
||||
element: element,
|
||||
clone: stickyClone
|
||||
};
|
||||
self.items.push(item);
|
||||
|
||||
contentEl.parent().prepend(item.clone);
|
||||
|
||||
debouncedRefreshElements();
|
||||
|
||||
return function remove() {
|
||||
self.items.forEach(function(item, index) {
|
||||
if (item.element[0] === element[0]) {
|
||||
self.items.splice(index, 1);
|
||||
item.clone.remove();
|
||||
}
|
||||
});
|
||||
debouncedRefreshElements();
|
||||
};
|
||||
}
|
||||
|
||||
function refreshElements() {
|
||||
// Sort our collection of elements by their current position in the DOM.
|
||||
// We need to do this because our elements' order of being added may not
|
||||
// be the same as their order of display.
|
||||
self.items.forEach(refreshPosition);
|
||||
self.items = self.items.sort(function(a, b) {
|
||||
return a.top < b.top ? -1 : 1;
|
||||
});
|
||||
|
||||
// Find which item in the list should be active,
|
||||
// based upon the content's current scroll position
|
||||
var item;
|
||||
var currentScrollTop = contentEl.prop('scrollTop');
|
||||
for (var i = self.items.length - 1; i >= 0; i--) {
|
||||
if (currentScrollTop > self.items[i].top) {
|
||||
item = self.items[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
setCurrentItem(item);
|
||||
}
|
||||
|
||||
|
||||
/***************
|
||||
* Private
|
||||
***************/
|
||||
|
||||
// Find the `top` of an item relative to the content element,
|
||||
// and also the height.
|
||||
function refreshPosition(item) {
|
||||
// Find the top of an item by adding to the offsetHeight until we reach the
|
||||
// content element.
|
||||
var current = item.element[0];
|
||||
item.top = 0;
|
||||
item.left = 0;
|
||||
while (current && current !== contentEl[0]) {
|
||||
item.top += current.offsetTop;
|
||||
item.left += current.offsetLeft;
|
||||
current = current.offsetParent;
|
||||
}
|
||||
item.height = item.element.prop('offsetHeight');
|
||||
item.clone.css('margin-left', item.left + 'px');
|
||||
if ($mdUtil.floatingScrollbars()) {
|
||||
item.clone.css('margin-right', '0');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// As we scroll, push in and select the correct sticky element.
|
||||
function onScroll() {
|
||||
var scrollTop = contentEl.prop('scrollTop');
|
||||
var isScrollingDown = scrollTop > (onScroll.prevScrollTop || 0);
|
||||
onScroll.prevScrollTop = scrollTop;
|
||||
|
||||
// At the top?
|
||||
if (scrollTop === 0) {
|
||||
setCurrentItem(null);
|
||||
|
||||
// Going to next item?
|
||||
} else if (isScrollingDown && self.next) {
|
||||
if (self.next.top - scrollTop <= 0) {
|
||||
// Sticky the next item if we've scrolled past its position.
|
||||
setCurrentItem(self.next);
|
||||
} else if (self.current) {
|
||||
// Push the current item up when we're almost at the next item.
|
||||
if (self.next.top - scrollTop <= self.next.height) {
|
||||
translate(self.current, self.next.top - self.next.height - scrollTop);
|
||||
} else {
|
||||
translate(self.current, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Scrolling up with a current sticky item?
|
||||
} else if (!isScrollingDown && self.current) {
|
||||
if (scrollTop < self.current.top) {
|
||||
// Sticky the previous item if we've scrolled up past
|
||||
// the original position of the currently stickied item.
|
||||
setCurrentItem(self.prev);
|
||||
}
|
||||
// Scrolling up, and just bumping into the item above (just set to current)?
|
||||
// If we have a next item bumping into the current item, translate
|
||||
// the current item up from the top as it scrolls into view.
|
||||
if (self.current && self.next) {
|
||||
if (scrollTop >= self.next.top - self.current.height) {
|
||||
translate(self.current, self.next.top - scrollTop - self.current.height);
|
||||
} else {
|
||||
translate(self.current, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function setCurrentItem(item) {
|
||||
if (self.current === item) return;
|
||||
// Deactivate currently active item
|
||||
if (self.current) {
|
||||
translate(self.current, null);
|
||||
setStickyState(self.current, null);
|
||||
}
|
||||
|
||||
// Activate new item if given
|
||||
if (item) {
|
||||
setStickyState(item, 'active');
|
||||
}
|
||||
|
||||
self.current = item;
|
||||
var index = self.items.indexOf(item);
|
||||
// If index === -1, index + 1 = 0. It works out.
|
||||
self.next = self.items[index + 1];
|
||||
self.prev = self.items[index - 1];
|
||||
setStickyState(self.next, 'next');
|
||||
setStickyState(self.prev, 'prev');
|
||||
}
|
||||
|
||||
function setStickyState(item, state) {
|
||||
if (!item || item.state === state) return;
|
||||
if (item.state) {
|
||||
item.clone.attr('sticky-prev-state', item.state);
|
||||
item.element.attr('sticky-prev-state', item.state);
|
||||
}
|
||||
item.clone.attr('sticky-state', state);
|
||||
item.element.attr('sticky-state', state);
|
||||
item.state = state;
|
||||
}
|
||||
|
||||
function translate(item, amount) {
|
||||
if (!item) return;
|
||||
if (amount === null || amount === undefined) {
|
||||
if (item.translateY) {
|
||||
item.translateY = null;
|
||||
item.clone.css($mdConstant.CSS.TRANSFORM, '');
|
||||
}
|
||||
} else {
|
||||
item.translateY = amount;
|
||||
item.clone.css(
|
||||
$mdConstant.CSS.TRANSFORM,
|
||||
'translate3d(' + item.left + 'px,' + amount + 'px,0)'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to check for browser sticky support
|
||||
function checkStickySupport($el) {
|
||||
var stickyProp;
|
||||
var testEl = angular.element('<div>');
|
||||
$document[0].body.appendChild(testEl[0]);
|
||||
|
||||
var stickyProps = ['sticky', '-webkit-sticky'];
|
||||
for (var i = 0; i < stickyProps.length; ++i) {
|
||||
testEl.css({position: stickyProps[i], top: 0, 'z-index': 2});
|
||||
if (testEl.css('position') == stickyProps[i]) {
|
||||
stickyProp = stickyProps[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
testEl.remove();
|
||||
return stickyProp;
|
||||
}
|
||||
|
||||
// Android 4.4 don't accurately give scroll events.
|
||||
// To fix this problem, we setup a fake scroll event. We say:
|
||||
// > If a scroll or touchmove event has happened in the last DELAY milliseconds,
|
||||
// then send a `$scroll` event every animationFrame.
|
||||
// Additionally, we add $scrollstart and $scrollend events.
|
||||
function setupAugmentedScrollEvents(element) {
|
||||
var SCROLL_END_DELAY = 200;
|
||||
var isScrolling;
|
||||
var lastScrollTime;
|
||||
element.on('scroll touchmove', function() {
|
||||
if (!isScrolling) {
|
||||
isScrolling = true;
|
||||
$$rAF(loopScrollEvent);
|
||||
element.triggerHandler('$scrollstart');
|
||||
}
|
||||
element.triggerHandler('$scroll');
|
||||
lastScrollTime = +$mdUtil.now();
|
||||
});
|
||||
|
||||
function loopScrollEvent() {
|
||||
if (+$mdUtil.now() - lastScrollTime > SCROLL_END_DELAY) {
|
||||
isScrolling = false;
|
||||
element.triggerHandler('$scrollend');
|
||||
} else {
|
||||
element.triggerHandler('$scroll');
|
||||
$$rAF(loopScrollEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MdSticky.$inject = ["$document", "$mdConstant", "$compile", "$$rAF", "$mdUtil"];
|
||||
|
||||
ng.material.components.sticky = angular.module("material.components.sticky");
|
||||
@@ -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-subheader.md-THEME_NAME-theme {
|
||||
color: '{{ foreground-2-0.23 }}';
|
||||
background-color: '{{background-color}}'; }
|
||||
.md-subheader.md-THEME_NAME-theme.md-primary {
|
||||
color: '{{primary-color}}'; }
|
||||
.md-subheader.md-THEME_NAME-theme.md-accent {
|
||||
color: '{{accent-color}}'; }
|
||||
.md-subheader.md-THEME_NAME-theme.md-warn {
|
||||
color: '{{warn-color}}'; }
|
||||
@@ -0,0 +1,63 @@
|
||||
/*!
|
||||
* 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 subheaderStickyHoverIn {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 transparent; }
|
||||
|
||||
100% {
|
||||
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); } }
|
||||
@keyframes subheaderStickyHoverIn {
|
||||
0% {
|
||||
box-shadow: 0 0 0 0 transparent; }
|
||||
|
||||
100% {
|
||||
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); } }
|
||||
|
||||
@-webkit-keyframes subheaderStickyHoverOut {
|
||||
0% {
|
||||
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); }
|
||||
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent; } }
|
||||
|
||||
@keyframes subheaderStickyHoverOut {
|
||||
0% {
|
||||
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.16); }
|
||||
|
||||
100% {
|
||||
box-shadow: 0 0 0 0 transparent; } }
|
||||
|
||||
.md-subheader {
|
||||
display: block;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1em;
|
||||
margin: 0 0 0 0;
|
||||
margin-right: 16px;
|
||||
position: relative; }
|
||||
.md-subheader .md-subheader-inner {
|
||||
padding: 16px 0px 16px 16px; }
|
||||
.md-subheader:not(.md-sticky-no-effect) {
|
||||
transition: 0.2s ease-out margin; }
|
||||
.md-subheader:not(.md-sticky-no-effect):after {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
right: -16px;
|
||||
content: ''; }
|
||||
.md-subheader:not(.md-sticky-no-effect).md-sticky-clone {
|
||||
z-index: 2; }
|
||||
.md-subheader:not(.md-sticky-no-effect)[sticky-state="active"] {
|
||||
margin-top: -2px; }
|
||||
.md-subheader:not(.md-sticky-no-effect):not(.md-sticky-clone)[sticky-prev-state="active"] .md-subheader-inner:after {
|
||||
-webkit-animation: subheaderStickyHoverOut 0.3s ease-out both;
|
||||
animation: subheaderStickyHoverOut 0.3s ease-out both; }
|
||||
.md-subheader .md-subheader-content {
|
||||
z-index: 1;
|
||||
position: relative; }
|
||||
93
www/lib/angular-material/modules/closure/subheader/subheader.js
vendored
Normal file
93
www/lib/angular-material/modules/closure/subheader/subheader.js
vendored
Normal file
@@ -0,0 +1,93 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.subheader');
|
||||
goog.require('ng.material.components.sticky');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.subheader
|
||||
* @description
|
||||
* SubHeader module
|
||||
*
|
||||
* Subheaders are special list tiles that delineate distinct sections of a
|
||||
* list or grid list and are typically related to the current filtering or
|
||||
* sorting criteria. Subheader tiles are either displayed inline with tiles or
|
||||
* can be associated with content, for example, in an adjacent column.
|
||||
*
|
||||
* Upon scrolling, subheaders remain pinned to the top of the screen and remain
|
||||
* pinned until pushed on or off screen by the next subheader. @see [Material
|
||||
* Design Specifications](https://www.google.com/design/spec/components/subheaders.html)
|
||||
*
|
||||
* > To improve the visual grouping of content, use the system color for your subheaders.
|
||||
*
|
||||
*/
|
||||
angular.module('material.components.subheader', [
|
||||
'material.core',
|
||||
'material.components.sticky'
|
||||
])
|
||||
.directive('mdSubheader', MdSubheaderDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdSubheader
|
||||
* @module material.components.subheader
|
||||
*
|
||||
* @restrict E
|
||||
*
|
||||
* @description
|
||||
* The `<md-subheader>` directive is a subheader for a section. By default it is sticky.
|
||||
* You can make it not sticky by applying the `md-no-sticky` class to the subheader.
|
||||
*
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-subheader>Online Friends</md-subheader>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
function MdSubheaderDirective($mdSticky, $compile, $mdTheming) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: true,
|
||||
template:
|
||||
'<h2 class="md-subheader">' +
|
||||
'<div class="md-subheader-inner">' +
|
||||
'<span class="md-subheader-content"></span>' +
|
||||
'</div>' +
|
||||
'</h2>',
|
||||
compile: function(element, attr, transclude) {
|
||||
return function postLink(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
var outerHTML = element[0].outerHTML;
|
||||
|
||||
function getContent(el) {
|
||||
return angular.element(el[0].querySelector('.md-subheader-content'));
|
||||
}
|
||||
|
||||
// Transclude the user-given contents of the subheader
|
||||
// the conventional way.
|
||||
transclude(scope, function(clone) {
|
||||
getContent(element).append(clone);
|
||||
});
|
||||
|
||||
// Create another clone, that uses the outer and inner contents
|
||||
// of the element, that will be 'stickied' as the user scrolls.
|
||||
if (!element.hasClass('md-no-sticky')) {
|
||||
transclude(scope, function(clone) {
|
||||
var stickyClone = $compile(angular.element(outerHTML))(scope);
|
||||
getContent(stickyClone).append(clone);
|
||||
$mdSticky(scope, element, stickyClone);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
MdSubheaderDirective.$inject = ["$mdSticky", "$compile", "$mdTheming"];
|
||||
|
||||
ng.material.components.subheader = angular.module("material.components.subheader");
|
||||
72
www/lib/angular-material/modules/closure/swipe/swipe.js
vendored
Normal file
72
www/lib/angular-material/modules/closure/swipe/swipe.js
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.swipe');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.swipe
|
||||
* @description Swipe module!
|
||||
*/
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module material.components.swipe
|
||||
* @name mdSwipeLeft
|
||||
*
|
||||
* @restrict A
|
||||
*
|
||||
* @description
|
||||
* The md-swipe-left directives allows you to specify custom behavior when an element is swiped
|
||||
* left.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div md-swipe-left="onSwipeLeft()">Swipe me left!</div>
|
||||
* </hljs>
|
||||
*/
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @module material.components.swipe
|
||||
* @name mdSwipeRight
|
||||
*
|
||||
* @restrict A
|
||||
*
|
||||
* @description
|
||||
* The md-swipe-right directives allows you to specify custom behavior when an element is swiped
|
||||
* right.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div md-swipe-right="onSwipeRight()">Swipe me right!</div>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
angular.module('material.components.swipe', ['material.core'])
|
||||
.directive('mdSwipeLeft', getDirective('SwipeLeft'))
|
||||
.directive('mdSwipeRight', getDirective('SwipeRight'));
|
||||
|
||||
function getDirective(name) {
|
||||
var directiveName = 'md' + name;
|
||||
var eventName = '$md.' + name.toLowerCase();
|
||||
|
||||
DirectiveFactory.$inject = ["$parse"];
|
||||
return DirectiveFactory;
|
||||
|
||||
/* ngInject */
|
||||
function DirectiveFactory($parse) {
|
||||
return { restrict: 'A', link: postLink };
|
||||
function postLink(scope, element, attr) {
|
||||
var fn = $parse(attr[directiveName]);
|
||||
element.on(eventName, function(ev) {
|
||||
scope.$apply(function() { fn(scope, { $event: ev }); });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
ng.material.components.swipe = angular.module("material.components.swipe");
|
||||
@@ -0,0 +1,33 @@
|
||||
/*!
|
||||
* 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-switch.md-THEME_NAME-theme .md-thumb {
|
||||
background-color: '{{background-50}}'; }
|
||||
md-switch.md-THEME_NAME-theme .md-bar {
|
||||
background-color: '{{background-500}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked .md-thumb {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked .md-bar {
|
||||
background-color: '{{accent-color-0.5}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-focused .md-thumb:before {
|
||||
background-color: '{{accent-color-0.26}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-thumb {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-primary .md-bar {
|
||||
background-color: '{{primary-color-0.5}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-primary.md-focused .md-thumb:before {
|
||||
background-color: '{{primary-color-0.26}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-thumb {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-warn .md-bar {
|
||||
background-color: '{{warn-color-0.5}}'; }
|
||||
md-switch.md-THEME_NAME-theme.md-checked.md-warn.md-focused .md-thumb:before {
|
||||
background-color: '{{warn-color-0.26}}'; }
|
||||
md-switch.md-THEME_NAME-theme[disabled] .md-thumb {
|
||||
background-color: '{{background-400}}'; }
|
||||
md-switch.md-THEME_NAME-theme[disabled] .md-bar {
|
||||
background-color: '{{foreground-4}}'; }
|
||||
110
www/lib/angular-material/modules/closure/switch/switch.css
Normal file
110
www/lib/angular-material/modules/closure/switch/switch.css
Normal file
@@ -0,0 +1,110 @@
|
||||
/*!
|
||||
* 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-switch {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
margin: 15px;
|
||||
white-space: nowrap;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none; }
|
||||
md-switch .md-container {
|
||||
cursor: -webkit-grab;
|
||||
cursor: grab;
|
||||
width: 36px;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
margin-right: 8px; }
|
||||
md-switch:not([disabled]) .md-dragging, md-switch:not([disabled]).md-dragging .md-container {
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: grabbing; }
|
||||
md-switch.md-focused:not([disabled]) .md-thumb:before {
|
||||
left: -8px;
|
||||
top: -8px;
|
||||
right: -8px;
|
||||
bottom: -8px; }
|
||||
md-switch.md-focused:not([disabled]):not(.md-checked) .md-thumb:before {
|
||||
background-color: rgba(0, 0, 0, 0.12); }
|
||||
md-switch .md-label {
|
||||
border-color: transparent;
|
||||
border-width: 0; }
|
||||
md-switch .md-bar {
|
||||
left: 1px;
|
||||
width: 34px;
|
||||
top: 5px;
|
||||
height: 14px;
|
||||
border-radius: 8px;
|
||||
position: absolute; }
|
||||
md-switch .md-thumb-container {
|
||||
top: 2px;
|
||||
left: 0;
|
||||
width: 16px;
|
||||
position: absolute;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
z-index: 1; }
|
||||
md-switch.md-checked .md-thumb-container {
|
||||
-webkit-transform: translate3d(100%, 0, 0);
|
||||
transform: translate3d(100%, 0, 0); }
|
||||
md-switch .md-thumb {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
outline: none;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-radius: 50%;
|
||||
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-switch .md-thumb: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-switch .md-thumb .md-ripple-container {
|
||||
position: absolute;
|
||||
display: block;
|
||||
width: auto;
|
||||
height: auto;
|
||||
left: -20px;
|
||||
top: -20px;
|
||||
right: -20px;
|
||||
bottom: -20px; }
|
||||
md-switch:not(.md-dragging) .md-bar, md-switch:not(.md-dragging) .md-thumb-container, md-switch:not(.md-dragging) .md-thumb {
|
||||
transition: all 0.5s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition-property: -webkit-transform, background-color;
|
||||
transition-property: transform, background-color; }
|
||||
md-switch:not(.md-dragging) .md-bar, md-switch:not(.md-dragging) .md-thumb {
|
||||
transition-delay: 0.05s; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-switch.md-default-theme .md-bar {
|
||||
background-color: #666; }
|
||||
md-switch.md-default-theme.md-checked .md-bar {
|
||||
background-color: #9E9E9E; }
|
||||
md-switch.md-default-theme .md-thumb {
|
||||
background-color: #fff; } }
|
||||
169
www/lib/angular-material/modules/closure/switch/switch.js
vendored
Normal file
169
www/lib/angular-material/modules/closure/switch/switch.js
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.switch');
|
||||
goog.require('ng.material.components.checkbox');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @private
|
||||
* @ngdoc module
|
||||
* @name material.components.switch
|
||||
*/
|
||||
|
||||
angular.module('material.components.switch', [
|
||||
'material.core',
|
||||
'material.components.checkbox'
|
||||
])
|
||||
.directive('mdSwitch', MdSwitch);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @ngdoc directive
|
||||
* @module material.components.switch
|
||||
* @name mdSwitch
|
||||
* @restrict E
|
||||
*
|
||||
* The switch directive is used very much 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 switch 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 Publish the button label used by screen-readers for accessibility. Defaults to the switch's text.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-switch ng-model="isActive" aria-label="Finished?">
|
||||
* Finished ?
|
||||
* </md-switch>
|
||||
*
|
||||
* <md-switch md-no-ink ng-model="hasInk" aria-label="No Ink Effects">
|
||||
* No Ink Effects
|
||||
* </md-switch>
|
||||
*
|
||||
* <md-switch ng-disabled="true" ng-model="isDisabled" aria-label="Disabled">
|
||||
* Disabled
|
||||
* </md-switch>
|
||||
*
|
||||
* </hljs>
|
||||
*/
|
||||
function MdSwitch(mdCheckboxDirective, $mdTheming, $mdUtil, $document, $mdConstant, $parse, $$rAF, $mdGesture) {
|
||||
var checkboxDirective = mdCheckboxDirective[0];
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
priority:210, // Run before ngAria
|
||||
transclude: true,
|
||||
template:
|
||||
'<div class="md-container">' +
|
||||
'<div class="md-bar"></div>' +
|
||||
'<div class="md-thumb-container">' +
|
||||
'<div class="md-thumb" md-ink-ripple md-ink-ripple-checkbox></div>' +
|
||||
'</div>'+
|
||||
'</div>' +
|
||||
'<div ng-transclude class="md-label">' +
|
||||
'</div>',
|
||||
require: '?ngModel',
|
||||
compile: compile
|
||||
};
|
||||
|
||||
function compile(element, attr) {
|
||||
var checkboxLink = checkboxDirective.compile(element, attr);
|
||||
// no transition on initial load
|
||||
element.addClass('md-dragging');
|
||||
|
||||
return function (scope, element, attr, ngModel) {
|
||||
ngModel = ngModel || $mdUtil.fakeNgModel();
|
||||
var disabledGetter = $parse(attr.ngDisabled);
|
||||
var thumbContainer = angular.element(element[0].querySelector('.md-thumb-container'));
|
||||
var switchContainer = angular.element(element[0].querySelector('.md-container'));
|
||||
|
||||
// no transition on initial load
|
||||
$$rAF(function() {
|
||||
element.removeClass('md-dragging');
|
||||
});
|
||||
|
||||
checkboxLink(scope, element, attr, ngModel);
|
||||
|
||||
if (angular.isDefined(attr.ngDisabled)) {
|
||||
scope.$watch(disabledGetter, function(isDisabled) {
|
||||
element.attr('tabindex', isDisabled ? -1 : 0);
|
||||
});
|
||||
}
|
||||
|
||||
// These events are triggered by setup drag
|
||||
$mdGesture.register(switchContainer, 'drag');
|
||||
switchContainer
|
||||
.on('$md.dragstart', onDragStart)
|
||||
.on('$md.drag', onDrag)
|
||||
.on('$md.dragend', onDragEnd);
|
||||
|
||||
var drag;
|
||||
function onDragStart(ev) {
|
||||
// Don't go if ng-disabled===true
|
||||
if (disabledGetter(scope)) return;
|
||||
ev.stopPropagation();
|
||||
|
||||
element.addClass('md-dragging');
|
||||
drag = {
|
||||
width: thumbContainer.prop('offsetWidth')
|
||||
};
|
||||
element.removeClass('transition');
|
||||
}
|
||||
|
||||
function onDrag(ev) {
|
||||
if (!drag) return;
|
||||
ev.stopPropagation();
|
||||
ev.srcEvent && ev.srcEvent.preventDefault();
|
||||
|
||||
var percent = ev.pointer.distanceX / drag.width;
|
||||
|
||||
//if checked, start from right. else, start from left
|
||||
var translate = ngModel.$viewValue ? 1 + percent : percent;
|
||||
// Make sure the switch stays inside its bounds, 0-1%
|
||||
translate = Math.max(0, Math.min(1, translate));
|
||||
|
||||
thumbContainer.css($mdConstant.CSS.TRANSFORM, 'translate3d(' + (100*translate) + '%,0,0)');
|
||||
drag.translate = translate;
|
||||
}
|
||||
|
||||
function onDragEnd(ev) {
|
||||
if (!drag) return;
|
||||
ev.stopPropagation();
|
||||
|
||||
element.removeClass('md-dragging');
|
||||
thumbContainer.css($mdConstant.CSS.TRANSFORM, '');
|
||||
|
||||
// We changed if there is no distance (this is a click a click),
|
||||
// or if the drag distance is >50% of the total.
|
||||
var isChanged = ngModel.$viewValue ? drag.translate < 0.5 : drag.translate > 0.5;
|
||||
if (isChanged) {
|
||||
applyModelValue(!ngModel.$viewValue);
|
||||
}
|
||||
drag = null;
|
||||
}
|
||||
|
||||
function applyModelValue(newValue) {
|
||||
scope.$apply(function() {
|
||||
ngModel.$setViewValue(newValue);
|
||||
ngModel.$render();
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
MdSwitch.$inject = ["mdCheckboxDirective", "$mdTheming", "$mdUtil", "$document", "$mdConstant", "$parse", "$$rAF", "$mdGesture"];
|
||||
|
||||
ng.material.components.switch = angular.module("material.components.switch");
|
||||
@@ -0,0 +1,7 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.7.1-master-b48be15
|
||||
*/
|
||||
<?xml version="1.0" encoding="utf-8"?> <!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> <svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="24px" height="24px" viewBox="0 0 24 24" enable-background="new 0 0 24 24" xml:space="preserve"> <g id="Header"> <g> <rect x="-618" y="-1208" fill="none" width="1400" height="3600"/> </g> </g> <g id="Label"> </g> <g id="Icon"> <g> <polygon points="15.4,7.4 14,6 8,12 14,18 15.4,16.6 10.8,12 " style="fill:white;"/> <rect fill="none" width="24" height="24"/> </g> </g> <g id="Grid" display="none"> <g display="inline"> </g> </g> </svg>
|
||||
@@ -0,0 +1,82 @@
|
||||
/*!
|
||||
* 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-tabs.md-THEME_NAME-theme md-tabs-wrapper {
|
||||
background-color: transparent;
|
||||
border-color: '{{foreground-4}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-paginator md-icon {
|
||||
color: '{{primary-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme md-ink-bar {
|
||||
color: '{{accent-color}}';
|
||||
background: '{{accent-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-tab {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-tab[disabled] {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-tab.md-active, md-tabs.md-THEME_NAME-theme .md-tab.md-focused {
|
||||
color: '{{primary-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-tab.md-focused {
|
||||
background: '{{primary-color-0.1}}'; }
|
||||
md-tabs.md-THEME_NAME-theme .md-tab .md-ripple-container {
|
||||
color: '{{accent-100}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-accent md-tabs-wrapper {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]) {
|
||||
color: '{{accent-100}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{accent-contrast}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-accent md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{accent-contrast-0.1}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-accent md-ink-bar {
|
||||
color: '{{primary-600-1}}';
|
||||
background: '{{primary-600-1}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-primary md-tabs-wrapper {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]) {
|
||||
color: '{{primary-100}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-primary md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{primary-contrast-0.1}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-warn md-tabs-wrapper {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]) {
|
||||
color: '{{warn-100}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-active, md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{warn-contrast}}'; }
|
||||
md-tabs.md-THEME_NAME-theme.md-warn md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{warn-contrast-0.1}}'; }
|
||||
|
||||
md-toolbar > md-tabs.md-THEME_NAME-theme md-tabs-wrapper {
|
||||
background-color: '{{primary-color}}'; }
|
||||
md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) {
|
||||
color: '{{primary-100}}'; }
|
||||
md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-toolbar > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{primary-contrast-0.1}}'; }
|
||||
|
||||
md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tabs-wrapper {
|
||||
background-color: '{{accent-color}}'; }
|
||||
md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) {
|
||||
color: '{{accent-100}}'; }
|
||||
md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{accent-contrast}}'; }
|
||||
md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{accent-contrast-0.1}}'; }
|
||||
md-toolbar.md-accent > md-tabs.md-THEME_NAME-theme md-ink-bar {
|
||||
color: '{{primary-600-1}}';
|
||||
background: '{{primary-600-1}}'; }
|
||||
|
||||
md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tabs-wrapper {
|
||||
background-color: '{{warn-color}}'; }
|
||||
md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]) {
|
||||
color: '{{warn-100}}'; }
|
||||
md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-active, md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
color: '{{warn-contrast}}'; }
|
||||
md-toolbar.md-warn > md-tabs.md-THEME_NAME-theme md-tab-item:not([disabled]).md-focused {
|
||||
background: '{{warn-contrast-0.1}}'; }
|
||||
274
www/lib/angular-material/modules/closure/tabs/tabs.css
Normal file
274
www/lib/angular-material/modules/closure/tabs/tabs.css
Normal file
@@ -0,0 +1,274 @@
|
||||
/*!
|
||||
* 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-tab-content-hide {
|
||||
0% {
|
||||
opacity: 1; }
|
||||
|
||||
50% {
|
||||
opacity: 1; }
|
||||
|
||||
100% {
|
||||
opacity: 0; } }
|
||||
@keyframes md-tab-content-hide {
|
||||
0% {
|
||||
opacity: 1; }
|
||||
|
||||
50% {
|
||||
opacity: 1; }
|
||||
|
||||
100% {
|
||||
opacity: 0; } }
|
||||
|
||||
md-tab-data {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
z-index: -1;
|
||||
opacity: 0; }
|
||||
|
||||
md-tabs {
|
||||
display: block;
|
||||
margin: 0;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
-webkit-flex-shrink: 0;
|
||||
-ms-flex-negative: 0;
|
||||
flex-shrink: 0; }
|
||||
md-tabs.ng-animate {
|
||||
transition: height 0.5s cubic-bezier(0.35, 0, 0.25, 1); }
|
||||
md-tabs:not(.md-no-tab-content):not(.md-dynamic-height) {
|
||||
min-height: 248px; }
|
||||
md-tabs[md-align-tabs="bottom"] md-tabs-wrapper {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 48px; }
|
||||
md-tabs[md-align-tabs="bottom"] md-tabs-content-wrapper {
|
||||
top: 0;
|
||||
bottom: 48px; }
|
||||
md-tabs.md-dynamic-height md-tabs-content-wrapper {
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
top: auto;
|
||||
left: auto;
|
||||
right: auto;
|
||||
bottom: auto;
|
||||
overflow: visible; }
|
||||
md-tabs.md-dynamic-height md-tab-content.md-active {
|
||||
position: relative; }
|
||||
md-tabs[md-border-bottom] md-tabs-wrapper {
|
||||
border-width: 0 0 1px;
|
||||
border-style: solid; }
|
||||
md-tabs[md-border-bottom]:not(.md-dynamic-height) md-tabs-content-wrapper {
|
||||
top: 49px; }
|
||||
|
||||
md-tabs-wrapper {
|
||||
display: block;
|
||||
position: relative; }
|
||||
md-tabs-wrapper md-prev-button, md-tabs-wrapper md-next-button {
|
||||
height: 100%;
|
||||
width: 32px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
-webkit-transform: translateY(-50%);
|
||||
transform: translateY(-50%);
|
||||
line-height: 1em;
|
||||
z-index: 2;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
background: transparent no-repeat center center;
|
||||
transition: all 0.5s cubic-bezier(0.35, 0, 0.25, 1); }
|
||||
md-tabs-wrapper md-prev-button:focus, md-tabs-wrapper md-next-button:focus {
|
||||
outline: none; }
|
||||
md-tabs-wrapper md-prev-button.md-disabled, md-tabs-wrapper md-next-button.md-disabled {
|
||||
opacity: 0.25;
|
||||
cursor: default; }
|
||||
md-tabs-wrapper md-prev-button.ng-leave, md-tabs-wrapper md-next-button.ng-leave {
|
||||
transition: none; }
|
||||
md-tabs-wrapper md-prev-button md-icon, md-tabs-wrapper md-next-button md-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate3d(-50%, -50%, 0);
|
||||
transform: translate3d(-50%, -50%, 0); }
|
||||
md-tabs-wrapper md-prev-button {
|
||||
left: 0;
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPiA8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPiA8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjQgMjQiIHhtbDpzcGFjZT0icHJlc2VydmUiPiA8ZyBpZD0iSGVhZGVyIj4gPGc+IDxyZWN0IHg9Ii02MTgiIHk9Ii0xMjA4IiBmaWxsPSJub25lIiB3aWR0aD0iMTQwMCIgaGVpZ2h0PSIzNjAwIi8+IDwvZz4gPC9nPiA8ZyBpZD0iTGFiZWwiPiA8L2c+IDxnIGlkPSJJY29uIj4gPGc+IDxwb2x5Z29uIHBvaW50cz0iMTUuNCw3LjQgMTQsNiA4LDEyIDE0LDE4IDE1LjQsMTYuNiAxMC44LDEyIAkJIiBzdHlsZT0iZmlsbDp3aGl0ZTsiLz4gPHJlY3QgZmlsbD0ibm9uZSIgd2lkdGg9IjI0IiBoZWlnaHQ9IjI0Ii8+IDwvZz4gPC9nPiA8ZyBpZD0iR3JpZCIgZGlzcGxheT0ibm9uZSI+IDxnIGRpc3BsYXk9ImlubGluZSI+IDwvZz4gPC9nPiA8L3N2Zz4NCg=='); }
|
||||
md-tabs-wrapper md-next-button {
|
||||
right: 0;
|
||||
background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPiA8IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPiA8c3ZnIHZlcnNpb249IjEuMSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgeD0iMHB4IiB5PSIwcHgiIHdpZHRoPSIyNHB4IiBoZWlnaHQ9IjI0cHgiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZW5hYmxlLWJhY2tncm91bmQ9Im5ldyAwIDAgMjQgMjQiIHhtbDpzcGFjZT0icHJlc2VydmUiPiA8ZyBpZD0iSGVhZGVyIj4gPGc+IDxyZWN0IHg9Ii02MTgiIHk9Ii0xMzM2IiBmaWxsPSJub25lIiB3aWR0aD0iMTQwMCIgaGVpZ2h0PSIzNjAwIi8+IDwvZz4gPC9nPiA8ZyBpZD0iTGFiZWwiPiA8L2c+IDxnIGlkPSJJY29uIj4gPGc+IDxwb2x5Z29uIHBvaW50cz0iMTAsNiA4LjYsNy40IDEzLjIsMTIgOC42LDE2LjYgMTAsMTggMTYsMTIgCQkiIHN0eWxlPSJmaWxsOndoaXRlOyIvPiA8cmVjdCBmaWxsPSJub25lIiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiLz4gPC9nPiA8L2c+IDxnIGlkPSJHcmlkIiBkaXNwbGF5PSJub25lIj4gPGcgZGlzcGxheT0iaW5saW5lIj4gPC9nPiA8L2c+IDwvc3ZnPg0K'); }
|
||||
md-tabs-wrapper md-next-button md-icon {
|
||||
-webkit-transform: translate3d(-50%, -50%, 0) rotate(180deg);
|
||||
transform: translate3d(-50%, -50%, 0) rotate(180deg); }
|
||||
md-tabs-wrapper.md-stretch-tabs md-pagination-wrapper {
|
||||
width: 100%;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row; }
|
||||
md-tabs-wrapper.md-stretch-tabs md-pagination-wrapper md-tab-item {
|
||||
-webkit-flex-grow: 1;
|
||||
-ms-flex-positive: 1;
|
||||
flex-grow: 1; }
|
||||
|
||||
md-tabs-canvas {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
height: 48px; }
|
||||
md-tabs-canvas:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both; }
|
||||
md-tabs-canvas .md-dummy-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0; }
|
||||
md-tabs-canvas.md-paginated {
|
||||
margin: 0 32px; }
|
||||
md-tabs-canvas.md-center-tabs {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
text-align: center; }
|
||||
md-tabs-canvas.md-center-tabs .md-tab {
|
||||
float: none;
|
||||
display: inline-block; }
|
||||
|
||||
md-pagination-wrapper {
|
||||
height: 48px;
|
||||
display: block;
|
||||
transition: -webkit-transform 0.5s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: transform 0.5s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
position: absolute;
|
||||
width: 999999px;
|
||||
left: 0;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
md-pagination-wrapper:after {
|
||||
content: '';
|
||||
display: table;
|
||||
clear: both; }
|
||||
md-pagination-wrapper.md-center-tabs {
|
||||
position: relative;
|
||||
width: initial;
|
||||
-webkit-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
margin: 0 auto; }
|
||||
|
||||
md-tabs-content-wrapper {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 48px;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
overflow: hidden; }
|
||||
|
||||
md-tab-content {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
-webkit-transform: translateX(0);
|
||||
transform: translateX(0);
|
||||
transition: -webkit-transform 0.5s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: transform 0.5s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
overflow: auto; }
|
||||
md-tab-content.md-no-scroll {
|
||||
bottom: auto;
|
||||
overflow: hidden; }
|
||||
md-tab-content.ng-leave, md-tab-content.md-no-transition {
|
||||
transition: none; }
|
||||
md-tab-content.md-left {
|
||||
-webkit-transform: translateX(-100%);
|
||||
transform: translateX(-100%);
|
||||
-webkit-animation: 1s md-tab-content-hide;
|
||||
animation: 1s md-tab-content-hide;
|
||||
opacity: 0; }
|
||||
md-tab-content.md-left * {
|
||||
transition: visibility 0s linear;
|
||||
transition-delay: 0.5s;
|
||||
visibility: hidden; }
|
||||
md-tab-content.md-right {
|
||||
-webkit-transform: translateX(100%);
|
||||
transform: translateX(100%);
|
||||
-webkit-animation: 1s md-tab-content-hide;
|
||||
animation: 1s md-tab-content-hide;
|
||||
opacity: 0; }
|
||||
md-tab-content.md-right * {
|
||||
transition: visibility 0s linear;
|
||||
transition-delay: 0.5s;
|
||||
visibility: hidden; }
|
||||
md-tab-content > div.ng-leave {
|
||||
-webkit-animation: 1s md-tab-content-hide;
|
||||
animation: 1s md-tab-content-hide; }
|
||||
|
||||
md-ink-bar {
|
||||
position: absolute;
|
||||
left: auto;
|
||||
right: auto;
|
||||
bottom: 0;
|
||||
height: 2px; }
|
||||
md-ink-bar.md-left {
|
||||
transition: left 0.225s cubic-bezier(0.35, 0, 0.25, 1), right 0.5s cubic-bezier(0.35, 0, 0.25, 1); }
|
||||
md-ink-bar.md-right {
|
||||
transition: left 0.5s cubic-bezier(0.35, 0, 0.25, 1), right 0.225s cubic-bezier(0.35, 0, 0.25, 1); }
|
||||
|
||||
md-tab {
|
||||
position: absolute;
|
||||
z-index: -1;
|
||||
left: -9999px; }
|
||||
|
||||
.md-tab {
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
padding: 12px 24px;
|
||||
transition: background-color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
text-transform: uppercase;
|
||||
float: left;
|
||||
font-weight: 500;
|
||||
box-sizing: border-box; }
|
||||
.md-tab.md-focused {
|
||||
box-shadow: none;
|
||||
outline: none; }
|
||||
.md-tab.md-active {
|
||||
cursor: default; }
|
||||
.md-tab.md-disabled {
|
||||
pointer-events: none;
|
||||
-ms-touch-action: pan-y;
|
||||
touch-action: pan-y;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
opacity: 0.5;
|
||||
cursor: default; }
|
||||
.md-tab.ng-leave {
|
||||
transition: none; }
|
||||
|
||||
md-toolbar + md-tabs {
|
||||
border-top-left-radius: 0;
|
||||
border-top-right-radius: 0; }
|
||||
1060
www/lib/angular-material/modules/closure/tabs/tabs.js
vendored
Normal file
1060
www/lib/angular-material/modules/closure/tabs/tabs.js
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,30 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.9.0-rc1-master-3c0ce9b
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-input-group.md-THEME_NAME-theme input, md-input-group.md-THEME_NAME-theme textarea {
|
||||
text-shadow: '{{foreground-shadow}}'; }
|
||||
md-input-group.md-THEME_NAME-theme input::-webkit-input-placeholder, md-input-group.md-THEME_NAME-theme input::-moz-placeholder, md-input-group.md-THEME_NAME-theme input:-moz-placeholder, md-input-group.md-THEME_NAME-theme input:-ms-input-placeholder, md-input-group.md-THEME_NAME-theme textarea::-webkit-input-placeholder, md-input-group.md-THEME_NAME-theme textarea::-moz-placeholder, md-input-group.md-THEME_NAME-theme textarea:-moz-placeholder, md-input-group.md-THEME_NAME-theme textarea:-ms-input-placeholder {
|
||||
color: '{{foreground-3}}'; }
|
||||
md-input-group.md-THEME_NAME-theme label {
|
||||
text-shadow: '{{foreground-shadow}}';
|
||||
color: '{{foreground-3}}'; }
|
||||
md-input-group.md-THEME_NAME-theme input, md-input-group.md-THEME_NAME-theme textarea {
|
||||
color: '{{foreground-1}}';
|
||||
border-color: '{{foreground-4}}'; }
|
||||
md-input-group.md-THEME_NAME-theme.md-input-focused input, md-input-group.md-THEME_NAME-theme.md-input-focused textarea {
|
||||
border-color: '{{primary-500}}'; }
|
||||
md-input-group.md-THEME_NAME-theme.md-input-focused label {
|
||||
color: '{{primary-500}}'; }
|
||||
md-input-group.md-THEME_NAME-theme.md-input-focused.md-accent input, md-input-group.md-THEME_NAME-theme.md-input-focused.md-accent textarea {
|
||||
border-color: '{{accent-500}}'; }
|
||||
md-input-group.md-THEME_NAME-theme.md-input-focused.md-accent label {
|
||||
color: '{{accent-500}}'; }
|
||||
md-input-group.md-THEME_NAME-theme.md-input-has-value:not(.md-input-focused) label {
|
||||
color: '{{foreground-2}}'; }
|
||||
md-input-group.md-THEME_NAME-theme .md-input[disabled] {
|
||||
border-bottom-color: '{{foreground-4}}';
|
||||
color: '{{foreground-3}}'; }
|
||||
111
www/lib/angular-material/modules/closure/textField/textField.css
Normal file
111
www/lib/angular-material/modules/closure/textField/textField.css
Normal file
@@ -0,0 +1,111 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.9.0-rc1-master-3c0ce9b
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-input-group label, .md-input-group label {
|
||||
display: block;
|
||||
font-size: 1.2rem; }
|
||||
md-input-group textarea, md-input-group input[type="text"], md-input-group input[type="password"], md-input-group input[type="datetime"], md-input-group input[type="datetime-local"], md-input-group input[type="date"], md-input-group input[type="month"], md-input-group input[type="time"], md-input-group input[type="week"], md-input-group input[type="number"], md-input-group input[type="email"], md-input-group input[type="url"], md-input-group input[type="search"], md-input-group input[type="tel"], md-input-group input[type="color"], .md-input-group textarea, .md-input-group input[type="text"], .md-input-group input[type="password"], .md-input-group input[type="datetime"], .md-input-group input[type="datetime-local"], .md-input-group input[type="date"], .md-input-group input[type="month"], .md-input-group input[type="time"], .md-input-group input[type="week"], .md-input-group input[type="number"], .md-input-group input[type="email"], .md-input-group input[type="url"], .md-input-group input[type="search"], .md-input-group input[type="tel"], .md-input-group input[type="color"] {
|
||||
display: block;
|
||||
border-width: 0 0 1px 0;
|
||||
padding-top: 2px;
|
||||
line-height: 26px;
|
||||
padding-bottom: 1px; }
|
||||
md-input-group textarea:focus, md-input-group input[type="text"]:focus, md-input-group input[type="password"]:focus, md-input-group input[type="datetime"]:focus, md-input-group input[type="datetime-local"]:focus, md-input-group input[type="date"]:focus, md-input-group input[type="month"]:focus, md-input-group input[type="time"]:focus, md-input-group input[type="week"]:focus, md-input-group input[type="number"]:focus, md-input-group input[type="email"]:focus, md-input-group input[type="url"]:focus, md-input-group input[type="search"]:focus, md-input-group input[type="tel"]:focus, md-input-group input[type="color"]:focus, .md-input-group textarea:focus, .md-input-group input[type="text"]:focus, .md-input-group input[type="password"]:focus, .md-input-group input[type="datetime"]:focus, .md-input-group input[type="datetime-local"]:focus, .md-input-group input[type="date"]:focus, .md-input-group input[type="month"]:focus, .md-input-group input[type="time"]:focus, .md-input-group input[type="week"]:focus, .md-input-group input[type="number"]:focus, .md-input-group input[type="email"]:focus, .md-input-group input[type="url"]:focus, .md-input-group input[type="search"]:focus, .md-input-group input[type="tel"]:focus, .md-input-group input[type="color"]:focus {
|
||||
outline: 0; }
|
||||
md-input-group input, md-input-group textarea, .md-input-group input, .md-input-group textarea {
|
||||
background: none; }
|
||||
|
||||
md-input-group, .md-input-group {
|
||||
padding-bottom: 2px;
|
||||
margin: 10px 0 8px 0;
|
||||
position: relative;
|
||||
display: block; }
|
||||
md-input-group label, .md-input-group label {
|
||||
font-size: 1.6rem;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
-webkit-font-smoothing: antialiased; }
|
||||
md-input-group label:hover, .md-input-group label:hover {
|
||||
cursor: text; }
|
||||
md-input-group label, .md-input-group label {
|
||||
-webkit-transform: translate3d(0, 22px, 0);
|
||||
transform: translate3d(0, 22px, 0);
|
||||
transition: all 0.15s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: all 0.15s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group label, html[dir=rtl] .md-input-group label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
md-input-group input, md-input-group textarea, .md-input-group input, .md-input-group textarea {
|
||||
border-bottom-width: 1px;
|
||||
transition: all 0.15s cubic-bezier(0.35, 0, 0.25, 1); }
|
||||
md-input-group.md-input-focused label, .md-input-group.md-input-focused label {
|
||||
-webkit-transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group.md-input-focused label, html[dir=rtl] .md-input-group.md-input-focused label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
md-input-group.md-input-focused input, md-input-group.md-input-focused textarea, .md-input-group.md-input-focused input, .md-input-group.md-input-focused textarea {
|
||||
border-bottom-width: 2px; }
|
||||
md-input-group.md-input-focused input, .md-input-group.md-input-focused input {
|
||||
padding-bottom: 0; }
|
||||
md-input-group.md-input-has-value label, .md-input-group.md-input-has-value label {
|
||||
-webkit-transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group.md-input-has-value label, html[dir=rtl] .md-input-group.md-input-has-value label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
md-input-group.md-input-has-value:not(.md-input-focused) label, .md-input-group.md-input-has-value:not(.md-input-focused) label {
|
||||
-webkit-transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group.md-input-has-value:not(.md-input-focused) label, html[dir=rtl] .md-input-group.md-input-has-value:not(.md-input-focused) label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
md-input-group[disabled] input, md-input-group[disabled] textarea, .md-input-group[disabled] input, .md-input-group[disabled] textarea {
|
||||
border-bottom-width: 0px; }
|
||||
md-input-group[disabled] input, md-input-group[disabled] textarea, .md-input-group[disabled] input, .md-input-group[disabled] textarea {
|
||||
background-size: 3px 1px;
|
||||
background-position: 0 bottom;
|
||||
background-size: 2px 1px;
|
||||
background-repeat: repeat-x;
|
||||
pointer-events: none; }
|
||||
md-input-group[disabled] label, .md-input-group[disabled] label {
|
||||
-webkit-transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
transform: translate3d(0, 4px, 0) scale(0.75);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group[disabled] label, html[dir=rtl] .md-input-group[disabled] label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
md-input-group[disabled] *:not(.md-input-has-value) label, .md-input-group[disabled] *:not(.md-input-has-value) label {
|
||||
-webkit-transform: translate3d(0, 22px, 0);
|
||||
transform: translate3d(0, 22px, 0);
|
||||
transition: all 0.15s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center; }
|
||||
html[dir=rtl] md-input-group[disabled] *:not(.md-input-has-value) label, html[dir=rtl] .md-input-group[disabled] *:not(.md-input-has-value) label {
|
||||
-webkit-transform-origin: left center;
|
||||
transform-origin: left center;
|
||||
-webkit-transform-origin: right center;
|
||||
transform-origin: right center; }
|
||||
145
www/lib/angular-material/modules/closure/textField/textField.js
vendored
Normal file
145
www/lib/angular-material/modules/closure/textField/textField.js
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.9.0-rc1-master-3c0ce9b
|
||||
*/
|
||||
goog.provide('ng.material.components.textField');
|
||||
goog.require('ng.material.core');
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.textField
|
||||
* @description
|
||||
* Form
|
||||
*/
|
||||
ng.material.components.textField = angular.module('material.components.textField', [
|
||||
'material.core'
|
||||
])
|
||||
.directive('mdInputGroup', mdInputGroupDirective)
|
||||
.directive('mdInput', mdInputDirective)
|
||||
.directive('mdTextFloat', mdTextFloatDirective);
|
||||
|
||||
|
||||
function mdTextFloatDirective($mdTheming, $mdUtil, $parse, $log) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
scope : {
|
||||
fid : '@?mdFid',
|
||||
label : '@?',
|
||||
value : '=ngModel'
|
||||
},
|
||||
compile : function(element, attr) {
|
||||
|
||||
$log.warn('<md-text-float> is deprecated. Please use `<md-input-container>` and `<input>`.' +
|
||||
'More information at http://material.angularjs.org/#/api/material.components.input/directive/mdInputContainer');
|
||||
|
||||
if ( angular.isUndefined(attr.mdFid) ) {
|
||||
attr.mdFid = $mdUtil.nextUid();
|
||||
}
|
||||
|
||||
return {
|
||||
pre : function(scope, element, attrs) {
|
||||
var disabledParsed = $parse(attrs.ngDisabled);
|
||||
scope.isDisabled = function() {
|
||||
return disabledParsed(scope.$parent);
|
||||
};
|
||||
|
||||
scope.inputType = attrs.type || "text";
|
||||
},
|
||||
post: $mdTheming
|
||||
};
|
||||
},
|
||||
template:
|
||||
'<md-input-group tabindex="-1">' +
|
||||
' <label for="{{fid}}" >{{label}}</label>' +
|
||||
' <md-input id="{{fid}}" ng-disabled="isDisabled()" ng-model="value" type="{{inputType}}"></md-input>' +
|
||||
'</md-input-group>'
|
||||
};
|
||||
}
|
||||
mdTextFloatDirective.$inject = ["$mdTheming", "$mdUtil", "$parse", "$log"];
|
||||
|
||||
function mdInputGroupDirective($log) {
|
||||
return {
|
||||
restrict: 'CE',
|
||||
controller: ['$element', function($element) {
|
||||
|
||||
$log.warn('<md-input-group> is deprecated. Please use `<md-input-container>` and `<input>`.' +
|
||||
'More information at http://material.angularjs.org/#/api/material.components.input/directive/mdInputContainer');
|
||||
this.setFocused = function(isFocused) {
|
||||
$element.toggleClass('md-input-focused', !!isFocused);
|
||||
};
|
||||
this.setHasValue = function(hasValue) {
|
||||
$element.toggleClass('md-input-has-value', hasValue );
|
||||
};
|
||||
}]
|
||||
};
|
||||
|
||||
}
|
||||
mdInputGroupDirective.$inject = ["$log"];
|
||||
|
||||
function mdInputDirective($mdUtil, $log) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
template: '<input >',
|
||||
require: ['^?mdInputGroup', '?ngModel'],
|
||||
link: function(scope, element, attr, ctrls) {
|
||||
if ( !ctrls[0] ) return;
|
||||
|
||||
$log.warn('<md-input> is deprecated. Please use `<md-input-container>` and `<input>`.' +
|
||||
'More information at http://material.angularjs.org/#/api/material.components.input/directive/mdInputContainer');
|
||||
|
||||
var inputGroupCtrl = ctrls[0];
|
||||
var ngModelCtrl = ctrls[1];
|
||||
|
||||
scope.$watch(scope.isDisabled, function(isDisabled) {
|
||||
element.attr('aria-disabled', !!isDisabled);
|
||||
element.attr('tabindex', !!isDisabled);
|
||||
});
|
||||
element.attr('type', attr.type || element.parent().attr('type') || "text");
|
||||
|
||||
// When the input value changes, check if it "has" a value, and
|
||||
// set the appropriate class on the input group
|
||||
if (ngModelCtrl) {
|
||||
//Add a $formatter so we don't use up the render function
|
||||
ngModelCtrl.$formatters.push(function(value) {
|
||||
inputGroupCtrl.setHasValue( isNotEmpty(value) );
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
element
|
||||
.on('input', function() {
|
||||
inputGroupCtrl.setHasValue( isNotEmpty() );
|
||||
})
|
||||
.on('focus', function(e) {
|
||||
// When the input focuses, add the focused class to the group
|
||||
inputGroupCtrl.setFocused(true);
|
||||
})
|
||||
.on('blur', function(e) {
|
||||
// When the input blurs, remove the focused class from the group
|
||||
inputGroupCtrl.setFocused(false);
|
||||
inputGroupCtrl.setHasValue( isNotEmpty() );
|
||||
});
|
||||
|
||||
scope.$on('$destroy', function() {
|
||||
inputGroupCtrl.setFocused(false);
|
||||
inputGroupCtrl.setHasValue(false);
|
||||
});
|
||||
|
||||
|
||||
function isNotEmpty(value) {
|
||||
value = angular.isUndefined(value) ? element.val() : value;
|
||||
return (angular.isDefined(value) && (value!==null) &&
|
||||
(value.toString().trim() !== ""));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
mdInputDirective.$inject = ["$mdUtil", "$log"];
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,18 @@
|
||||
/*!
|
||||
* 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-toast.md-THEME_NAME-theme {
|
||||
background-color: #323232;
|
||||
color: '{{background-50}}'; }
|
||||
md-toast.md-THEME_NAME-theme .md-button {
|
||||
color: '{{background-50}}'; }
|
||||
md-toast.md-THEME_NAME-theme .md-button.md-highlight {
|
||||
color: '{{primary-A200}}'; }
|
||||
md-toast.md-THEME_NAME-theme .md-button.md-highlight.md-accent {
|
||||
color: '{{accent-A200}}'; }
|
||||
md-toast.md-THEME_NAME-theme .md-button.md-highlight.md-warn {
|
||||
color: '{{warn-A200}}'; }
|
||||
119
www/lib/angular-material/modules/closure/toast/toast.css
Normal file
119
www/lib/angular-material/modules/closure/toast/toast.css
Normal file
@@ -0,0 +1,119 @@
|
||||
/*!
|
||||
* 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-toast {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
min-height: 48px;
|
||||
padding-left: 24px;
|
||||
padding-right: 24px;
|
||||
box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
|
||||
border-radius: 2px;
|
||||
font-size: 14px;
|
||||
cursor: default;
|
||||
max-width: 100%;
|
||||
max-height: 40px;
|
||||
height: 24px;
|
||||
z-index: 90;
|
||||
opacity: 1;
|
||||
-webkit-transform: translate3d(0, 0, 0) rotateZ(0deg);
|
||||
transform: translate3d(0, 0, 0) rotateZ(0deg);
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
/* Transition differently when swiping */ }
|
||||
md-toast.md-capsule {
|
||||
border-radius: 24px; }
|
||||
md-toast.ng-leave-active {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-toast.md-swipeleft, md-toast.md-swiperight, md-toast.md-swipeup, md-toast.md-swipedown {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
md-toast.ng-enter {
|
||||
-webkit-transform: translate3d(0, 100%, 0);
|
||||
transform: translate3d(0, 100%, 0);
|
||||
opacity: 0; }
|
||||
md-toast.ng-enter.md-top {
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0); }
|
||||
md-toast.ng-enter.ng-enter-active {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
opacity: 1; }
|
||||
md-toast.ng-leave.ng-leave-active {
|
||||
opacity: 0;
|
||||
-webkit-transform: translate3d(0, 100%, 0);
|
||||
transform: translate3d(0, 100%, 0); }
|
||||
md-toast.ng-leave.ng-leave-active.md-top {
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0); }
|
||||
md-toast.ng-leave.ng-leave-active.md-swipeleft {
|
||||
-webkit-transform: translate3d(-100%, 0%, 0);
|
||||
transform: translate3d(-100%, 0%, 0); }
|
||||
md-toast.ng-leave.ng-leave-active.md-swiperight {
|
||||
-webkit-transform: translate3d(100%, 0%, 0);
|
||||
transform: translate3d(100%, 0%, 0); }
|
||||
md-toast .md-action {
|
||||
line-height: 19px;
|
||||
margin-left: 24px;
|
||||
cursor: pointer;
|
||||
text-transform: uppercase;
|
||||
float: right; }
|
||||
md-toast .md-action.md-button {
|
||||
min-width: 0; }
|
||||
|
||||
@media (max-width: 600px) {
|
||||
md-toast {
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
border-radius: 0;
|
||||
bottom: 0; }
|
||||
md-toast.md-top {
|
||||
bottom: auto;
|
||||
top: 0; } }
|
||||
|
||||
@media (min-width: 600px) {
|
||||
md-toast {
|
||||
min-width: 288px;
|
||||
/*
|
||||
* When the toast doesn't take up the whole screen,
|
||||
* make it rotate when the user swipes it away
|
||||
*/ }
|
||||
md-toast.md-bottom {
|
||||
bottom: 8px; }
|
||||
md-toast.md-left {
|
||||
left: 8px; }
|
||||
md-toast.md-right {
|
||||
right: 8px; }
|
||||
md-toast.md-top {
|
||||
top: 8px; }
|
||||
md-toast.ng-leave.ng-leave-active.md-swipeleft {
|
||||
-webkit-transform: translate3d(-100%, 25%, 0) rotateZ(-15deg);
|
||||
transform: translate3d(-100%, 25%, 0) rotateZ(-15deg); }
|
||||
md-toast.ng-leave.ng-leave-active.md-swiperight {
|
||||
-webkit-transform: translate3d(100%, 25%, 0) rotateZ(15deg);
|
||||
transform: translate3d(100%, 25%, 0) rotateZ(15deg); }
|
||||
md-toast.ng-leave.ng-leave-active.md-top.md-swipeleft {
|
||||
-webkit-transform: translate3d(-100%, 0, 0) rotateZ(-15deg);
|
||||
transform: translate3d(-100%, 0, 0) rotateZ(-15deg); }
|
||||
md-toast.ng-leave.ng-leave-active.md-top.md-swiperight {
|
||||
-webkit-transform: translate3d(100%, 0, 0) rotateZ(15deg);
|
||||
transform: translate3d(100%, 0, 0) rotateZ(15deg); } }
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
md-toast {
|
||||
max-width: 568px; } }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-toast {
|
||||
border: 1px solid #fff; } }
|
||||
265
www/lib/angular-material/modules/closure/toast/toast.js
vendored
Normal file
265
www/lib/angular-material/modules/closure/toast/toast.js
vendored
Normal file
@@ -0,0 +1,265 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.toast');
|
||||
goog.require('ng.material.components.button');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.toast
|
||||
* @description
|
||||
* Toast
|
||||
*/
|
||||
angular.module('material.components.toast', [
|
||||
'material.core',
|
||||
'material.components.button'
|
||||
])
|
||||
.directive('mdToast', MdToastDirective)
|
||||
.provider('$mdToast', MdToastProvider);
|
||||
|
||||
function MdToastDirective() {
|
||||
return {
|
||||
restrict: 'E'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name $mdToast
|
||||
* @module material.components.toast
|
||||
*
|
||||
* @description
|
||||
* `$mdToast` is a service to build a toast notification on any position
|
||||
* on the screen with an optional duration, and provides a simple promise API.
|
||||
*
|
||||
*
|
||||
* ## Restrictions on custom toasts
|
||||
* - The toast's template must have an outer `<md-toast>` element.
|
||||
* - For a toast action, use element with class `md-action`.
|
||||
* - Add the class `md-capsule` for curved corners.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div ng-controller="MyController">
|
||||
* <md-button ng-click="openToast()">
|
||||
* Open a Toast!
|
||||
* </md-button>
|
||||
* </div>
|
||||
* </hljs>
|
||||
*
|
||||
* <hljs lang="js">
|
||||
* var app = angular.module('app', ['ngMaterial']);
|
||||
* app.controller('MyController', function($scope, $mdToast) {
|
||||
* $scope.openToast = function($event) {
|
||||
* $mdToast.show($mdToast.simple().content('Hello!'));
|
||||
* // Could also do $mdToast.showSimple('Hello');
|
||||
* };
|
||||
* });
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#showSimple
|
||||
*
|
||||
* @description
|
||||
* Convenience method which builds and shows a simple toast.
|
||||
*
|
||||
* @returns {promise} A promise that can be resolved with `$mdToast.hide()` or
|
||||
* rejected with `$mdToast.cancel()`.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#simple
|
||||
*
|
||||
* @description
|
||||
* Builds a preconfigured toast.
|
||||
*
|
||||
* @returns {obj} a `$mdToastPreset` with the chainable configuration methods:
|
||||
*
|
||||
* - $mdToastPreset#content(string) - sets toast content to string
|
||||
* - $mdToastPreset#action(string) - adds an action button, which resolves the promise returned from `show()` if clicked.
|
||||
* - $mdToastPreset#highlightAction(boolean) - sets action button to be highlighted
|
||||
* - $mdToastPreset#capsule(boolean) - adds 'md-capsule' class to the toast (curved corners)
|
||||
* - $mdToastPreset#theme(boolean) - sets the theme on the toast to theme (default is `$mdThemingProvider`'s default theme)
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#updateContent
|
||||
*
|
||||
* @description
|
||||
* Updates the content of an existing toast. Useful for updating things like counts, etc.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#build
|
||||
*
|
||||
* @description
|
||||
* Creates a custom `$mdToastPreset` that you can configure.
|
||||
*
|
||||
* @returns {obj} a `$mdToastPreset` with the chainable configuration methods for shows' options (see below).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#show
|
||||
*
|
||||
* @description Shows the toast.
|
||||
*
|
||||
* @param {object} optionsOrPreset Either provide an `$mdToastPreset` returned from `simple()`
|
||||
* and `build()`, or 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 toast. Restrictions: the template must
|
||||
* have an outer `md-toast` 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 toast is removed unless `preserveScope` is set to true.
|
||||
* - `preserveScope` - `{boolean=}`: whether to preserve the scope when the element is removed. Default is false
|
||||
* - `hideDelay` - `{number=}`: How many milliseconds the toast should stay
|
||||
* active before automatically closing. Set to 0 or false to have the toast stay open until
|
||||
* closed manually. Default: 3000.
|
||||
* - `position` - `{string=}`: Where to place the toast. Available: any combination
|
||||
* of 'bottom', 'left', 'top', 'right', 'fit'. Default: 'bottom left'.
|
||||
* - `controller` - `{string=}`: The controller to associate with this toast.
|
||||
* The controller will be injected the local `$hideToast`, which is a function
|
||||
* used to hide the toast.
|
||||
* - `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.
|
||||
* - `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 toast 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 toast to. Defaults to appending
|
||||
* to the root element of the application.
|
||||
*
|
||||
* @returns {promise} A promise that can be resolved with `$mdToast.hide()` or
|
||||
* rejected with `$mdToast.cancel()`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#hide
|
||||
*
|
||||
* @description
|
||||
* Hide an existing toast and resolve the promise returned from `$mdToast.show()`.
|
||||
*
|
||||
* @param {*=} response An argument for the resolved promise.
|
||||
*
|
||||
* @returns {promise} a promise that is called when the existing element is removed from the DOM
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $mdToast#cancel
|
||||
*
|
||||
* @description
|
||||
* Hide the existing toast and reject the promise returned from
|
||||
* `$mdToast.show()`.
|
||||
*
|
||||
* @param {*=} response An argument for the rejected promise.
|
||||
*
|
||||
* @returns {promise} a promise that is called when the existing element is removed from the DOM
|
||||
*
|
||||
*/
|
||||
|
||||
function MdToastProvider($$interimElementProvider) {
|
||||
var activeToastContent;
|
||||
var $mdToast = $$interimElementProvider('$mdToast')
|
||||
.setDefaults({
|
||||
methods: ['position', 'hideDelay', 'capsule' ],
|
||||
options: toastDefaultOptions
|
||||
})
|
||||
.addPreset('simple', {
|
||||
argOption: 'content',
|
||||
methods: ['content', 'action', 'highlightAction', 'theme', 'parent'],
|
||||
options: /* ngInject */ ["$mdToast", "$mdTheming", function($mdToast, $mdTheming) {
|
||||
var opts = {
|
||||
template: [
|
||||
'<md-toast md-theme="{{ toast.theme }}" ng-class="{\'md-capsule\': toast.capsule}">',
|
||||
'<span flex>{{ toast.content }}</span>',
|
||||
'<md-button class="md-action" ng-if="toast.action" ng-click="toast.resolve()" ng-class="{\'md-highlight\': toast.highlightAction}">',
|
||||
'{{ toast.action }}',
|
||||
'</md-button>',
|
||||
'</md-toast>'
|
||||
].join(''),
|
||||
controller: /* ngInject */ ["$scope", function mdToastCtrl($scope) {
|
||||
var self = this;
|
||||
$scope.$watch(function() { return activeToastContent; }, function() {
|
||||
self.content = activeToastContent;
|
||||
});
|
||||
this.resolve = function() {
|
||||
$mdToast.hide();
|
||||
};
|
||||
}],
|
||||
theme: $mdTheming.defaultTheme(),
|
||||
controllerAs: 'toast',
|
||||
bindToController: true
|
||||
};
|
||||
return opts;
|
||||
}]
|
||||
})
|
||||
.addMethod('updateContent', function(newContent) {
|
||||
activeToastContent = newContent;
|
||||
});
|
||||
|
||||
toastDefaultOptions.$inject = ["$timeout", "$animate", "$mdToast", "$mdUtil"];
|
||||
return $mdToast;
|
||||
|
||||
/* ngInject */
|
||||
function toastDefaultOptions($timeout, $animate, $mdToast, $mdUtil) {
|
||||
return {
|
||||
onShow: onShow,
|
||||
onRemove: onRemove,
|
||||
position: 'bottom left',
|
||||
themable: true,
|
||||
hideDelay: 3000
|
||||
};
|
||||
|
||||
function onShow(scope, element, options) {
|
||||
element = $mdUtil.extractElementByName(element, 'md-toast');
|
||||
|
||||
// 'top left' -> 'md-top md-left'
|
||||
activeToastContent = options.content;
|
||||
element.addClass(options.position.split(' ').map(function(pos) {
|
||||
return 'md-' + pos;
|
||||
}).join(' '));
|
||||
options.parent.addClass(toastOpenClass(options.position));
|
||||
|
||||
options.onSwipe = function(ev, gesture) {
|
||||
//Add swipeleft/swiperight class to element so it can animate correctly
|
||||
element.addClass('md-' + ev.type.replace('$md.',''));
|
||||
$timeout($mdToast.cancel);
|
||||
};
|
||||
element.on('$md.swipeleft $md.swiperight', options.onSwipe);
|
||||
return $animate.enter(element, options.parent);
|
||||
}
|
||||
|
||||
function onRemove(scope, element, options) {
|
||||
element.off('$md.swipeleft $md.swiperight', options.onSwipe);
|
||||
options.parent.removeClass(toastOpenClass(options.position));
|
||||
return $animate.leave(element);
|
||||
}
|
||||
|
||||
function toastOpenClass(position) {
|
||||
return 'md-toast-open-' +
|
||||
(position.indexOf('top') > -1 ? 'top' : 'bottom');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
MdToastProvider.$inject = ["$$interimElementProvider"];
|
||||
|
||||
ng.material.components.toast = angular.module("material.components.toast");
|
||||
@@ -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-toolbar.md-THEME_NAME-theme {
|
||||
background-color: '{{primary-color}}';
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-toolbar.md-THEME_NAME-theme md-icon {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-toolbar.md-THEME_NAME-theme .md-button {
|
||||
color: '{{primary-contrast}}'; }
|
||||
md-toolbar.md-THEME_NAME-theme.md-accent {
|
||||
background-color: '{{accent-color}}';
|
||||
color: '{{accent-contrast}}'; }
|
||||
md-toolbar.md-THEME_NAME-theme.md-warn {
|
||||
background-color: '{{warn-color}}';
|
||||
color: '{{warn-contrast}}'; }
|
||||
83
www/lib/angular-material/modules/closure/toolbar/toolbar.css
Normal file
83
www/lib/angular-material/modules/closure/toolbar/toolbar.css
Normal file
@@ -0,0 +1,83 @@
|
||||
/*!
|
||||
* 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-toolbar {
|
||||
box-sizing: border-box;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-flex-direction: column;
|
||||
-ms-flex-direction: column;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
font-size: 20px;
|
||||
min-height: 64px;
|
||||
width: 100%; }
|
||||
md-toolbar.md-whiteframe-z1-add, md-toolbar.md-whiteframe-z1-remove {
|
||||
transition: box-shadow 0.5s linear; }
|
||||
md-toolbar *, md-toolbar *:before, md-toolbar *:after {
|
||||
box-sizing: border-box; }
|
||||
md-toolbar.md-tall {
|
||||
height: 128px;
|
||||
min-height: 128px;
|
||||
max-height: 128px; }
|
||||
md-toolbar.md-medium-tall {
|
||||
height: 88px;
|
||||
min-height: 88px;
|
||||
max-height: 88px; }
|
||||
md-toolbar.md-medium-tall .md-toolbar-tools {
|
||||
height: 48px;
|
||||
min-height: 48px;
|
||||
max-height: 48px; }
|
||||
md-toolbar .md-indent {
|
||||
margin-left: 64px; }
|
||||
md-toolbar ~ md-content > md-list {
|
||||
padding: 0; }
|
||||
md-toolbar ~ md-content > md-list md-list-item:last-child md-divider {
|
||||
display: none; }
|
||||
|
||||
.md-toolbar-tools {
|
||||
font-weight: 400;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
-webkit-flex-direction: row;
|
||||
-ms-flex-direction: row;
|
||||
flex-direction: row;
|
||||
width: 100%;
|
||||
height: 64px;
|
||||
max-height: 64px;
|
||||
padding: 0 16px;
|
||||
margin: 0; }
|
||||
.md-toolbar-tools h1, .md-toolbar-tools h2, .md-toolbar-tools h3 {
|
||||
font-size: inherit;
|
||||
font-weight: inherit;
|
||||
margin: inherit; }
|
||||
.md-toolbar-tools a {
|
||||
color: inherit;
|
||||
text-decoration: none; }
|
||||
.md-toolbar-tools .fill-height {
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
align-items: center; }
|
||||
.md-toolbar-tools .md-button {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0; }
|
||||
.md-toolbar-tools > .md-button:first-child {
|
||||
margin-left: -8px; }
|
||||
.md-toolbar-tools > .md-button:last-child {
|
||||
margin-right: -8px; }
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
.md-toolbar-tools {
|
||||
border-bottom: 1px solid #fff; } }
|
||||
169
www/lib/angular-material/modules/closure/toolbar/toolbar.js
vendored
Normal file
169
www/lib/angular-material/modules/closure/toolbar/toolbar.js
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.toolbar');
|
||||
goog.require('ng.material.components.content');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.toolbar
|
||||
*/
|
||||
angular.module('material.components.toolbar', [
|
||||
'material.core',
|
||||
'material.components.content'
|
||||
])
|
||||
.directive('mdToolbar', mdToolbarDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdToolbar
|
||||
* @module material.components.toolbar
|
||||
* @restrict E
|
||||
* @description
|
||||
* `md-toolbar` is used to place a toolbar in your app.
|
||||
*
|
||||
* Toolbars are usually used above a content area to display the title of the
|
||||
* current page, and show relevant action buttons for that page.
|
||||
*
|
||||
* You can change the height of the toolbar by adding either the
|
||||
* `md-medium-tall` or `md-tall` class to the toolbar.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <div layout="column" layout-fill>
|
||||
* <md-toolbar>
|
||||
*
|
||||
* <div class="md-toolbar-tools">
|
||||
* <span>My App's Title</span>
|
||||
*
|
||||
* <!-- fill up the space between left and right area -->
|
||||
* <span flex></span>
|
||||
*
|
||||
* <md-button>
|
||||
* Right Bar Button
|
||||
* </md-button>
|
||||
* </div>
|
||||
*
|
||||
* </md-toolbar>
|
||||
* <md-content>
|
||||
* Hello!
|
||||
* </md-content>
|
||||
* </div>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {boolean=} md-scroll-shrink Whether the header should shrink away as
|
||||
* the user scrolls down, and reveal itself as the user scrolls up.
|
||||
* Note: for scrollShrink to work, the toolbar must be a sibling of a
|
||||
* `md-content` element, placed before it. See the scroll shrink demo.
|
||||
*
|
||||
*
|
||||
* @param {number=} md-shrink-speed-factor How much to change the speed of the toolbar's
|
||||
* shrinking by. For example, if 0.25 is given then the toolbar will shrink
|
||||
* at one fourth the rate at which the user scrolls down. Default 0.5.
|
||||
*/
|
||||
function mdToolbarDirective($$rAF, $mdConstant, $mdUtil, $mdTheming, $animate, $timeout) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
controller: angular.noop,
|
||||
link: function(scope, element, attr) {
|
||||
$mdTheming(element);
|
||||
|
||||
if (angular.isDefined(attr.mdScrollShrink)) {
|
||||
setupScrollShrink();
|
||||
}
|
||||
|
||||
function setupScrollShrink() {
|
||||
// Current "y" position of scroll
|
||||
var y = 0;
|
||||
// Store the last scroll top position
|
||||
var prevScrollTop = 0;
|
||||
|
||||
var shrinkSpeedFactor = attr.mdShrinkSpeedFactor || 0.5;
|
||||
|
||||
var toolbarHeight;
|
||||
var contentElement;
|
||||
|
||||
var debouncedContentScroll = $$rAF.throttle(onContentScroll);
|
||||
var debouncedUpdateHeight = $mdUtil.debounce(updateToolbarHeight, 5 * 1000);
|
||||
|
||||
// Wait for $mdContentLoaded event from mdContent directive.
|
||||
// If the mdContent element is a sibling of our toolbar, hook it up
|
||||
// to scroll events.
|
||||
scope.$on('$mdContentLoaded', onMdContentLoad);
|
||||
|
||||
function onMdContentLoad($event, newContentEl) {
|
||||
// Toolbar and content must be siblings
|
||||
if (element.parent()[0] === newContentEl.parent()[0]) {
|
||||
// unhook old content event listener if exists
|
||||
if (contentElement) {
|
||||
contentElement.off('scroll', debouncedContentScroll);
|
||||
}
|
||||
|
||||
newContentEl.on('scroll', debouncedContentScroll);
|
||||
newContentEl.attr('scroll-shrink', 'true');
|
||||
|
||||
contentElement = newContentEl;
|
||||
$$rAF(updateToolbarHeight);
|
||||
}
|
||||
}
|
||||
|
||||
function updateToolbarHeight() {
|
||||
toolbarHeight = element.prop('offsetHeight');
|
||||
// Add a negative margin-top the size of the toolbar to the content el.
|
||||
// The content will start transformed down the toolbarHeight amount,
|
||||
// so everything looks normal.
|
||||
//
|
||||
// As the user scrolls down, the content will be transformed up slowly
|
||||
// to put the content underneath where the toolbar was.
|
||||
var margin = (-toolbarHeight * shrinkSpeedFactor) + 'px';
|
||||
contentElement.css('margin-top', margin);
|
||||
contentElement.css('margin-bottom', margin);
|
||||
|
||||
onContentScroll();
|
||||
}
|
||||
|
||||
function onContentScroll(e) {
|
||||
var scrollTop = e ? e.target.scrollTop : prevScrollTop;
|
||||
|
||||
debouncedUpdateHeight();
|
||||
|
||||
y = Math.min(
|
||||
toolbarHeight / shrinkSpeedFactor,
|
||||
Math.max(0, y + scrollTop - prevScrollTop)
|
||||
);
|
||||
|
||||
element.css(
|
||||
$mdConstant.CSS.TRANSFORM,
|
||||
'translate3d(0,' + (-y * shrinkSpeedFactor) + 'px,0)'
|
||||
);
|
||||
contentElement.css(
|
||||
$mdConstant.CSS.TRANSFORM,
|
||||
'translate3d(0,' + ((toolbarHeight - y) * shrinkSpeedFactor) + 'px,0)'
|
||||
);
|
||||
|
||||
prevScrollTop = scrollTop;
|
||||
|
||||
if (element.hasClass('md-whiteframe-z1')) {
|
||||
if (!y) {
|
||||
$timeout(function () { $animate.removeClass(element, 'md-whiteframe-z1'); });
|
||||
}
|
||||
} else {
|
||||
if (y) {
|
||||
$timeout(function () { $animate.addClass(element, 'md-whiteframe-z1'); });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
mdToolbarDirective.$inject = ["$$rAF", "$mdConstant", "$mdUtil", "$mdTheming", "$animate", "$timeout"];
|
||||
|
||||
ng.material.components.toolbar = angular.module("material.components.toolbar");
|
||||
@@ -0,0 +1,11 @@
|
||||
/*!
|
||||
* 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-tooltip.md-THEME_NAME-theme {
|
||||
color: '{{background-A100}}'; }
|
||||
md-tooltip.md-THEME_NAME-theme .md-background {
|
||||
background-color: '{{foreground-2}}'; }
|
||||
72
www/lib/angular-material/modules/closure/tooltip/tooltip.css
Normal file
72
www/lib/angular-material/modules/closure/tooltip/tooltip.css
Normal file
@@ -0,0 +1,72 @@
|
||||
/*!
|
||||
* 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-tooltip {
|
||||
position: absolute;
|
||||
z-index: 100;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
border-radius: 4px;
|
||||
font-weight: 500;
|
||||
font-size: 14px; }
|
||||
@media screen and (min-width: 600px) {
|
||||
md-tooltip {
|
||||
font-size: 10px; } }
|
||||
md-tooltip .md-background {
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
-webkit-transform: translate(-50%, -50%) scale(0);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 1; }
|
||||
md-tooltip .md-background.md-show-add {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
-webkit-transform: translate(-50%, -50%) scale(0);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0; }
|
||||
md-tooltip .md-background.md-show, md-tooltip .md-background.md-show-add-active {
|
||||
-webkit-transform: translate(-50%, -50%) scale(1);
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1; }
|
||||
md-tooltip .md-background.md-show-remove {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-tooltip .md-background.md-show-remove.md-show-remove-active {
|
||||
-webkit-transform: translate(-50%, -50%) scale(0);
|
||||
transform: translate(-50%, -50%) scale(0);
|
||||
opacity: 0; }
|
||||
md-tooltip .md-content {
|
||||
position: relative;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
background: transparent;
|
||||
opacity: 0;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
padding-left: 16px;
|
||||
padding-right: 16px; }
|
||||
@media screen and (min-width: 600px) {
|
||||
md-tooltip .md-content {
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
padding-left: 8px;
|
||||
padding-right: 8px; } }
|
||||
md-tooltip .md-content.md-show-add {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
opacity: 0; }
|
||||
md-tooltip .md-content.md-show, md-tooltip .md-content.md-show-add-active {
|
||||
opacity: 1; }
|
||||
md-tooltip .md-content.md-show-remove {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-tooltip .md-content.md-show-remove.md-show-remove-active {
|
||||
opacity: 0; }
|
||||
md-tooltip.md-hide {
|
||||
transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); }
|
||||
md-tooltip.md-show {
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
|
||||
pointer-events: auto;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0); }
|
||||
267
www/lib/angular-material/modules/closure/tooltip/tooltip.js
vendored
Normal file
267
www/lib/angular-material/modules/closure/tooltip/tooltip.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.tooltip');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.tooltip
|
||||
*/
|
||||
angular
|
||||
.module('material.components.tooltip', [ 'material.core' ])
|
||||
.directive('mdTooltip', MdTooltipDirective);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdTooltip
|
||||
* @module material.components.tooltip
|
||||
* @description
|
||||
* Tooltips are used to describe elements that are interactive and primarily graphical (not textual).
|
||||
*
|
||||
* Place a `<md-tooltip>` as a child of the element it describes.
|
||||
*
|
||||
* A tooltip will activate when the user focuses, hovers over, or touches the parent.
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <md-button class="md-fab md-accent" aria-label="Play">
|
||||
* <md-tooltip>
|
||||
* Play Music
|
||||
* </md-tooltip>
|
||||
* <md-icon icon="img/icons/ic_play_arrow_24px.svg"></md-icon>
|
||||
* </md-button>
|
||||
* </hljs>
|
||||
*
|
||||
* @param {expression=} md-visible Boolean bound to whether the tooltip is
|
||||
* currently visible.
|
||||
* @param {number=} md-delay How many milliseconds to wait to show the tooltip after the user focuses, hovers, or touches the parent. Defaults to 400ms.
|
||||
* @param {string=} md-direction Which direction would you like the tooltip to go? Supports left, right, top, and bottom. Defaults to bottom.
|
||||
* @param {boolean=} md-autohide If present or provided with a boolean value, the tooltip will hide on mouse leave, regardless of focus
|
||||
*/
|
||||
function MdTooltipDirective($timeout, $window, $$rAF, $document, $mdUtil, $mdTheming, $rootElement,
|
||||
$animate, $q) {
|
||||
|
||||
var TOOLTIP_SHOW_DELAY = 300;
|
||||
var TOOLTIP_WINDOW_EDGE_SPACE = 8;
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
priority:210, // Before ngAria
|
||||
template: '\
|
||||
<div class="md-background"></div>\
|
||||
<div class="md-content" ng-transclude></div>',
|
||||
scope: {
|
||||
visible: '=?mdVisible',
|
||||
delay: '=?mdDelay',
|
||||
autohide: '=?mdAutohide'
|
||||
},
|
||||
link: postLink
|
||||
};
|
||||
|
||||
function postLink(scope, element, attr) {
|
||||
|
||||
$mdTheming(element);
|
||||
|
||||
var parent = getParentWithPointerEvents(),
|
||||
background = angular.element(element[0].getElementsByClassName('md-background')[0]),
|
||||
content = angular.element(element[0].getElementsByClassName('md-content')[0]),
|
||||
direction = attr.mdDirection,
|
||||
current = getNearestContentElement(),
|
||||
tooltipParent = angular.element(current || document.body),
|
||||
debouncedOnResize = $$rAF.throttle(function () { if (scope.visible) positionTooltip(); });
|
||||
|
||||
return init();
|
||||
|
||||
function init () {
|
||||
setDefaults();
|
||||
manipulateElement();
|
||||
bindEvents();
|
||||
configureWatchers();
|
||||
addAriaLabel();
|
||||
}
|
||||
|
||||
function setDefaults () {
|
||||
if (!angular.isDefined(attr.mdDelay)) scope.delay = TOOLTIP_SHOW_DELAY;
|
||||
}
|
||||
|
||||
function configureWatchers () {
|
||||
scope.$on('$destroy', function() {
|
||||
scope.visible = false;
|
||||
element.remove();
|
||||
angular.element($window).off('resize', debouncedOnResize);
|
||||
});
|
||||
scope.$watch('visible', function (isVisible) {
|
||||
if (isVisible) showTooltip();
|
||||
else hideTooltip();
|
||||
});
|
||||
}
|
||||
|
||||
function addAriaLabel () {
|
||||
if (!parent.attr('aria-label') && !parent.text().trim()) {
|
||||
parent.attr('aria-label', element.text().trim());
|
||||
}
|
||||
}
|
||||
|
||||
function manipulateElement () {
|
||||
element.detach();
|
||||
element.attr('role', 'tooltip');
|
||||
}
|
||||
|
||||
function getParentWithPointerEvents () {
|
||||
var parent = element.parent();
|
||||
while (parent && $window.getComputedStyle(parent[0])['pointer-events'] == 'none') {
|
||||
parent = parent.parent();
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
function getNearestContentElement () {
|
||||
var current = element.parent()[0];
|
||||
// Look for the nearest parent md-content, stopping at the rootElement.
|
||||
while (current && current !== $rootElement[0] && current !== document.body) {
|
||||
current = current.parentNode;
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
function hasComputedStyleValue(key, value) {
|
||||
// Check if we should show it or not...
|
||||
var computedStyles = $window.getComputedStyle(element[0]);
|
||||
return angular.isDefined(computedStyles[key]) && (computedStyles[key] == value);
|
||||
}
|
||||
|
||||
function bindEvents () {
|
||||
var mouseActive = false;
|
||||
var enterHandler = function() {
|
||||
if (!hasComputedStyleValue('pointer-events','none')) {
|
||||
setVisible(true);
|
||||
}
|
||||
};
|
||||
var leaveHandler = function () {
|
||||
var autohide = scope.hasOwnProperty('autohide') ? scope.autohide : attr.hasOwnProperty('mdAutohide');
|
||||
if (autohide || mouseActive || ($document[0].activeElement !== parent[0]) ) {
|
||||
setVisible(false);
|
||||
}
|
||||
mouseActive = false;
|
||||
};
|
||||
|
||||
// to avoid `synthetic clicks` we listen to mousedown instead of `click`
|
||||
parent.on('mousedown', function() { mouseActive = true; });
|
||||
parent.on('focus mouseenter touchstart', enterHandler );
|
||||
parent.on('blur mouseleave touchend touchcancel', leaveHandler );
|
||||
|
||||
|
||||
angular.element($window).on('resize', debouncedOnResize);
|
||||
}
|
||||
|
||||
function setVisible (value) {
|
||||
setVisible.value = !!value;
|
||||
if (!setVisible.queued) {
|
||||
if (value) {
|
||||
setVisible.queued = true;
|
||||
$timeout(function() {
|
||||
scope.visible = setVisible.value;
|
||||
setVisible.queued = false;
|
||||
}, scope.delay);
|
||||
} else {
|
||||
$timeout(function() { scope.visible = false; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showTooltip() {
|
||||
// Insert the element before positioning it, so we can get the position
|
||||
// and check if we should display it
|
||||
tooltipParent.append(element);
|
||||
|
||||
// Check if we should display it or not.
|
||||
// This handles hide-* and show-* along with any user defined css
|
||||
if ( hasComputedStyleValue('display','none') ) {
|
||||
scope.visible = false;
|
||||
element.detach();
|
||||
return;
|
||||
}
|
||||
|
||||
positionTooltip();
|
||||
angular.forEach([element, background, content], function (element) {
|
||||
$animate.addClass(element, 'md-show');
|
||||
});
|
||||
}
|
||||
|
||||
function hideTooltip() {
|
||||
$q.all([
|
||||
$animate.removeClass(content, 'md-show'),
|
||||
$animate.removeClass(background, 'md-show'),
|
||||
$animate.removeClass(element, 'md-show')
|
||||
]).then(function () {
|
||||
if (!scope.visible) element.detach();
|
||||
});
|
||||
}
|
||||
|
||||
function positionTooltip() {
|
||||
var tipRect = $mdUtil.offsetRect(element, tooltipParent);
|
||||
var parentRect = $mdUtil.offsetRect(parent, tooltipParent);
|
||||
var newPosition = getPosition(direction);
|
||||
|
||||
// If the user provided a direction, just nudge the tooltip onto the screen
|
||||
// Otherwise, recalculate based on 'top' since default is 'bottom'
|
||||
if (direction) {
|
||||
newPosition = fitInParent(newPosition);
|
||||
} else if (newPosition.top > element.prop('offsetParent').scrollHeight - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE) {
|
||||
newPosition = fitInParent(getPosition('top'));
|
||||
}
|
||||
|
||||
element.css({top: newPosition.top + 'px', left: newPosition.left + 'px'});
|
||||
|
||||
positionBackground();
|
||||
|
||||
function positionBackground () {
|
||||
var size = direction === 'left' || direction === 'right'
|
||||
? Math.sqrt(Math.pow(tipRect.width, 2) + Math.pow(tipRect.height / 2, 2)) * 2
|
||||
: Math.sqrt(Math.pow(tipRect.width / 2, 2) + Math.pow(tipRect.height, 2)) * 2,
|
||||
position = direction === 'left' ? { left: 100, top: 50 }
|
||||
: direction === 'right' ? { left: 0, top: 50 }
|
||||
: direction === 'top' ? { left: 50, top: 100 }
|
||||
: { left: 50, top: 0 };
|
||||
background.css({
|
||||
width: size + 'px',
|
||||
height: size + 'px',
|
||||
left: position.left + '%',
|
||||
top: position.top + '%'
|
||||
});
|
||||
}
|
||||
|
||||
function fitInParent (pos) {
|
||||
var newPosition = { left: pos.left, top: pos.top };
|
||||
newPosition.left = Math.min( newPosition.left, tooltipParent.prop('scrollWidth') - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE );
|
||||
newPosition.left = Math.max( newPosition.left, TOOLTIP_WINDOW_EDGE_SPACE );
|
||||
newPosition.top = Math.min( newPosition.top, tooltipParent.prop('scrollHeight') - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE );
|
||||
newPosition.top = Math.max( newPosition.top, TOOLTIP_WINDOW_EDGE_SPACE );
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
function getPosition (dir) {
|
||||
return dir === 'left'
|
||||
? { left: parentRect.left - tipRect.width - TOOLTIP_WINDOW_EDGE_SPACE,
|
||||
top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
|
||||
: dir === 'right'
|
||||
? { left: parentRect.left + parentRect.width + TOOLTIP_WINDOW_EDGE_SPACE,
|
||||
top: parentRect.top + parentRect.height / 2 - tipRect.height / 2 }
|
||||
: dir === 'top'
|
||||
? { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
|
||||
top: parentRect.top - tipRect.height - TOOLTIP_WINDOW_EDGE_SPACE }
|
||||
: { left: parentRect.left + parentRect.width / 2 - tipRect.width / 2,
|
||||
top: parentRect.top + parentRect.height + TOOLTIP_WINDOW_EDGE_SPACE };
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
MdTooltipDirective.$inject = ["$timeout", "$window", "$$rAF", "$document", "$mdUtil", "$mdTheming", "$rootElement", "$animate", "$q"];
|
||||
|
||||
ng.material.components.tooltip = angular.module("material.components.tooltip");
|
||||
@@ -0,0 +1,25 @@
|
||||
/*!
|
||||
* 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-whiteframe-z1 {
|
||||
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-whiteframe-z2 {
|
||||
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, 0.14), 0 4px 5px 0 rgba(0, 0, 0, 0.098), 0 1px 10px 0 rgba(0, 0, 0, 0.084); }
|
||||
|
||||
.md-whiteframe-z3 {
|
||||
box-shadow: 0px 3px 5px -1px rgba(0, 0, 0, 0.14), 0px 6px 10px 0px rgba(0, 0, 0, 0.098), 0px 1px 18px 0px rgba(0, 0, 0, 0.084); }
|
||||
|
||||
.md-whiteframe-z4 {
|
||||
box-shadow: 0px 5px 5px -3px rgba(0, 0, 0, 0.14), 0px 8px 10px 1px rgba(0, 0, 0, 0.098), 0px 3px 14px 2px rgba(0, 0, 0, 0.084); }
|
||||
|
||||
.md-whiteframe-z5 {
|
||||
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); }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-whiteframe {
|
||||
border: 1px solid #fff; } }
|
||||
15
www/lib/angular-material/modules/closure/whiteframe/whiteframe.js
vendored
Normal file
15
www/lib/angular-material/modules/closure/whiteframe/whiteframe.js
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.whiteframe');
|
||||
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.whiteframe
|
||||
*/
|
||||
angular.module('material.components.whiteframe', []);
|
||||
|
||||
ng.material.components.whiteframe = angular.module("material.components.whiteframe");
|
||||
Reference in New Issue
Block a user