summaryrefslogtreecommitdiffstats
path: root/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select
diff options
context:
space:
mode:
authortalasila <talasila@research.att.com>2017-02-07 15:03:57 -0500
committertalasila <talasila@research.att.com>2017-02-07 15:05:15 -0500
commit4ad39a5c96dd99acf819ce189b13fec946d7506b (patch)
treea1449286441947cc3d07a45227fa0d6f978e1a7d /ecomp-portal-FE/client/bower_components/angular-material/modules/js/select
parent5500448cbd1f374d0ac743ee2fd636fe2d3c0027 (diff)
Initial OpenECOMP Portal commit
Change-Id: I804b80e0830c092e307da1599bd9fbb5c3e2da77 Signed-off-by: talasila <talasila@research.att.com>
Diffstat (limited to 'ecomp-portal-FE/client/bower_components/angular-material/modules/js/select')
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/bower.json8
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.css42
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.min.css6
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.css168
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.js1056
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.css6
-rw-r--r--ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.js7
7 files changed, 1293 insertions, 0 deletions
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/bower.json b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/bower.json
new file mode 100644
index 00000000..339f153b
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/bower.json
@@ -0,0 +1,8 @@
+{
+ "name": "angular-material-select",
+ "version": "0.9.8",
+ "dependencies": {
+ "angular-material-core": "0.9.8",
+ "angular-material-backdrop": "0.9.8"
+ }
+} \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.css b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.css
new file mode 100644
index 00000000..fc712622
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.css
@@ -0,0 +1,42 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */
+/* 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}}'; }
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.min.css b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.min.css
new file mode 100644
index 00000000..5f51cc2c
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select-default-theme.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */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,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-menu.md-THEME_NAME-theme md-optgroup,md-select.md-THEME_NAME-theme .md-select-label.md-placeholder{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:0 0} \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.css b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.css
new file mode 100644
index 00000000..d1744af9
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.css
@@ -0,0 +1,168 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */
+/* 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: -webkit-transform all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1);
+ transition: transform 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: 2px solid;
+ padding-bottom: 0; }
+ md-select:not([disabled]):focus .md-select-label {
+ border-bottom: 2px 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: 1px 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; } }
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.js b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.js
new file mode 100644
index 00000000..969e06b7
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.js
@@ -0,0 +1,1056 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */
+(function( window, angular, undefined ){
+"use strict";
+
+/**
+ * @ngdoc module
+ * @name material.components.select
+ */
+
+/***************************************************
+
+### TODO ###
+**DOCUMENTATION AND DEMOS**
+
+- [ ] ng-model with child mdOptions (basic)
+- [ ] ng-model="foo" ng-model-options="{ trackBy: '$value.id' }" for objects
+- [ ] mdOption with value
+- [ ] Usage with input inside
+
+### TODO - POST RC1 ###
+- [ ] Abstract placement logic in $mdSelect service to $mdMenu service
+
+***************************************************/
+
+var SELECT_EDGE_MARGIN = 8;
+var selectNextId = 0;
+
+angular.module('material.components.select', [
+ 'material.core',
+ 'material.components.backdrop'
+])
+.directive('mdSelect', SelectDirective)
+.directive('mdSelectMenu', SelectMenuDirective)
+.directive('mdOption', OptionDirective)
+.directive('mdOptgroup', OptgroupDirective)
+.provider('$mdSelect', SelectProvider);
+
+
+/**
+ * @ngdoc directive
+ * @name mdSelect
+ * @restrict E
+ * @module material.components.select
+ *
+ * @description Displays a select box, bound to an ng-model.
+ *
+ * @param {expression} ng-model The model!
+ * @param {boolean=} multiple Whether it's multiple.
+ * @param {string=} placeholder Placeholder hint text.
+ * @param {string=} aria-label Optional label for accessibility. Only necessary if no placeholder or
+ * explicit label is present.
+ *
+ * @usage
+ * With a placeholder (label and aria-label are added dynamically)
+ * <hljs lang="html">
+ * <md-select
+ * ng-model="someModel"
+ * placeholder="Select a state">
+ * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
+ * </md-select>
+ * </hljs>
+ *
+ * With an explicit label
+ * <hljs lang="html">
+ * <md-select
+ * ng-model="someModel">
+ * <md-select-label>Select a state</md-select-label>
+ * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option>
+ * </md-select>
+ * </hljs>
+ */
+function SelectDirective($mdSelect, $mdUtil, $mdTheming, $mdAria, $interpolate, $compile, $parse) {
+ return {
+ restrict: 'E',
+ require: ['mdSelect', 'ngModel', '?^form'],
+ compile: compile,
+ controller: function() { } // empty placeholder controller to be initialized in link
+ };
+
+ function compile(element, attr) {
+ // The user is allowed to provide a label for the select as md-select-label child
+ var labelEl = element.find('md-select-label').remove();
+
+ // If not provided, we automatically make one
+ if (!labelEl.length) {
+ labelEl = angular.element('<md-select-label><span></span></md-select-label>');
+ } else {
+ if (!labelEl[0].firstElementChild) {
+ var spanWrapper = angular.element('<span>');
+ spanWrapper.append(labelEl.contents());
+ labelEl.append(spanWrapper);
+ }
+ }
+ labelEl.append('<span class="md-select-icon" aria-hidden="true"></span>');
+ labelEl.addClass('md-select-label');
+ if (!labelEl[0].hasAttribute('id')) {
+ labelEl.attr('id', 'select_label_' + $mdUtil.nextUid());
+ }
+
+ // There's got to be an md-content inside. If there's not one, let's add it.
+ if (!element.find('md-content').length) {
+ element.append( angular.element('<md-content>').append(element.contents()) );
+ }
+
+ // Add progress spinner for md-options-loading
+ if (attr.mdOnOpen) {
+ element.find('md-content').prepend(
+ angular.element('<md-progress-circular>')
+ .attr('md-mode', 'indeterminate')
+ .attr('ng-hide', '$$loadingAsyncDone')
+ .wrap('<div>')
+ .parent()
+ );
+ }
+
+ if (attr.name) {
+ var autofillClone = angular.element('<select class="md-visually-hidden">');
+ autofillClone.attr({
+ 'name': '.' + attr.name,
+ 'ng-model': attr.ngModel,
+ 'aria-hidden': 'true',
+ 'tabindex': '-1'
+ });
+ var opts = element.find('md-option');
+ angular.forEach(opts, function(el) {
+ var newEl = angular.element('<option>' + el.innerHTML + '</option>');
+ if (el.hasAttribute('ng-value')) newEl.attr('ng-value', el.getAttribute('ng-value'));
+ else if (el.hasAttribute('value')) newEl.attr('value', el.getAttribute('value'));
+ autofillClone.append(newEl);
+ });
+
+ element.parent().append(autofillClone);
+ }
+
+ // Use everything that's left inside element.contents() as the contents of the menu
+ var selectTemplate = '<div class="md-select-menu-container">' +
+ '<md-select-menu ' +
+ (angular.isDefined(attr.multiple) ? 'multiple' : '') + '>' +
+ element.html() +
+ '</md-select-menu></div>';
+
+ element.empty().append(labelEl);
+
+ attr.tabindex = attr.tabindex || '0';
+
+ return function postLink(scope, element, attr, ctrls) {
+ var isOpen;
+ var isDisabled;
+
+ var mdSelectCtrl = ctrls[0];
+ var ngModel = ctrls[1];
+ var formCtrl = ctrls[2];
+
+ var labelEl = element.find('md-select-label');
+ var customLabel = labelEl.text().length !== 0;
+ var selectContainer, selectScope, selectMenuCtrl;
+ createSelect();
+
+ $mdTheming(element);
+
+ if (attr.name && formCtrl) {
+ var selectEl = element.parent()[0].querySelector('select[name=".' + attr.name + '"]')
+ formCtrl.$removeControl(angular.element(selectEl).controller());
+ }
+
+ var originalRender = ngModel.$render;
+ ngModel.$render = function() {
+ originalRender();
+ syncLabelText();
+ };
+
+ mdSelectCtrl.setLabelText = function(text) {
+ if (customLabel) return; // Assume that user is handling it on their own
+ mdSelectCtrl.setIsPlaceholder(!text);
+ text = text || attr.placeholder || '';
+ var target = customLabel ? labelEl : labelEl.children().eq(0);
+ target.text(text);
+ };
+
+ mdSelectCtrl.setIsPlaceholder = function(val) {
+ val ? labelEl.addClass('md-placeholder') : labelEl.removeClass('md-placeholder');
+ };
+
+ scope.$$postDigest(function() {
+ setAriaLabel();
+ syncLabelText();
+ });
+
+ function setAriaLabel() {
+ var labelText = element.attr('placeholder');
+ if (!labelText) {
+ labelText = element.find('md-select-label').text();
+ }
+ $mdAria.expect(element, 'aria-label', labelText);
+ }
+
+ function syncLabelText() {
+ if (selectContainer) {
+ selectMenuCtrl = selectMenuCtrl || selectContainer.find('md-select-menu').controller('mdSelectMenu');
+ mdSelectCtrl.setLabelText(selectMenuCtrl.selectedLabels());
+ }
+ }
+
+ var deregisterWatcher;
+ attr.$observe('ngMultiple', function(val) {
+ if (deregisterWatcher) deregisterWatcher();
+ var parser = $parse(val);
+ deregisterWatcher = scope.$watch(function() { return parser(scope); }, function(multiple, prevVal) {
+ if (multiple === undefined && prevVal === undefined) return; // assume compiler did a good job
+ if (multiple) {
+ element.attr('multiple', 'multiple');
+ } else {
+ element.removeAttr('multiple');
+ }
+ if (selectContainer) {
+ selectMenuCtrl.setMultiple(multiple);
+ originalRender = ngModel.$render;
+ ngModel.$render = function() {
+ originalRender();
+ syncLabelText();
+ };
+ selectMenuCtrl.refreshViewValue();
+ ngModel.$render();
+ }
+ });
+ });
+
+ attr.$observe('disabled', function(disabled) {
+ if (typeof disabled == "string") {
+ disabled = true;
+ }
+ // Prevent click event being registered twice
+ if (isDisabled !== undefined && isDisabled === disabled) {
+ return;
+ }
+ isDisabled = disabled;
+ if (disabled) {
+ element.attr({'tabindex': -1, 'aria-disabled': 'true'});
+ element.off('click', openSelect);
+ element.off('keydown', handleKeypress);
+ } else {
+ element.attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'});
+ element.on('click', openSelect);
+ element.on('keydown', handleKeypress);
+ }
+ });
+ if (!attr.disabled && !attr.ngDisabled) {
+ element.attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'});
+ element.on('click', openSelect);
+ element.on('keydown', handleKeypress);
+ }
+
+ var ariaAttrs = {
+ role: 'combobox',
+ 'aria-expanded': 'false'
+ };
+ if (!element[0].hasAttribute('id')) {
+ ariaAttrs.id = 'select_' + $mdUtil.nextUid();
+ }
+ element.attr(ariaAttrs);
+
+ scope.$on('$destroy', function() {
+ if (isOpen) {
+ $mdSelect.cancel().then(function() {
+ selectContainer.remove();
+ });
+ } else {
+ selectContainer.remove();
+ }
+ });
+
+
+ // Create a fake select to find out the label value
+ function createSelect() {
+ selectContainer = angular.element(selectTemplate);
+ var selectEl = selectContainer.find('md-select-menu');
+ selectEl.data('$ngModelController', ngModel);
+ selectEl.data('$mdSelectController', mdSelectCtrl);
+ selectScope = scope.$new();
+ selectContainer = $compile(selectContainer)(selectScope);
+ selectMenuCtrl = selectContainer.find('md-select-menu').controller('mdSelectMenu');
+ }
+
+ function handleKeypress(e) {
+ var allowedCodes = [32, 13, 38, 40];
+ if (allowedCodes.indexOf(e.keyCode) != -1 ) {
+ // prevent page scrolling on interaction
+ e.preventDefault();
+ openSelect(e);
+ } else {
+ if (e.keyCode <= 90 && e.keyCode >= 31) {
+ e.preventDefault();
+ var node = selectMenuCtrl.optNodeForKeyboardSearch(e);
+ if (!node) return;
+ var optionCtrl = angular.element(node).controller('mdOption');
+ if (!selectMenuCtrl.isMultiple) {
+ selectMenuCtrl.deselect( Object.keys(selectMenuCtrl.selected)[0] );
+ }
+ selectMenuCtrl.select(optionCtrl.hashKey, optionCtrl.value);
+ selectMenuCtrl.refreshViewValue();
+ ngModel.$render();
+ }
+ }
+ }
+
+ function openSelect() {
+ scope.$evalAsync(function() {
+ isOpen = true;
+ $mdSelect.show({
+ scope: selectScope,
+ preserveScope: true,
+ skipCompile: true,
+ element: selectContainer,
+ target: element[0],
+ hasBackdrop: true,
+ loadingAsync: attr.mdOnOpen ? scope.$eval(attr.mdOnOpen) || true : false,
+ }).then(function(selectedText) {
+ isOpen = false;
+ });
+ });
+ }
+ };
+ }
+}
+SelectDirective.$inject = ["$mdSelect", "$mdUtil", "$mdTheming", "$mdAria", "$interpolate", "$compile", "$parse"];
+
+function SelectMenuDirective($parse, $mdUtil, $mdTheming) {
+
+ SelectMenuController.$inject = ["$scope", "$attrs", "$element"];
+ return {
+ restrict: 'E',
+ require: ['mdSelectMenu', '?ngModel'],
+ controller: SelectMenuController,
+ link: { pre: preLink }
+ };
+
+ // We use preLink instead of postLink to ensure that the select is initialized before
+ // its child options run postLink.
+ function preLink(scope, element, attr, ctrls) {
+ var selectCtrl = ctrls[0];
+ var ngModel = ctrls[1];
+
+ $mdTheming(element);
+ element.on('click', clickListener);
+ element.on('keypress', keyListener);
+ if (ngModel) selectCtrl.init(ngModel);
+ configureAria();
+
+ function configureAria() {
+ element.attr({
+ 'id': 'select_menu_' + $mdUtil.nextUid(),
+ 'role': 'listbox',
+ 'aria-multiselectable': (selectCtrl.isMultiple ? 'true' : 'false')
+ });
+ }
+
+ function keyListener(e) {
+ if (e.keyCode == 13 || e.keyCode == 32) {
+ clickListener(e);
+ }
+ }
+
+ function clickListener(ev) {
+ var option = $mdUtil.getClosest(ev.target, 'md-option');
+ var optionCtrl = option && angular.element(option).data('$mdOptionController');
+ if (!option || !optionCtrl) return;
+
+ var optionHashKey = selectCtrl.hashGetter(optionCtrl.value);
+ var isSelected = angular.isDefined(selectCtrl.selected[optionHashKey]);
+
+ scope.$apply(function() {
+ if (selectCtrl.isMultiple) {
+ if (isSelected) {
+ selectCtrl.deselect(optionHashKey);
+ } else {
+ selectCtrl.select(optionHashKey, optionCtrl.value);
+ }
+ } else {
+ if (!isSelected) {
+ selectCtrl.deselect( Object.keys(selectCtrl.selected)[0] );
+ selectCtrl.select( optionHashKey, optionCtrl.value );
+ }
+ }
+ selectCtrl.refreshViewValue();
+ });
+ }
+ }
+
+
+
+ function SelectMenuController($scope, $attrs, $element) {
+ var self = this;
+ self.isMultiple = angular.isDefined($attrs.multiple);
+ // selected is an object with keys matching all of the selected options' hashed values
+ self.selected = {};
+ // options is an object with keys matching every option's hash value,
+ // and values matching every option's controller.
+ self.options = {};
+
+ $scope.$watch(function() { return self.options; }, function() {
+ self.ngModel.$render();
+ }, true);
+
+ var deregisterCollectionWatch;
+ self.setMultiple = function(isMultiple) {
+ var ngModel = self.ngModel;
+ self.isMultiple = isMultiple;
+ if (deregisterCollectionWatch) deregisterCollectionWatch();
+
+ if (self.isMultiple) {
+ ngModel.$validators['md-multiple'] = validateArray;
+ ngModel.$render = renderMultiple;
+
+ // watchCollection on the model because by default ngModel only watches the model's
+ // reference. This allowed the developer to also push and pop from their array.
+ $scope.$watchCollection($attrs.ngModel, function(value) {
+ if (validateArray(value)) renderMultiple(value);
+ });
+ } else {
+ delete ngModel.$validators['md-multiple'];
+ ngModel.$render = renderSingular;
+ }
+
+ function validateArray(modelValue, viewValue) {
+ // If a value is truthy but not an array, reject it.
+ // If value is undefined/falsy, accept that it's an empty array.
+ return angular.isArray(modelValue || viewValue || []);
+ }
+ };
+
+ var searchStr = '';
+ var clearSearchTimeout, optNodes, optText;
+ var CLEAR_SEARCH_AFTER = 300;
+ self.optNodeForKeyboardSearch = function(e) {
+ clearSearchTimeout && clearTimeout(clearSearchTimeout);
+ clearSearchTimeout = setTimeout(function() {
+ clearSearchTimeout = undefined;
+ searchStr = '';
+ optText = undefined;
+ optNodes = undefined;
+ }, CLEAR_SEARCH_AFTER);
+ searchStr += String.fromCharCode(e.keyCode);
+ var search = new RegExp('^' + searchStr, 'i');
+ if (!optNodes) {
+ optNodes = $element.find('md-option');
+ optText = new Array(optNodes.length);
+ angular.forEach(optNodes, function(el, i) {
+ optText[i] = el.textContent.trim();
+ });
+ }
+ for (var i = 0; i < optText.length; ++i) {
+ if (search.test(optText[i])) {
+ return optNodes[i];
+ }
+ }
+ };
+
+
+ self.init = function(ngModel) {
+ self.ngModel = ngModel;
+
+ // Allow users to provide `ng-model="foo" ng-model-options="{trackBy: 'foo.id'}"` so
+ // that we can properly compare objects set on the model to the available options
+ if (ngModel.$options && ngModel.$options.trackBy) {
+ var trackByLocals = {};
+ var trackByParsed = $parse(ngModel.$options.trackBy);
+ self.hashGetter = function(value, valueScope) {
+ trackByLocals.$value = value;
+ return trackByParsed(valueScope || $scope, trackByLocals);
+ };
+ // If the user doesn't provide a trackBy, we automatically generate an id for every
+ // value passed in
+ } else {
+ self.hashGetter = function getHashValue(value) {
+ if (angular.isObject(value)) {
+ return 'object_' + (value.$$mdSelectId || (value.$$mdSelectId = ++selectNextId));
+ }
+ return value;
+ };
+ }
+ self.setMultiple(self.isMultiple);
+ };
+
+ self.selectedLabels = function() {
+ var selectedOptionEls = nodesToArray($element[0].querySelectorAll('md-option[selected]'));
+ if (selectedOptionEls.length) {
+ return selectedOptionEls.map(function(el) { return el.textContent; }).join(', ');
+ } else {
+ return '';
+ }
+ };
+
+ self.select = function(hashKey, hashedValue) {
+ var option = self.options[hashKey];
+ option && option.setSelected(true);
+ self.selected[hashKey] = hashedValue;
+ };
+ self.deselect = function(hashKey) {
+ var option = self.options[hashKey];
+ option && option.setSelected(false);
+ delete self.selected[hashKey];
+ };
+
+ self.addOption = function(hashKey, optionCtrl) {
+ if (angular.isDefined(self.options[hashKey])) {
+ throw new Error('Duplicate md-option values are not allowed in a select. ' +
+ 'Duplicate value "' + optionCtrl.value + '" found.');
+ }
+ self.options[hashKey] = optionCtrl;
+
+ // If this option's value was already in our ngModel, go ahead and select it.
+ if (angular.isDefined(self.selected[hashKey])) {
+ self.select(hashKey, optionCtrl.value);
+ self.refreshViewValue();
+ }
+ };
+ self.removeOption = function(hashKey) {
+ delete self.options[hashKey];
+ // Don't deselect an option when it's removed - the user's ngModel should be allowed
+ // to have values that do not match a currently available option.
+ };
+
+ self.refreshViewValue = function() {
+ var values = [];
+ var option;
+ for (var hashKey in self.selected) {
+ // If this hashKey has an associated option, push that option's value to the model.
+ if ((option = self.options[hashKey])) {
+ values.push(option.value);
+ } else {
+ // Otherwise, the given hashKey has no associated option, and we got it
+ // from an ngModel value at an earlier time. Push the unhashed value of
+ // this hashKey to the model.
+ // This allows the developer to put a value in the model that doesn't yet have
+ // an associated option.
+ values.push(self.selected[hashKey]);
+ }
+ }
+ self.ngModel.$setViewValue(self.isMultiple ? values : values[0]);
+ };
+
+ function renderMultiple() {
+ var newSelectedValues = self.ngModel.$modelValue || self.ngModel.$viewValue;
+ if (!angular.isArray(newSelectedValues)) return;
+
+ var oldSelected = Object.keys(self.selected);
+
+ var newSelectedHashes = newSelectedValues.map(self.hashGetter);
+ var deselected = oldSelected.filter(function(hash) {
+ return newSelectedHashes.indexOf(hash) === -1;
+ });
+
+ deselected.forEach(self.deselect);
+ newSelectedHashes.forEach(function(hashKey, i) {
+ self.select(hashKey, newSelectedValues[i]);
+ });
+ }
+ function renderSingular() {
+ var value = self.ngModel.$viewValue || self.ngModel.$modelValue;
+ Object.keys(self.selected).forEach(self.deselect);
+ self.select( self.hashGetter(value), value );
+ }
+ }
+
+}
+SelectMenuDirective.$inject = ["$parse", "$mdUtil", "$mdTheming"];
+
+function OptionDirective($mdButtonInkRipple, $mdUtil) {
+
+ OptionController.$inject = ["$element"];
+ return {
+ restrict: 'E',
+ require: ['mdOption', '^^mdSelectMenu'],
+ controller: OptionController,
+ compile: compile
+ };
+
+ function compile(element, attr) {
+ // Manual transclusion to avoid the extra inner <span> that ng-transclude generates
+ element.append( angular.element('<div class="md-text">').append(element.contents()) );
+
+ element.attr('tabindex', attr.tabindex || '0');
+ return postLink;
+ }
+
+ function postLink(scope, element, attr, ctrls) {
+ var optionCtrl = ctrls[0];
+ var selectCtrl = ctrls[1];
+
+ if (angular.isDefined(attr.ngValue)) {
+ scope.$watch(attr.ngValue, setOptionValue);
+ } else if (angular.isDefined(attr.value)) {
+ setOptionValue(attr.value);
+ } else {
+ scope.$watch(function() { return element.text(); }, setOptionValue);
+ }
+
+ scope.$$postDigest(function() {
+ attr.$observe('selected', function(selected) {
+ if (!angular.isDefined(selected)) return;
+ if (selected) {
+ if (!selectCtrl.isMultiple) {
+ selectCtrl.deselect( Object.keys(selectCtrl.selected)[0] );
+ }
+ selectCtrl.select(optionCtrl.hashKey, optionCtrl.value);
+ } else {
+ selectCtrl.deselect(optionCtrl.hashKey);
+ }
+ selectCtrl.refreshViewValue();
+ selectCtrl.ngModel.$render();
+ });
+ });
+
+ $mdButtonInkRipple.attach(scope, element);
+ configureAria();
+
+ function setOptionValue(newValue, oldValue) {
+ var oldHashKey = selectCtrl.hashGetter(oldValue, scope);
+ var newHashKey = selectCtrl.hashGetter(newValue, scope);
+
+ optionCtrl.hashKey = newHashKey;
+ optionCtrl.value = newValue;
+
+ selectCtrl.removeOption(oldHashKey, optionCtrl);
+ selectCtrl.addOption(newHashKey, optionCtrl);
+ }
+
+ scope.$on('$destroy', function() {
+ selectCtrl.removeOption(optionCtrl.hashKey, optionCtrl);
+ });
+
+ function configureAria() {
+ var ariaAttrs = {
+ 'role': 'option',
+ 'aria-selected': 'false'
+ };
+
+ if (!element[0].hasAttribute('id')) {
+ ariaAttrs.id = 'select_option_' + $mdUtil.nextUid();
+ }
+ element.attr(ariaAttrs);
+ }
+ }
+
+ function OptionController($element) {
+ this.selected = false;
+ this.setSelected = function(isSelected) {
+ if (isSelected && !this.selected) {
+ $element.attr({
+ 'selected': 'selected',
+ 'aria-selected': 'true'
+ });
+ } else if (!isSelected && this.selected) {
+ $element.removeAttr('selected');
+ $element.attr('aria-selected', 'false');
+ }
+ this.selected = isSelected;
+ };
+ }
+
+}
+OptionDirective.$inject = ["$mdButtonInkRipple", "$mdUtil"];
+
+function OptgroupDirective() {
+ return {
+ restrict: 'E',
+ compile: compile
+ };
+ function compile(el, attrs) {
+ var labelElement = el.find('label');
+ if (!labelElement.length) {
+ labelElement = angular.element('<label>');
+ el.prepend(labelElement);
+ }
+ if (attrs.label) labelElement.text(attrs.label);
+ }
+}
+
+function SelectProvider($$interimElementProvider) {
+ selectDefaultOptions.$inject = ["$mdSelect", "$mdConstant", "$$rAF", "$mdUtil", "$mdTheming", "$timeout", "$window"];
+ return $$interimElementProvider('$mdSelect')
+ .setDefaults({
+ methods: ['target'],
+ options: selectDefaultOptions
+ });
+
+ /* ngInject */
+ function selectDefaultOptions($mdSelect, $mdConstant, $$rAF, $mdUtil, $mdTheming, $timeout, $window ) {
+ return {
+ parent: 'body',
+ onShow: onShow,
+ onRemove: onRemove,
+ hasBackdrop: true,
+ disableParentScroll: true,
+ themable: true
+ };
+
+ function onShow(scope, element, opts) {
+ if (!opts.target) {
+ throw new Error('$mdSelect.show() expected a target element in options.target but got ' +
+ '"' + opts.target + '"!');
+ }
+
+ angular.extend(opts, {
+ isRemoved: false,
+ target: angular.element(opts.target), //make sure it's not a naked dom node
+ parent: angular.element(opts.parent),
+ selectEl: element.find('md-select-menu'),
+ contentEl: element.find('md-content'),
+ backdrop: opts.hasBackdrop && angular.element('<md-backdrop class="md-select-backdrop md-click-catcher">')
+ });
+
+ opts.resizeFn = function() {
+ $$rAF(function() {
+ $$rAF(function() {
+ animateSelect(scope, element, opts);
+ });
+ });
+ };
+
+ angular.element($window).on('resize', opts.resizeFn);
+ angular.element($window).on('orientationchange', opts.resizeFn);
+
+
+ configureAria();
+
+ element.removeClass('md-leave');
+
+ var optionNodes = opts.selectEl[0].getElementsByTagName('md-option');
+
+ if (opts.loadingAsync && opts.loadingAsync.then) {
+ opts.loadingAsync.then(function() {
+ scope.$$loadingAsyncDone = true;
+ // Give ourselves two frames for the progress loader to clear out.
+ $$rAF(function() {
+ $$rAF(function() {
+ // Don't go forward if the select has been removed in this time...
+ if (opts.isRemoved) return;
+ animateSelect(scope, element, opts);
+ });
+ });
+ });
+ } else if (opts.loadingAsync) {
+ scope.$$loadingAsyncDone = true;
+ }
+
+ if (opts.disableParentScroll && !$mdUtil.getClosest(opts.target, 'MD-DIALOG')) {
+ opts.restoreScroll = $mdUtil.disableScrollAround(opts.target);
+ } else {
+ opts.disableParentScroll = false;
+ }
+ // 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);
+ }
+ opts.parent.append(element);
+
+ // Give the select a frame to 'initialize' in the DOM,
+ // so we can read its height/width/position
+ $$rAF(function() {
+ $$rAF(function() {
+ if (opts.isRemoved) return;
+ animateSelect(scope, element, opts);
+ });
+ });
+
+ return $mdUtil.transitionEndPromise(opts.selectEl, {timeout: 350});
+
+ function configureAria() {
+ opts.target.attr('aria-expanded', 'true');
+ }
+
+ function activateInteraction() {
+ if (opts.isRemoved) return;
+ var selectCtrl = opts.selectEl.controller('mdSelectMenu') || {};
+ element.addClass('md-clickable');
+
+ opts.backdrop && opts.backdrop.on('click', function(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ opts.restoreFocus = false;
+ scope.$apply($mdSelect.cancel);
+ });
+
+ // Escape to close
+ opts.selectEl.on('keydown', function(ev) {
+ switch (ev.keyCode) {
+ case $mdConstant.KEY_CODE.SPACE:
+ case $mdConstant.KEY_CODE.ENTER:
+ var option = $mdUtil.getClosest(ev.target, 'md-option');
+ if (option) {
+ opts.selectEl.triggerHandler({
+ type: 'click',
+ target: option
+ });
+ ev.preventDefault();
+ }
+ break;
+ case $mdConstant.KEY_CODE.TAB:
+ case $mdConstant.KEY_CODE.ESCAPE:
+ ev.preventDefault();
+ opts.restoreFocus = true;
+ scope.$apply($mdSelect.cancel);
+ }
+ });
+
+ // Cycling of options, and closing on enter
+ opts.selectEl.on('keydown', function(ev) {
+ switch (ev.keyCode) {
+ case $mdConstant.KEY_CODE.UP_ARROW: return focusPrevOption();
+ case $mdConstant.KEY_CODE.DOWN_ARROW: return focusNextOption();
+ default:
+ if (ev.keyCode >= 31 && ev.keyCode <= 90) {
+ var optNode = opts.selectEl.controller('mdSelectMenu').optNodeForKeyboardSearch(ev);
+ optNode && optNode.focus();
+ }
+ }
+ });
+
+
+ function focusOption(direction) {
+ var optionsArray = nodesToArray(optionNodes);
+ var index = optionsArray.indexOf(opts.focusedNode);
+ if (index === -1) {
+ // We lost the previously focused element, reset to first option
+ index = 0;
+ } else if (direction === 'next' && index < optionsArray.length - 1) {
+ index++;
+ } else if (direction === 'prev' && index > 0) {
+ index--;
+ }
+ var newOption = opts.focusedNode = optionsArray[index];
+ newOption && newOption.focus();
+ }
+ function focusNextOption() {
+ focusOption('next');
+ }
+ function focusPrevOption() {
+ focusOption('prev');
+ }
+
+ opts.selectEl.on('click', checkCloseMenu);
+ opts.selectEl.on('keydown', function(e) {
+ if (e.keyCode == 32 || e.keyCode == 13) {
+ checkCloseMenu();
+ }
+ });
+
+ function checkCloseMenu() {
+ if (!selectCtrl.isMultiple) {
+ opts.restoreFocus = true;
+ scope.$evalAsync(function() {
+ $mdSelect.hide(selectCtrl.ngModel.$viewValue);
+ });
+ }
+ }
+ }
+
+ }
+
+ function onRemove(scope, element, opts) {
+ opts.isRemoved = true;
+ element.addClass('md-leave')
+ .removeClass('md-clickable');
+ opts.target.attr('aria-expanded', 'false');
+
+
+ angular.element($window).off('resize', opts.resizeFn);
+ angular.element($window).off('orientationchange', opts.resizefn);
+ opts.resizeFn = undefined;
+
+ var mdSelect = opts.selectEl.controller('mdSelect');
+ if (mdSelect) {
+ mdSelect.setLabelText(opts.selectEl.controller('mdSelectMenu').selectedLabels());
+ }
+
+ 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]); // use browser to avoid $destroy event
+ }
+ if (opts.disableParentScroll) {
+ opts.restoreScroll();
+ }
+ if (opts.restoreFocus) opts.target.focus();
+ });
+ }
+
+ function animateSelect(scope, element, opts) {
+ var containerNode = element[0],
+ targetNode = opts.target[0].firstElementChild.firstElementChild, // target the first span, functioning as the label
+ parentNode = opts.parent[0],
+ selectNode = opts.selectEl[0],
+ contentNode = opts.contentEl[0],
+ parentRect = parentNode.getBoundingClientRect(),
+ targetRect = targetNode.getBoundingClientRect(),
+ shouldOpenAroundTarget = false,
+ bounds = {
+ left: parentRect.left + SELECT_EDGE_MARGIN,
+ top: SELECT_EDGE_MARGIN,
+ bottom: parentRect.height - SELECT_EDGE_MARGIN,
+ right: parentRect.width - SELECT_EDGE_MARGIN - ($mdUtil.floatingScrollbars() ? 16 : 0)
+ },
+ spaceAvailable = {
+ top: targetRect.top - bounds.top,
+ left: targetRect.left - bounds.left,
+ right: bounds.right - (targetRect.left + targetRect.width),
+ bottom: bounds.bottom - (targetRect.top + targetRect.height)
+ },
+ maxWidth = parentRect.width - SELECT_EDGE_MARGIN * 2,
+ isScrollable = contentNode.scrollHeight > contentNode.offsetHeight,
+ selectedNode = selectNode.querySelector('md-option[selected]'),
+ optionNodes = selectNode.getElementsByTagName('md-option'),
+ optgroupNodes = selectNode.getElementsByTagName('md-optgroup');
+
+
+ var centeredNode;
+ // If a selected node, center around that
+ if (selectedNode) {
+ centeredNode = selectedNode;
+ // If there are option groups, center around the first option group
+ } else if (optgroupNodes.length) {
+ centeredNode = optgroupNodes[0];
+ // Otherwise, center around the first optionNode
+ } else if (optionNodes.length){
+ centeredNode = optionNodes[0];
+ // In case there are no options, center on whatever's in there... (eg progress indicator)
+ } else {
+ centeredNode = contentNode.firstElementChild || contentNode;
+ }
+
+ if (contentNode.offsetWidth > maxWidth) {
+ contentNode.style['max-width'] = maxWidth + 'px';
+ }
+ if (shouldOpenAroundTarget) {
+ contentNode.style['min-width'] = targetRect.width + 'px';
+ }
+
+ // Remove padding before we compute the position of the menu
+ if (isScrollable) {
+ selectNode.classList.add('md-overflow');
+ }
+
+ // Get the selectMenuRect *after* max-width is possibly set above
+ var selectMenuRect = selectNode.getBoundingClientRect();
+ var centeredRect = getOffsetRect(centeredNode);
+
+ if (centeredNode) {
+ var centeredStyle = $window.getComputedStyle(centeredNode);
+ centeredRect.paddingLeft = parseInt(centeredStyle.paddingLeft, 10) || 0;
+ centeredRect.paddingRight = parseInt(centeredStyle.paddingRight, 10) || 0;
+ }
+
+ var focusedNode = centeredNode;
+ if ((focusedNode.tagName || '').toUpperCase() === 'MD-OPTGROUP') {
+ focusedNode = optionNodes[0] || contentNode.firstElementChild || contentNode;
+ }
+
+ if (isScrollable) {
+ var scrollBuffer = contentNode.offsetHeight / 2;
+ contentNode.scrollTop = centeredRect.top + centeredRect.height / 2 - scrollBuffer;
+
+ if (spaceAvailable.top < scrollBuffer) {
+ contentNode.scrollTop = Math.min(
+ centeredRect.top,
+ contentNode.scrollTop + scrollBuffer - spaceAvailable.top
+ );
+ } else if (spaceAvailable.bottom < scrollBuffer) {
+ contentNode.scrollTop = Math.max(
+ centeredRect.top + centeredRect.height - selectMenuRect.height,
+ contentNode.scrollTop - scrollBuffer + spaceAvailable.bottom
+ );
+ }
+ }
+
+ var left, top, transformOrigin;
+ if (shouldOpenAroundTarget) {
+ left = targetRect.left;
+ top = targetRect.top + targetRect.height;
+ transformOrigin = '50% 0';
+ if (top + selectMenuRect.height > bounds.bottom) {
+ top = targetRect.top - selectMenuRect.height;
+ transformOrigin = '50% 100%';
+ }
+ } else {
+ left = targetRect.left + centeredRect.left - centeredRect.paddingLeft;
+ top = Math.floor(targetRect.top + targetRect.height / 2 - centeredRect.height / 2 -
+ centeredRect.top + contentNode.scrollTop);
+
+
+ transformOrigin = (centeredRect.left + targetRect.width / 2) + 'px ' +
+ (centeredRect.top + centeredRect.height / 2 - contentNode.scrollTop) + 'px 0px';
+
+ containerNode.style.minWidth = targetRect.width + centeredRect.paddingLeft +
+ centeredRect.paddingRight + 'px';
+ }
+
+ // Keep left and top within the window
+ var containerRect = containerNode.getBoundingClientRect();
+ containerNode.style.left = clamp(bounds.left, left, bounds.right - containerRect.width) + 'px';
+ containerNode.style.top = clamp(bounds.top, top, bounds.bottom - containerRect.height) + 'px';
+ selectNode.style[$mdConstant.CSS.TRANSFORM_ORIGIN] = transformOrigin;
+
+ selectNode.style[$mdConstant.CSS.TRANSFORM] = 'scale(' +
+ Math.min(targetRect.width / selectMenuRect.width, 1.0) + ',' +
+ Math.min(targetRect.height / selectMenuRect.height, 1.0) +
+ ')';
+
+
+ $$rAF(function() {
+ element.addClass('md-active');
+ selectNode.style[$mdConstant.CSS.TRANSFORM] = '';
+ if (focusedNode) {
+ opts.focusedNode = focusedNode;
+ focusedNode.focus();
+ }
+ });
+ }
+
+ }
+
+ function clamp(min, n, max) {
+ return Math.max(min, Math.min(n, max));
+ }
+
+ function getOffsetRect(node) {
+ return node ? {
+ left: node.offsetLeft,
+ top: node.offsetTop,
+ width: node.offsetWidth,
+ height: node.offsetHeight
+ } : { left: 0, top: 0, width: 0, height: 0 };
+ }
+}
+SelectProvider.$inject = ["$$interimElementProvider"];
+
+// Annoying method to copy nodes to an array, thanks to IE
+function nodesToArray(nodes) {
+ var results = [];
+ for (var i = 0; i < nodes.length; ++i) {
+ results.push(nodes.item(i));
+ }
+ return results;
+}
+
+})(window, window.angular); \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.css b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.css
new file mode 100644
index 00000000..21fe130d
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.css
@@ -0,0 +1,6 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */.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:-webkit-transform all .4s cubic-bezier(.25,.8,.25,1);transition:transform all .4s cubic-bezier(.25,.8,.25,1);transition-duration:200ms}.md-select-menu-container.md-active md-select-menu>*{opacity:1;transition:all .3s cubic-bezier(.55,0,.55,.2);transition-duration:200ms;transition-delay:100ms}.md-select-menu-container.md-leave{opacity:0;transition:all .3s cubic-bezier(.55,0,.55,.2);transition-duration:250ms}md-input-container>md-select{margin:3px 0 0}md-select{padding:24px 2px 26px;display:-webkit-flex;display:-ms-flexbox;display:flex}md-select:focus{outline:0}md-select[disabled]:hover{cursor:default}md-select:not([disabled]):hover{cursor:pointer}md-select:not([disabled]).ng-invalid.ng-dirty .md-select-label,md-select:not([disabled]):focus .md-select-label{border-bottom:2px 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:1px 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(.6) scaleX(1);transform:scaleY(.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:0 3px 1px -2px rgba(0,0,0,.14),0 2px 2px 0 rgba(0,0,0,.098),0 1px 5px 0 rgba(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;height:48px}md-option:focus{outline:0}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}} \ No newline at end of file
diff --git a/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.js b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.js
new file mode 100644
index 00000000..536f69ac
--- /dev/null
+++ b/ecomp-portal-FE/client/bower_components/angular-material/modules/js/select/select.min.js
@@ -0,0 +1,7 @@
+/*!
+ * Angular Material Design
+ * https://github.com/angular/material
+ * @license MIT
+ * v0.9.8
+ */
+!function(e,t,n){"use strict";function l(e,l,o,i,r,a,d){function c(r,c){var s=r.find("md-select-label").remove();if(s.length){if(!s[0].firstElementChild){var u=t.element("<span>");u.append(s.contents()),s.append(u)}}else s=t.element("<md-select-label><span></span></md-select-label>");if(s.append('<span class="md-select-icon" aria-hidden="true"></span>'),s.addClass("md-select-label"),s[0].hasAttribute("id")||s.attr("id","select_label_"+l.nextUid()),r.find("md-content").length||r.append(t.element("<md-content>").append(r.contents())),c.mdOnOpen&&r.find("md-content").prepend(t.element("<md-progress-circular>").attr("md-mode","indeterminate").attr("ng-hide","$$loadingAsyncDone").wrap("<div>").parent()),c.name){var p=t.element('<select class="md-visually-hidden">');p.attr({name:"."+c.name,"ng-model":c.ngModel,"aria-hidden":"true",tabindex:"-1"});var f=r.find("md-option");t.forEach(f,function(e){var n=t.element("<option>"+e.innerHTML+"</option>");e.hasAttribute("ng-value")?n.attr("ng-value",e.getAttribute("ng-value")):e.hasAttribute("value")&&n.attr("value",e.getAttribute("value")),p.append(n)}),r.parent().append(p)}var m='<div class="md-select-menu-container"><md-select-menu '+(t.isDefined(c.multiple)?"multiple":"")+">"+r.html()+"</md-select-menu></div>";return r.empty().append(s),c.tabindex=c.tabindex||"0",function(r,c,s,u){function p(){var e=c.attr("placeholder");e||(e=c.find("md-select-label").text()),i.expect(c,"aria-label",e)}function f(){y&&(w=w||y.find("md-select-menu").controller("mdSelectMenu"),E.setLabelText(w.selectedLabels()))}function h(){y=t.element(m);var e=y.find("md-select-menu");e.data("$ngModelController",k),e.data("$mdSelectController",E),C=r.$new(),y=a(y)(C),w=y.find("md-select-menu").controller("mdSelectMenu")}function g(e){var n=[32,13,38,40];if(-1!=n.indexOf(e.keyCode))e.preventDefault(),v(e);else if(e.keyCode<=90&&e.keyCode>=31){e.preventDefault();var l=w.optNodeForKeyboardSearch(e);if(!l)return;var o=t.element(l).controller("mdOption");w.isMultiple||w.deselect(Object.keys(w.selected)[0]),w.select(o.hashKey,o.value),w.refreshViewValue(),k.$render()}}function v(){r.$evalAsync(function(){$=!0,e.show({scope:C,preserveScope:!0,skipCompile:!0,element:y,target:c[0],hasBackdrop:!0,loadingAsync:s.mdOnOpen?r.$eval(s.mdOnOpen)||!0:!1}).then(function(e){$=!1})})}var $,b,y,C,w,E=u[0],k=u[1],S=u[2],x=c.find("md-select-label"),M=0!==x.text().length;if(h(),o(c),s.name&&S){var O=c.parent()[0].querySelector('select[name=".'+s.name+'"]');S.$removeControl(t.element(O).controller())}var A=k.$render;k.$render=function(){A(),f()},E.setLabelText=function(e){if(!M){E.setIsPlaceholder(!e),e=e||s.placeholder||"";var t=M?x:x.children().eq(0);t.text(e)}},E.setIsPlaceholder=function(e){e?x.addClass("md-placeholder"):x.removeClass("md-placeholder")},r.$$postDigest(function(){p(),f()});var D;s.$observe("ngMultiple",function(e){D&&D();var t=d(e);D=r.$watch(function(){return t(r)},function(e,t){(e!==n||t!==n)&&(e?c.attr("multiple","multiple"):c.removeAttr("multiple"),y&&(w.setMultiple(e),A=k.$render,k.$render=function(){A(),f()},w.refreshViewValue(),k.$render()))})}),s.$observe("disabled",function(e){"string"==typeof e&&(e=!0),(b===n||b!==e)&&(b=e,e?(c.attr({tabindex:-1,"aria-disabled":"true"}),c.off("click",v),c.off("keydown",g)):(c.attr({tabindex:s.tabindex,"aria-disabled":"false"}),c.on("click",v),c.on("keydown",g)))}),s.disabled||s.ngDisabled||(c.attr({tabindex:s.tabindex,"aria-disabled":"false"}),c.on("click",v),c.on("keydown",g));var R={role:"combobox","aria-expanded":"false"};c[0].hasAttribute("id")||(R.id="select_"+l.nextUid()),c.attr(R),r.$on("$destroy",function(){$?e.cancel().then(function(){y.remove()}):y.remove()})}}return{restrict:"E",require:["mdSelect","ngModel","?^form"],compile:c,controller:function(){}}}function o(e,l,o){function i(e,n,i,r){function a(){n.attr({id:"select_menu_"+l.nextUid(),role:"listbox","aria-multiselectable":s.isMultiple?"true":"false"})}function d(e){(13==e.keyCode||32==e.keyCode)&&c(e)}function c(n){var o=l.getClosest(n.target,"md-option"),i=o&&t.element(o).data("$mdOptionController");if(o&&i){var r=s.hashGetter(i.value),a=t.isDefined(s.selected[r]);e.$apply(function(){s.isMultiple?a?s.deselect(r):s.select(r,i.value):a||(s.deselect(Object.keys(s.selected)[0]),s.select(r,i.value)),s.refreshViewValue()})}}var s=r[0],u=r[1];o(n),n.on("click",c),n.on("keypress",d),u&&s.init(u),a()}function r(l,o,i){function r(){var e=c.ngModel.$modelValue||c.ngModel.$viewValue;if(t.isArray(e)){var n=Object.keys(c.selected),l=e.map(c.hashGetter),o=n.filter(function(e){return-1===l.indexOf(e)});o.forEach(c.deselect),l.forEach(function(t,n){c.select(t,e[n])})}}function a(){var e=c.ngModel.$viewValue||c.ngModel.$modelValue;Object.keys(c.selected).forEach(c.deselect),c.select(c.hashGetter(e),e)}var c=this;c.isMultiple=t.isDefined(o.multiple),c.selected={},c.options={},l.$watch(function(){return c.options},function(){c.ngModel.$render()},!0);var u;c.setMultiple=function(e){function n(e,n){return t.isArray(e||n||[])}var i=c.ngModel;c.isMultiple=e,u&&u(),c.isMultiple?(i.$validators["md-multiple"]=n,i.$render=r,l.$watchCollection(o.ngModel,function(e){n(e)&&r(e)})):(delete i.$validators["md-multiple"],i.$render=a)};var p,f,m,h="",g=300;c.optNodeForKeyboardSearch=function(e){p&&clearTimeout(p),p=setTimeout(function(){p=n,h="",m=n,f=n},g),h+=String.fromCharCode(e.keyCode);var l=new RegExp("^"+h,"i");f||(f=i.find("md-option"),m=new Array(f.length),t.forEach(f,function(e,t){m[t]=e.textContent.trim()}));for(var o=0;o<m.length;++o)if(l.test(m[o]))return f[o]},c.init=function(n){if(c.ngModel=n,n.$options&&n.$options.trackBy){var o={},i=e(n.$options.trackBy);c.hashGetter=function(e,t){return o.$value=e,i(t||l,o)}}else c.hashGetter=function(e){return t.isObject(e)?"object_"+(e.$$mdSelectId||(e.$$mdSelectId=++s)):e};c.setMultiple(c.isMultiple)},c.selectedLabels=function(){var e=d(i[0].querySelectorAll("md-option[selected]"));return e.length?e.map(function(e){return e.textContent}).join(", "):""},c.select=function(e,t){var n=c.options[e];n&&n.setSelected(!0),c.selected[e]=t},c.deselect=function(e){var t=c.options[e];t&&t.setSelected(!1),delete c.selected[e]},c.addOption=function(e,n){if(t.isDefined(c.options[e]))throw new Error('Duplicate md-option values are not allowed in a select. Duplicate value "'+n.value+'" found.');c.options[e]=n,t.isDefined(c.selected[e])&&(c.select(e,n.value),c.refreshViewValue())},c.removeOption=function(e){delete c.options[e]},c.refreshViewValue=function(){var e,t=[];for(var n in c.selected)t.push((e=c.options[n])?e.value:c.selected[n]);c.ngModel.$setViewValue(c.isMultiple?t:t[0])}}return r.$inject=["$scope","$attrs","$element"],{restrict:"E",require:["mdSelectMenu","?ngModel"],controller:r,link:{pre:i}}}function i(e,n){function l(e,n){return e.append(t.element('<div class="md-text">').append(e.contents())),e.attr("tabindex",n.tabindex||"0"),o}function o(l,o,i,r){function a(e,t){var n=s.hashGetter(t,l),o=s.hashGetter(e,l);c.hashKey=o,c.value=e,s.removeOption(n,c),s.addOption(o,c)}function d(){var e={role:"option","aria-selected":"false"};o[0].hasAttribute("id")||(e.id="select_option_"+n.nextUid()),o.attr(e)}var c=r[0],s=r[1];t.isDefined(i.ngValue)?l.$watch(i.ngValue,a):t.isDefined(i.value)?a(i.value):l.$watch(function(){return o.text()},a),l.$$postDigest(function(){i.$observe("selected",function(e){t.isDefined(e)&&(e?(s.isMultiple||s.deselect(Object.keys(s.selected)[0]),s.select(c.hashKey,c.value)):s.deselect(c.hashKey),s.refreshViewValue(),s.ngModel.$render())})}),e.attach(l,o),d(),l.$on("$destroy",function(){s.removeOption(c.hashKey,c)})}function i(e){this.selected=!1,this.setSelected=function(t){t&&!this.selected?e.attr({selected:"selected","aria-selected":"true"}):!t&&this.selected&&(e.removeAttr("selected"),e.attr("aria-selected","false")),this.selected=t}}return i.$inject=["$element"],{restrict:"E",require:["mdOption","^^mdSelectMenu"],controller:i,compile:l}}function r(){function e(e,n){var l=e.find("label");l.length||(l=t.element("<label>"),e.prepend(l)),n.label&&l.text(n.label)}return{restrict:"E",compile:e}}function a(e){function l(e,l,r,a,s,u,p){function f(n,o,i){function c(){i.target.attr("aria-expanded","true")}function f(){function t(e){var t=d(m),n=t.indexOf(i.focusedNode);-1===n?n=0:"next"===e&&n<t.length-1?n++:"prev"===e&&n>0&&n--;var l=i.focusedNode=t[n];l&&l.focus()}function r(){t("next")}function c(){t("prev")}function s(){u.isMultiple||(i.restoreFocus=!0,n.$evalAsync(function(){e.hide(u.ngModel.$viewValue)}))}if(!i.isRemoved){var u=i.selectEl.controller("mdSelectMenu")||{};o.addClass("md-clickable"),i.backdrop&&i.backdrop.on("click",function(t){t.preventDefault(),t.stopPropagation(),i.restoreFocus=!1,n.$apply(e.cancel)}),i.selectEl.on("keydown",function(t){switch(t.keyCode){case l.KEY_CODE.SPACE:case l.KEY_CODE.ENTER:var o=a.getClosest(t.target,"md-option");o&&(i.selectEl.triggerHandler({type:"click",target:o}),t.preventDefault());break;case l.KEY_CODE.TAB:case l.KEY_CODE.ESCAPE:t.preventDefault(),i.restoreFocus=!0,n.$apply(e.cancel)}}),i.selectEl.on("keydown",function(e){switch(e.keyCode){case l.KEY_CODE.UP_ARROW:return c();case l.KEY_CODE.DOWN_ARROW:return r();default:if(e.keyCode>=31&&e.keyCode<=90){var t=i.selectEl.controller("mdSelectMenu").optNodeForKeyboardSearch(e);t&&t.focus()}}}),i.selectEl.on("click",s),i.selectEl.on("keydown",function(e){(32==e.keyCode||13==e.keyCode)&&s()})}}if(!i.target)throw new Error('$mdSelect.show() expected a target element in options.target but got "'+i.target+'"!');t.extend(i,{isRemoved:!1,target:t.element(i.target),parent:t.element(i.parent),selectEl:o.find("md-select-menu"),contentEl:o.find("md-content"),backdrop:i.hasBackdrop&&t.element('<md-backdrop class="md-select-backdrop md-click-catcher">')}),i.resizeFn=function(){r(function(){r(function(){h(n,o,i)})})},t.element(p).on("resize",i.resizeFn),t.element(p).on("orientationchange",i.resizeFn),c(),o.removeClass("md-leave");var m=i.selectEl[0].getElementsByTagName("md-option");return i.loadingAsync&&i.loadingAsync.then?i.loadingAsync.then(function(){n.$$loadingAsyncDone=!0,r(function(){r(function(){i.isRemoved||h(n,o,i)})})}):i.loadingAsync&&(n.$$loadingAsyncDone=!0),i.disableParentScroll&&!a.getClosest(i.target,"MD-DIALOG")?i.restoreScroll=a.disableScrollAround(i.target):i.disableParentScroll=!1,u(f,75,!1),i.backdrop&&(s.inherit(i.backdrop,i.parent),i.parent.append(i.backdrop)),i.parent.append(o),r(function(){r(function(){i.isRemoved||h(n,o,i)})}),a.transitionEndPromise(i.selectEl,{timeout:350})}function m(e,l,o){o.isRemoved=!0,l.addClass("md-leave").removeClass("md-clickable"),o.target.attr("aria-expanded","false"),t.element(p).off("resize",o.resizeFn),t.element(p).off("orientationchange",o.resizefn),o.resizeFn=n;var i=o.selectEl.controller("mdSelect");return i&&i.setLabelText(o.selectEl.controller("mdSelectMenu").selectedLabels()),a.transitionEndPromise(l,{timeout:350}).then(function(){l.removeClass("md-active"),o.backdrop&&o.backdrop.remove(),l[0].parentNode===o.parent[0]&&o.parent[0].removeChild(l[0]),o.disableParentScroll&&o.restoreScroll(),o.restoreFocus&&o.target.focus()})}function h(e,t,n){var d,s=t[0],u=n.target[0].firstElementChild.firstElementChild,f=n.parent[0],m=n.selectEl[0],h=n.contentEl[0],g=f.getBoundingClientRect(),v=u.getBoundingClientRect(),$=!1,b={left:g.left+c,top:c,bottom:g.height-c,right:g.width-c-(a.floatingScrollbars()?16:0)},y={top:v.top-b.top,left:v.left-b.left,right:b.right-(v.left+v.width),bottom:b.bottom-(v.top+v.height)},C=g.width-2*c,w=h.scrollHeight>h.offsetHeight,E=m.querySelector("md-option[selected]"),k=m.getElementsByTagName("md-option"),S=m.getElementsByTagName("md-optgroup");d=E?E:S.length?S[0]:k.length?k[0]:h.firstElementChild||h,h.offsetWidth>C&&(h.style["max-width"]=C+"px"),$&&(h.style["min-width"]=v.width+"px"),w&&m.classList.add("md-overflow");var x=m.getBoundingClientRect(),M=i(d);if(d){var O=p.getComputedStyle(d);M.paddingLeft=parseInt(O.paddingLeft,10)||0,M.paddingRight=parseInt(O.paddingRight,10)||0}var A=d;if("MD-OPTGROUP"===(A.tagName||"").toUpperCase()&&(A=k[0]||h.firstElementChild||h),w){var D=h.offsetHeight/2;h.scrollTop=M.top+M.height/2-D,y.top<D?h.scrollTop=Math.min(M.top,h.scrollTop+D-y.top):y.bottom<D&&(h.scrollTop=Math.max(M.top+M.height-x.height,h.scrollTop-D+y.bottom))}var R,T,V;$?(R=v.left,T=v.top+v.height,V="50% 0",T+x.height>b.bottom&&(T=v.top-x.height,V="50% 100%")):(R=v.left+M.left-M.paddingLeft,T=Math.floor(v.top+v.height/2-M.height/2-M.top+h.scrollTop),V=M.left+v.width/2+"px "+(M.top+M.height/2-h.scrollTop)+"px 0px",s.style.minWidth=v.width+M.paddingLeft+M.paddingRight+"px");var N=s.getBoundingClientRect();s.style.left=o(b.left,R,b.right-N.width)+"px",s.style.top=o(b.top,T,b.bottom-N.height)+"px",m.style[l.CSS.TRANSFORM_ORIGIN]=V,m.style[l.CSS.TRANSFORM]="scale("+Math.min(v.width/x.width,1)+","+Math.min(v.height/x.height,1)+")",r(function(){t.addClass("md-active"),m.style[l.CSS.TRANSFORM]="",A&&(n.focusedNode=A,A.focus())})}return{parent:"body",onShow:f,onRemove:m,hasBackdrop:!0,disableParentScroll:!0,themable:!0}}function o(e,t,n){return Math.max(e,Math.min(t,n))}function i(e){return e?{left:e.offsetLeft,top:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}:{left:0,top:0,width:0,height:0}}return l.$inject=["$mdSelect","$mdConstant","$$rAF","$mdUtil","$mdTheming","$timeout","$window"],e("$mdSelect").setDefaults({methods:["target"],options:l})}function d(e){for(var t=[],n=0;n<e.length;++n)t.push(e.item(n));return t}var c=8,s=0;t.module("material.components.select",["material.core","material.components.backdrop"]).directive("mdSelect",l).directive("mdSelectMenu",o).directive("mdOption",i).directive("mdOptgroup",r).provider("$mdSelect",a),l.$inject=["$mdSelect","$mdUtil","$mdTheming","$mdAria","$interpolate","$compile","$parse"],o.$inject=["$parse","$mdUtil","$mdTheming"],i.$inject=["$mdButtonInkRipple","$mdUtil"],a.$inject=["$$interimElementProvider"]}(window,window.angular); \ No newline at end of file