diff --git a/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.html b/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.html
index 11fb29cdbe..ffe0d8c7bd 100644
--- a/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.html
+++ b/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.html
@@ -104,6 +104,7 @@
{{ctrl.metadata.title}}
@@ -112,6 +113,7 @@
{{ctrl.metadata.title}}
@@ -322,6 +324,7 @@
{{ctrl.metadata.byline}}
@@ -370,6 +373,7 @@
{{ctrl.metadata.credit}}
@@ -400,6 +404,7 @@
{{ctrl.metadata[prop]}}
{{ctrl.metadata.copyright}}
@@ -559,6 +565,7 @@
{{ctrl.extraInfo.uploadedBy | stripEmailDomain}}
@@ -639,6 +646,7 @@
{{key | spaceWords}}
{{value}}
@@ -647,6 +655,7 @@
{{key}}
{{metadata.value}}
@@ -832,6 +841,7 @@
ng-repeat="collection in ctrl.singleImage.data.collections"
ng-switch-default>
{{collection.data.path.join(' ▸ ')}}
diff --git a/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.js b/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.js
index 6cf4f31079..fbccf1b0ec 100644
--- a/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.js
+++ b/kahuna/public/js/components/gr-image-metadata/gr-image-metadata.js
@@ -12,6 +12,8 @@ import { editOptions, overwrite } from '../../util/constants/editOptions';
import '../../services/image-accessor';
import '../../services/image-list';
import '../../services/label';
+import '../../search/query-filter';
+
import { List } from 'immutable';
export const module = angular.module('gr.imageMetadata', [
@@ -34,8 +36,7 @@ module.controller('grImageMetadataCtrl', [
'inject$',
'labelService',
'storage',
-
-
+ 'searchWithModifiers',
function ($rootScope,
$scope,
$window,
@@ -47,7 +48,8 @@ module.controller('grImageMetadataCtrl', [
imageAccessor,
inject$,
labelService,
- storage) {
+ storage,
+ searchWithModifiers) {
let ctrl = this;
@@ -58,14 +60,14 @@ module.controller('grImageMetadataCtrl', [
ctrl.metadataUpdatedByTemplate = [];
ctrl.$onInit = () => {
- $scope.$watchCollection('ctrl.selectedImages', function() {
+ $scope.$watchCollection('ctrl.selectedImages', function () {
ctrl.singleImage = singleImage();
ctrl.selectedLabels = selectedLabels();
ctrl.usageRights = selectedUsageRights();
inject$($scope, Rx.Observable.fromPromise(selectedUsageCategory(ctrl.usageRights)), ctrl, 'usageCategory');
ctrl.rawMetadata = rawMetadata();
ctrl.metadata = displayMetadata();
- ctrl.metadata.dateTaken = ctrl.displayDateTakenMetadata();
+ ctrl.metadata.dateTaken = ctrl.displayDateTakenMetadata();
ctrl.newPeopleInImage = "";
ctrl.newKeywords = "";
ctrl.extraInfo = extraInfo();
@@ -76,7 +78,7 @@ module.controller('grImageMetadataCtrl', [
});
const freeUpdateListener = $rootScope.$on('images-updated',
- (e, updatedImages) => updateHandler(updatedImages));
+ (e, updatedImages) => updateHandler(updatedImages));
const updateHandler = (updatedImages) => {
ctrl.selectedImages = new List(updatedImages);
@@ -84,18 +86,20 @@ module.controller('grImageMetadataCtrl', [
ctrl.hasMultipleValues = (val) => Array.isArray(val) && val.length > 1;
- ctrl.displayDateTakenMetadata = function() {
+ ctrl.displayDateTakenMetadata = function () {
let dateTaken = ctrl.metadata.dateTaken ? new Date(ctrl.metadata.dateTaken) : undefined;
- if (dateTaken) { dateTaken.setSeconds(0, 0); }
+ if (dateTaken) {
+ dateTaken.setSeconds(0, 0);
+ }
return dateTaken;
};
- ctrl.credits = function(searchText) {
+ ctrl.credits = function (searchText) {
return ctrl.metadataSearch('credit', searchText);
};
ctrl.metadataSearch = (field, q) => {
- return mediaApi.metadataSearch(field, { q }).then(resource => {
+ return mediaApi.metadataSearch(field, {q}).then(resource => {
return resource.data.map(d => d.key);
});
};
@@ -104,11 +108,11 @@ module.controller('grImageMetadataCtrl', [
ctrl.descriptionOptions = editOptions;
- ctrl.updateDescriptionField = function() {
+ ctrl.updateDescriptionField = function () {
ctrl.updateMetadataField('description', ctrl.metadata.description);
};
- ctrl.updateLocationField = function(data, value) {
+ ctrl.updateLocationField = function (data, value) {
Object.keys(value).forEach(key => {
if (value[key] === undefined) {
delete value[key];
@@ -120,7 +124,7 @@ module.controller('grImageMetadataCtrl', [
ctrl.updateMetadataField = function (field, value) {
var imageArray = Array.from(ctrl.selectedImages);
if (field === 'dateTaken') {
- value = value.toISOString();
+ value = value.toISOString();
}
if (field === 'peopleInImage') {
ctrl.addPersonToImages(imageArray, value);
@@ -138,7 +142,7 @@ module.controller('grImageMetadataCtrl', [
);
};
- ctrl.updateDomainMetadataField = function(name, field, value) {
+ ctrl.updateDomainMetadataField = function (name, field, value) {
return editsService.updateDomainMetadataField(ctrl.singleImage, name, field, value)
.then((updatedImage) => {
if (updatedImage) {
@@ -240,7 +244,7 @@ module.controller('grImageMetadataCtrl', [
.map(([key, value]) => {
let fieldAlias = ctrl.fieldAliases.find(_ => _.alias === key);
if (fieldAlias && fieldAlias.displayInAdditionalMetadata === true) {
- return [fieldAlias.label, { value, alias: fieldAlias.alias}];
+ return [fieldAlias.label, {value, alias: fieldAlias.alias}];
}
})
.filter(_ => _ !== undefined));
@@ -250,7 +254,7 @@ module.controller('grImageMetadataCtrl', [
ctrl.domainMetadata = ctrl.domainMetadataSpecs
.filter(domainMetadataSpec => domainMetadataSpec.fields.length > 0)
.reduce((acc, domainMetadataSpec) => {
- let domainMetadata = { ...domainMetadataSpec };
+ let domainMetadata = {...domainMetadataSpec};
if (ctrl.singleImage.data.metadata) {
const imageDomainMetadata = ctrl.singleImage.data.metadata.domainMetadata ? ctrl.singleImage.data.metadata.domainMetadata : {};
@@ -284,7 +288,7 @@ module.controller('grImageMetadataCtrl', [
field.selectOptions = field.options
.filter(option => option)
.map(option => {
- return { value: option, text: option };
+ return {value: option, text: option};
});
}
@@ -332,7 +336,7 @@ module.controller('grImageMetadataCtrl', [
ctrl.hasLocationInformation = hasLocationInformation;
function singleImage() {
- if (ctrl.selectedImages.size === 1){
+ if (ctrl.selectedImages.size === 1) {
return ctrl.selectedImages.first();
}
}
@@ -371,9 +375,12 @@ module.controller('grImageMetadataCtrl', [
function rawMetadata() {
return selectedMetadata().map((values) => {
switch (values.size) {
- case 0: return undefined;
- case 1: return values.first();
- default: return Array.from(values);
+ case 0:
+ return undefined;
+ case 1:
+ return values.first();
+ default:
+ return Array.from(values);
}
}).toObject();
}
@@ -381,8 +388,10 @@ module.controller('grImageMetadataCtrl', [
function displayMetadata() {
return selectedMetadata().map((values) => {
switch (values.size) {
- case 1: return values.first();
- default: return undefined;
+ case 1:
+ return values.first();
+ default:
+ return undefined;
}
}).toObject();
}
@@ -392,9 +401,12 @@ module.controller('grImageMetadataCtrl', [
const properties = imageList.getSetOfProperties(info);
return properties.map((values) => {
switch (values.size) {
- case 0: return undefined;
- case 1: return values.first();
- default: return Array.from(values);
+ case 0:
+ return undefined;
+ case 1:
+ return values.first();
+ default:
+ return Array.from(values);
}
}).toObject();
}
@@ -421,11 +433,11 @@ module.controller('grImageMetadataCtrl', [
ctrl.removeImageFromCollection = (collection) => {
ctrl.removingCollection = collection;
collections.removeImageFromCollection(collection, ctrl.singleImage)
- .then(() => ctrl.removingCollection = false);
+ .then(() => ctrl.removingCollection = false);
};
- $scope.$on('$destroy', function() {
- freeUpdateListener();
+ $scope.$on('$destroy', function () {
+ freeUpdateListener();
});
ctrl.onMetadataTemplateSelected = (metadata, usageRights, collection, leasesWithConfig) => {
@@ -498,16 +510,18 @@ module.controller('grImageMetadataCtrl', [
};
ctrl.isDomainMetadataEmpty = (key) => {
- return ctrl.domainMetadata.find(obj => obj.name === key ).fields.every(field => field.value === undefined );
+ return ctrl.domainMetadata.find(obj => obj.name === key).fields.every(field => field.value === undefined);
};
ctrl.isAdditionalMetadataEmpty = () => {
const totalAdditionalMetadataCount = Object.keys(ctrl.metadata).filter(key => ctrl.isUsefulMetadata(key)).length +
- Object.keys(ctrl.additionalMetadata).length +
- Object.keys(ctrl.identifiers).length;
+ Object.keys(ctrl.additionalMetadata).length +
+ Object.keys(ctrl.identifiers).length;
return totalAdditionalMetadataCount == 0;
};
+
+ ctrl.searchWithModifiers = searchWithModifiers;
};
}
]);
diff --git a/kahuna/public/js/edits/list-editor-compact.html b/kahuna/public/js/edits/list-editor-compact.html
index 1851bbcdf2..326ae0e8d3 100644
--- a/kahuna/public/js/edits/list-editor-compact.html
+++ b/kahuna/public/js/edits/list-editor-compact.html
@@ -8,6 +8,7 @@
{{element}}
diff --git a/kahuna/public/js/edits/list-editor-info-panel.html b/kahuna/public/js/edits/list-editor-info-panel.html
index 9fcf8c4e1f..81208af2fa 100644
--- a/kahuna/public/js/edits/list-editor-info-panel.html
+++ b/kahuna/public/js/edits/list-editor-info-panel.html
@@ -8,6 +8,7 @@
library_add
diff --git a/kahuna/public/js/edits/list-editor.js b/kahuna/public/js/edits/list-editor.js
index cf86f91f9d..c26f84e547 100644
--- a/kahuna/public/js/edits/list-editor.js
+++ b/kahuna/public/js/edits/list-editor.js
@@ -22,13 +22,15 @@ listEditor.controller('ListEditorCtrl', [
'imageLogic',
'imageList',
'storage',
+ 'searchWithModifiers',
function($rootScope,
$scope,
$window,
$timeout,
imageLogic,
imageList,
- storage) {
+ storage,
+ searchWithModifiers) {
var ctrl = this;
ctrl.$onInit = () => {
@@ -147,6 +149,8 @@ listEditor.controller('ListEditorCtrl', [
$scope.$on('$destroy', function() {
updateListener();
});
+
+ ctrl.searchWithModifiers = searchWithModifiers;
};
}]);
diff --git a/kahuna/public/js/preview/image.html b/kahuna/public/js/preview/image.html
index 02ed16870c..285c010118 100644
--- a/kahuna/public/js/preview/image.html
+++ b/kahuna/public/js/preview/image.html
@@ -79,6 +79,7 @@
gr-tooltip-position="top">
{{::collection.data.description}}
diff --git a/kahuna/public/js/preview/image.js b/kahuna/public/js/preview/image.js
index 7983968c18..7909ff5d14 100644
--- a/kahuna/public/js/preview/image.js
+++ b/kahuna/public/js/preview/image.js
@@ -17,6 +17,7 @@ import '../components/gr-add-label/gr-add-label';
import '../components/gr-archiver-status/gr-archiver-status';
import '../components/gr-syndication-icon/gr-syndication-icon';
import {graphicImageBlurService} from "../services/graphic-image-blur";
+import '../search/query-filter';
export var image = angular.module('kahuna.preview.image', [
'gr.image.service',
@@ -43,6 +44,7 @@ image.controller('uiPreviewImageCtrl', [
'imageAccessor',
'storage',
'graphicImageBlurService',
+ 'searchWithModifiers',
function (
$scope,
inject$,
@@ -53,7 +55,8 @@ image.controller('uiPreviewImageCtrl', [
labelService,
imageAccessor,
storage,
- graphicImageBlurService) {
+ graphicImageBlurService,
+ searchWithModifiers) {
var ctrl = this;
ctrl.$onInit = () => {
@@ -131,6 +134,8 @@ image.controller('uiPreviewImageCtrl', [
return $window._clientConfig.imagePreviewFlagAlertCopy;
}
};
+
+ ctrl.searchWithModifiers = searchWithModifiers;
};
}]);
diff --git a/kahuna/public/js/search/query-filter.js b/kahuna/public/js/search/query-filter.js
index aeafcb017b..04de18c597 100644
--- a/kahuna/public/js/search/query-filter.js
+++ b/kahuna/public/js/search/query-filter.js
@@ -21,6 +21,37 @@ export function fieldFilter(field, value) {
return `${field}:${valueMaybeQuoted}`;
}
+queryFilters.factory('searchWithModifiers',
+ ['$state', '$stateParams', 'storage',
+ function($state, $stateParams, storage) {
+ function updateQueryWithModifiers(field, fieldValue, alt, shift, prevQuery) {
+ if (alt && prevQuery) {
+ return `${prevQuery} -${fieldFilter(field, fieldValue)}`;
+ }
+ if (alt) {
+ return `-${fieldFilter(field, fieldValue)}`;
+ }
+ if (shift && prevQuery) {
+ return `${prevQuery} ${fieldFilter(field, fieldValue)}`;
+ }
+ return fieldFilter(field, fieldValue);
+ }
+
+ return ($event, fieldName, fieldValue) => {
+ const alt = $event.getModifierState('Alt');
+ const shift = $event.getModifierState('Shift');
+ if (alt || shift) {
+ $event.preventDefault();
+ const nonFree = storage.getJs("isNonFree", true) ? true : undefined;
+
+ return $state.go('search.results', {
+ query: updateQueryWithModifiers(fieldName, fieldValue, alt, shift, $stateParams.query),
+ nonFree: nonFree
+ });
+ }
+ };
+ }]);
+
queryFilters.filter('queryFilter', function() {
return (value, field) => fieldFilter(field, value);
});
diff --git a/media-api/app/lib/querysyntax/QuerySyntax.scala b/media-api/app/lib/querysyntax/QuerySyntax.scala
index 1f5abd2930..2770e5e9ba 100644
--- a/media-api/app/lib/querysyntax/QuerySyntax.scala
+++ b/media-api/app/lib/querysyntax/QuerySyntax.scala
@@ -34,7 +34,8 @@ class QuerySyntax(val input: ParserInput) extends Parser with ImageFields {
DateConstraintMatch |
DateRangeMatch ~> Match | AtMatch |
FileTypeMatch ~> Match |
- ScopedMatch ~> Match | HashMatch | CollectionRule |
+ CollectionRule |
+ ScopedMatch ~> Match | HashMatch |
AnyMatch
}
@@ -83,7 +84,7 @@ class QuerySyntax(val input: ParserInput) extends Parser with ImageFields {
)
)}
- def CollectionRule = rule { '~' ~ ExactMatchValue ~> (
+ def CollectionRule = rule { ("~" | "collection:") ~ ExactMatchValue ~> (
collection => Match(
HierarchyField,
Phrase(collection.string.toLowerCase)
@@ -120,7 +121,6 @@ class QuerySyntax(val input: ParserInput) extends Parser with ImageFields {
"supplier" |
"specialInstructions" |
"title" |
- "collection" |
"keyword" |
"label" |
"croppedBy" |
@@ -134,7 +134,6 @@ class QuerySyntax(val input: ParserInput) extends Parser with ImageFields {
case "illustrator" => "credit"
case "uploader" => "uploadedBy"
case "label" => "labels"
- case "collection" => "suppliersCollection"
case "subject" => "subjects"
case "location" => "subLocation"
case "by" | "photographer" => "byline"