Skip to content

Commit

Permalink
feat: add search dropdown
Browse files Browse the repository at this point in the history
  • Loading branch information
volishevko committed Sep 10, 2024
1 parent 6c15023 commit c4f8908
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 6 deletions.
21 changes: 21 additions & 0 deletions sources/models/facets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const facets = {};

function getFacets() {
return facets;
}

function addFacet(id, values) {
facets[id] = values;
}

function getFacetOptions(facet) {
return facet.options;
}

const facetsModel = {
getFacets,
addFacet,
getFacetOptions,
};

export default facetsModel;
3 changes: 2 additions & 1 deletion sources/models/state.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ const state = {
filteredImages: {
isImagesFiltered: false,
filteredImagesCount: 0
}
},
imagesTotalCounts: {},
};

export default state;
60 changes: 58 additions & 2 deletions sources/services/gallery/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import WZoom from "vanilla-js-wheel-zoom";
import constants from "../../constants";
import appliedFilterModel from "../../models/appliedFilters";
import collectionsModel from "../../models/collectionsModel";
import facetsModel from "../../models/facets";
import galleryImagesUrls from "../../models/galleryImagesUrls";
import filtersData from "../../models/imagesFilters";
import lesionsModel from "../../models/lesionsModel";
Expand All @@ -17,6 +18,7 @@ import ajax from "../ajaxActions";
import authService from "../auth";
import filterService from "./filter";
import searchButtonModel from "./searchButtonModel";
import suggestService from "./suggest";

const layoutHeightAfterHide = 1;
const layoutHeightAfterShow = 32;
Expand Down Expand Up @@ -58,7 +60,8 @@ class GalleryService {
imageWindowTemplateWithoutControls,
enlargeContextMenu,
portraitClearAllFiltersTemplate,
landscapeClearAllFiltersTemplate
landscapeClearAllFiltersTemplate,
searchSuggest,
) {
this._view = view;
this._pager = pager;
Expand Down Expand Up @@ -91,6 +94,7 @@ class GalleryService {
this._enlargeContextMenu = enlargeContextMenu;
this._portraitClearAllFiltersTemplate = portraitClearAllFiltersTemplate;
this._landscapeClearAllFiltersTemplate = landscapeClearAllFiltersTemplate;
this._searchSuggest = searchSuggest;
this._init();
}

Expand Down Expand Up @@ -313,10 +317,55 @@ class GalleryService {
}
});

this._searchInput.attachEvent("onAfterRender", () => {
// Suggest start
const suggestList = this._searchSuggest.getList();

this._searchSuggest.attachEvent("onBeforeShow", () => {
const searchValue = this._searchInput.getValue();
if (searchValue.length < 3) {
this._searchSuggest.hide();
return false;
}
return true;
});


suggestList.detachEvent("onItemClick");

suggestList.attachEvent("onItemClick", (id, event) => {
const item = suggestList.getItem(id);
if (event.ctrlKey) {
const controlId = item.key === constants.COLLECTION_KEY
? util.getOptionId(item.key, item.optionId)
: util.getOptionId(item.key, item.value);
/** @type {webix.ui.checkbox} */
const control = $$(controlId);
const controlValue = control.getValue();
control.setValue(!controlValue);
}
});

this._searchSuggest.attachEvent("onShow", () => {
const filters = appliedFilterModel.getFiltersArray();
const suggestData = suggestList.serialize();
const selectedItems = [];
filters.forEach((f) => {
const found = suggestData.find((item) => {
if (f.id === item.id) {
return true;
}
return false;
});
if (found) {
selectedItems.push(f.id);
}
});
suggestList.blockEvent();
suggestList.select(selectedItems);
suggestList.unblockEvent();
});
// Suggest end

let dataviewSelectionId = util.getDataviewSelectionId()
? util.getDataviewSelectionId() : constants.DEFAULT_DATAVIEW_COLUMNS;
this._dataviewYCountSelection?.blockEvent();
Expand Down Expand Up @@ -1109,7 +1158,14 @@ class GalleryService {
doc_count: facets[id]?.meta?.missing_count
});
}
const facetValues = state.imagesTotalCounts[id].map(
f => f.key
);
facetsModel.addFacet(id, facetValues);
});
await suggestService.buildSuggestionsForFilter(this._searchSuggest);
const suggestions = suggestService.getSuggestionsForFilter();
this._searchSuggest.getList().parse(suggestions);
let appliedFiltersArray = appliedFilterModel.getFiltersArray();
const paramFilters = this._view.$scope.getParam("filter");
if (appliedFiltersArray.length) {
Expand Down
51 changes: 51 additions & 0 deletions sources/services/gallery/suggest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import constants from "../../constants";
import collectionsModel from "../../models/collectionsModel";
import facetsModel from "../../models/facets";
import imagesFilters from "../../models/imagesFilters";

const filterSuggestions = [];

function getSuggestionsForFilter() {
return filterSuggestions;
}

async function buildSuggestionsForFilter() {
const facets = facetsModel.getFacets();
const facetsKeys = Object.keys(facets);
const collections = collectionsModel.getAllCollections();
const newSuggestions = [];
const filtersData = await imagesFilters.getFiltersData();
const filterArray = [];
filterArray.push(...filtersData.map(f => f.data).flat(Infinity));
facetsKeys.forEach((key) => {
const values = facets[key].map((v) => {
if (key === constants.COLLECTION_KEY) {
const item = collections.find(c => c.id === v);
return {
id: `${key}|${v}`,
key,
value: item.name,
optionId: v,
isCollection: true,
};
}
return {
id: `${key}|${v}`,
key,
value: v,
};
}).flat();
newSuggestions.push(...values);
});
if (newSuggestions.length > 0) {
filterSuggestions.length = 0;
filterSuggestions.push(...newSuggestions);
}
}

const suggestService = {
buildSuggestionsForFilter,
getSuggestionsForFilter,
};

export default suggestService;
4 changes: 3 additions & 1 deletion sources/views/subviews/gallery/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ export default class GalleryView extends JetView {
const imageWindowZoomButtons = $$(imageWindow.getZoomButtonTemplateId());
const imageWindowTemplate = $$(imageWindow.getViewerId());
const imageWindowTemplateWithoutControls = $$(imageWindow.getViewerWithoutControlsId());
const searchSuggest = $$(filterPanel.getSearchSuggestID());
this._galleryService = new GalleryService(
view,
$$(ID_PAGER),
Expand Down Expand Up @@ -382,7 +383,8 @@ export default class GalleryView extends JetView {
imageWindowTemplateWithoutControls,
this.enlargeContextMenu,
null, // portraitClearAllFiltersTemplate
null // landscapeClearAllFiltersTemplate
null, // landscapeClearAllFiltersTemplate
searchSuggest,
);

// multi lesion
Expand Down
3 changes: 2 additions & 1 deletion sources/views/subviews/gallery/galleryMobile.js
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,8 @@ export default class GalleryMobileView extends JetView {
this.imageWindowTemplate,
this.enlargeContextMenu,
portraitClearAllFiltersTemplate,
landscapeClearAllFiltersTemplate
landscapeClearAllFiltersTemplate,
null, // searchSuggest
);

this.heaaderService = new MobileHeaderService(
Expand Down
18 changes: 17 additions & 1 deletion sources/views/subviews/gallery/parts/filterPanel.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import appliedFiltersModel from "../../../../models/appliedFilters";
import searchButtonModel from "../../../../services/gallery/searchButtonModel";
import appliedFiltersList from "./appliedFiltersList";
import searchSuggest from "./searchSuggest";

const ID_SEARCH_FIELD = `search-field-id-${webix.uid()}`;
const ID_SEARCH_SUGGESTION = `search-suggestion-id-${webix.uid()}`;
const ID_DOWNLOAD_FILTERED_IMAGES_BUTTON = `download-filtered-images-button-id-${webix.uid()}`;
const ID_APPLIED_FILTERS_LIST = `applied-filters-list-id-${webix.uid()}`;
const ID_CLEAR_ALL_FILTERS_TEMPLATE = `clear-all-filters-template-id-${webix.uid()}`;
Expand Down Expand Up @@ -34,6 +36,14 @@ function getConfig(config) {
hidden: true
};

/** @type {webix.ui.suggestConfig} */
const searchSuggestView = searchSuggest.getConfig(ID_SEARCH_SUGGESTION);
searchSuggestView.body.template = obj => `${obj.key}: ${obj.value}`;
searchSuggestView.filter = (obj, value) => {
const result = `${obj.id}: ${obj.value}`.toLowerCase().includes(value.toLowerCase());
return result;
};

const searchField = {
view: "search",
icon: "fas fa-search gallery-search-filter",
Expand All @@ -43,6 +53,7 @@ function getConfig(config) {
css: "gallery-search-block",
placeholder: "Search images",
width: 270,
suggest: searchSuggestView,
on: {
onAfterRender: () => {
const searchInputWidth = $$(ID_SEARCH_FIELD).$width;
Expand Down Expand Up @@ -164,6 +175,10 @@ function getAppliedFiltersListID() {
return ID_APPLIED_FILTERS_LIST;
}

function getSearchSuggestID() {
return ID_SEARCH_SUGGESTION;
}

export default {
getConfig,
getFilterScrollViewName,
Expand All @@ -172,5 +187,6 @@ export default {
getFiltersFormName,
getClearAllFiltersTemplateName,
getDownloadFilteredImagesButtonName,
getAppliedFiltersListID
getAppliedFiltersListID,
getSearchSuggestID,
};
26 changes: 26 additions & 0 deletions sources/views/subviews/gallery/parts/searchSuggest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
function getView() {
/** @type {webix.ui.suggestConfig} */
const view = {
view: "suggest",
width: 70,
yCount: 10,
keyPressTimeout: 500,
body: {
multiselect: true,
},
};

return view;
}

function getConfig(id) {
const config = getView();
config.id = id;
return config;
}

const searchSuggest = {
getConfig,
};

export default searchSuggest;

0 comments on commit c4f8908

Please sign in to comment.