kahuna/public/js/search/structured-query/query-suggestions.js (197 lines of code) (raw):
import angular from 'angular';
import {List, Map} from 'immutable';
import {mediaApi} from '../../services/api/media-api';
export const querySuggestions = angular.module('querySuggestions', [
mediaApi.name
]);
const fieldAliases = window._clientConfig.fieldAliases
.filter(fieldAlias => fieldAlias.displaySearchHint === true)
.reduce(function(map, fieldAlias) {
map[fieldAlias.alias] = fieldAlias;
return map;
}, {});
// FIXME: get fields and subjects from API
export const filterFields = [
'by',
'category',
'city',
'copyright',
'country',
'credit',
'description',
'fileType',
'illustrator',
'in',
'keyword',
'label',
'location',
'person',
'source',
'specialInstructions',
'state',
'subject',
'supplier',
'suppliersReference',
'title',
'uploader',
'usages@<added',
'usages@>added',
'usages@platform',
'usages@status',
'usages@reference',
'has',
'croppedBy',
'filename',
'photoshoot',
'leasedBy',
'is',
... Object.keys(fieldAliases)
].sort();
// TODO: add date fields
const subjects = [
'arts',
'crime',
'disaster',
'finance',
'education',
'environment',
'health',
'human',
'labour',
'lifestyle',
'nature',
'news',
'politics',
'religion',
'science',
'social',
'sport',
'war',
'weather'
];
const fileTypes = [
'jpeg',
'tiff',
'png'
];
const staffPhotographerOrganisation = window._clientConfig.staffPhotographerOrganisation;
const isSearch = [
`${staffPhotographerOrganisation}-owned-photo`,
`${staffPhotographerOrganisation}-owned-illustration`,
`${staffPhotographerOrganisation}-owned`,
'under-quota',
'deleted'
];
if (window._clientConfig.useReaper === true) {
isSearch.push('reapable');
}
querySuggestions.factory('querySuggestions', ['mediaApi', 'editsApi', function(mediaApi, editsApi) {
function prefixFilter(prefix) {
const lowerPrefix = prefix.toLowerCase();
return (values) => values.filter(val => val.toLowerCase().startsWith(lowerPrefix));
}
function listSuppliers() {
return editsApi.getUsageRightsCategories().
then(results => {
return new List(results).
filter(res => res.value === 'agency').
flatMap(res => res.properties).
filter(prop => prop.name === 'supplier').
flatMap(prop => prop.options).
toJS();
});
}
function listCategories() {
// TODO: would be nice to use user friendly labels and map
// them to the key internally
return editsApi.getUsageRightsCategories().
then(results => {
return results.
map(res => res.value).
filter(key => key !== ''); // no empty category
});
}
const photographerCategories = List.of(
'staff-photographer',
'contract-photographer'
);
function listPhotographers() {
return editsApi.getUsageRightsCategories().
then(results => {
return new List(results).
filter(res => photographerCategories.includes(res.value)).
flatMap(res => res.properties).
filter(prop => prop.name === 'photographer').
flatMap(prop => new Map(prop.optionsMap).valueSeq()).
flatMap(list => list).
sort().
toJS();
});
}
function listIllustrators() {
return editsApi.getUsageRightsCategories().
then(results => {
return new List(results).
filter(res => res.value === 'contract-illustrator').
flatMap(res => res.properties).
filter(prop => prop.name === 'creator').
flatMap(prop => prop.options).
toJS();
});
}
function suggestCredit(prefix) {
return mediaApi.metadataSearch('credit', {q: prefix}).
then(results => results.data.map(res => res.key));
}
function suggestSource(prefix) {
return mediaApi.metadataSearch('source', {q: prefix}).
then(results => results.data.map(res => res.key));
}
function suggestLabels(prefix) {
return mediaApi.labelsSuggest({q: prefix}).
then(labels => labels.data);
}
function suggestPhotoshoot(prefix) {
return mediaApi.metadataSearch('photoshoot', {q: prefix}).
then(results => results.data.map(res => res.key));
}
function listUsagePlatforms() {
let suggestions = ['print', 'digital'];
if (window._clientConfig.recordDownloadAsUsage === true) {
suggestions.push('download');
}
if (window._clientConfig.showSendToPhotoSales) {
suggestions.push('Added to Photo Sales');
}
return suggestions;
}
function suggestFieldAliasOptions(fieldAlias) {
return fieldAliases[fieldAlias].searchHintOptions;
}
function getFilterSuggestions(field, value) {
switch (field) {
case 'usages@status': return ['published', 'pending', 'removed'];
case 'usages@platform': return listUsagePlatforms();
case 'subject': return prefixFilter(value)(subjects);
case 'fileType': return prefixFilter(value)(fileTypes);
case 'label': return suggestLabels(value);
case 'credit': return suggestCredit(value);
case 'source': return suggestSource(value);
case 'supplier': return listSuppliers().then(prefixFilter(value));
// TODO: list all known bylines, not just our photographers
case 'by': return listPhotographers().then(prefixFilter(value));
case 'illustrator': return listIllustrators().then(prefixFilter(value));
case 'category': return listCategories().then(prefixFilter(value));
case 'photoshoot': return suggestPhotoshoot(value);
case 'is': return isSearch;
// No suggestions
default: return fieldAliases.hasOwnProperty(field) ? prefixFilter(value)(suggestFieldAliasOptions(field)) : [];
}
}
function getChipSuggestions(chip) {
if (chip.type === 'filter-chooser') {
return filterFields.filter(f => f.startsWith(chip.value));
} else if (chip.type === 'filter') {
return getFilterSuggestions(chip.key, chip.value);
} else {
return [];
}
}
return {
getChipSuggestions
};
}]);