in ui-modules/blueprint-composer/app/components/catalog-selector/catalog-selector.directive.js [105:370]
function controller($scope, $element, $timeout, $q, $uibModal, $log, $templateCache, paletteApi, paletteDragAndDropService, iconGenerator, composerOverrides, recentlyUsedService) {
this.$timeout = $timeout;
$scope.viewModes = PALETTE_VIEW_MODES;
$scope.viewOrders = PALETTE_VIEW_ORDERS;
if (!$scope.state) $scope.state = {};
if (!$scope.state.viewMode) {
let savedViewMode;
try {
savedViewMode = JSON.parse(sessionStorage.getItem(SESSION_KEYS.VIEW_MODE));
} catch(err) {
savedViewMode = null;
}
$scope.state.viewMode = ((typeof savedViewMode === 'object') && (savedViewMode !== null))
? savedViewMode
: PALETTE_VIEW_MODES.normal
};
if(!$scope.search && !$scope.iconSelects) { // Do not restore search when the icon triggers selection directly or shows popup - `iconSelects == true`.
const savedSearch = sessionStorage.getItem(SESSION_KEYS.QUERY);
if (typeof savedSearch === 'string' && savedSearch.length) $scope.search = savedSearch;
}
$scope.pagination = {
page: 1,
itemsPerPage: $scope.state.viewMode.itemsPerRow * ($scope.rowsPerPage || 1) // will fill out after load
};
$scope.getEntityNameForPalette = function(item, entityName) {
return (composerOverrides.getEntityNameForPalette ||
// above can be overridden with function of signature below to customize display name in palette
function(item, entityName, scope) { return entityName; }
)(item, entityName, $scope);
};
$scope.getPlaceHolder = function () {
return 'Search';
};
$scope.isLoading = true;
$scope.$watch('search', (newValue) => {
$scope.freeFormTile = {
symbolicName: $scope.search,
name: $scope.search,
id: $scope.search,
displayName: $scope.search,
supertypes: ($scope.family ? [ $scope.family.superType ] : []),
};
if (typeof newValue === 'string') sessionStorage.setItem(SESSION_KEYS.QUERY, newValue);
});
$scope.getItems = function (search) {
let defer = $q.resolve([]);
switch ($scope.family) {
case EntityFamily.ENTITY:
case EntityFamily.SPEC:
defer = paletteApi.getTypes({params: {supertype: 'entity', fragment: search}});
break;
case EntityFamily.POLICY:
defer = paletteApi.getTypes({params: {supertype: 'policy', fragment: search}});
break;
case EntityFamily.ENRICHER:
defer = paletteApi.getTypes({params: {supertype: 'enricher', fragment: search}});
break;
case EntityFamily.LOCATION:
defer = paletteApi.getLocations();
break;
}
return defer.then(data => {
data = $scope.filterPaletteItemsForMode(data, $scope);
data.forEach( recentlyUsedService.embellish );
return data;
}).catch(error => {
return [];
}).finally(() => {
$scope.isLoading = false;
});
};
function tryMarkUsed(item) {
try {
recentlyUsedService.markUsed(item);
} catch (e) {
// session storage can get full; usually the culprit is icons not this,
// but we may wish to clear out old items to ensure we don't bleed here
$log.warn("Could not mark item as used: "+item, e);
}
}
$scope.mouseInfoPopover = (item, enter) => {
if ($scope.popoverModal && $scope.popoverVisible && $scope.popover==item) {
// ignore if modal
return;
}
$scope.popoverModal = false;
if (enter) {
$scope.popover = item;
$scope.popoverVisible = true;
} else {
$scope.popoverVisible = false;
}
};
$scope.onClickItem = (item, isInfoIcon, $event) => {
if (!isInfoIcon && $scope.iconSelects) {
$scope.onSelectItem(item);
} else if ($scope.popoverModal && $scope.popoverVisible && $scope.popover == item) {
$scope.closePopover();
} else {
$scope.popover = item;
$scope.popoverVisible = true;
$scope.popoverModal = true;
}
if ($event) $event.stopPropagation();
};
$scope.closePopover = () => {
$scope.popoverVisible = false;
$scope.popoverModal = false;
};
$scope.getOnSelectText = function (item) {
if (!($scope.onSelectText)) return "Select";
return $scope.onSelectText({item: item});
};
$scope.onSelectItem = function (item) {
$scope.closePopover();
if (angular.isFunction($scope.onSelect)) {
tryMarkUsed(item);
$scope.onSelect({item: item});
}
$scope.search = '';
};
$scope.onDragItem = function (item, event) {
let frame = document.createElement('div');
frame.classList.add('drag-frame');
event.target.appendChild(frame);
setTimeout(function() {
// can remove at end of this cycle, browser will have grabbed its drag image
frame.parentNode.removeChild(frame);
}, 0);
/* have tried many other ways to get a nice drag image;
this seems to work best, adding an empty div which forces the size to be larger,
so when grabbing the image it grabs the drop-shadow.
things that _didn't_ work include:
- styling event.target now then unstyling (normally this would work, in posts on the web, but it doesn't here; angular?)
- make a restyled cloned copy offscreen (this comes so close but remote img srcs aren't loaded
*/
paletteDragAndDropService.dragStart(item);
};
$scope.onDragEnd = function (item, event) {
paletteDragAndDropService.dragEnd();
tryMarkUsed(item);
};
$scope.getOpenCatalogLink = (item) => {
return "/brooklyn-ui-catalog/#!/bundles/"+item.containingBundle.replace(":","/")+"/types/"+item.symbolicName+"/"+item.version;
};
$scope.sortBy = function (order) {
let newFirst = {};
if (order) {
newFirst[order.id] = order;
}
$scope.state.currentOrder = Object.assign(newFirst, $scope.state.currentOrder, newFirst);
$scope.state.currentOrderFields = [];
$scope.state.currentOrderValues = [];
Object.values($scope.state.currentOrder).forEach( it => {
$scope.state.currentOrderValues.push(it);
$scope.state.currentOrderFields.push(it.field);
});
};
if (!$scope.state.currentOrder) $scope.state.currentOrder = Object.assign({}, PALETTE_VIEW_ORDERS);
$scope.sortBy();
$scope.allowFreeForm = function () {
return [
EntityFamily.LOCATION
].indexOf($scope.family) > -1;
};
$scope.isReserved = function () {
if (!$scope.reservedKeys || !angular.isArray($scope.reservedKeys)) {
return false;
}
return $scope.reservedKeys.indexOf($scope.search) > -1;
};
$scope.onImageError = (scope, el, attrs) => {
$log.warn("Icon for "+attrs.itemId+" at "+angular.element(el).attr("src")+" could not be loaded; generating icon");
angular.element(el).attr("src", iconGenerator(attrs.itemId));
};
// Init
$scope.items = [];
function getDisplayTags(tags) {
if (!Array.isArray(tags) || !tags.length) return tags;
return tags.filter(tag => !(/[=:\[\]()]/.exec(tag)));
}
$scope.getItems().then((items)=> {
// add displayTags, as any tag that doesn't contain = : or ( ) [ ]
// any tag that is an object will be eliminated as it is toStringed to make [ object object ]
// add display name=symbolicName for those that don't have one, to avoid issues with the 'Name' property sorting
items.forEach(item => {
if (item.tags) {
item.displayTags = getDisplayTags(item.tags);
}
if(!item.displayName) {
item.displayName = item.symbolicName;
}
});
$scope.items = items;
});
$scope.lastUsedText = (item) => {
if (item==null) return "";
let l = (Number)(item.lastUsed);
if (!l || isNaN(l) || l<=0) return "";
if (l < 100000) return 'Preselected for inclusion in "Recent" filter.';
return 'Last used: ' + distanceInWordsToNow(l, { includeSeconds: true, addSuffix: true });
};
$scope.showPaletteControls = false;
$scope.onFiltersShown = () => {
$timeout( () => {
// check do we need to show the multiline
let filters = angular.element($element[0].querySelector(".filters"));
$scope.$apply( () => $scope.filterSettings.filtersMultilineAvailable = filters[0].scrollHeight > filters[0].offsetHeight + 6 );
repaginate($scope, $element);
} );
};
$scope.togglePaletteControls = () => {
$scope.showPaletteControls = !$scope.showPaletteControls;
$timeout( () => repaginate($scope, $element) );
};
$scope.toggleShowAllFilters = () => {
$scope.filterSettings.showAllFilters = !$scope.filterSettings.showAllFilters;
$timeout( () => repaginate($scope, $element) );
};
$scope.filterSettings = {};
$scope.filters = [
{ label: 'Recent', icon: 'clock-o', title: "Recently used and standard favorites", limitToOnePage: true,
filterInit: items => {
$scope.recentItems = items.filter( i => i.lastUsed && i.lastUsed>0 );
$scope.recentItems.sort( (a,b) => b.lastUsed - a.lastUsed );
return $scope.recentItems;
}, enabled: false },
];
$scope.disableFilters = (showFilters) => {
$scope.filters.forEach( f => f.enabled = false );
if (showFilters !== false) {
$scope.showPaletteControls = true;
}
};
// can be overridden to disable "open in catalog" button
$scope.allowOpenInCatalog = true;
// this can be overridden for palette sections/modes which show a subset of the types returned by the server;
// this is applied when the data is received from the server.
// it is used by catalogSelectorFiltersFilter;
$scope.filterPaletteItemsForMode = (items) => items;
// allow downstream to configure this controller and/or scope
(composerOverrides.configurePaletteController || function() {})(this, $scope, $element);
}