Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add recent places to search dropdown #902

Merged
merged 4 commits into from
Nov 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions OZprivate/rawJS/OZTreeModule/src/OZui.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import search_manager from './ui/search_manager';
import { searchPopulate, setup_location_list } from './ui/search.js';
import { searchPopulate, setup_location_list, setup_recents_list, add_element_to_recents_list, push_recent_place } from './ui/search.js';
import { fullLeafBase, fullLeaf, natural_theme } from './ui/leaf_draw.js';
import { sortList, teaseTour } from './ui/tours_list.js';

export { search_manager, searchPopulate, setup_location_list };
export { search_manager, searchPopulate, setup_location_list, setup_recents_list, add_element_to_recents_list, push_recent_place };

export const leaf_draw = {
fullLeafBase: fullLeafBase,
Expand Down
22 changes: 20 additions & 2 deletions OZprivate/rawJS/OZTreeModule/src/button_manager.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,32 @@
import config from './global_config';
import tree_state from './tree_state';
import {color_theme} from './themes/color_theme';
import {node_to_pinpoint} from './navigation/pinpoint';


export let global_button_action = {
"action": null,
"data": null
"data": null,
"node": null
}

function try_make_search_result_for_node(node) {
const pinpoint = node_to_pinpoint(node);
if (pinpoint && (node.cname || node.latin_name)) {
return {
vernacular: node.cname,
sciname: node.latin_name,
pinpoint: pinpoint,
href: "/life/" + pinpoint,
};
}
return null;
}

export function reset_global_button_action() {
global_button_action.action = null;
global_button_action.data = null;
global_button_action.node = null;
}

export function click_on_button_cb(controller) {
Expand Down Expand Up @@ -54,13 +71,14 @@ export function click_on_button_cb(controller) {
// callback_arg is either middle part of ow_iucn_leaf / ow_ozspons_leaf, or nothing
const linkoutArg = m ? m[1] : undefined;
const is_ozid = global_button_action.action.endsWith("_node");
const search_result = global_button_action.node ? try_make_search_result_for_node(global_button_action.node) : null;

// most internal nodes don't have an OTT, so node actions pass in the OneZoom ID
config.ui.openLinkouts(global_button_action.data, is_ozid ? 'OZid' : 'ott');
$.ajax({
'url': (is_ozid ? config.api.OZ_node_json_url_func : config.api.OZ_leaf_json_url_func)(global_button_action.data, config.lang),
success: (result) => {
config.ui.populateLinkouts(result, linkoutArg);
config.ui.populateLinkouts(result, linkoutArg, search_result);
},
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {global_button_action} from '../button_manager';
* register_button_event: function(node) {
* global_button_action.action = "xxxx"
* global_button_action.data = XXXXX
* global_button_action.node = node
* }
* }
*
Expand All @@ -24,20 +25,23 @@ live_area_config.interior_low_res_circle = {
register_button_event: function(node) {
global_button_action.action = "fly_node";
global_button_action.data = node.metacode;
global_button_action.node = node;
}
}

live_area_config.interior_high_res_text = {
register_button_event: function(node) {
global_button_action.action = "ow_node";
global_button_action.data = node.metacode;
global_button_action.node = node;
}
}

live_area_config.interior_sponsor_text = {
register_button_event: function(node) {
global_button_action.action = "ow_ozspons_node";
global_button_action.data = node.metacode;
global_button_action.node = node;
}
}

Expand All @@ -52,34 +56,39 @@ live_area_config.signpost = {
register_button_event: function(node) {
global_button_action.action = "tap2zoom";
global_button_action.data = node.ozid;
global_button_action.node = node;
}
}

live_area_config.leaf_low_res_leafbase = {
register_button_event: function(node) {
global_button_action.action = "tap2zoom";
global_button_action.data = node.ozid;
global_button_action.node = node;
}
}

live_area_config.leaf_sponsor_text = {
register_button_event: function(node) {
global_button_action.action = "ow_ozspons_leaf";
global_button_action.data = node.ott;
global_button_action.node = node;
}
}

live_area_config.leaf_high_res_text = {
register_button_event: function(node) {
global_button_action.action = "ow_leaf";
global_button_action.data = node.ott;
global_button_action.node = node;
}
}

live_area_config.leaf_conservation_text = {
register_button_event: function(node) {
global_button_action.action = "ow_iucn_leaf";
global_button_action.data = node.ott;
global_button_action.node = node;
}
}

Expand Down
178 changes: 161 additions & 17 deletions OZprivate/rawJS/OZTreeModule/src/ui/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ function searchPopulate(searchbox, original_search, search_result) {
var dropdown = $(".search_dropdown", searchbox);
if (window.is_testing) { console.log("Hiding popular species section of dropdown"); }
$('.popular_species', dropdown).hide();
$('.recents', dropdown).hide();
$('.search_hits', dropdown).empty();
if (search_result.tree.length + search_result.tour.length == 0) {
$('.no_results', dropdown).show();
Expand Down Expand Up @@ -131,26 +132,169 @@ function setup_location_list(target, locations_json) {
if (typeof taxon === "string") {
return $('<dt>').text(OZstrings.hasOwnProperty(taxon) ? OZstrings[taxon] : taxon);
}
return $('<dd>')
// Attach compile_searchbox_data()-esque results to reconstitute on advanced_search_box click
.attr("data-vernacular", taxon.vernacular)
.attr("data-sciname", taxon.sciname)
.attr("data-pinpoint", '@=' + taxon.ott)
.html($('<p>').html($('<a>')
.attr('href', taxon.href)
.attr("draggable","true")
.on('dragstart', function(event) {
return create_location_dd_element(taxon.vernacular, taxon.sciname, '@=' + taxon.ott, taxon.href, taxon.ozid, false);
}));
});
}

function create_location_dd_element(vernacular, sciname, pinpoint, href, ozid, allow_multiple_names) {
const link = $('<a>')
.attr('href', href)
.attr("draggable", "true")
.on('dragstart', function(event) {
// Recreate a compile_searchbox_data() format
event.originalEvent.dataTransfer.setData('result', JSON.stringify({
0: taxon.vernacular,
1: taxon.sciname,
2: taxon.ozid,
"pinpoint": '@=' + taxon.ott,
0: vernacular,
1: sciname,
2: ozid,
"pinpoint": pinpoint,
}));
})
.html(taxon.vernacular ? $('<span>').text(taxon.vernacular) : $('<i>').text(taxon.sciname) )));
});

const dd = $('<dd>')
.attr("data-vernacular", vernacular)
.attr("data-sciname", sciname)
.attr("data-pinpoint", pinpoint);

if (vernacular && sciname && allow_multiple_names) {
dd.append($('<p>').append(link.clone().text(vernacular)))
.append('(')
.append($('<i>').append(link.clone().text(sciname)))
.append(')');
} else if (vernacular) {
dd.append($('<p>').append(link.text(vernacular)));
} else if (sciname) {
dd.append($('<p>').append(link.html($('<i>').text(sciname))));
}

return dd;
}




const MAX_RECENT_PLACES = 8;

/**
* @typedef {Object} SearchResult
* @property {string|undefined} vernacular
* @property {string|undefined} sciname
* @property {string} pinpoint
* @property {string} href
*/

/**
* @returns {SearchResult|null}
*/
function get_search_result_from_element(element) {
if ($(element).attr('data-pinpoint')) {
return {
// Recreate a compile_searchbox_data() format
"vernacular": $(element).attr('data-vernacular'),
"sciname": $(element).attr('data-sciname'),
"pinpoint": $(element).attr('data-pinpoint'),
"href": $(element).find('a').attr('href'),
};
}
return null;
}

/**
* Recently used places from the search menu.
* @type {SearchResult[]}
* */
let recent_places = (() => {
try {
const stored = JSON.parse(localStorage.getItem('recent_places') || '[]');
if (!Array.isArray(stored)) return [];

const valid = stored.every(item =>
item &&
typeof item === 'object' &&
typeof item.pinpoint === 'string' &&
typeof item.href === 'string' &&
(item.vernacular == undefined || typeof item.vernacular === 'string') &&
(item.sciname == undefined || typeof item.sciname === 'string')
);

return valid ? stored : [];
} catch {
return [];
}
})();

/**
* Push a recent place to the front of the list, removing duplicates and limiting the size.
* @param {SearchResult} recent_search_result
* */
function push_recent_place(recent_search_result) {
recent_places = recent_places.filter(function (place) {
return place.pinpoint !== recent_search_result.pinpoint;
});
const newLength = recent_places.unshift(recent_search_result);
if (newLength > MAX_RECENT_PLACES) {
recent_places.pop();
}
localStorage.setItem('recent_places', JSON.stringify(recent_places));
}

/**
* Push a recent search result to the front of the list using its containing dd element.
* */
function add_element_to_recents_list(element) {
const search_result = get_search_result_from_element(element);
if (search_result) {
push_recent_place(search_result);
}
}

function make_clear_recents_button() {
return $('<button>')
.addClass('uk-button uk-button-default uk-button-small')
.text(OZstrings.hasOwnProperty("Clear recents") ? OZstrings["Clear recents"] : "Clear recents")
.on('click', clear_recents);
}

function clear_recents() {
recent_places = [];
localStorage.setItem('recent_places', '[]');
$('.uk-dropdown.uk-open .recents').each(function() {
update_recents_list($(this));
});
}

function update_recents_list($target) {
$target.empty()

if (recent_places.length === 0) {
return;
}

const dl = $('<dl>');
$target.append(dl);
dl.append($('<dt>').text(OZstrings.hasOwnProperty("Recent places") ? OZstrings["Recent places"] : "Recent places"));
dl.append(recent_places.map(function (recent_place) {
return create_location_dd_element(recent_place.vernacular, recent_place.sciname, recent_place.pinpoint, recent_place.href, undefined, true);
}));
});
$target.append(make_clear_recents_button());
};

function setup_recents_list($target) {
const elements = $target.get();
if (elements.length !== 1) {
console.error("setup_recents_list: target must have exactly one element");
return;
}
const $element = $(elements[0]);
const dropdownElement = $element.closest('.search_dropdown')[0];
if (dropdownElement) {
$(document).on('beforeshow', function(event) {
if (event.target === dropdownElement) {
update_recents_list($element);
}
});
}
update_recents_list($element);
}

export { searchPopulate, setup_location_list };
export { searchPopulate, setup_location_list, setup_recents_list, push_recent_place, get_search_result_from_element, add_element_to_recents_list };
8 changes: 8 additions & 0 deletions OZprivate/scss/search_ui.scss
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,14 @@ ul#searchboxes {
}
}

.search_dropdown div:not(:empty) {
margin-bottom: 1rem;
}

.search-nav .search_dropdown dd:last-child {
margin-bottom: 1rem;
}

.search-nav .search_dropdown dd:hover, .search-nav .search_dropdown dd p:hover {
color: black;
}
Expand Down
2 changes: 2 additions & 0 deletions languages/en-us.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,8 @@
'Polytomy': 'Polytomy',
'Polytomy2': 'Polytomy2',
'Popular places': 'Popular places',
'Recent places': 'Recent places',
'Clear recents': 'Clear recents',
'Popularity': 'Popularity',
'Popularity index': 'Popularity index',
'Pre Siderian': 'Pre Siderian',
Expand Down
4 changes: 3 additions & 1 deletion languages/fr.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,9 @@
'Plugins': 'Plugins',
'Polytomy': 'Polytomie',
'Polytomy2': '',
'Popular places': 'Régions populaires',
'Popular places': 'Lieux populaires',
'Recent places': 'Lieux récents',
'Clear recents': 'Effacer les récents',
'Popularity': 'Popularité',
'Powered by': 'Alimenté par',
'Preface': 'Préface',
Expand Down
2 changes: 2 additions & 0 deletions languages/sv.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@
'Polytomy': 'Polytomi',
'Polytomy2': 'Polytomy2',
'Popular places': 'Populära platser',
'Recent places': 'Senaste platser',
'Clear recents': 'Rensa senaste',
'Popularity': 'Popularitet',
'Pre Siderian': 'Presiderium',
'Preview of your sponsored leaf': 'Förhandsgranskning av ditt sponsrade blad',
Expand Down
4 changes: 3 additions & 1 deletion languages/zh-cn.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,9 @@
'Please select a species in the second search box': 'Please select a species in the second search box',
'Plugins': 'Plugins',
'Polytomy': 'Polytomy',
'Popular places': 'Popular places',
'Popular places': '热门位置',
'Recent places': '最近位置',
'Clear recents': '清除最近记录',
'Popularity': 'Popularity',
'Powered by': '基于下列技术构建:',
'Preface': 'Preface',
Expand Down
1 change: 1 addition & 0 deletions views/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@
var dropdown = $('.search_dropdown', searchbox);
if (search_term.length==0) {
$('.popular_species', dropdown).show();
$('.recents', dropdown).show();
{{if is_testing:}}console.log("Hiding no_result section of dropdown");{{pass}}
$('.no_results', dropdown).hide();
$('.search_hits', dropdown).empty();
Expand Down
Loading