diff options
Diffstat (limited to 'vnfmarket/common/thirdparty/angular-material/modules/closure/select')
6 files changed, 2190 insertions, 0 deletions
diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.css b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.css new file mode 100644 index 00000000..780ef770 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.css @@ -0,0 +1,121 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.3 + */ +md-input-container md-select.md-THEME_NAME-theme .md-select-value span:first-child:after { + color: '{{warn-A700}}'; } + +md-input-container:not(.md-input-focused):not(.md-input-invalid) md-select.md-THEME_NAME-theme .md-select-value span:first-child:after { + color: '{{foreground-3}}'; } + +md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value { + color: '{{primary-color}}'; } + md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder { + color: '{{primary-color}}'; } + +md-input-container.md-input-invalid md-select.md-THEME_NAME-theme .md-select-value { + color: '{{warn-A700}}' !important; + border-bottom-color: '{{warn-A700}}' !important; } + +md-input-container.md-input-invalid md-select.md-THEME_NAME-theme.md-no-underline .md-select-value { + border-bottom-color: transparent !important; } + +md-select.md-THEME_NAME-theme[disabled] .md-select-value { + border-bottom-color: transparent; + background-image: -webkit-linear-gradient(left, "{{foreground-3}}" 0%, "{{foreground-3}}" 33%, transparent 0%); + background-image: linear-gradient(to right, "{{foreground-3}}" 0%, "{{foreground-3}}" 33%, transparent 0%); + background-image: -ms-linear-gradient(left, transparent 0%, "{{foreground-3}}" 100%); } + +md-select.md-THEME_NAME-theme .md-select-value { + border-bottom-color: '{{foreground-4}}'; } + md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder { + color: '{{foreground-3}}'; } + md-select.md-THEME_NAME-theme .md-select-value span:first-child:after { + color: '{{warn-A700}}'; } + +md-select.md-THEME_NAME-theme.md-no-underline .md-select-value { + border-bottom-color: transparent !important; } + +md-select.md-THEME_NAME-theme.ng-invalid.ng-touched .md-select-value { + color: '{{warn-A700}}' !important; + border-bottom-color: '{{warn-A700}}' !important; } + +md-select.md-THEME_NAME-theme.ng-invalid.ng-touched.md-no-underline .md-select-value { + border-bottom-color: transparent !important; } + +md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value { + border-bottom-color: '{{primary-color}}'; + color: '{{ foreground-1 }}'; } + md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value.md-select-placeholder { + color: '{{ foreground-1 }}'; } + +md-select.md-THEME_NAME-theme:not([disabled]):focus.md-no-underline .md-select-value { + border-bottom-color: transparent !important; } + +md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-value { + border-bottom-color: '{{accent-color}}'; } + +md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-value { + border-bottom-color: '{{warn-color}}'; } + +md-select.md-THEME_NAME-theme[disabled] .md-select-value { + color: '{{foreground-3}}'; } + md-select.md-THEME_NAME-theme[disabled] .md-select-value.md-select-placeholder { + color: '{{foreground-3}}'; } + +md-select.md-THEME_NAME-theme[disabled] .md-select-icon { + color: '{{foreground-3}}'; } + +md-select.md-THEME_NAME-theme .md-select-icon { + color: '{{foreground-2}}'; } + +md-select-menu.md-THEME_NAME-theme md-content { + background: '{{background-A100}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-optgroup { + color: '{{background-600-0.87}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option { + color: '{{background-900-0.87}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option[disabled] .md-text { + color: '{{background-400-0.87}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):focus, md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):hover { + background: '{{background-200}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option[selected] { + color: '{{primary-500}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option[selected]:focus { + color: '{{primary-600}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent { + color: '{{accent-color}}'; } + md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent:focus { + color: '{{accent-A700}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme .md-ripple { + color: '{{primary-600}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ripple { + color: '{{background-600}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme .md-ink-ripple { + color: '{{foreground-2}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ink-ripple { + color: '{{primary-color-0.87}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme:not(.md-checked) .md-icon { + border-color: '{{foreground-2}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon { + background-color: '{{primary-color-0.87}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme[selected].md-focused .md-container:before { + background-color: '{{primary-color-0.26}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon:after { + border-color: '{{primary-contrast-0.87}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme .md-indeterminate[disabled] .md-container { + color: '{{foreground-3}}'; } + +.md-checkbox-enabled.md-THEME_NAME-theme md-option .md-text { + color: '{{background-900-0.87}}'; } diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.min.css b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.min.css new file mode 100644 index 00000000..b9fd2682 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select-default-theme.min.css @@ -0,0 +1,6 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.2-master-a9ba340 + */md-input-container md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:"{{warn-A700}}"}md-input-container:not(.md-input-focused):not(.md-input-invalid) md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:"{{foreground-3}}"}md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value,md-input-container.md-input-focused:not(.md-input-has-value) md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder{color:"{{primary-color}}"}md-input-container.md-input-invalid md-select.md-THEME_NAME-theme .md-select-value{color:"{{warn-A700}}"!important;border-bottom-color:"{{warn-A700}}"!important}md-input-container.md-input-invalid md-select.md-THEME_NAME-theme.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme[disabled] .md-select-value{border-bottom-color:transparent;background-image:-webkit-linear-gradient(left,"{{foreground-3}}","{{foreground-3}}" 33%,transparent 0);background-image:linear-gradient(90deg,"{{foreground-3}}" 0,"{{foreground-3}}" 33%,transparent 0);background-image:-ms-linear-gradient(left,transparent 0,"{{foreground-3}}" 100%)}md-select.md-THEME_NAME-theme .md-select-value{border-bottom-color:"{{foreground-4}}"}md-select.md-THEME_NAME-theme .md-select-value.md-select-placeholder{color:"{{foreground-3}}"}md-select.md-THEME_NAME-theme .md-select-value span:first-child:after{color:"{{warn-A700}}"}md-select.md-THEME_NAME-theme.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme.ng-invalid.ng-touched .md-select-value{color:"{{warn-A700}}"!important;border-bottom-color:"{{warn-A700}}"!important}md-select.md-THEME_NAME-theme.ng-invalid.ng-touched.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value{border-bottom-color:"{{primary-color}}";color:"{{ foreground-1 }}"}md-select.md-THEME_NAME-theme:not([disabled]):focus .md-select-value.md-select-placeholder{color:"{{ foreground-1 }}"}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-no-underline .md-select-value{border-bottom-color:transparent!important}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-accent .md-select-value{border-bottom-color:"{{accent-color}}"}md-select.md-THEME_NAME-theme:not([disabled]):focus.md-warn .md-select-value{border-bottom-color:"{{warn-color}}"}md-select.md-THEME_NAME-theme[disabled] .md-select-icon,md-select.md-THEME_NAME-theme[disabled] .md-select-value,md-select.md-THEME_NAME-theme[disabled] .md-select-value.md-select-placeholder{color:"{{foreground-3}}"}md-select.md-THEME_NAME-theme .md-select-icon{color:"{{foreground-2}}"}md-select-menu.md-THEME_NAME-theme md-content{background:"{{background-A100}}"}md-select-menu.md-THEME_NAME-theme md-content md-optgroup{color:"{{background-600-0.87}}"}md-select-menu.md-THEME_NAME-theme md-content md-option{color:"{{background-900-0.87}}"}md-select-menu.md-THEME_NAME-theme md-content md-option[disabled] .md-text{color:"{{background-400-0.87}}"}md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):focus,md-select-menu.md-THEME_NAME-theme md-content md-option:not([disabled]):hover{background:"{{background-200}}"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected]{color:"{{primary-500}}"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected]:focus{color:"{{primary-600}}"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent{color:"{{accent-color}}"}md-select-menu.md-THEME_NAME-theme md-content md-option[selected].md-accent:focus{color:"{{accent-A700}}"}.md-checkbox-enabled.md-THEME_NAME-theme .md-ripple{color:"{{primary-600}}"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ripple{color:"{{background-600}}"}.md-checkbox-enabled.md-THEME_NAME-theme .md-ink-ripple{color:"{{foreground-2}}"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-ink-ripple{color:"{{primary-color-0.87}}"}.md-checkbox-enabled.md-THEME_NAME-theme:not(.md-checked) .md-icon{border-color:"{{foreground-2}}"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon{background-color:"{{primary-color-0.87}}"}.md-checkbox-enabled.md-THEME_NAME-theme[selected].md-focused .md-container:before{background-color:"{{primary-color-0.26}}"}.md-checkbox-enabled.md-THEME_NAME-theme[selected] .md-icon:after{border-color:"{{primary-contrast-0.87}}"}.md-checkbox-enabled.md-THEME_NAME-theme .md-indeterminate[disabled] .md-container{color:"{{foreground-3}}"}.md-checkbox-enabled.md-THEME_NAME-theme md-option .md-text{color:"{{background-900-0.87}}"}
\ No newline at end of file diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.css b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.css new file mode 100644 index 00000000..0f3440d0 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.css @@ -0,0 +1,356 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.3 + */ +md-input-container:not([md-no-float]) .md-select-placeholder span:first-child { + -webkit-transition: -webkit-transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: -webkit-transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1), -webkit-transform 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + -webkit-transform-origin: left top; + transform-origin: left top; } + [dir=rtl] md-input-container:not([md-no-float]) .md-select-placeholder span:first-child { + -webkit-transform-origin: right top; + transform-origin: right top; } + +md-input-container.md-input-focused:not([md-no-float]) .md-select-placeholder span:first-child { + -webkit-transform: translateY(-22px) translateX(-2px) scale(0.75); + transform: translateY(-22px) translateX(-2px) scale(0.75); } + +.md-select-menu-container { + position: fixed; + left: 0; + top: 0; + z-index: 90; + opacity: 0; + display: none; + -webkit-transform: translateY(-1px); + transform: translateY(-1px); } + .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 { + display: block; + opacity: 1; } + .md-select-menu-container.md-active md-select-menu { + -webkit-transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); + -webkit-transition-duration: 150ms; + transition-duration: 150ms; } + .md-select-menu-container.md-active md-select-menu > * { + opacity: 1; + -webkit-transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); + transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); + -webkit-transition-duration: 150ms; + transition-duration: 150ms; + -webkit-transition-delay: 100ms; + transition-delay: 100ms; } + .md-select-menu-container.md-leave { + opacity: 0; + -webkit-transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); + transition: all 0.3s cubic-bezier(0.55, 0, 0.55, 0.2); + -webkit-transition-duration: 250ms; + transition-duration: 250ms; } + +md-input-container > md-select { + margin: 0; + -webkit-box-ordinal-group: 3; + -webkit-order: 2; + order: 2; } + +md-input-container:not(.md-input-has-value) md-select[required]:not(.md-no-asterisk) .md-select-value span:first-child:after, md-input-container:not(.md-input-has-value) md-select.ng-required:not(.md-no-asterisk) .md-select-value span:first-child:after { + content: ' *'; + font-size: 13px; + vertical-align: top; } + +md-input-container.md-input-invalid md-select .md-select-value { + border-bottom-style: solid; + padding-bottom: 1px; } + +md-select { + display: -webkit-box; + display: -webkit-flex; + display: flex; + margin: 20px 0 26px 0; } + md-select[required].ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after, md-select.ng-required.ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after { + content: ' *'; + font-size: 13px; + vertical-align: top; } + md-select[disabled] .md-select-value { + background-position: 0 bottom; + background-size: 4px 1px; + background-repeat: repeat-x; + margin-bottom: -1px; } + 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-touched .md-select-value { + border-bottom-style: solid; + padding-bottom: 1px; } + md-select:not([disabled]):focus .md-select-value { + border-bottom-width: 2px; + border-bottom-style: solid; + padding-bottom: 0; } + md-select:not([disabled]):focus.ng-invalid.ng-touched .md-select-value { + padding-bottom: 0; } + +md-input-container.md-input-has-value .md-select-value > span:not(.md-select-icon) { + -webkit-transform: translate3d(0, 1px, 0); + transform: translate3d(0, 1px, 0); } + +.md-select-value { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + padding: 2px 2px 1px; + border-bottom-width: 1px; + border-bottom-style: solid; + background-color: transparent; + position: relative; + box-sizing: content-box; + min-width: 64px; + min-height: 26px; + -webkit-box-flex: 1; + -webkit-flex-grow: 1; + flex-grow: 1; } + .md-select-value > span:not(.md-select-icon) { + max-width: 100%; + -webkit-box-flex: 1; + -webkit-flex: 1 1 auto; + flex: 1 1 auto; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; } + .md-select-value > span:not(.md-select-icon) .md-text { + display: inline; } + .md-select-value .md-select-icon { + display: block; + -webkit-box-align: end; + -webkit-align-items: flex-end; + align-items: flex-end; + text-align: end; + width: 24px; + margin: 0 4px; + -webkit-transform: translate3d(0, -2px, 0); + transform: translate3d(0, -2px, 0); + font-size: 1.2rem; } + .md-select-value .md-select-icon:after { + display: block; + content: '\25BC'; + position: relative; + top: 2px; + speak: none; + font-size: 13px; + -webkit-transform: scaleY(0.5) scaleX(1); + transform: scaleY(0.5) scaleX(1); } + .md-select-value.md-select-placeholder { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-ordinal-group: 2; + -webkit-order: 1; + order: 1; + pointer-events: none; + -webkit-font-smoothing: antialiased; + padding-left: 2px; + z-index: 1; } + +md-select-menu { + display: -webkit-box; + display: -webkit-flex; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + -webkit-flex-direction: column; + flex-direction: column; + box-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.2), 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 2px 1px -1px rgba(0, 0, 0, 0.12); + 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-box-orient: vertical; + -webkit-box-direction: reverse; + -webkit-flex-direction: column-reverse; + flex-direction: column-reverse; } + md-select-menu:not(.md-overflow) md-content { + padding-top: 8px; + padding-bottom: 8px; } + [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-box; + display: -webkit-flex; + display: flex; + -webkit-box-align: center; + -webkit-align-items: center; + align-items: center; + width: auto; + -webkit-transition: background 0.15s linear; + transition: background 0.15s linear; + padding: 0 16px 0 16px; + height: 48px; } + md-option[disabled] { + cursor: default; } + md-option:focus { + outline: none; } + md-option .md-text { + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + width: auto; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } + +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; } } + +md-select-menu[multiple] md-option.md-checkbox-enabled { + padding-left: 40px; + padding-right: 16px; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled { + padding-left: 16px; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled { + padding-right: 40px; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + position: absolute; + top: 50%; + -webkit-transform: translateY(-50%); + transform: translateY(-50%); + box-sizing: border-box; + display: inline-block; + width: 20px; + height: 20px; + left: 0; + right: auto; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + left: auto; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + right: 0; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:before { + box-sizing: border-box; + background-color: transparent; + border-radius: 50%; + content: ''; + position: absolute; + display: block; + height: auto; + left: 0; + top: 0; + right: 0; + bottom: 0; + -webkit-transition: all 0.5s; + transition: all 0.5s; + width: auto; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:after { + box-sizing: border-box; + content: ''; + position: absolute; + top: -10px; + right: -10px; + bottom: -10px; + left: -10px; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-container .md-ripple-container { + position: absolute; + display: block; + width: auto; + height: auto; + left: -15px; + top: -15px; + right: -15px; + bottom: -15px; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-icon { + box-sizing: border-box; + -webkit-transition: 240ms; + transition: 240ms; + position: absolute; + top: 0; + left: 0; + width: 20px; + height: 20px; + border-width: 2px; + border-style: solid; + border-radius: 2px; } + md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon { + border-color: transparent; } + md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon:after { + box-sizing: border-box; + -webkit-transform: rotate(45deg); + transform: rotate(45deg); + position: absolute; + left: 4.66667px; + top: 0.22222px; + display: table; + width: 6.66667px; + height: 13.33333px; + border-width: 2px; + border-style: solid; + border-top: 0; + border-left: 0; + content: ''; } + md-select-menu[multiple] md-option.md-checkbox-enabled[disabled] { + cursor: default; } + md-select-menu[multiple] md-option.md-checkbox-enabled.md-indeterminate .md-icon:after { + box-sizing: border-box; + position: absolute; + top: 50%; + left: 50%; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + display: table; + width: 12px; + height: 2px; + border-width: 2px; + border-style: solid; + border-top: 0; + border-left: 0; + content: ''; } + md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + margin-left: 10.66667px; + margin-right: auto; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + margin-left: auto; } + [dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container { + margin-right: 10.66667px; } diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.js b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.js new file mode 100644 index 00000000..e1c57939 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.js @@ -0,0 +1,1694 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.3 + */ +goog.provide('ngmaterial.components.select'); +goog.require('ngmaterial.components.backdrop'); +goog.require('ngmaterial.core'); +/** + * @ngdoc module + * @name material.components.select + */ + +/*************************************************** + + ### TODO - POST RC1 ### + - [ ] Abstract placement logic in $mdSelect service to $mdMenu service + + ***************************************************/ + +SelectDirective['$inject'] = ["$mdSelect", "$mdUtil", "$mdConstant", "$mdTheming", "$mdAria", "$parse", "$sce", "$injector"]; +SelectMenuDirective['$inject'] = ["$parse", "$mdUtil", "$mdConstant", "$mdTheming"]; +OptionDirective['$inject'] = ["$mdButtonInkRipple", "$mdUtil"]; +SelectProvider['$inject'] = ["$$interimElementProvider"]; +var SELECT_EDGE_MARGIN = 8; +var selectNextId = 0; +var CHECKBOX_SELECTION_INDICATOR = + angular.element('<div class="md-container"><div class="md-icon"></div></div>'); + +angular.module('material.components.select', [ + 'material.core', + 'material.components.backdrop' + ]) + .directive('mdSelect', SelectDirective) + .directive('mdSelectMenu', SelectMenuDirective) + .directive('mdOption', OptionDirective) + .directive('mdOptgroup', OptgroupDirective) + .directive('mdSelectHeader', SelectHeaderDirective) + .provider('$mdSelect', SelectProvider); + +/** + * @ngdoc directive + * @name mdSelect + * @restrict E + * @module material.components.select + * + * @description Displays a select box, bound to an ng-model. + * + * When the select is required and uses a floating label, then the label will automatically contain + * an asterisk (`*`). This behavior can be disabled by using the `md-no-asterisk` attribute. + * + * By default, the select will display with an underline to match other form elements. This can be + * disabled by applying the `md-no-underline` CSS class. + * + * ### Option Params + * + * When applied, `md-option-empty` will mark the option as "empty" allowing the option to clear the + * select and put it back in it's default state. You may supply this attribute on any option you + * wish, however, it is automatically applied to an option whose `value` or `ng-value` are not + * defined. + * + * **Automatically Applied** + * + * - `<md-option>` + * - `<md-option value>` + * - `<md-option value="">` + * - `<md-option ng-value>` + * - `<md-option ng-value="">` + * + * **NOT Automatically Applied** + * + * - `<md-option ng-value="1">` + * - `<md-option ng-value="''">` + * - `<md-option ng-value="undefined">` + * - `<md-option value="undefined">` (this evaluates to the string `"undefined"`) + * - <code ng-non-bindable><md-option ng-value="{{someValueThatMightBeUndefined}}"></code> + * + * **Note:** A value of `undefined` ***is considered a valid value*** (and does not auto-apply this + * attribute) since you may wish this to be your "Not Available" or "None" option. + * + * **Note:** Using the `value` attribute (as opposed to `ng-value`) always evaluates to a string, so + * `value="null"` will require the test `ng-if="myValue != 'null'"` rather than `ng-if="!myValue"`. + * + * @param {expression} ng-model The model! + * @param {boolean=} multiple When set to true, allows for more than one option to be selected. The model is an array with the selected choices. + * @param {expression=} md-on-close Expression to be evaluated when the select is closed. + * @param {expression=} md-on-open Expression to be evaluated when opening the select. + * Will hide the select options and show a spinner until the evaluated promise resolves. + * @param {expression=} md-selected-text Expression to be evaluated that will return a string + * to be displayed as a placeholder in the select input box when it is closed. The value + * will be treated as *text* (not html). + * @param {expression=} md-selected-html Expression to be evaluated that will return a string + * to be displayed as a placeholder in the select input box when it is closed. The value + * will be treated as *html*. The value must either be explicitly marked as trustedHtml or + * the ngSanitize module must be loaded. + * @param {string=} placeholder Placeholder hint text. + * @param md-no-asterisk {boolean=} When set to true, an asterisk will not be appended to the + * floating label. **Note:** This attribute is only evaluated once; it is not watched. + * @param {string=} aria-label Optional label for accessibility. Only necessary if no placeholder or + * explicit label is present. + * @param {string=} md-container-class Class list to get applied to the `.md-select-menu-container` + * element (for custom styling). + * + * @usage + * With a placeholder (label and aria-label are added dynamically) + * <hljs lang="html"> + * <md-input-container> + * <md-select + * ng-model="someModel" + * placeholder="Select a state"> + * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option> + * </md-select> + * </md-input-container> + * </hljs> + * + * With an explicit label + * <hljs lang="html"> + * <md-input-container> + * <label>State</label> + * <md-select + * ng-model="someModel"> + * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option> + * </md-select> + * </md-input-container> + * </hljs> + * + * With a select-header + * + * When a developer needs to put more than just a text label in the + * md-select-menu, they should use the md-select-header. + * The user can put custom HTML inside of the header and style it to their liking. + * One common use case of this would be a sticky search bar. + * + * When using the md-select-header the labels that would previously be added to the + * OptGroupDirective are ignored. + * + * <hljs lang="html"> + * <md-input-container> + * <md-select ng-model="someModel"> + * <md-select-header> + * <span> Neighborhoods - </span> + * </md-select-header> + * <md-option ng-value="opt" ng-repeat="opt in neighborhoods2">{{ opt }}</md-option> + * </md-select> + * </md-input-container> + * </hljs> + * + * ## Selects and object equality + * When using a `md-select` to pick from a list of objects, it is important to realize how javascript handles + * equality. Consider the following example: + * <hljs lang="js"> + * angular.controller('MyCtrl', function($scope) { + * $scope.users = [ + * { id: 1, name: 'Bob' }, + * { id: 2, name: 'Alice' }, + * { id: 3, name: 'Steve' } + * ]; + * $scope.selectedUser = { id: 1, name: 'Bob' }; + * }); + * </hljs> + * <hljs lang="html"> + * <div ng-controller="MyCtrl"> + * <md-select ng-model="selectedUser"> + * <md-option ng-value="user" ng-repeat="user in users">{{ user.name }}</md-option> + * </md-select> + * </div> + * </hljs> + * + * At first one might expect that the select should be populated with "Bob" as the selected user. However, + * this is not true. To determine whether something is selected, + * `ngModelController` is looking at whether `$scope.selectedUser == (any user in $scope.users);`; + * + * Javascript's `==` operator does not check for deep equality (ie. that all properties + * on the object are the same), but instead whether the objects are *the same object in memory*. + * In this case, we have two instances of identical objects, but they exist in memory as unique + * entities. Because of this, the select will have no value populated for a selected user. + * + * To get around this, `ngModelController` provides a `track by` option that allows us to specify a different + * expression which will be used for the equality operator. As such, we can update our `html` to + * make use of this by specifying the `ng-model-options="{trackBy: '$value.id'}"` on the `md-select` + * element. This converts our equality expression to be + * `$scope.selectedUser.id == (any id in $scope.users.map(function(u) { return u.id; }));` + * which results in Bob being selected as desired. + * + * Working HTML: + * <hljs lang="html"> + * <div ng-controller="MyCtrl"> + * <md-select ng-model="selectedUser" ng-model-options="{trackBy: '$value.id'}"> + * <md-option ng-value="user" ng-repeat="user in users">{{ user.name }}</md-option> + * </md-select> + * </div> + * </hljs> + */ +function SelectDirective($mdSelect, $mdUtil, $mdConstant, $mdTheming, $mdAria, $parse, $sce, + $injector) { + var keyCodes = $mdConstant.KEY_CODE; + var NAVIGATION_KEYS = [keyCodes.SPACE, keyCodes.ENTER, keyCodes.UP_ARROW, keyCodes.DOWN_ARROW]; + + return { + restrict: 'E', + require: ['^?mdInputContainer', 'mdSelect', 'ngModel', '?^form'], + compile: compile, + controller: function() { + } // empty placeholder controller to be initialized in link + }; + + function compile(element, attr) { + // add the select value that will hold our placeholder or selected option value + var valueEl = angular.element('<md-select-value><span></span></md-select-value>'); + valueEl.append('<span class="md-select-icon" aria-hidden="true"></span>'); + valueEl.addClass('md-select-value'); + if (!valueEl[0].hasAttribute('id')) { + valueEl.attr('id', 'select_value_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) { + + // Show progress indicator while loading async + // Use ng-hide for `display:none` so the indicator does not interfere with the options list + element + .find('md-content') + .prepend(angular.element( + '<div>' + + ' <md-progress-circular md-mode="indeterminate" ng-if="$$loadingAsyncDone === false" md-diameter="25px"></md-progress-circular>' + + '</div>' + )); + + // Hide list [of item options] while loading async + element + .find('md-option') + .attr('ng-show', '$$loadingAsyncDone'); + } + + if (attr.name) { + var autofillClone = angular.element('<select class="md-visually-hidden">'); + autofillClone.attr({ + 'name': attr.name, + '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); + }); + + // Adds an extra option that will hold the selected value for the + // cases where the select is a part of a non-angular form. This can be done with a ng-model, + // however if the `md-option` is being `ng-repeat`-ed, Angular seems to insert a similar + // `option` node, but with a value of `? string: <value> ?` which would then get submitted. + // This also goes around having to prepend a dot to the name attribute. + autofillClone.append( + '<option ng-value="' + attr.ngModel + '" selected></option>' + ); + + element.parent().append(autofillClone); + } + + var isMultiple = $mdUtil.parseAttributeBoolean(attr.multiple); + + // Use everything that's left inside element.contents() as the contents of the menu + var multipleContent = isMultiple ? 'multiple' : ''; + var selectTemplate = '' + + '<div class="md-select-menu-container" aria-hidden="true">' + + '<md-select-menu {0}>{1}</md-select-menu>' + + '</div>'; + + selectTemplate = $mdUtil.supplant(selectTemplate, [multipleContent, element.html()]); + element.empty().append(valueEl); + element.append(selectTemplate); + + if(!attr.tabindex){ + attr.$set('tabindex', 0); + } + + return function postLink(scope, element, attr, ctrls) { + var untouched = true; + var isDisabled, ariaLabelBase; + + var containerCtrl = ctrls[0]; + var mdSelectCtrl = ctrls[1]; + var ngModelCtrl = ctrls[2]; + var formCtrl = ctrls[3]; + // grab a reference to the select menu value label + var valueEl = element.find('md-select-value'); + var isReadonly = angular.isDefined(attr.readonly); + var disableAsterisk = $mdUtil.parseAttributeBoolean(attr.mdNoAsterisk); + + if (disableAsterisk) { + element.addClass('md-no-asterisk'); + } + + if (containerCtrl) { + var isErrorGetter = containerCtrl.isErrorGetter || function() { + return ngModelCtrl.$invalid && (ngModelCtrl.$touched || (formCtrl && formCtrl.$submitted)); + }; + + if (containerCtrl.input) { + // We ignore inputs that are in the md-select-header (one + // case where this might be useful would be adding as searchbox) + if (element.find('md-select-header').find('input')[0] !== containerCtrl.input[0]) { + throw new Error("<md-input-container> can only have *one* child <input>, <textarea> or <select> element!"); + } + } + + containerCtrl.input = element; + if (!containerCtrl.label) { + $mdAria.expect(element, 'aria-label', element.attr('placeholder')); + } + + scope.$watch(isErrorGetter, containerCtrl.setInvalid); + } + + var selectContainer, selectScope, selectMenuCtrl; + + findSelectContainer(); + $mdTheming(element); + + if (formCtrl && angular.isDefined(attr.multiple)) { + $mdUtil.nextTick(function() { + var hasModelValue = ngModelCtrl.$modelValue || ngModelCtrl.$viewValue; + if (hasModelValue) { + formCtrl.$setPristine(); + } + }); + } + + var originalRender = ngModelCtrl.$render; + ngModelCtrl.$render = function() { + originalRender(); + syncLabelText(); + syncAriaLabel(); + inputCheckValue(); + }; + + attr.$observe('placeholder', ngModelCtrl.$render); + + if (containerCtrl && containerCtrl.label) { + attr.$observe('required', function (value) { + // Toggle the md-required class on the input containers label, because the input container is automatically + // applying the asterisk indicator on the label. + containerCtrl.label.toggleClass('md-required', value && !disableAsterisk); + }); + } + + mdSelectCtrl.setLabelText = function(text) { + mdSelectCtrl.setIsPlaceholder(!text); + + // Whether the select label has been given via user content rather than the internal + // template of <md-option> + var isSelectLabelFromUser = false; + + if (attr.mdSelectedText && attr.mdSelectedHtml) { + throw Error('md-select cannot have both `md-selected-text` and `md-selected-html`'); + } + + if (attr.mdSelectedText || attr.mdSelectedHtml) { + text = $parse(attr.mdSelectedText || attr.mdSelectedHtml)(scope); + isSelectLabelFromUser = true; + } else if (!text) { + // Use placeholder attribute, otherwise fallback to the md-input-container label + var tmpPlaceholder = attr.placeholder || + (containerCtrl && containerCtrl.label ? containerCtrl.label.text() : ''); + + text = tmpPlaceholder || ''; + isSelectLabelFromUser = true; + } + + var target = valueEl.children().eq(0); + + if (attr.mdSelectedHtml) { + // Using getTrustedHtml will run the content through $sanitize if it is not already + // explicitly trusted. If the ngSanitize module is not loaded, this will + // *correctly* throw an sce error. + target.html($sce.getTrustedHtml(text)); + } else if (isSelectLabelFromUser) { + target.text(text); + } else { + // If we've reached this point, the text is not user-provided. + target.html(text); + } + }; + + mdSelectCtrl.setIsPlaceholder = function(isPlaceholder) { + if (isPlaceholder) { + valueEl.addClass('md-select-placeholder'); + if (containerCtrl && containerCtrl.label) { + containerCtrl.label.addClass('md-placeholder'); + } + } else { + valueEl.removeClass('md-select-placeholder'); + if (containerCtrl && containerCtrl.label) { + containerCtrl.label.removeClass('md-placeholder'); + } + } + }; + + if (!isReadonly) { + element + .on('focus', function(ev) { + // Always focus the container (if we have one) so floating labels and other styles are + // applied properly + containerCtrl && containerCtrl.setFocused(true); + }); + + // Attach before ngModel's blur listener to stop propagation of blur event + // to prevent from setting $touched. + element.on('blur', function(event) { + if (untouched) { + untouched = false; + if (selectScope._mdSelectIsOpen) { + event.stopImmediatePropagation(); + } + } + + if (selectScope._mdSelectIsOpen) return; + containerCtrl && containerCtrl.setFocused(false); + inputCheckValue(); + }); + } + + mdSelectCtrl.triggerClose = function() { + $parse(attr.mdOnClose)(scope); + }; + + scope.$$postDigest(function() { + initAriaLabel(); + syncLabelText(); + syncAriaLabel(); + }); + + function initAriaLabel() { + var labelText = element.attr('aria-label') || element.attr('placeholder'); + if (!labelText && containerCtrl && containerCtrl.label) { + labelText = containerCtrl.label.text(); + } + ariaLabelBase = labelText; + $mdAria.expect(element, 'aria-label', labelText); + } + + scope.$watch(function() { + return selectMenuCtrl.selectedLabels(); + }, syncLabelText); + + function syncLabelText() { + if (selectContainer) { + selectMenuCtrl = selectMenuCtrl || selectContainer.find('md-select-menu').controller('mdSelectMenu'); + mdSelectCtrl.setLabelText(selectMenuCtrl.selectedLabels()); + } + } + + function syncAriaLabel() { + if (!ariaLabelBase) return; + var ariaLabels = selectMenuCtrl.selectedLabels({mode: 'aria'}); + element.attr('aria-label', ariaLabels.length ? ariaLabelBase + ': ' + ariaLabels : ariaLabelBase); + } + + 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'); + } + element.attr('aria-multiselectable', multiple ? 'true' : 'false'); + if (selectContainer) { + selectMenuCtrl.setMultiple(multiple); + originalRender = ngModelCtrl.$render; + ngModelCtrl.$render = function() { + originalRender(); + syncLabelText(); + syncAriaLabel(); + inputCheckValue(); + }; + ngModelCtrl.$render(); + } + }); + }); + + attr.$observe('disabled', function(disabled) { + if (angular.isString(disabled)) { + disabled = true; + } + // Prevent click event being registered twice + if (isDisabled !== undefined && isDisabled === disabled) { + return; + } + isDisabled = disabled; + if (disabled) { + element + .attr({'aria-disabled': 'true'}) + .removeAttr('tabindex') + .off('click', openSelect) + .off('keydown', handleKeypress); + } else { + element + .attr({'tabindex': attr.tabindex, 'aria-disabled': 'false'}) + .on('click', openSelect) + .on('keydown', handleKeypress); + } + }); + + if (!attr.hasOwnProperty('disabled') && !attr.hasOwnProperty('ngDisabled')) { + element.attr({'aria-disabled': 'false'}); + element.on('click', openSelect); + element.on('keydown', handleKeypress); + } + + var ariaAttrs = { + role: 'listbox', + 'aria-expanded': 'false', + 'aria-multiselectable': isMultiple && !attr.ngMultiple ? 'true' : 'false' + }; + + if (!element[0].hasAttribute('id')) { + ariaAttrs.id = 'select_' + $mdUtil.nextUid(); + } + + var containerId = 'select_container_' + $mdUtil.nextUid(); + selectContainer.attr('id', containerId); + ariaAttrs['aria-owns'] = containerId; + element.attr(ariaAttrs); + + scope.$on('$destroy', function() { + $mdSelect + .destroy() + .finally(function() { + if (containerCtrl) { + containerCtrl.setFocused(false); + containerCtrl.setHasValue(false); + containerCtrl.input = null; + } + ngModelCtrl.$setTouched(); + }); + }); + + + + function inputCheckValue() { + // The select counts as having a value if one or more options are selected, + // or if the input's validity state says it has bad input (eg string in a number input) + containerCtrl && containerCtrl.setHasValue(selectMenuCtrl.selectedLabels().length > 0 || (element[0].validity || {}).badInput); + } + + function findSelectContainer() { + selectContainer = angular.element( + element[0].querySelector('.md-select-menu-container') + ); + selectScope = scope; + if (attr.mdContainerClass) { + var value = selectContainer[0].getAttribute('class') + ' ' + attr.mdContainerClass; + selectContainer[0].setAttribute('class', value); + } + selectMenuCtrl = selectContainer.find('md-select-menu').controller('mdSelectMenu'); + selectMenuCtrl.init(ngModelCtrl, attr.ngModel); + element.on('$destroy', function() { + selectContainer.remove(); + }); + } + + function handleKeypress(e) { + if ($mdConstant.isNavigationKey(e)) { + // prevent page scrolling on interaction + e.preventDefault(); + openSelect(e); + } else { + if ($mdConstant.isInputKey(e) || $mdConstant.isNumPadKey(e)) { + e.preventDefault(); + + var node = selectMenuCtrl.optNodeForKeyboardSearch(e); + if (!node || node.hasAttribute('disabled')) 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(); + } + } + } + + function openSelect() { + selectScope._mdSelectIsOpen = true; + element.attr('aria-expanded', 'true'); + + $mdSelect.show({ + scope: selectScope, + preserveScope: true, + skipCompile: true, + element: selectContainer, + target: element[0], + selectCtrl: mdSelectCtrl, + preserveElement: true, + hasBackdrop: true, + loadingAsync: attr.mdOnOpen ? scope.$eval(attr.mdOnOpen) || true : false + }).finally(function() { + selectScope._mdSelectIsOpen = false; + element.focus(); + element.attr('aria-expanded', 'false'); + ngModelCtrl.$setTouched(); + }); + } + + }; + } +} + +function SelectMenuDirective($parse, $mdUtil, $mdConstant, $mdTheming) { + // We want the scope to be set to 'false' so an isolated scope is not created + // which would interfere with the md-select-header's access to the + // parent scope. + SelectMenuController['$inject'] = ["$scope", "$attrs", "$element"]; + return { + restrict: 'E', + require: ['mdSelectMenu'], + scope: false, + 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]; + + element.addClass('_md'); // private md component indicator for styling + + $mdTheming(element); + element.on('click', clickListener); + element.on('keypress', keyListener); + + 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; + if (option.hasAttribute('disabled')) { + ev.stopImmediatePropagation(); + return false; + } + + 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.$watchCollection(function() { + return self.options; + }, function() { + self.ngModel.$render(); + }); + + var deregisterCollectionWatch; + var defaultIsEmpty; + self.setMultiple = function(isMultiple) { + var ngModel = self.ngModel; + defaultIsEmpty = defaultIsEmpty || ngModel.$isEmpty; + + 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(self.modelBinding, function(value) { + if (validateArray(value)) renderMultiple(value); + self.ngModel.$setPristine(); + }); + + ngModel.$isEmpty = function(value) { + return !value || value.length === 0; + }; + } 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); + + // Support 1-9 on numpad + var keyCode = e.keyCode - ($mdConstant.isNumPadKey(e) ? 48 : 0); + + searchStr += String.fromCharCode(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, binding) { + self.ngModel = ngModel; + self.modelBinding = binding; + + // Setup a more robust version of isEmpty to ensure value is a valid option + self.ngModel.$isEmpty = function($viewValue) { + // We have to transform the viewValue into the hashKey, because otherwise the + // OptionCtrl may not exist. Developers may have specified a trackBy function. + return !self.options[self.hashGetter($viewValue)]; + }; + + // 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 + var trackByOption = $mdUtil.getModelOption(ngModel, 'trackBy'); + + if (trackByOption) { + var trackByLocals = {}; + var trackByParsed = $parse(trackByOption); + 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(opts) { + opts = opts || {}; + var mode = opts.mode || 'html'; + var selectedOptionEls = $mdUtil.nodesToArray($element[0].querySelectorAll('md-option[selected]')); + if (selectedOptionEls.length) { + var mapFn; + + if (mode == 'html') { + // Map the given element to its innerHTML string. If the element has a child ripple + // container remove it from the HTML string, before returning the string. + mapFn = function(el) { + // If we do not have a `value` or `ng-value`, assume it is an empty option which clears the select + if (el.hasAttribute('md-option-empty')) { + return ''; + } + + var html = el.innerHTML; + + // Remove the ripple container from the selected option, copying it would cause a CSP violation. + var rippleContainer = el.querySelector('.md-ripple-container'); + if (rippleContainer) { + html = html.replace(rippleContainer.outerHTML, ''); + } + + // Remove the checkbox container, because it will cause the label to wrap inside of the placeholder. + // It should be not displayed inside of the label element. + var checkboxContainer = el.querySelector('.md-container'); + if (checkboxContainer) { + html = html.replace(checkboxContainer.outerHTML, ''); + } + + return html; + }; + } else if (mode == 'aria') { + mapFn = function(el) { return el.hasAttribute('aria-label') ? el.getAttribute('aria-label') : el.textContent; }; + } + + // Ensure there are no duplicates; see https://github.com/angular/material/issues/9442 + return $mdUtil.uniq(selectedOptionEls.map(mapFn)).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); + + // When the current $modelValue of the ngModel Controller is using the same hash as + // the current option, which will be added, then we can be sure, that the validation + // of the option has occurred before the option was added properly. + // This means, that we have to manually trigger a new validation of the current option. + if (angular.isDefined(self.ngModel.$modelValue) && self.hashGetter(self.ngModel.$modelValue) === hashKey) { + self.ngModel.$validate(); + } + + 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]); + } + } + var usingTrackBy = $mdUtil.getModelOption(self.ngModel, 'trackBy'); + + var newVal = self.isMultiple ? values : values[0]; + var prevVal = self.ngModel.$modelValue; + + if (usingTrackBy ? !angular.equals(prevVal, newVal) : (prevVal + '') !== newVal) { + self.ngModel.$setViewValue(newVal); + self.ngModel.$render(); + } + }; + + 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); + } + } + +} + +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'); + + if (!hasDefinedValue(attr)) { + element.attr('md-option-empty', ''); + } + + return postLink; + } + + function hasDefinedValue(attr) { + var value = attr.value; + var ngValue = attr.ngValue; + + return value || ngValue; + } + + function postLink(scope, element, attr, ctrls) { + var optionCtrl = ctrls[0]; + var selectCtrl = ctrls[1]; + + if (selectCtrl.isMultiple) { + element.addClass('md-checkbox-enabled'); + element.prepend(CHECKBOX_SELECTION_INDICATOR.clone()); + } + + 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().trim(); + }, setOptionValue); + } + + attr.$observe('disabled', function(disabled) { + if (disabled) { + element.attr('tabindex', '-1'); + } else { + element.attr('tabindex', '0'); + } + }); + + scope.$$postDigest(function() { + attr.$observe('selected', function(selected) { + if (!angular.isDefined(selected)) return; + if (typeof selected == 'string') selected = true; + 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(); + }); + }); + + $mdButtonInkRipple.attach(scope, element); + configureAria(); + + function setOptionValue(newValue, oldValue, prevAttempt) { + if (!selectCtrl.hashGetter) { + if (!prevAttempt) { + scope.$$postDigest(function() { + setOptionValue(newValue, oldValue, true); + }); + } + return; + } + 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; + }; + } + +} + +function OptgroupDirective() { + return { + restrict: 'E', + compile: compile + }; + function compile(el, attrs) { + // If we have a select header element, we don't want to add the normal label + // header. + if (!hasSelectHeader()) { + setupLabelElement(); + } + + function hasSelectHeader() { + return el.parent().find('md-select-header').length; + } + + function setupLabelElement() { + var labelElement = el.find('label'); + if (!labelElement.length) { + labelElement = angular.element('<label>'); + el.prepend(labelElement); + } + labelElement.addClass('md-container-ignore'); + if (attrs.label) labelElement.text(attrs.label); + } + } +} + +function SelectHeaderDirective() { + return { + restrict: 'E', + }; +} + +function SelectProvider($$interimElementProvider) { + selectDefaultOptions['$inject'] = ["$mdSelect", "$mdConstant", "$mdUtil", "$window", "$q", "$$rAF", "$animateCss", "$animate", "$document"]; + return $$interimElementProvider('$mdSelect') + .setDefaults({ + methods: ['target'], + options: selectDefaultOptions + }); + + /* ngInject */ + function selectDefaultOptions($mdSelect, $mdConstant, $mdUtil, $window, $q, $$rAF, $animateCss, $animate, $document) { + var ERROR_TARGET_EXPECTED = "$mdSelect.show() expected a target element in options.target but got '{0}'!"; + var animator = $mdUtil.dom.animator; + var keyCodes = $mdConstant.KEY_CODE; + + return { + parent: 'body', + themable: true, + onShow: onShow, + onRemove: onRemove, + hasBackdrop: true, + disableParentScroll: true + }; + + /** + * Interim-element onRemove logic.... + */ + function onRemove(scope, element, opts) { + opts = opts || { }; + opts.cleanupInteraction(); + opts.cleanupResizing(); + opts.hideBackdrop(); + + // For navigation $destroy events, do a quick, non-animated removal, + // but for normal closes (from clicks, etc) animate the removal + + return (opts.$destroy === true) ? cleanElement() : animateRemoval().then( cleanElement ); + + /** + * For normal closes (eg clicks), animate the removal. + * For forced closes (like $destroy events from navigation), + * skip the animations + */ + function animateRemoval() { + return $animateCss(element, {addClass: 'md-leave'}).start(); + } + + /** + * Restore the element to a closed state + */ + function cleanElement() { + + element.removeClass('md-active'); + element.attr('aria-hidden', 'true'); + element[0].style.display = 'none'; + + announceClosed(opts); + + if (!opts.$destroy && opts.restoreFocus) { + opts.target.focus(); + } + } + + } + + /** + * Interim-element onShow logic.... + */ + function onShow(scope, element, opts) { + + watchAsyncLoad(); + sanitizeAndConfigure(scope, opts); + + opts.hideBackdrop = showBackdrop(scope, element, opts); + + return showDropDown(scope, element, opts) + .then(function(response) { + element.attr('aria-hidden', 'false'); + opts.alreadyOpen = true; + opts.cleanupInteraction = activateInteraction(); + opts.cleanupResizing = activateResizing(); + + return response; + }, opts.hideBackdrop); + + // ************************************ + // Closure Functions + // ************************************ + + /** + * Attach the select DOM element(s) and animate to the correct positions + * and scalings... + */ + function showDropDown(scope, element, opts) { + opts.parent.append(element); + + return $q(function(resolve, reject) { + + try { + + $animateCss(element, {removeClass: 'md-leave', duration: 0}) + .start() + .then(positionAndFocusMenu) + .then(resolve); + + } catch (e) { + reject(e); + } + + }); + } + + /** + * Initialize container and dropDown menu positions/scale, then animate + * to show... and autoFocus. + */ + function positionAndFocusMenu() { + return $q(function(resolve) { + if (opts.isRemoved) return $q.reject(false); + + var info = calculateMenuPositions(scope, element, opts); + + info.container.element.css(animator.toCss(info.container.styles)); + info.dropDown.element.css(animator.toCss(info.dropDown.styles)); + + $$rAF(function() { + element.addClass('md-active'); + info.dropDown.element.css(animator.toCss({transform: ''})); + + autoFocus(opts.focusedNode); + resolve(); + }); + + }); + } + + /** + * Show modal backdrop element... + */ + function showBackdrop(scope, element, options) { + + // If we are not within a dialog... + if (options.disableParentScroll && !$mdUtil.getClosest(options.target, 'MD-DIALOG')) { + // !! DO this before creating the backdrop; since disableScrollAround() + // configures the scroll offset; which is used by mdBackDrop postLink() + options.restoreScroll = $mdUtil.disableScrollAround(options.element, options.parent); + } else { + options.disableParentScroll = false; + } + + if (options.hasBackdrop) { + // Override duration to immediately show invisible backdrop + options.backdrop = $mdUtil.createBackdrop(scope, "md-select-backdrop md-click-catcher"); + $animate.enter(options.backdrop, $document[0].body, null, {duration: 0}); + } + + /** + * Hide modal backdrop element... + */ + return function hideBackdrop() { + if (options.backdrop) options.backdrop.remove(); + if (options.disableParentScroll) options.restoreScroll(); + + delete options.restoreScroll; + }; + } + + /** + * + */ + function autoFocus(focusedNode) { + if (focusedNode && !focusedNode.hasAttribute('disabled')) { + focusedNode.focus(); + } + } + + /** + * Check for valid opts and set some sane defaults + */ + function sanitizeAndConfigure(scope, options) { + var selectEl = element.find('md-select-menu'); + + if (!options.target) { + throw new Error($mdUtil.supplant(ERROR_TARGET_EXPECTED, [options.target])); + } + + angular.extend(options, { + isRemoved: false, + target: angular.element(options.target), //make sure it's not a naked dom node + parent: angular.element(options.parent), + selectEl: selectEl, + contentEl: element.find('md-content'), + optionNodes: selectEl[0].getElementsByTagName('md-option') + }); + } + + /** + * Configure various resize listeners for screen changes + */ + function activateResizing() { + var debouncedOnResize = (function(scope, target, options) { + + return function() { + if (options.isRemoved) return; + + var updates = calculateMenuPositions(scope, target, options); + var container = updates.container; + var dropDown = updates.dropDown; + + container.element.css(animator.toCss(container.styles)); + dropDown.element.css(animator.toCss(dropDown.styles)); + }; + + })(scope, element, opts); + + var window = angular.element($window); + window.on('resize', debouncedOnResize); + window.on('orientationchange', debouncedOnResize); + + // Publish deactivation closure... + return function deactivateResizing() { + + // Disable resizing handlers + window.off('resize', debouncedOnResize); + window.off('orientationchange', debouncedOnResize); + }; + } + + /** + * If asynchronously loading, watch and update internal + * '$$loadingAsyncDone' flag + */ + function watchAsyncLoad() { + if (opts.loadingAsync && !opts.isRemoved) { + scope.$$loadingAsyncDone = false; + + $q.when(opts.loadingAsync) + .then(function() { + scope.$$loadingAsyncDone = true; + delete opts.loadingAsync; + }).then(function() { + $$rAF(positionAndFocusMenu); + }); + } + } + + /** + * + */ + function activateInteraction() { + if (opts.isRemoved) return; + + var dropDown = opts.selectEl; + var selectCtrl = dropDown.controller('mdSelectMenu') || {}; + + element.addClass('md-clickable'); + + // Close on backdrop click + opts.backdrop && opts.backdrop.on('click', onBackdropClick); + + // Escape to close + // Cycling of options, and closing on enter + dropDown.on('keydown', onMenuKeyDown); + dropDown.on('click', checkCloseMenu); + + return function cleanupInteraction() { + opts.backdrop && opts.backdrop.off('click', onBackdropClick); + dropDown.off('keydown', onMenuKeyDown); + dropDown.off('click', checkCloseMenu); + + element.removeClass('md-clickable'); + opts.isRemoved = true; + }; + + // ************************************ + // Closure Functions + // ************************************ + + function onBackdropClick(e) { + e.preventDefault(); + e.stopPropagation(); + opts.restoreFocus = false; + $mdUtil.nextTick($mdSelect.hide, true); + } + + function onMenuKeyDown(ev) { + ev.preventDefault(); + ev.stopPropagation(); + + switch (ev.keyCode) { + case keyCodes.UP_ARROW: + return focusPrevOption(); + case keyCodes.DOWN_ARROW: + return focusNextOption(); + case keyCodes.SPACE: + case keyCodes.ENTER: + var option = $mdUtil.getClosest(ev.target, 'md-option'); + if (option) { + dropDown.triggerHandler({ + type: 'click', + target: option + }); + ev.preventDefault(); + } + checkCloseMenu(ev); + break; + case keyCodes.TAB: + case keyCodes.ESCAPE: + ev.stopPropagation(); + ev.preventDefault(); + opts.restoreFocus = true; + $mdUtil.nextTick($mdSelect.hide, true); + break; + default: + if ($mdConstant.isInputKey(ev) || $mdConstant.isNumPadKey(ev)) { + var optNode = dropDown.controller('mdSelectMenu').optNodeForKeyboardSearch(ev); + opts.focusedNode = optNode || opts.focusedNode; + optNode && optNode.focus(); + } + } + } + + function focusOption(direction) { + var optionsArray = $mdUtil.nodesToArray(opts.optionNodes); + var index = optionsArray.indexOf(opts.focusedNode); + + var newOption; + + do { + 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--; + } + newOption = optionsArray[index]; + if (newOption.hasAttribute('disabled')) newOption = undefined; + } while (!newOption && index < optionsArray.length - 1 && index > 0); + + newOption && newOption.focus(); + opts.focusedNode = newOption; + } + + function focusNextOption() { + focusOption('next'); + } + + function focusPrevOption() { + focusOption('prev'); + } + + function checkCloseMenu(ev) { + if (ev && ( ev.type == 'click') && (ev.currentTarget != dropDown[0])) return; + if ( mouseOnScrollbar() ) return; + + var option = $mdUtil.getClosest(ev.target, 'md-option'); + if (option && option.hasAttribute && !option.hasAttribute('disabled')) { + ev.preventDefault(); + ev.stopPropagation(); + if (!selectCtrl.isMultiple) { + opts.restoreFocus = true; + + $mdUtil.nextTick(function () { + $mdSelect.hide(selectCtrl.ngModel.$viewValue); + }, true); + } + } + /** + * check if the mouseup event was on a scrollbar + */ + function mouseOnScrollbar() { + var clickOnScrollbar = false; + if (ev && (ev.currentTarget.children.length > 0)) { + var child = ev.currentTarget.children[0]; + var hasScrollbar = child.scrollHeight > child.clientHeight; + if (hasScrollbar && child.children.length > 0) { + var relPosX = ev.pageX - ev.currentTarget.getBoundingClientRect().left; + if (relPosX > child.querySelector('md-option').offsetWidth) + clickOnScrollbar = true; + } + } + return clickOnScrollbar; + } + } + } + + } + + /** + * To notify listeners that the Select menu has closed, + * trigger the [optional] user-defined expression + */ + function announceClosed(opts) { + var mdSelect = opts.selectCtrl; + if (mdSelect) { + var menuController = opts.selectEl.controller('mdSelectMenu'); + mdSelect.setLabelText(menuController ? menuController.selectedLabels() : ''); + mdSelect.triggerClose(); + } + } + + + /** + * Calculate the + */ + function calculateMenuPositions(scope, element, opts) { + var + containerNode = element[0], + targetNode = opts.target[0].children[0], // target the label + parentNode = $document[0].body, + 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, + selectedNode = selectNode.querySelector('md-option[selected]'), + optionNodes = selectNode.getElementsByTagName('md-option'), + optgroupNodes = selectNode.getElementsByTagName('md-optgroup'), + isScrollable = calculateScrollable(element, contentNode), + centeredNode; + + var loading = isPromiseLike(opts.loadingAsync); + if (!loading) { + // 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 - if we are not loading async - 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; + } + } else { + // If loading, center on progress indicator + centeredNode = contentNode.firstElementChild || contentNode; + } + + if (contentNode.offsetWidth > maxWidth) { + contentNode.style['max-width'] = maxWidth + 'px'; + } else { + contentNode.style.maxWidth = null; + } + 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'); + } + + var focusedNode = centeredNode; + if ((focusedNode.tagName || '').toUpperCase() === 'MD-OPTGROUP') { + focusedNode = optionNodes[0] || contentNode.firstElementChild || contentNode; + centeredNode = focusedNode; + } + // Cache for autoFocus() + opts.focusedNode = focusedNode; + + // Get the selectMenuRect *after* max-width is possibly set above + containerNode.style.display = 'block'; + 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; + } + + 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, minWidth, fontSize; + 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) + 2; + top = Math.floor(targetRect.top + targetRect.height / 2 - centeredRect.height / 2 - + centeredRect.top + contentNode.scrollTop) + 2; + + transformOrigin = (centeredRect.left + targetRect.width / 2) + 'px ' + + (centeredRect.top + centeredRect.height / 2 - contentNode.scrollTop) + 'px 0px'; + + minWidth = Math.min(targetRect.width + centeredRect.paddingLeft + centeredRect.paddingRight, maxWidth); + + fontSize = window.getComputedStyle(targetNode)['font-size']; + } + + // Keep left and top within the window + var containerRect = containerNode.getBoundingClientRect(); + var scaleX = Math.round(100 * Math.min(targetRect.width / selectMenuRect.width, 1.0)) / 100; + var scaleY = Math.round(100 * Math.min(targetRect.height / selectMenuRect.height, 1.0)) / 100; + + return { + container: { + element: angular.element(containerNode), + styles: { + left: Math.floor(clamp(bounds.left, left, bounds.right - containerRect.width)), + top: Math.floor(clamp(bounds.top, top, bounds.bottom - containerRect.height)), + 'min-width': minWidth, + 'font-size': fontSize + } + }, + dropDown: { + element: angular.element(selectNode), + styles: { + transformOrigin: transformOrigin, + transform: !opts.alreadyOpen ? $mdUtil.supplant('scale({0},{1})', [scaleX, scaleY]) : "" + } + } + }; + + } + + } + + function isPromiseLike(obj) { + return obj && angular.isFunction(obj.then); + } + + 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}; + } + + function calculateScrollable(element, contentNode) { + var isScrollable = false; + + try { + var oldDisplay = element[0].style.display; + + // Set the element's display to block so that this calculation is correct + element[0].style.display = 'block'; + + isScrollable = contentNode.scrollHeight > contentNode.offsetHeight; + + // Reset it back afterwards + element[0].style.display = oldDisplay; + } finally { + // Nothing to do + } + return isScrollable; + } +} + +ngmaterial.components.select = angular.module("material.components.select");
\ No newline at end of file diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.css b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.css new file mode 100644 index 00000000..24ddf066 --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.css @@ -0,0 +1,6 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.2-master-a9ba340 + */md-input-container:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:-webkit-transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1);transition:transform .4s cubic-bezier(.25,.8,.25,1),-webkit-transform .4s cubic-bezier(.25,.8,.25,1);-webkit-transform-origin:left top;transform-origin:left top}[dir=rtl] md-input-container:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transform-origin:right top;transform-origin:right top}md-input-container.md-input-focused:not([md-no-float]) .md-select-placeholder span:first-child{-webkit-transform:translateY(-22px) translateX(-2px) scale(.75);transform:translateY(-22px) translateX(-2px) scale(.75)}.md-select-menu-container{position:fixed;left:0;top:0;z-index:90;opacity:0;display:none;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.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{display:block;opacity:1}.md-select-menu-container.md-active md-select-menu{-webkit-transition:all .4s cubic-bezier(.25,.8,.25,1);transition:all .4s cubic-bezier(.25,.8,.25,1);-webkit-transition-duration:.15s;transition-duration:.15s}.md-select-menu-container.md-active md-select-menu>*{opacity:1;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.15s;transition-duration:.15s;-webkit-transition-delay:.1s;transition-delay:.1s}.md-select-menu-container.md-leave{opacity:0;-webkit-transition:all .3s cubic-bezier(.55,0,.55,.2);transition:all .3s cubic-bezier(.55,0,.55,.2);-webkit-transition-duration:.25s;transition-duration:.25s}md-input-container>md-select{margin:0;-webkit-box-ordinal-group:3;-webkit-order:2;order:2}md-input-container:not(.md-input-has-value) md-select.ng-required:not(.md-no-asterisk) .md-select-value span:first-child:after,md-input-container:not(.md-input-has-value) md-select[required]:not(.md-no-asterisk) .md-select-value span:first-child:after{content:" *";font-size:13px;vertical-align:top}md-input-container.md-input-invalid md-select .md-select-value{border-bottom-style:solid;padding-bottom:1px}md-select{display:-webkit-box;display:-webkit-flex;display:flex;margin:20px 0 26px}md-select.ng-required.ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after,md-select[required].ng-invalid:not(.md-no-asterisk) .md-select-value span:first-child:after{content:" *";font-size:13px;vertical-align:top}md-select[disabled] .md-select-value{background-position:0 bottom;background-size:4px 1px;background-repeat:repeat-x;margin-bottom:-1px}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-touched .md-select-value{border-bottom-style:solid;padding-bottom:1px}md-select:not([disabled]):focus .md-select-value{border-bottom-width:2px;border-bottom-style:solid;padding-bottom:0}md-select:not([disabled]):focus.ng-invalid.ng-touched .md-select-value{padding-bottom:0}md-input-container.md-input-has-value .md-select-value>span:not(.md-select-icon){-webkit-transform:translate3d(0,1px,0);transform:translate3d(0,1px,0)}.md-select-value{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;padding:2px 2px 1px;border-bottom-width:1px;border-bottom-style:solid;background-color:transparent;position:relative;box-sizing:content-box;min-width:64px;min-height:26px;-webkit-box-flex:1;-webkit-flex-grow:1;flex-grow:1}.md-select-value>span:not(.md-select-icon){max-width:100%;-webkit-box-flex:1;-webkit-flex:1 1 auto;flex:1 1 auto;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.md-select-value>span:not(.md-select-icon) .md-text{display:inline}.md-select-value .md-select-icon{display:block;-webkit-box-align:end;-webkit-align-items:flex-end;align-items:flex-end;text-align:end;width:24px;margin:0 4px;-webkit-transform:translate3d(0,-2px,0);transform:translate3d(0,-2px,0);font-size:1.2rem}.md-select-value .md-select-icon:after{display:block;content:"\25BC";position:relative;top:2px;speak:none;font-size:13px;-webkit-transform:scaleY(.5) scaleX(1);transform:scaleY(.5) scaleX(1)}.md-select-value.md-select-placeholder{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-ordinal-group:2;-webkit-order:1;order:1;pointer-events:none;-webkit-font-smoothing:antialiased;padding-left:2px;z-index:1}md-select-menu{display:-webkit-box;display:-webkit-flex;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-webkit-flex-direction:column;flex-direction:column;box-shadow:0 1px 3px 0 rgba(0,0,0,.2),0 1px 1px 0 rgba(0,0,0,.14),0 2px 1px -1px rgba(0,0,0,.12);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-box-orient:vertical;-webkit-box-direction:reverse;-webkit-flex-direction:column-reverse;flex-direction:column-reverse}md-select-menu:not(.md-overflow) md-content{padding-top:8px;padding-bottom:8px}[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-box;display:-webkit-flex;display:flex;-webkit-box-align:center;-webkit-align-items:center;align-items:center;width:auto;-webkit-transition:background .15s linear;transition:background .15s linear;padding:0 16px;height:48px}md-option[disabled]{cursor:default}md-option:focus{outline:none}md-option .md-text{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}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}}md-select-menu[multiple] md-option.md-checkbox-enabled{padding-left:40px;padding-right:16px}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled{padding-left:16px;padding-right:40px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);box-sizing:border-box;display:inline-block;width:20px;height:20px;left:0;right:auto}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{left:auto;right:0}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:before{box-sizing:border-box;background-color:transparent;border-radius:50%;content:"";position:absolute;display:block;height:auto;left:0;top:0;right:0;bottom:0;-webkit-transition:all .5s;transition:all .5s;width:auto}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container:after{box-sizing:border-box;content:"";position:absolute;top:-10px;right:-10px;bottom:-10px;left:-10px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container .md-ripple-container{position:absolute;display:block;width:auto;height:auto;left:-15px;top:-15px;right:-15px;bottom:-15px}md-select-menu[multiple] md-option.md-checkbox-enabled .md-icon{box-sizing:border-box;-webkit-transition:.24s;transition:.24s;position:absolute;top:0;left:0;width:20px;height:20px;border-width:2px;border-style:solid;border-radius:2px}md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon{border-color:transparent}md-select-menu[multiple] md-option.md-checkbox-enabled[selected] .md-icon:after{box-sizing:border-box;-webkit-transform:rotate(45deg);transform:rotate(45deg);position:absolute;left:4.66667px;top:.22222px;display:table;width:6.66667px;height:13.33333px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-select-menu[multiple] md-option.md-checkbox-enabled[disabled]{cursor:default}md-select-menu[multiple] md-option.md-checkbox-enabled.md-indeterminate .md-icon:after{box-sizing:border-box;position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:table;width:12px;height:2px;border-width:2px;border-style:solid;border-top:0;border-left:0;content:""}md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{margin-left:10.66667px;margin-right:auto}[dir=rtl] md-select-menu[multiple] md-option.md-checkbox-enabled .md-container{margin-left:auto;margin-right:10.66667px}
\ No newline at end of file diff --git a/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.js b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.js new file mode 100644 index 00000000..80ab7d3b --- /dev/null +++ b/vnfmarket/common/thirdparty/angular-material/modules/closure/select/select.min.js @@ -0,0 +1,7 @@ +/*! + * Angular Material Design + * https://github.com/angular/material + * @license MIT + * v1.1.2-master-a9ba340 + */ +function SelectDirective(e,t,n,r,l,a,i,o){function d(o,d){var s=angular.element("<md-select-value><span></span></md-select-value>");if(s.append('<span class="md-select-icon" aria-hidden="true"></span>'),s.addClass("md-select-value"),s[0].hasAttribute("id")||s.attr("id","select_value_label_"+t.nextUid()),o.find("md-content").length||o.append(angular.element("<md-content>").append(o.contents())),d.mdOnOpen&&(o.find("md-content").prepend(angular.element('<div> <md-progress-circular md-mode="indeterminate" ng-if="$$loadingAsyncDone === false" md-diameter="25px"></md-progress-circular></div>')),o.find("md-option").attr("ng-show","$$loadingAsyncDone")),d.name){var c=angular.element('<select class="md-visually-hidden">');c.attr({name:d.name,"aria-hidden":"true",tabindex:"-1"});var u=o.find("md-option");angular.forEach(u,function(e){var t=angular.element("<option>"+e.innerHTML+"</option>");e.hasAttribute("ng-value")?t.attr("ng-value",e.getAttribute("ng-value")):e.hasAttribute("value")&&t.attr("value",e.getAttribute("value")),c.append(t)}),c.append('<option ng-value="'+d.ngModel+'" selected></option>'),o.parent().append(c)}var p=t.parseAttributeBoolean(d.multiple),m=p?"multiple":"",f='<div class="md-select-menu-container" aria-hidden="true"><md-select-menu {0}>{1}</md-select-menu></div>';return f=t.supplant(f,[m,o.html()]),o.empty().append(s),o.append(f),d.tabindex||d.$set("tabindex",0),function(o,d,s,c){function u(){var e=d.attr("aria-label")||d.attr("placeholder");!e&&S&&S.label&&(e=S.label.text()),y=e,l.expect(d,"aria-label",e)}function m(){O&&(R=R||O.find("md-select-menu").controller("mdSelectMenu"),E.setLabelText(R.selectedLabels()))}function f(){if(y){var e=R.selectedLabels({mode:"aria"});d.attr("aria-label",e.length?y+": "+e:y)}}function h(){S&&S.setHasValue(R.selectedLabels().length>0||(d[0].validity||{}).badInput)}function g(){if(O=angular.element(d[0].querySelector(".md-select-menu-container")),T=o,s.mdContainerClass){var e=O[0].getAttribute("class")+" "+s.mdContainerClass;O[0].setAttribute("class",e)}R=O.find("md-select-menu").controller("mdSelectMenu"),R.init(M,s.ngModel),d.on("$destroy",function(){O.remove()})}function v(e){if(n.isNavigationKey(e))e.preventDefault(),b(e);else if(n.isInputKey(e)||n.isNumPadKey(e)){e.preventDefault();var t=R.optNodeForKeyboardSearch(e);if(!t||t.hasAttribute("disabled"))return;var r=angular.element(t).controller("mdOption");R.isMultiple||R.deselect(Object.keys(R.selected)[0]),R.select(r.hashKey,r.value),R.refreshViewValue()}}function b(){T._mdSelectIsOpen=!0,d.attr("aria-expanded","true"),e.show({scope:T,preserveScope:!0,skipCompile:!0,element:O,target:d[0],selectCtrl:E,preserveElement:!0,hasBackdrop:!0,loadingAsync:!!s.mdOnOpen&&(o.$eval(s.mdOnOpen)||!0)})["finally"](function(){T._mdSelectIsOpen=!1,d.focus(),d.attr("aria-expanded","false"),M.$setTouched()})}var $,y,C=!0,S=c[0],E=c[1],M=c[2],w=c[3],k=d.find("md-select-value"),D=angular.isDefined(s.readonly),x=t.parseAttributeBoolean(s.mdNoAsterisk);if(x&&d.addClass("md-no-asterisk"),S){var A=S.isErrorGetter||function(){return M.$invalid&&(M.$touched||w&&w.$submitted)};if(S.input&&d.find("md-select-header").find("input")[0]!==S.input[0])throw new Error("<md-input-container> can only have *one* child <input>, <textarea> or <select> element!");S.input=d,S.label||l.expect(d,"aria-label",d.attr("placeholder")),o.$watch(A,S.setInvalid)}var O,T,R;g(),r(d),w&&angular.isDefined(s.multiple)&&t.nextTick(function(){var e=M.$modelValue||M.$viewValue;e&&w.$setPristine()});var N=M.$render;M.$render=function(){N(),m(),f(),h()},s.$observe("placeholder",M.$render),S&&S.label&&s.$observe("required",function(e){S.label.toggleClass("md-required",e&&!x)}),E.setLabelText=function(e){E.setIsPlaceholder(!e);var t=!1;if(s.mdSelectedText&&s.mdSelectedHtml)throw Error("md-select cannot have both `md-selected-text` and `md-selected-html`");if(s.mdSelectedText||s.mdSelectedHtml)e=a(s.mdSelectedText||s.mdSelectedHtml)(o),t=!0;else if(!e){var n=s.placeholder||(S&&S.label?S.label.text():"");e=n||"",t=!0}var r=k.children().eq(0);s.mdSelectedHtml?r.html(i.getTrustedHtml(e)):t?r.text(e):r.html(e)},E.setIsPlaceholder=function(e){e?(k.addClass("md-select-placeholder"),S&&S.label&&S.label.addClass("md-placeholder")):(k.removeClass("md-select-placeholder"),S&&S.label&&S.label.removeClass("md-placeholder"))},D||(d.on("focus",function(e){S&&S.setFocused(!0)}),d.on("blur",function(e){C&&(C=!1,T._mdSelectIsOpen&&e.stopImmediatePropagation()),T._mdSelectIsOpen||(S&&S.setFocused(!1),h())})),E.triggerClose=function(){a(s.mdOnClose)(o)},o.$$postDigest(function(){u(),m(),f()}),o.$watch(function(){return R.selectedLabels()},m);var _;s.$observe("ngMultiple",function(e){_&&_();var t=a(e);_=o.$watch(function(){return t(o)},function(e,t){void 0===e&&void 0===t||(e?d.attr("multiple","multiple"):d.removeAttr("multiple"),d.attr("aria-multiselectable",e?"true":"false"),O&&(R.setMultiple(e),N=M.$render,M.$render=function(){N(),m(),f(),h()},M.$render()))})}),s.$observe("disabled",function(e){angular.isString(e)&&(e=!0),void 0!==$&&$===e||($=e,e?d.attr({"aria-disabled":"true"}).removeAttr("tabindex").off("click",b).off("keydown",v):d.attr({tabindex:s.tabindex,"aria-disabled":"false"}).on("click",b).on("keydown",v))}),s.hasOwnProperty("disabled")||s.hasOwnProperty("ngDisabled")||(d.attr({"aria-disabled":"false"}),d.on("click",b),d.on("keydown",v));var I={role:"listbox","aria-expanded":"false","aria-multiselectable":p&&!s.ngMultiple?"true":"false"};d[0].hasAttribute("id")||(I.id="select_"+t.nextUid());var P="select_container_"+t.nextUid();O.attr("id",P),I["aria-owns"]=P,d.attr(I),o.$on("$destroy",function(){e.destroy()["finally"](function(){S&&(S.setFocused(!1),S.setHasValue(!1),S.input=null),M.$setTouched()})})}}var s=n.KEY_CODE;[s.SPACE,s.ENTER,s.UP_ARROW,s.DOWN_ARROW];return{restrict:"E",require:["^?mdInputContainer","mdSelect","ngModel","?^form"],compile:d,controller:function(){}}}function SelectMenuDirective(e,t,n,r){function l(e,n,l,a){function i(e){13!=e.keyCode&&32!=e.keyCode||o(e)}function o(n){var r=t.getClosest(n.target,"md-option"),l=r&&angular.element(r).data("$mdOptionController");if(r&&l){if(r.hasAttribute("disabled"))return n.stopImmediatePropagation(),!1;var a=d.hashGetter(l.value),i=angular.isDefined(d.selected[a]);e.$apply(function(){d.isMultiple?i?d.deselect(a):d.select(a,l.value):i||(d.deselect(Object.keys(d.selected)[0]),d.select(a,l.value)),d.refreshViewValue()})}}var d=a[0];n.addClass("_md"),r(n),n.on("click",o),n.on("keypress",i)}function a(r,l,a){function i(){var e=d.ngModel.$modelValue||d.ngModel.$viewValue||[];if(angular.isArray(e)){var t=Object.keys(d.selected),n=e.map(d.hashGetter),r=t.filter(function(e){return n.indexOf(e)===-1});r.forEach(d.deselect),n.forEach(function(t,n){d.select(t,e[n])})}}function o(){var e=d.ngModel.$viewValue||d.ngModel.$modelValue;Object.keys(d.selected).forEach(d.deselect),d.select(d.hashGetter(e),e)}var d=this;d.isMultiple=angular.isDefined(l.multiple),d.selected={},d.options={},r.$watchCollection(function(){return d.options},function(){d.ngModel.$render()});var s,c;d.setMultiple=function(e){function t(e,t){return angular.isArray(e||t||[])}var n=d.ngModel;c=c||n.$isEmpty,d.isMultiple=e,s&&s(),d.isMultiple?(n.$validators["md-multiple"]=t,n.$render=i,r.$watchCollection(d.modelBinding,function(e){t(e)&&i(e),d.ngModel.$setPristine()}),n.$isEmpty=function(e){return!e||0===e.length}):(delete n.$validators["md-multiple"],n.$render=o)};var u,p,m,f="",h=300;d.optNodeForKeyboardSearch=function(e){u&&clearTimeout(u),u=setTimeout(function(){u=void 0,f="",m=void 0,p=void 0},h);var t=e.keyCode-(n.isNumPadKey(e)?48:0);f+=String.fromCharCode(t);var r=new RegExp("^"+f,"i");p||(p=a.find("md-option"),m=new Array(p.length),angular.forEach(p,function(e,t){m[t]=e.textContent.trim()}));for(var l=0;l<m.length;++l)if(r.test(m[l]))return p[l]},d.init=function(n,l){d.ngModel=n,d.modelBinding=l,d.ngModel.$isEmpty=function(e){return!d.options[d.hashGetter(e)]};var a=t.getModelOption(n,"trackBy");if(a){var i={},o=e(a);d.hashGetter=function(e,t){return i.$value=e,o(t||r,i)}}else d.hashGetter=function(e){return angular.isObject(e)?"object_"+(e.$$mdSelectId||(e.$$mdSelectId=++selectNextId)):e};d.setMultiple(d.isMultiple)},d.selectedLabels=function(e){e=e||{};var n=e.mode||"html",r=t.nodesToArray(a[0].querySelectorAll("md-option[selected]"));if(r.length){var l;return"html"==n?l=function(e){if(e.hasAttribute("md-option-empty"))return"";var t=e.innerHTML,n=e.querySelector(".md-ripple-container");n&&(t=t.replace(n.outerHTML,""));var r=e.querySelector(".md-container");return r&&(t=t.replace(r.outerHTML,"")),t}:"aria"==n&&(l=function(e){return e.hasAttribute("aria-label")?e.getAttribute("aria-label"):e.textContent}),t.uniq(r.map(l)).join(", ")}return""},d.select=function(e,t){var n=d.options[e];n&&n.setSelected(!0),d.selected[e]=t},d.deselect=function(e){var t=d.options[e];t&&t.setSelected(!1),delete d.selected[e]},d.addOption=function(e,t){if(angular.isDefined(d.options[e]))throw new Error('Duplicate md-option values are not allowed in a select. Duplicate value "'+t.value+'" found.');d.options[e]=t,angular.isDefined(d.selected[e])&&(d.select(e,t.value),angular.isDefined(d.ngModel.$modelValue)&&d.hashGetter(d.ngModel.$modelValue)===e&&d.ngModel.$validate(),d.refreshViewValue())},d.removeOption=function(e){delete d.options[e]},d.refreshViewValue=function(){var e,n=[];for(var r in d.selected)(e=d.options[r])?n.push(e.value):n.push(d.selected[r]);var l=t.getModelOption(d.ngModel,"trackBy"),a=d.isMultiple?n:n[0],i=d.ngModel.$modelValue;(l?angular.equals(i,a):i===a)||(d.ngModel.$setViewValue(a),d.ngModel.$render())}}return a.$inject=["$scope","$attrs","$element"],{restrict:"E",require:["mdSelectMenu"],scope:!1,controller:a,link:{pre:l}}}function OptionDirective(e,t){function n(e,t){return e.append(angular.element('<div class="md-text">').append(e.contents())),e.attr("tabindex",t.tabindex||"0"),r(t)||e.attr("md-option-empty",""),l}function r(e){var t=e.value,n=e.ngValue;return t||n}function l(n,r,l,a){function i(e,t,r){if(!s.hashGetter)return void(r||n.$$postDigest(function(){i(e,t,!0)}));var l=s.hashGetter(t,n),a=s.hashGetter(e,n);d.hashKey=a,d.value=e,s.removeOption(l,d),s.addOption(a,d)}function o(){var e={role:"option","aria-selected":"false"};r[0].hasAttribute("id")||(e.id="select_option_"+t.nextUid()),r.attr(e)}var d=a[0],s=a[1];s.isMultiple&&(r.addClass("md-checkbox-enabled"),r.prepend(CHECKBOX_SELECTION_INDICATOR.clone())),angular.isDefined(l.ngValue)?n.$watch(l.ngValue,i):angular.isDefined(l.value)?i(l.value):n.$watch(function(){return r.text().trim()},i),l.$observe("disabled",function(e){e?r.attr("tabindex","-1"):r.attr("tabindex","0")}),n.$$postDigest(function(){l.$observe("selected",function(e){angular.isDefined(e)&&("string"==typeof e&&(e=!0),e?(s.isMultiple||s.deselect(Object.keys(s.selected)[0]),s.select(d.hashKey,d.value)):s.deselect(d.hashKey),s.refreshViewValue())})}),e.attach(n,r),o(),n.$on("$destroy",function(){s.removeOption(d.hashKey,d)})}function a(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 a.$inject=["$element"],{restrict:"E",require:["mdOption","^^mdSelectMenu"],controller:a,compile:n}}function OptgroupDirective(){function e(e,t){function n(){return e.parent().find("md-select-header").length}function r(){var n=e.find("label");n.length||(n=angular.element("<label>"),e.prepend(n)),n.addClass("md-container-ignore"),t.label&&n.text(t.label)}n()||r()}return{restrict:"E",compile:e}}function SelectHeaderDirective(){return{restrict:"E"}}function SelectProvider(e){function t(e,t,i,o,d,s,c,u,p){function m(e,t,n){function r(){return c(t,{addClass:"md-leave"}).start()}function l(){t.removeClass("md-active"),t.attr("aria-hidden","true"),t[0].style.display="none",h(n),!n.$destroy&&n.restoreFocus&&n.target.focus()}return n=n||{},n.cleanupInteraction(),n.cleanupResizing(),n.hideBackdrop(),n.$destroy===!0?l():r().then(l)}function f(n,r,l){function a(e,t,n){return n.parent.append(t),d(function(e,n){try{c(t,{removeClass:"md-leave",duration:0}).start().then(m).then(e)}catch(r){n(r)}})}function m(){return d(function(e){if(l.isRemoved)return d.reject(!1);var t=g(n,r,l);t.container.element.css(b.toCss(t.container.styles)),t.dropDown.element.css(b.toCss(t.dropDown.styles)),s(function(){r.addClass("md-active"),t.dropDown.element.css(b.toCss({transform:""})),h(l.focusedNode),e()})})}function f(e,t,n){return n.disableParentScroll&&!i.getClosest(n.target,"MD-DIALOG")?n.restoreScroll=i.disableScrollAround(n.element,n.parent):n.disableParentScroll=!1,n.hasBackdrop&&(n.backdrop=i.createBackdrop(e,"md-select-backdrop md-click-catcher"),u.enter(n.backdrop,p[0].body,null,{duration:0})),function(){n.backdrop&&n.backdrop.remove(),n.disableParentScroll&&n.restoreScroll(),delete n.restoreScroll}}function h(e){e&&!e.hasAttribute("disabled")&&e.focus()}function y(e,t){var n=r.find("md-select-menu");if(!t.target)throw new Error(i.supplant(v,[t.target]));angular.extend(t,{isRemoved:!1,target:angular.element(t.target),parent:angular.element(t.parent),selectEl:n,contentEl:r.find("md-content"),optionNodes:n[0].getElementsByTagName("md-option")})}function C(){var e=function(e,t,n){return function(){if(!n.isRemoved){var r=g(e,t,n),l=r.container,a=r.dropDown;l.element.css(b.toCss(l.styles)),a.element.css(b.toCss(a.styles))}}}(n,r,l),t=angular.element(o);return t.on("resize",e),t.on("orientationchange",e),function(){t.off("resize",e),t.off("orientationchange",e)}}function S(){l.loadingAsync&&!l.isRemoved&&(n.$$loadingAsyncDone=!1,d.when(l.loadingAsync).then(function(){n.$$loadingAsyncDone=!0,delete l.loadingAsync}).then(function(){s(m)}))}function E(){function n(t){t.preventDefault(),t.stopPropagation(),l.restoreFocus=!1,i.nextTick(e.hide,!0)}function a(n){switch(n.preventDefault(),n.stopPropagation(),n.keyCode){case $.UP_ARROW:return s();case $.DOWN_ARROW:return d();case $.SPACE:case $.ENTER:var r=i.getClosest(n.target,"md-option");r&&(u.triggerHandler({type:"click",target:r}),n.preventDefault()),c(n);break;case $.TAB:case $.ESCAPE:n.stopPropagation(),n.preventDefault(),l.restoreFocus=!0,i.nextTick(e.hide,!0);break;default:if(t.isInputKey(n)||t.isNumPadKey(n)){var a=u.controller("mdSelectMenu").optNodeForKeyboardSearch(n);l.focusedNode=a||l.focusedNode,a&&a.focus()}}}function o(e){var t,n=i.nodesToArray(l.optionNodes),r=n.indexOf(l.focusedNode);do r===-1?r=0:"next"===e&&r<n.length-1?r++:"prev"===e&&r>0&&r--,t=n[r],t.hasAttribute("disabled")&&(t=void 0);while(!t&&r<n.length-1&&r>0);t&&t.focus(),l.focusedNode=t}function d(){o("next")}function s(){o("prev")}function c(t){function n(){var e=!1;if(t&&t.currentTarget.children.length>0){var n=t.currentTarget.children[0],r=n.scrollHeight>n.clientHeight;if(r&&n.children.length>0){var l=t.pageX-t.currentTarget.getBoundingClientRect().left;l>n.querySelector("md-option").offsetWidth&&(e=!0)}}return e}if(!(t&&"click"==t.type&&t.currentTarget!=u[0]||n())){var r=i.getClosest(t.target,"md-option");r&&r.hasAttribute&&!r.hasAttribute("disabled")&&(t.preventDefault(),t.stopPropagation(),p.isMultiple||(l.restoreFocus=!0,i.nextTick(function(){e.hide(p.ngModel.$viewValue)},!0)))}}if(!l.isRemoved){var u=l.selectEl,p=u.controller("mdSelectMenu")||{};return r.addClass("md-clickable"),l.backdrop&&l.backdrop.on("click",n),u.on("keydown",a),u.on("click",c),function(){l.backdrop&&l.backdrop.off("click",n),u.off("keydown",a),u.off("click",c),r.removeClass("md-clickable"),l.isRemoved=!0}}}return S(),y(n,l),l.hideBackdrop=f(n,r,l),a(n,r,l).then(function(e){return r.attr("aria-hidden","false"),l.alreadyOpen=!0,l.cleanupInteraction=E(),l.cleanupResizing=C(),e},l.hideBackdrop)}function h(e){var t=e.selectCtrl;if(t){var n=e.selectEl.controller("mdSelectMenu");t.setLabelText(n?n.selectedLabels():""),t.triggerClose()}}function g(e,t,d){var s,c=t[0],u=d.target[0].children[0],m=p[0].body,f=d.selectEl[0],h=d.contentEl[0],g=m.getBoundingClientRect(),v=u.getBoundingClientRect(),b=!1,$={left:g.left+SELECT_EDGE_MARGIN,top:SELECT_EDGE_MARGIN,bottom:g.height-SELECT_EDGE_MARGIN,right:g.width-SELECT_EDGE_MARGIN-(i.floatingScrollbars()?16:0)},y={top:v.top-$.top,left:v.left-$.left,right:$.right-(v.left+v.width),bottom:$.bottom-(v.top+v.height)},C=g.width-2*SELECT_EDGE_MARGIN,S=f.querySelector("md-option[selected]"),E=f.getElementsByTagName("md-option"),M=f.getElementsByTagName("md-optgroup"),w=a(t,h),k=n(d.loadingAsync);s=k?h.firstElementChild||h:S?S:M.length?M[0]:E.length?E[0]:h.firstElementChild||h,h.offsetWidth>C?h.style["max-width"]=C+"px":h.style.maxWidth=null,b&&(h.style["min-width"]=v.width+"px"),w&&f.classList.add("md-overflow");var D=s;"MD-OPTGROUP"===(D.tagName||"").toUpperCase()&&(D=E[0]||h.firstElementChild||h,s=D),d.focusedNode=D,c.style.display="block";var x=f.getBoundingClientRect(),A=l(s);if(s){var O=o.getComputedStyle(s);A.paddingLeft=parseInt(O.paddingLeft,10)||0,A.paddingRight=parseInt(O.paddingRight,10)||0}if(w){var T=h.offsetHeight/2;h.scrollTop=A.top+A.height/2-T,y.top<T?h.scrollTop=Math.min(A.top,h.scrollTop+T-y.top):y.bottom<T&&(h.scrollTop=Math.max(A.top+A.height-x.height,h.scrollTop-T+y.bottom))}var R,N,_,I,P;b?(R=v.left,N=v.top+v.height,_="50% 0",N+x.height>$.bottom&&(N=v.top-x.height,_="50% 100%")):(R=v.left+A.left-A.paddingLeft+2,N=Math.floor(v.top+v.height/2-A.height/2-A.top+h.scrollTop)+2,_=A.left+v.width/2+"px "+(A.top+A.height/2-h.scrollTop)+"px 0px",I=Math.min(v.width+A.paddingLeft+A.paddingRight,C),P=window.getComputedStyle(u)["font-size"]);var L=c.getBoundingClientRect(),V=Math.round(100*Math.min(v.width/x.width,1))/100,B=Math.round(100*Math.min(v.height/x.height,1))/100;return{container:{element:angular.element(c),styles:{left:Math.floor(r($.left,R,$.right-L.width)),top:Math.floor(r($.top,N,$.bottom-L.height)),"min-width":I,"font-size":P}},dropDown:{element:angular.element(f),styles:{transformOrigin:_,transform:d.alreadyOpen?"":i.supplant("scale({0},{1})",[V,B])}}}}var v="$mdSelect.show() expected a target element in options.target but got '{0}'!",b=i.dom.animator,$=t.KEY_CODE;return{parent:"body",themable:!0,onShow:f,onRemove:m,hasBackdrop:!0,disableParentScroll:!0}}function n(e){return e&&angular.isFunction(e.then)}function r(e,t,n){return Math.max(e,Math.min(t,n))}function l(e){return e?{left:e.offsetLeft,top:e.offsetTop,width:e.offsetWidth,height:e.offsetHeight}:{left:0,top:0,width:0,height:0}}function a(e,t){var n=!1;try{var r=e[0].style.display;e[0].style.display="block",n=t.scrollHeight>t.offsetHeight,e[0].style.display=r}finally{}return n}return t.$inject=["$mdSelect","$mdConstant","$mdUtil","$window","$q","$$rAF","$animateCss","$animate","$document"],e("$mdSelect").setDefaults({methods:["target"],options:t})}goog.provide("ngmaterial.components.select"),goog.require("ngmaterial.components.backdrop"),goog.require("ngmaterial.core"),SelectDirective.$inject=["$mdSelect","$mdUtil","$mdConstant","$mdTheming","$mdAria","$parse","$sce","$injector"],SelectMenuDirective.$inject=["$parse","$mdUtil","$mdConstant","$mdTheming"],OptionDirective.$inject=["$mdButtonInkRipple","$mdUtil"],SelectProvider.$inject=["$$interimElementProvider"];var SELECT_EDGE_MARGIN=8,selectNextId=0,CHECKBOX_SELECTION_INDICATOR=angular.element('<div class="md-container"><div class="md-icon"></div></div>');angular.module("material.components.select",["material.core","material.components.backdrop"]).directive("mdSelect",SelectDirective).directive("mdSelectMenu",SelectMenuDirective).directive("mdOption",OptionDirective).directive("mdOptgroup",OptgroupDirective).directive("mdSelectHeader",SelectHeaderDirective).provider("$mdSelect",SelectProvider),ngmaterial.components.select=angular.module("material.components.select");
\ No newline at end of file |