ionic-Material Design , Codecanyon
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
md-autocomplete.md-THEME_NAME-theme {
|
||||
background: '{{background-50}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme[disabled] {
|
||||
background: '{{background-100}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme button md-icon path {
|
||||
fill: '{{background-600}}'; }
|
||||
md-autocomplete.md-THEME_NAME-theme button:after {
|
||||
background: '{{background-600-0.3}}'; }
|
||||
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme {
|
||||
background: '{{background-50}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li {
|
||||
color: '{{background-900}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li .highlight {
|
||||
color: '{{background-600}}'; }
|
||||
.md-autocomplete-suggestions.md-THEME_NAME-theme li:hover, .md-autocomplete-suggestions.md-THEME_NAME-theme li.selected {
|
||||
background: '{{background-200}}'; }
|
||||
@@ -0,0 +1,220 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
/* mixin definition ; sets LTR and RTL within the same style call */
|
||||
@-webkit-keyframes md-autocomplete-list-out {
|
||||
0% {
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in; }
|
||||
|
||||
100% {
|
||||
height: 0;
|
||||
opacity: 0; } }
|
||||
@keyframes md-autocomplete-list-out {
|
||||
0% {
|
||||
-webkit-animation-timing-function: linear;
|
||||
animation-timing-function: linear; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px;
|
||||
-webkit-animation-timing-function: ease-in;
|
||||
animation-timing-function: ease-in; }
|
||||
|
||||
100% {
|
||||
height: 0;
|
||||
opacity: 0; } }
|
||||
|
||||
@-webkit-keyframes md-autocomplete-list-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 40px; } }
|
||||
|
||||
@keyframes md-autocomplete-list-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
height: 0;
|
||||
-webkit-animation-timing-function: ease-out;
|
||||
animation-timing-function: ease-out; }
|
||||
|
||||
50% {
|
||||
opacity: 0;
|
||||
height: 40px; }
|
||||
|
||||
100% {
|
||||
opacity: 1;
|
||||
height: 40px; } }
|
||||
|
||||
md-autocomplete {
|
||||
border-radius: 2px;
|
||||
display: block;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
min-width: 190px; }
|
||||
md-autocomplete[disabled] input {
|
||||
cursor: not-allowed; }
|
||||
md-autocomplete[md-floating-label] {
|
||||
padding-bottom: 26px;
|
||||
border-radius: 0;
|
||||
background: transparent;
|
||||
height: auto; }
|
||||
md-autocomplete[md-floating-label] md-input-container {
|
||||
padding-bottom: 0; }
|
||||
md-autocomplete[md-floating-label] md-autocomplete-wrap {
|
||||
height: auto; }
|
||||
md-autocomplete[md-floating-label] button {
|
||||
position: absolute;
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
width: 30px;
|
||||
height: 30px; }
|
||||
md-autocomplete md-autocomplete-wrap {
|
||||
display: block;
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
height: 40px; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate] {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
transition: none; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate] .md-container {
|
||||
transition: none;
|
||||
top: auto;
|
||||
height: 3px; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-enter {
|
||||
transition: opacity 0.15s linear; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-enter.ng-enter-active {
|
||||
opacity: 1; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-leave {
|
||||
transition: opacity 0.15s linear; }
|
||||
md-autocomplete md-autocomplete-wrap md-progress-linear[md-mode=indeterminate].ng-leave.ng-leave-active {
|
||||
opacity: 0; }
|
||||
md-autocomplete input:not(.md-input) {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
padding: 0 15px;
|
||||
font-size: 14px;
|
||||
line-height: 40px;
|
||||
height: 40px;
|
||||
outline: none;
|
||||
background: transparent; }
|
||||
md-autocomplete input:not(.md-input)::-ms-clear {
|
||||
display: none; }
|
||||
md-autocomplete button {
|
||||
position: relative;
|
||||
line-height: 20px;
|
||||
text-align: center;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
border-radius: 50%;
|
||||
padding: 0;
|
||||
font-size: 12px;
|
||||
background: transparent;
|
||||
margin: auto 5px; }
|
||||
md-autocomplete button:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
right: -6px;
|
||||
bottom: -6px;
|
||||
left: -6px;
|
||||
border-radius: 50%;
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
opacity: 0;
|
||||
transition: all 0.4s cubic-bezier(0.25, 0.8, 0.25, 1); }
|
||||
md-autocomplete button:focus {
|
||||
outline: none; }
|
||||
md-autocomplete button:focus:after {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1);
|
||||
opacity: 1; }
|
||||
md-autocomplete button md-icon {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
-webkit-transform: translate3d(-50%, -50%, 0) scale(0.9);
|
||||
transform: translate3d(-50%, -50%, 0) scale(0.9); }
|
||||
md-autocomplete button md-icon path {
|
||||
stroke-width: 0; }
|
||||
md-autocomplete button.ng-enter {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
transition: -webkit-transform 0.15s ease-out;
|
||||
transition: transform 0.15s ease-out; }
|
||||
md-autocomplete button.ng-enter.ng-enter-active {
|
||||
-webkit-transform: scale(1);
|
||||
transform: scale(1); }
|
||||
md-autocomplete button.ng-leave {
|
||||
transition: -webkit-transform 0.15s ease-out;
|
||||
transition: transform 0.15s ease-out; }
|
||||
md-autocomplete button.ng-leave.ng-leave-active {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0); }
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-autocomplete input {
|
||||
border: 1px solid #fff; }
|
||||
md-autocomplete li:focus {
|
||||
color: #fff; } }
|
||||
|
||||
.md-autocomplete-suggestions {
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
overflow: auto;
|
||||
max-height: 225.5px;
|
||||
z-index: 100; }
|
||||
.md-autocomplete-suggestions li {
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
overflow: hidden;
|
||||
padding: 0 15px;
|
||||
line-height: 48px;
|
||||
height: 48px;
|
||||
transition: background 0.15s linear;
|
||||
margin: 0;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis; }
|
||||
.md-autocomplete-suggestions li.ng-enter, .md-autocomplete-suggestions li.ng-hide-remove {
|
||||
transition: none;
|
||||
-webkit-animation: md-autocomplete-list-in 0.2s;
|
||||
animation: md-autocomplete-list-in 0.2s; }
|
||||
.md-autocomplete-suggestions li.ng-leave, .md-autocomplete-suggestions li.ng-hide-add {
|
||||
transition: none;
|
||||
-webkit-animation: md-autocomplete-list-out 0.2s;
|
||||
animation: md-autocomplete-list-out 0.2s; }
|
||||
.md-autocomplete-suggestions li:focus {
|
||||
outline: none; }
|
||||
|
||||
@media screen and (-ms-high-contrast: active) {
|
||||
md-autocomplete, .md-autocomplete-suggestions {
|
||||
border: 1px solid #fff; } }
|
||||
951
IonicMaterialDesign/www/lib/angular-material/modules/closure/autocomplete/autocomplete.js
vendored
Normal file
951
IonicMaterialDesign/www/lib/angular-material/modules/closure/autocomplete/autocomplete.js
vendored
Normal file
@@ -0,0 +1,951 @@
|
||||
/*!
|
||||
* Angular Material Design
|
||||
* https://github.com/angular/material
|
||||
* @license MIT
|
||||
* v0.10.0
|
||||
*/
|
||||
goog.provide('ng.material.components.autocomplete');
|
||||
goog.require('ng.material.components.icon');
|
||||
goog.require('ng.material.core');
|
||||
/**
|
||||
* @ngdoc module
|
||||
* @name material.components.autocomplete
|
||||
*/
|
||||
/*
|
||||
* @see js folder for autocomplete implementation
|
||||
*/
|
||||
angular.module('material.components.autocomplete', [
|
||||
'material.core',
|
||||
'material.components.icon'
|
||||
]);
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.controller('MdAutocompleteCtrl', MdAutocompleteCtrl);
|
||||
|
||||
var ITEM_HEIGHT = 41,
|
||||
MAX_HEIGHT = 5.5 * ITEM_HEIGHT,
|
||||
MENU_PADDING = 8;
|
||||
|
||||
function MdAutocompleteCtrl ($scope, $element, $mdUtil, $mdConstant, $timeout, $mdTheming, $window,
|
||||
$animate, $rootElement, $attrs) {
|
||||
//-- private variables
|
||||
var ctrl = this,
|
||||
itemParts = $scope.itemsExpr.split(/ in /i),
|
||||
itemExpr = itemParts[1],
|
||||
elements = null,
|
||||
promise = null,
|
||||
cache = {},
|
||||
noBlur = false,
|
||||
selectedItemWatchers = [],
|
||||
hasFocus = false,
|
||||
lastCount = 0;
|
||||
|
||||
//-- public variables with handlers
|
||||
defineProperty('hidden', handleHiddenChange, true);
|
||||
|
||||
//-- public variables
|
||||
ctrl.scope = $scope;
|
||||
ctrl.parent = $scope.$parent;
|
||||
ctrl.itemName = itemParts[0];
|
||||
ctrl.matches = [];
|
||||
ctrl.loading = false;
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = null;
|
||||
ctrl.messages = [];
|
||||
ctrl.id = $mdUtil.nextUid();
|
||||
ctrl.isDisabled = null;
|
||||
ctrl.isRequired = null;
|
||||
|
||||
//-- public methods
|
||||
ctrl.keydown = keydown;
|
||||
ctrl.blur = blur;
|
||||
ctrl.focus = focus;
|
||||
ctrl.clear = clearValue;
|
||||
ctrl.select = select;
|
||||
ctrl.listEnter = onListEnter;
|
||||
ctrl.listLeave = onListLeave;
|
||||
ctrl.mouseUp = onMouseup;
|
||||
ctrl.getCurrentDisplayValue = getCurrentDisplayValue;
|
||||
ctrl.registerSelectedItemWatcher = registerSelectedItemWatcher;
|
||||
ctrl.unregisterSelectedItemWatcher = unregisterSelectedItemWatcher;
|
||||
|
||||
return init();
|
||||
|
||||
//-- initialization methods
|
||||
|
||||
/**
|
||||
* Initialize the controller, setup watchers, gather elements
|
||||
*/
|
||||
function init () {
|
||||
$mdUtil.initOptionalProperties($scope, $attrs, { searchText: null, selectedItem: null } );
|
||||
$mdTheming($element);
|
||||
configureWatchers();
|
||||
$timeout(function () {
|
||||
gatherElements();
|
||||
focusElement();
|
||||
moveDropdown();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the dropdown's position and applies the new styles to the menu element
|
||||
* @returns {*}
|
||||
*/
|
||||
function positionDropdown () {
|
||||
if (!elements) return $timeout(positionDropdown, 0, false);
|
||||
var hrect = elements.wrap.getBoundingClientRect(),
|
||||
vrect = elements.snap.getBoundingClientRect(),
|
||||
root = elements.root.getBoundingClientRect(),
|
||||
top = vrect.bottom - root.top,
|
||||
bot = root.bottom - vrect.top,
|
||||
left = hrect.left - root.left,
|
||||
width = hrect.width,
|
||||
styles = {
|
||||
left: left + 'px',
|
||||
minWidth: width + 'px',
|
||||
maxWidth: Math.max(hrect.right - root.left, root.right - hrect.left) - MENU_PADDING + 'px'
|
||||
};
|
||||
if (top > bot && root.height - hrect.bottom - MENU_PADDING < MAX_HEIGHT) {
|
||||
styles.top = 'auto';
|
||||
styles.bottom = bot + 'px';
|
||||
styles.maxHeight = Math.min(MAX_HEIGHT, hrect.top - root.top - MENU_PADDING) + 'px';
|
||||
} else {
|
||||
styles.top = top + 'px';
|
||||
styles.bottom = 'auto';
|
||||
styles.maxHeight = Math.min(MAX_HEIGHT, root.bottom - hrect.bottom - MENU_PADDING) + 'px';
|
||||
}
|
||||
elements.$.ul.css(styles);
|
||||
$timeout(correctHorizontalAlignment, 0, false);
|
||||
|
||||
/**
|
||||
* Makes sure that the menu doesn't go off of the screen on either side.
|
||||
*/
|
||||
function correctHorizontalAlignment () {
|
||||
var dropdown = elements.ul.getBoundingClientRect(),
|
||||
styles = {};
|
||||
if (dropdown.right > root.right - MENU_PADDING) {
|
||||
styles.left = (hrect.right - dropdown.width) + 'px';
|
||||
}
|
||||
elements.$.ul.css(styles);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the dropdown menu to the body tag in order to avoid z-index and overflow issues.
|
||||
*/
|
||||
function moveDropdown () {
|
||||
if (!elements.$.root.length) return;
|
||||
$mdTheming(elements.$.ul);
|
||||
elements.$.ul.detach();
|
||||
elements.$.root.append(elements.$.ul);
|
||||
if ($animate.pin) $animate.pin(elements.$.ul, $rootElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends focus to the input element.
|
||||
*/
|
||||
function focusElement () {
|
||||
if ($scope.autofocus) elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up any watchers used by autocomplete
|
||||
*/
|
||||
function configureWatchers () {
|
||||
var wait = parseInt($scope.delay, 10) || 0;
|
||||
$attrs.$observe('disabled', function (value) { ctrl.isDisabled = value; });
|
||||
$attrs.$observe('required', function (value) { ctrl.isRequired = value !== null; });
|
||||
$scope.$watch('searchText', wait ? $mdUtil.debounce(handleSearchText, wait) : handleSearchText);
|
||||
registerSelectedItemWatcher(selectedItemChange);
|
||||
$scope.$watch('selectedItem', handleSelectedItemChange);
|
||||
angular.element($window).on('resize', positionDropdown);
|
||||
$scope.$on('$destroy', cleanup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes any events or leftover elements created by this controller
|
||||
*/
|
||||
function cleanup () {
|
||||
angular.element($window).off('resize', positionDropdown);
|
||||
elements.$.ul.remove();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers all of the elements needed for this controller
|
||||
*/
|
||||
function gatherElements () {
|
||||
elements = {
|
||||
main: $element[0],
|
||||
ul: $element.find('ul')[0],
|
||||
input: $element.find('input')[0],
|
||||
wrap: $element.find('md-autocomplete-wrap')[0],
|
||||
root: document.body
|
||||
};
|
||||
elements.li = elements.ul.getElementsByTagName('li');
|
||||
elements.snap = getSnapTarget();
|
||||
elements.$ = getAngularElements(elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds the element that the menu will base its position on
|
||||
* @returns {*}
|
||||
*/
|
||||
function getSnapTarget () {
|
||||
for (var element = $element; element.length; element = element.parent()) {
|
||||
if (angular.isDefined(element.attr('md-autocomplete-snap'))) return element[0];
|
||||
}
|
||||
return elements.wrap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gathers angular-wrapped versions of each element
|
||||
* @param elements
|
||||
* @returns {{}}
|
||||
*/
|
||||
function getAngularElements (elements) {
|
||||
var obj = {};
|
||||
for (var key in elements) {
|
||||
obj[key] = angular.element(elements[key]);
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
//-- event/change handlers
|
||||
|
||||
/**
|
||||
* Handles changes to the `hidden` property.
|
||||
* @param hidden
|
||||
* @param oldHidden
|
||||
*/
|
||||
function handleHiddenChange (hidden, oldHidden) {
|
||||
if (!hidden && oldHidden) positionDropdown();
|
||||
if (!hidden) {
|
||||
if (elements) $timeout(function () { $mdUtil.disableScrollAround(elements.ul); }, 0, false);
|
||||
} else {
|
||||
$mdUtil.enableScrolling();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user mouses over the dropdown menu, ignore blur events.
|
||||
*/
|
||||
function onListEnter () {
|
||||
noBlur = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the user's mouse leaves the menu, blur events may hide the menu again.
|
||||
*/
|
||||
function onListLeave () {
|
||||
noBlur = false;
|
||||
if (!hasFocus) ctrl.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* When the mouse button is released, send focus back to the input field.
|
||||
*/
|
||||
function onMouseup () {
|
||||
elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes to the selected item.
|
||||
* @param selectedItem
|
||||
* @param previousSelectedItem
|
||||
*/
|
||||
function selectedItemChange (selectedItem, previousSelectedItem) {
|
||||
if (selectedItem) {
|
||||
$scope.searchText = getDisplayValue(selectedItem);
|
||||
}
|
||||
if ($scope.itemChange && selectedItem !== previousSelectedItem)
|
||||
$scope.itemChange(getItemScope(selectedItem));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls any external watchers listening for the selected item. Used in conjunction with
|
||||
* `registerSelectedItemWatcher`.
|
||||
* @param selectedItem
|
||||
* @param previousSelectedItem
|
||||
*/
|
||||
function handleSelectedItemChange(selectedItem, previousSelectedItem) {
|
||||
for (var i = 0; i < selectedItemWatchers.length; ++i) {
|
||||
selectedItemWatchers[i](selectedItem, previousSelectedItem);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a function to be called when the selected item changes.
|
||||
* @param cb
|
||||
*/
|
||||
function registerSelectedItemWatcher(cb) {
|
||||
if (selectedItemWatchers.indexOf(cb) == -1) {
|
||||
selectedItemWatchers.push(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a function previously registered for selected item changes.
|
||||
* @param cb
|
||||
*/
|
||||
function unregisterSelectedItemWatcher(cb) {
|
||||
var i = selectedItemWatchers.indexOf(cb);
|
||||
if (i != -1) {
|
||||
selectedItemWatchers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles changes to the searchText property.
|
||||
* @param searchText
|
||||
* @param previousSearchText
|
||||
*/
|
||||
function handleSearchText (searchText, previousSearchText) {
|
||||
ctrl.index = getDefaultIndex();
|
||||
//-- do nothing on init
|
||||
if (searchText === previousSearchText) return;
|
||||
//-- clear selected item if search text no longer matches it
|
||||
if (searchText !== getDisplayValue($scope.selectedItem)) $scope.selectedItem = null;
|
||||
else return;
|
||||
//-- trigger change event if available
|
||||
if ($scope.textChange && searchText !== previousSearchText)
|
||||
$scope.textChange(getItemScope($scope.selectedItem));
|
||||
//-- cancel results if search text is not long enough
|
||||
if (!isMinLengthMet()) {
|
||||
ctrl.loading = false;
|
||||
ctrl.matches = [];
|
||||
ctrl.hidden = shouldHide();
|
||||
updateMessages();
|
||||
} else {
|
||||
handleQuery();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input blur event, determines if the dropdown should hide.
|
||||
*/
|
||||
function blur () {
|
||||
hasFocus = false;
|
||||
if (!noBlur) ctrl.hidden = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles input focus event, determines if the dropdown should show.
|
||||
*/
|
||||
function focus () {
|
||||
hasFocus = true;
|
||||
//-- if searchText is null, let's force it to be a string
|
||||
if (!angular.isString($scope.searchText)) $scope.searchText = '';
|
||||
if ($scope.minLength > 0) return;
|
||||
ctrl.hidden = shouldHide();
|
||||
if (!ctrl.hidden) handleQuery();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles keyboard input.
|
||||
* @param event
|
||||
*/
|
||||
function keydown (event) {
|
||||
switch (event.keyCode) {
|
||||
case $mdConstant.KEY_CODE.DOWN_ARROW:
|
||||
if (ctrl.loading) return;
|
||||
event.preventDefault();
|
||||
ctrl.index = Math.min(ctrl.index + 1, ctrl.matches.length - 1);
|
||||
updateScroll();
|
||||
updateMessages();
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.UP_ARROW:
|
||||
if (ctrl.loading) return;
|
||||
event.preventDefault();
|
||||
ctrl.index = ctrl.index < 0 ? ctrl.matches.length - 1 : Math.max(0, ctrl.index - 1);
|
||||
updateScroll();
|
||||
updateMessages();
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.TAB:
|
||||
case $mdConstant.KEY_CODE.ENTER:
|
||||
if (ctrl.hidden || ctrl.loading || ctrl.index < 0 || ctrl.matches.length < 1) return;
|
||||
event.preventDefault();
|
||||
select(ctrl.index);
|
||||
break;
|
||||
case $mdConstant.KEY_CODE.ESCAPE:
|
||||
ctrl.matches = [];
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = getDefaultIndex();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
//-- getters
|
||||
|
||||
/**
|
||||
* Returns the minimum length needed to display the dropdown.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getMinLength () {
|
||||
return angular.isNumber($scope.minLength) ? $scope.minLength : 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display value for an item.
|
||||
* @param item
|
||||
* @returns {*}
|
||||
*/
|
||||
function getDisplayValue (item) {
|
||||
return (item && $scope.itemText) ? $scope.itemText(getItemScope(item)) : item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locals object for compiling item templates.
|
||||
* @param item
|
||||
* @returns {{}}
|
||||
*/
|
||||
function getItemScope (item) {
|
||||
if (!item) return;
|
||||
var locals = {};
|
||||
if (ctrl.itemName) locals[ctrl.itemName] = item;
|
||||
return locals;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default index based on whether or not autoselect is enabled.
|
||||
* @returns {number}
|
||||
*/
|
||||
function getDefaultIndex () {
|
||||
return $scope.autoselect ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the menu should be hidden.
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function shouldHide () {
|
||||
if (!isMinLengthMet()) return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the display value of the current item.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getCurrentDisplayValue () {
|
||||
return getDisplayValue(ctrl.matches[ctrl.index]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the minimum length is met by the search text.
|
||||
* @returns {*}
|
||||
*/
|
||||
function isMinLengthMet () {
|
||||
return angular.isDefined($scope.searchText) && $scope.searchText.length >= getMinLength();
|
||||
}
|
||||
|
||||
//-- actions
|
||||
|
||||
/**
|
||||
* Defines a public property with a handler and a default value.
|
||||
* @param key
|
||||
* @param handler
|
||||
* @param value
|
||||
*/
|
||||
function defineProperty (key, handler, value) {
|
||||
Object.defineProperty(ctrl, key, {
|
||||
get: function () { return value; },
|
||||
set: function (newValue) {
|
||||
var oldValue = value;
|
||||
value = newValue;
|
||||
handler(newValue, oldValue);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects the item at the given index.
|
||||
* @param index
|
||||
*/
|
||||
function select (index) {
|
||||
$scope.selectedItem = ctrl.matches[index];
|
||||
ctrl.hidden = true;
|
||||
ctrl.index = 0;
|
||||
ctrl.matches = [];
|
||||
//-- force form to update state for validation
|
||||
$timeout(function () {
|
||||
elements.$.input.controller('ngModel').$setViewValue(getDisplayValue($scope.selectedItem) ||
|
||||
$scope.searchText);
|
||||
ctrl.hidden = true;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the searchText value and selected item.
|
||||
*/
|
||||
function clearValue () {
|
||||
$scope.searchText = '';
|
||||
select(-1);
|
||||
|
||||
// Per http://www.w3schools.com/jsref/event_oninput.asp
|
||||
var eventObj = document.createEvent('CustomEvent');
|
||||
eventObj.initCustomEvent('input', true, true, {value: $scope.searchText});
|
||||
elements.input.dispatchEvent(eventObj);
|
||||
|
||||
elements.input.focus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the results for the provided search text.
|
||||
* @param searchText
|
||||
*/
|
||||
function fetchResults (searchText) {
|
||||
var items = $scope.$parent.$eval(itemExpr),
|
||||
term = searchText.toLowerCase();
|
||||
if (angular.isArray(items)) {
|
||||
handleResults(items);
|
||||
} else if (items) {
|
||||
ctrl.loading = true;
|
||||
if (items.success) items.success(handleResults);
|
||||
if (items.then) items.then(handleResults);
|
||||
if (items.error) items.error(function () { ctrl.loading = false; });
|
||||
}
|
||||
function handleResults (matches) {
|
||||
cache[term] = matches;
|
||||
if (searchText !== $scope.searchText) return; //-- just cache the results if old request
|
||||
ctrl.loading = false;
|
||||
promise = null;
|
||||
ctrl.matches = matches;
|
||||
ctrl.hidden = shouldHide();
|
||||
updateMessages();
|
||||
positionDropdown();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the ARIA messages
|
||||
*/
|
||||
function updateMessages () {
|
||||
ctrl.messages = [ getCountMessage(), getCurrentDisplayValue() ];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the ARIA message for how many results match the current query.
|
||||
* @returns {*}
|
||||
*/
|
||||
function getCountMessage () {
|
||||
if (lastCount === ctrl.matches.length) return '';
|
||||
lastCount = ctrl.matches.length;
|
||||
switch (ctrl.matches.length) {
|
||||
case 0: return 'There are no matches available.';
|
||||
case 1: return 'There is 1 match available.';
|
||||
default: return 'There are ' + ctrl.matches.length + ' matches available.';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes sure that the focused element is within view.
|
||||
*/
|
||||
function updateScroll () {
|
||||
if (!elements.li[ctrl.index]) return;
|
||||
var li = elements.li[ctrl.index],
|
||||
top = li.offsetTop,
|
||||
bot = top + li.offsetHeight,
|
||||
hgt = elements.ul.clientHeight;
|
||||
if (top < elements.ul.scrollTop) {
|
||||
elements.ul.scrollTop = top;
|
||||
} else if (bot > elements.ul.scrollTop + hgt) {
|
||||
elements.ul.scrollTop = bot - hgt;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the query to gather the results for the current searchText. Attempts to return cached
|
||||
* results first, then forwards the process to `fetchResults` if necessary.
|
||||
*/
|
||||
function handleQuery () {
|
||||
var searchText = $scope.searchText,
|
||||
term = searchText.toLowerCase();
|
||||
//-- cancel promise if a promise is in progress
|
||||
if (promise && promise.cancel) {
|
||||
promise.cancel();
|
||||
promise = null;
|
||||
}
|
||||
//-- if results are cached, pull in cached results
|
||||
if (!$scope.noCache && cache[term]) {
|
||||
ctrl.matches = cache[term];
|
||||
updateMessages();
|
||||
} else {
|
||||
fetchResults(searchText);
|
||||
}
|
||||
if (hasFocus) ctrl.hidden = shouldHide();
|
||||
}
|
||||
|
||||
}
|
||||
MdAutocompleteCtrl.$inject = ["$scope", "$element", "$mdUtil", "$mdConstant", "$timeout", "$mdTheming", "$window", "$animate", "$rootElement", "$attrs"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocomplete', MdAutocomplete);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdAutocomplete
|
||||
* @module material.components.autocomplete
|
||||
*
|
||||
* @description
|
||||
* `<md-autocomplete>` is a special input component with a drop-down of all possible matches to a custom query.
|
||||
* This component allows you to provide real-time suggestions as the user types in the input area.
|
||||
*
|
||||
* To start, you will need to specify the required parameters and provide a template for your results.
|
||||
* The content inside `md-autocomplete` will be treated as a template.
|
||||
*
|
||||
* In more complex cases, you may want to include other content such as a message to display when
|
||||
* no matches were found. You can do this by wrapping your template in `md-item-template` and adding
|
||||
* a tag for `md-not-found`. An example of this is shown below.
|
||||
* ### Validation
|
||||
*
|
||||
* You can use `ng-messages` to include validation the same way that you would normally validate;
|
||||
* however, if you want to replicate a standard input with a floating label, you will have to do the
|
||||
* following:
|
||||
*
|
||||
* - Make sure that your template is wrapped in `md-item-template`
|
||||
* - Add your `ng-messages` code inside of `md-autocomplete`
|
||||
* - Add your validation properties to `md-autocomplete` (ie. `required`)
|
||||
* - Add a `name` to `md-autocomplete` (to be used on the generated `input`)
|
||||
*
|
||||
* There is an example below of how this should look.
|
||||
*
|
||||
*
|
||||
* @param {expression} md-items An expression in the format of `item in items` to iterate over matches for your search.
|
||||
* @param {expression=} md-selected-item-change An expression to be run each time a new item is selected
|
||||
* @param {expression=} md-search-text-change An expression to be run each time the search text updates
|
||||
* @param {string=} md-search-text A model to bind the search query text to
|
||||
* @param {object=} md-selected-item A model to bind the selected item to
|
||||
* @param {string=} md-item-text An expression that will convert your object to a single string.
|
||||
* @param {string=} placeholder Placeholder text that will be forwarded to the input.
|
||||
* @param {boolean=} md-no-cache Disables the internal caching that happens in autocomplete
|
||||
* @param {boolean=} ng-disabled Determines whether or not to disable the input field
|
||||
* @param {number=} md-min-length Specifies the minimum length of text before autocomplete will make suggestions
|
||||
* @param {number=} md-delay Specifies the amount of time (in milliseconds) to wait before looking for results
|
||||
* @param {boolean=} md-autofocus If true, will immediately focus the input element
|
||||
* @param {boolean=} md-autoselect If true, the first item will be selected by default
|
||||
* @param {string=} md-menu-class This will be applied to the dropdown menu for styling
|
||||
* @param {string=} md-floating-label This will add a floating label to autocomplete and wrap it in `md-input-container`
|
||||
*
|
||||
* @usage
|
||||
* ###Basic Example
|
||||
* <hljs lang="html">
|
||||
* <md-autocomplete
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-autocomplete>
|
||||
* </hljs>
|
||||
*
|
||||
* ###Example with "not found" message
|
||||
* <hljs lang="html">
|
||||
* <md-autocomplete
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <md-item-template>
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-item-template>
|
||||
* <md-not-found>
|
||||
* No matches found.
|
||||
* </md-not-found>
|
||||
* </md-autocomplete>
|
||||
* </hljs>
|
||||
*
|
||||
* In this example, our code utilizes `md-item-template` and `md-not-found` to specify the different
|
||||
* parts that make up our component.
|
||||
*
|
||||
* ### Example with validation
|
||||
* <hljs lang="html">
|
||||
* <form name="autocompleteForm">
|
||||
* <md-autocomplete
|
||||
* required
|
||||
* input-name="autocomplete"
|
||||
* md-selected-item="selectedItem"
|
||||
* md-search-text="searchText"
|
||||
* md-items="item in getMatches(searchText)"
|
||||
* md-item-text="item.display">
|
||||
* <md-item-template>
|
||||
* <span md-highlight-text="searchText">{{item.display}}</span>
|
||||
* </md-item-template>
|
||||
* <div ng-messages="autocompleteForm.autocomplete.$error">
|
||||
* <div ng-message="required">This field is required</div>
|
||||
* </div>
|
||||
* </md-autocomplete>
|
||||
* </form>
|
||||
* </hljs>
|
||||
*
|
||||
* In this example, our code utilizes `md-item-template` and `md-not-found` to specify the different
|
||||
* parts that make up our component.
|
||||
*/
|
||||
|
||||
function MdAutocomplete ($mdTheming, $mdUtil) {
|
||||
return {
|
||||
controller: 'MdAutocompleteCtrl',
|
||||
controllerAs: '$mdAutocompleteCtrl',
|
||||
scope: {
|
||||
inputName: '@mdInputName',
|
||||
inputMinlength: '@mdInputMinlength',
|
||||
inputMaxlength: '@mdInputMaxlength',
|
||||
searchText: '=?mdSearchText',
|
||||
selectedItem: '=?mdSelectedItem',
|
||||
itemsExpr: '@mdItems',
|
||||
itemText: '&mdItemText',
|
||||
placeholder: '@placeholder',
|
||||
noCache: '=?mdNoCache',
|
||||
itemChange: '&?mdSelectedItemChange',
|
||||
textChange: '&?mdSearchTextChange',
|
||||
minLength: '=?mdMinLength',
|
||||
delay: '=?mdDelay',
|
||||
autofocus: '=?mdAutofocus',
|
||||
floatingLabel: '@?mdFloatingLabel',
|
||||
autoselect: '=?mdAutoselect',
|
||||
menuClass: '@?mdMenuClass'
|
||||
},
|
||||
template: function (element, attr) {
|
||||
var noItemsTemplate = getNoItemsTemplate(),
|
||||
itemTemplate = getItemTemplate(),
|
||||
leftover = element.html();
|
||||
return '\
|
||||
<md-autocomplete-wrap\
|
||||
layout="row"\
|
||||
ng-class="{ \'md-whiteframe-z1\': !floatingLabel }"\
|
||||
role="listbox">\
|
||||
' + getInputElement() + '\
|
||||
<md-progress-linear\
|
||||
ng-if="$mdAutocompleteCtrl.loading"\
|
||||
md-mode="indeterminate"></md-progress-linear>\
|
||||
<ul role="presentation"\
|
||||
class="md-autocomplete-suggestions md-whiteframe-z1 {{menuClass || \'\'}}"\
|
||||
id="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
ng-hide="$mdAutocompleteCtrl.hidden"\
|
||||
ng-mouseenter="$mdAutocompleteCtrl.listEnter()"\
|
||||
ng-mouseleave="$mdAutocompleteCtrl.listLeave()"\
|
||||
ng-mouseup="$mdAutocompleteCtrl.mouseUp()">\
|
||||
<li ng-repeat="(index, item) in $mdAutocompleteCtrl.matches"\
|
||||
ng-class="{ selected: index === $mdAutocompleteCtrl.index }"\
|
||||
ng-click="$mdAutocompleteCtrl.select(index)"\
|
||||
md-autocomplete-list-item="$mdAutocompleteCtrl.itemName">\
|
||||
' + itemTemplate + '\
|
||||
</li>\
|
||||
' + noItemsTemplate + '\
|
||||
</ul>\
|
||||
</md-autocomplete-wrap>\
|
||||
<aria-status\
|
||||
class="md-visually-hidden"\
|
||||
role="status"\
|
||||
aria-live="assertive">\
|
||||
<p ng-repeat="message in $mdAutocompleteCtrl.messages" ng-if="message">{{message}}</p>\
|
||||
</aria-status>';
|
||||
|
||||
function getItemTemplate() {
|
||||
var templateTag = element.find('md-item-template').remove(),
|
||||
html = templateTag.length ? templateTag.html() : element.html();
|
||||
if (!templateTag.length) element.empty();
|
||||
return html;
|
||||
}
|
||||
|
||||
function getNoItemsTemplate() {
|
||||
var templateTag = element.find('md-not-found').remove(),
|
||||
template = templateTag.length ? templateTag.html() : '';
|
||||
return template
|
||||
? '<li ng-if="!$mdAutocompleteCtrl.matches.length && !$mdAutocompleteCtrl.loading\
|
||||
&& !$mdAutocompleteCtrl.hidden"\
|
||||
ng-hide="$mdAutocompleteCtrl.hidden"\
|
||||
md-autocomplete-parent-scope>' + template + '</li>'
|
||||
: '';
|
||||
|
||||
}
|
||||
|
||||
function getInputElement() {
|
||||
if (attr.mdFloatingLabel) {
|
||||
return '\
|
||||
<md-input-container flex ng-if="floatingLabel">\
|
||||
<label>{{floatingLabel}}</label>\
|
||||
<input type="search"\
|
||||
id="fl-input-{{$mdAutocompleteCtrl.id}}"\
|
||||
name="{{inputName}}"\
|
||||
autocomplete="off"\
|
||||
ng-required="isRequired"\
|
||||
ng-minlength="inputMinlength"\
|
||||
ng-maxlength="inputMaxlength"\
|
||||
ng-disabled="$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-model="$mdAutocompleteCtrl.scope.searchText"\
|
||||
ng-keydown="$mdAutocompleteCtrl.keydown($event)"\
|
||||
ng-blur="$mdAutocompleteCtrl.blur()"\
|
||||
ng-focus="$mdAutocompleteCtrl.focus()"\
|
||||
aria-owns="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
aria-label="{{floatingLabel}}"\
|
||||
aria-autocomplete="list"\
|
||||
aria-haspopup="true"\
|
||||
aria-activedescendant=""\
|
||||
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
|
||||
<div md-autocomplete-parent-scope md-autocomplete-replace>' + leftover + '</div>\
|
||||
</md-input-container>';
|
||||
} else {
|
||||
return '\
|
||||
<input flex type="search"\
|
||||
id="input-{{$mdAutocompleteCtrl.id}}"\
|
||||
name="{{inputName}}"\
|
||||
ng-if="!floatingLabel"\
|
||||
autocomplete="off"\
|
||||
ng-required="isRequired"\
|
||||
ng-disabled="$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-model="$mdAutocompleteCtrl.scope.searchText"\
|
||||
ng-keydown="$mdAutocompleteCtrl.keydown($event)"\
|
||||
ng-blur="$mdAutocompleteCtrl.blur()"\
|
||||
ng-focus="$mdAutocompleteCtrl.focus()"\
|
||||
placeholder="{{placeholder}}"\
|
||||
aria-owns="ul-{{$mdAutocompleteCtrl.id}}"\
|
||||
aria-label="{{placeholder}}"\
|
||||
aria-autocomplete="list"\
|
||||
aria-haspopup="true"\
|
||||
aria-activedescendant=""\
|
||||
aria-expanded="{{!$mdAutocompleteCtrl.hidden}}"/>\
|
||||
<button\
|
||||
type="button"\
|
||||
tabindex="-1"\
|
||||
ng-if="$mdAutocompleteCtrl.scope.searchText && !$mdAutocompleteCtrl.isDisabled"\
|
||||
ng-click="$mdAutocompleteCtrl.clear()">\
|
||||
<md-icon md-svg-icon="md-close"></md-icon>\
|
||||
<span class="md-visually-hidden">Clear</span>\
|
||||
</button>\
|
||||
';
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
MdAutocomplete.$inject = ["$mdTheming", "$mdUtil"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.controller('MdHighlightCtrl', MdHighlightCtrl);
|
||||
|
||||
function MdHighlightCtrl ($scope, $element, $interpolate) {
|
||||
this.init = init;
|
||||
|
||||
return init();
|
||||
|
||||
function init (term) {
|
||||
var unsafeText = $interpolate($element.html())($scope),
|
||||
text = angular.element('<div>').text(unsafeText).html(),
|
||||
flags = $element.attr('md-highlight-flags') || '',
|
||||
watcher = $scope.$watch(term, function (term) {
|
||||
var regex = getRegExp(term, flags),
|
||||
html = text.replace(regex, '<span class="highlight">$&</span>');
|
||||
$element.html(html);
|
||||
});
|
||||
$element.on('$destroy', function () { watcher(); });
|
||||
}
|
||||
|
||||
function sanitize (term) {
|
||||
if (!term) return term;
|
||||
return term.replace(/[\\\^\$\*\+\?\.\(\)\|\{\}\[\]]/g, '\\$&');
|
||||
}
|
||||
|
||||
function getRegExp (text, flags) {
|
||||
var str = '';
|
||||
if (flags.indexOf('^') >= 1) str += '^';
|
||||
str += text;
|
||||
if (flags.indexOf('$') >= 1) str += '$';
|
||||
return new RegExp(sanitize(str), flags.replace(/[\$\^]/g, ''));
|
||||
}
|
||||
}
|
||||
MdHighlightCtrl.$inject = ["$scope", "$element", "$interpolate"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdHighlightText', MdHighlight);
|
||||
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name mdHighlightText
|
||||
* @module material.components.autocomplete
|
||||
*
|
||||
* @description
|
||||
* The `md-highlight-text` directive allows you to specify text that should be highlighted within
|
||||
* an element. Highlighted text will be wrapped in `<span class="highlight"></span>` which can
|
||||
* be styled through CSS. Please note that child elements may not be used with this directive.
|
||||
*
|
||||
* @param {string} md-highlight-text A model to be searched for
|
||||
* @param {string=} md-highlight-flags A list of flags (loosely based on JavaScript RexExp flags).
|
||||
* #### **Supported flags**:
|
||||
* - `g`: Find all matches within the provided text
|
||||
* - `i`: Ignore case when searching for matches
|
||||
* - `$`: Only match if the text ends with the search term
|
||||
* - `^`: Only match if the text begins with the search term
|
||||
*
|
||||
* @usage
|
||||
* <hljs lang="html">
|
||||
* <input placeholder="Enter a search term..." ng-model="searchTerm" type="text" />
|
||||
* <ul>
|
||||
* <li ng-repeat="result in results" md-highlight-text="searchTerm">
|
||||
* {{result.text}}
|
||||
* </li>
|
||||
* </ul>
|
||||
* </hljs>
|
||||
*/
|
||||
|
||||
function MdHighlight () {
|
||||
return {
|
||||
terminal: true,
|
||||
scope: false,
|
||||
controller: 'MdHighlightCtrl',
|
||||
link: function (scope, element, attr, ctrl) {
|
||||
ctrl.init(attr.mdHighlightText);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocompleteListItem', MdAutocompleteListItem);
|
||||
|
||||
function MdAutocompleteListItem ($compile, $mdUtil) {
|
||||
return {
|
||||
terminal: true,
|
||||
link: postLink,
|
||||
scope: false
|
||||
};
|
||||
function postLink (scope, element, attr) {
|
||||
var ctrl = scope.$parent.$mdAutocompleteCtrl,
|
||||
newScope = ctrl.parent.$new(false, ctrl.parent),
|
||||
itemName = ctrl.scope.$eval(attr.mdAutocompleteListItem);
|
||||
newScope[itemName] = scope.item;
|
||||
$compile(element.contents())(newScope);
|
||||
element.attr({
|
||||
role: 'option',
|
||||
id: 'item_' + $mdUtil.nextUid()
|
||||
});
|
||||
}
|
||||
}
|
||||
MdAutocompleteListItem.$inject = ["$compile", "$mdUtil"];
|
||||
|
||||
angular
|
||||
.module('material.components.autocomplete')
|
||||
.directive('mdAutocompleteParentScope', MdAutocompleteParentScope);
|
||||
|
||||
function MdAutocompleteParentScope ($compile, $mdUtil) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
terminal: true,
|
||||
link: postLink,
|
||||
scope: false
|
||||
};
|
||||
function postLink (scope, element, attr) {
|
||||
var ctrl = scope.$parent.$mdAutocompleteCtrl;
|
||||
$compile(element.contents())(ctrl.parent);
|
||||
if (attr.hasOwnProperty('mdAutocompleteReplace')) {
|
||||
element.after(element.contents());
|
||||
element.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
MdAutocompleteParentScope.$inject = ["$compile", "$mdUtil"];
|
||||
|
||||
ng.material.components.autocomplete = angular.module("material.components.autocomplete");
|
||||
Reference in New Issue
Block a user