2015-02-19 21:21:54 +00:00
|
|
|
|
/**
|
|
|
|
|
* An element which displays a dropdown select box which is (optionally) editable. This box
|
|
|
|
|
* is displayed with an <input> and a menu on the right.
|
|
|
|
|
*/
|
|
|
|
|
angular.module('quay').directive('dropdownSelect', function ($compile) {
|
|
|
|
|
var directiveDefinitionObject = {
|
|
|
|
|
priority: 0,
|
|
|
|
|
templateUrl: '/static/directives/dropdown-select.html',
|
|
|
|
|
replace: true,
|
|
|
|
|
transclude: true,
|
|
|
|
|
restrict: 'C',
|
|
|
|
|
scope: {
|
|
|
|
|
'selectedItem': '=selectedItem',
|
|
|
|
|
'placeholder': '=placeholder',
|
|
|
|
|
'lookaheadItems': '=lookaheadItems',
|
2015-04-28 22:15:12 +00:00
|
|
|
|
'hideDropdown': '=hideDropdown',
|
2015-02-19 21:21:54 +00:00
|
|
|
|
|
|
|
|
|
'allowCustomInput': '@allowCustomInput',
|
|
|
|
|
|
|
|
|
|
'handleItemSelected': '&handleItemSelected',
|
|
|
|
|
'handleInput': '&handleInput',
|
|
|
|
|
|
|
|
|
|
'clearValue': '=clearValue'
|
|
|
|
|
},
|
|
|
|
|
controller: function($scope, $element, $rootScope) {
|
|
|
|
|
if (!$rootScope.__dropdownSelectCounter) {
|
|
|
|
|
$rootScope.__dropdownSelectCounter = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$scope.placeholder = $scope.placeholder || '';
|
2016-09-27 14:52:34 +00:00
|
|
|
|
$scope.lookaheadSetup = false;
|
2015-02-19 21:21:54 +00:00
|
|
|
|
|
|
|
|
|
// Setup lookahead.
|
|
|
|
|
var input = $($element).find('.lookahead-input');
|
|
|
|
|
|
|
|
|
|
$scope.$watch('clearValue', function(cv) {
|
2016-09-27 14:52:34 +00:00
|
|
|
|
if (cv && $scope.lookaheadSetup) {
|
2015-02-19 21:21:54 +00:00
|
|
|
|
$scope.selectedItem = null;
|
2016-09-27 14:52:34 +00:00
|
|
|
|
$(input).typeahead('val', '');
|
|
|
|
|
$(input).typeahead('close');
|
2015-02-19 21:21:54 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$scope.$watch('selectedItem', function(item) {
|
2016-09-27 14:52:34 +00:00
|
|
|
|
if (item != null && $scope.lookaheadSetup) {
|
|
|
|
|
$(input).typeahead('val', item.toString());
|
|
|
|
|
$(input).typeahead('close');
|
2015-02-19 21:21:54 +00:00
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$scope.$watch('lookaheadItems', function(items) {
|
|
|
|
|
$(input).off();
|
2016-09-27 14:52:34 +00:00
|
|
|
|
items = items || [];
|
2015-02-19 21:21:54 +00:00
|
|
|
|
|
|
|
|
|
var formattedItems = [];
|
|
|
|
|
for (var i = 0; i < items.length; ++i) {
|
|
|
|
|
var formattedItem = items[i];
|
|
|
|
|
if (typeof formattedItem == 'string') {
|
|
|
|
|
formattedItem = {
|
|
|
|
|
'value': formattedItem
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
formattedItems.push(formattedItem);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var dropdownHound = new Bloodhound({
|
|
|
|
|
name: 'dropdown-items-' + $rootScope.__dropdownSelectCounter,
|
|
|
|
|
local: formattedItems,
|
|
|
|
|
datumTokenizer: function(d) {
|
|
|
|
|
return Bloodhound.tokenizers.whitespace(d.val || d.value || '');
|
|
|
|
|
},
|
|
|
|
|
queryTokenizer: Bloodhound.tokenizers.whitespace
|
|
|
|
|
});
|
|
|
|
|
dropdownHound.initialize();
|
|
|
|
|
|
2016-09-27 14:52:34 +00:00
|
|
|
|
$(input).typeahead({
|
|
|
|
|
'hint': false,
|
|
|
|
|
'highlight': false
|
|
|
|
|
}, {
|
2015-02-19 21:21:54 +00:00
|
|
|
|
source: dropdownHound.ttAdapter(),
|
|
|
|
|
templates: {
|
|
|
|
|
'suggestion': function (datum) {
|
2017-05-09 19:25:21 +00:00
|
|
|
|
template = datum['template'] ? datum['template'](datum) : '<span>' + datum['value'] + '</span>';
|
2015-02-19 21:21:54 +00:00
|
|
|
|
return template;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$(input).on('input', function(e) {
|
|
|
|
|
$scope.$apply(function() {
|
|
|
|
|
$scope.selectedItem = null;
|
|
|
|
|
if ($scope.handleInput) {
|
|
|
|
|
$scope.handleInput({'input': $(input).val()});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$(input).on('typeahead:selected', function(e, datum) {
|
|
|
|
|
$scope.$apply(function() {
|
|
|
|
|
$scope.selectedItem = datum['item'] || datum['value'];
|
|
|
|
|
if ($scope.handleItemSelected) {
|
|
|
|
|
$scope.handleItemSelected({'datum': datum});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
$rootScope.__dropdownSelectCounter++;
|
2016-09-27 14:52:34 +00:00
|
|
|
|
$scope.lookaheadSetup = true;
|
2015-02-19 21:21:54 +00:00
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
link: function(scope, element, attrs) {
|
|
|
|
|
var transcludedBlock = element.find('div.transcluded');
|
|
|
|
|
var transcludedElements = transcludedBlock.children();
|
|
|
|
|
|
|
|
|
|
var iconContainer = element.find('div.dropdown-select-icon-transclude');
|
|
|
|
|
var menuContainer = element.find('div.dropdown-select-menu-transclude');
|
|
|
|
|
|
|
|
|
|
angular.forEach(transcludedElements, function(elem) {
|
|
|
|
|
if (angular.element(elem).hasClass('dropdown-select-icon')) {
|
|
|
|
|
iconContainer.append(elem);
|
|
|
|
|
} else if (angular.element(elem).hasClass('dropdown-select-menu')) {
|
|
|
|
|
menuContainer.replaceWith(elem);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
transcludedBlock.remove();
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return directiveDefinitionObject;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* An icon in the dropdown select. Only one icon will be displayed at a time.
|
|
|
|
|
*/
|
|
|
|
|
angular.module('quay').directive('dropdownSelectIcon', function () {
|
|
|
|
|
var directiveDefinitionObject = {
|
|
|
|
|
priority: 1,
|
|
|
|
|
require: '^dropdownSelect',
|
|
|
|
|
templateUrl: '/static/directives/dropdown-select-icon.html',
|
|
|
|
|
replace: false,
|
|
|
|
|
transclude: false,
|
|
|
|
|
restrict: 'C',
|
|
|
|
|
scope: {
|
|
|
|
|
},
|
|
|
|
|
controller: function($scope, $element) {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return directiveDefinitionObject;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* The menu for the dropdown select.
|
|
|
|
|
*/
|
|
|
|
|
angular.module('quay').directive('dropdownSelectMenu', function () {
|
|
|
|
|
var directiveDefinitionObject = {
|
|
|
|
|
priority: 1,
|
|
|
|
|
require: '^dropdownSelect',
|
|
|
|
|
templateUrl: '/static/directives/dropdown-select-menu.html',
|
|
|
|
|
replace: true,
|
|
|
|
|
transclude: true,
|
|
|
|
|
restrict: 'C',
|
|
|
|
|
scope: {
|
|
|
|
|
},
|
|
|
|
|
controller: function($scope, $element) {
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
return directiveDefinitionObject;
|
|
|
|
|
});
|