Skip to content

Move global search to a single search input. Display results in a grid within accordions. (CFM-220) #63

Merged
merged 1 commit into from
Dec 13, 2022
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
9 changes: 9 additions & 0 deletions app/resources/locales/en_US/field.po
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,15 @@ msgstr "Required"
msgid "room"
msgstr "Room"

msgid "search.global"
msgstr "Global search"

msgid "search.global.submit"
msgstr "Submit global search"

msgid "search.global.clear"
msgstr "Clear global search"

msgid "search.placeholder"
msgstr "Search..."

Expand Down
174 changes: 67 additions & 107 deletions app/templates/Dashboards/search.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,65 +40,10 @@

<div class="pageTitleContainer">
<div class="pageTitle">
<h1><?= __d('operation','search.global'); ?></h1>
<h1><?= $vv_title; ?></h1>
</div>
</div>

<div id="search-container" aria-labelledby="global-search-toggle">
<?php
print $this->Form->create(null, $options);
print $this->Form->hidden('co_id', ['default' => $vv_cur_co->id]);
?>
<div class="input-group">
<?php
print $this->Form->label(
'q',
__d('operation','search'),
[
'class' => 'visually-hidden'
]
);
print $this->Form->input(
'q',
[
'id' => 'q',
'class' => 'form-control',
'placeholder' => __d('field','search.placeholder')
]
);
print $this->Form->button(
'<span class="material-icons-outlined">close</span>',
['type' => 'button', 'escapeTitle' => false, 'id' => 'search-clear', 'class' => 'btn btn-link']
);
print $this->Form->button(
__d('operation','search'),
['type' => 'submit', 'escapeTitle' => false, 'class' => 'btn btn-primary btn-sm']
);
?>
</div>
<?php
print $this->Form->end();
?>

<?php /* keep the following temporarily:
<div id="global-search-type">
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="gs-type-basic" name="gs-type">
<label class="form-check-label" for="gs-type-basic">
basic
</label>
</div>
<div class="form-check form-check-inline">
<input class="form-check-input" type="radio" id="gs-type-advanced" name="gs-type">
<label class="form-check-label" for="gs-type-advanced">
advanced
</label>
</div>
</div> */ ?>
</div>

<h2><?= $vv_title; ?></h2>

<!-- Flash Messages and defined Info Banners -->
<div class="alert-container" id="flash-messages">
<?= $this->Flash->render() ?>
Expand Down Expand Up @@ -126,69 +71,84 @@
<li class="search-results-found"><?= __d('result', 'search.result.found') ?></li>
<?php if($peopleResultsCount): ?>
<li>
<?= __d('result','search.result.found.modelCount', [$peopleResultsCount, __d('controller', "People", [$peopleResultsCount])]); ?>
<a href="#search-results-people" class="nospin">
<?= __d('result','search.result.found.modelCount', [$peopleResultsCount, __d('controller', "People", [$peopleResultsCount])]); ?>
</a>
</li>
<?php endif; ?>
<?php if($groupsResultsCount): ?>
<li>
<?= __d('result','search.result.found.modelCount', [$groupsResultsCount, __d('controller', "Groups", [$groupsResultsCount])]); ?>
<a href="#search-results-groups" class="nospin">
<?= __d('result','search.result.found.modelCount', [$groupsResultsCount, __d('controller', "Groups", [$groupsResultsCount])]); ?>
</a>
</li>
<?php endif; ?>
</ul>
<?php endif; ?>

<div id="search-results">
<div id="search-results" class="accordion">
<!-- Start with the Primary Registry objects -->
<?php foreach(['People', 'Groups'] as $pm): ?>
<?php if(!empty($vv_results[$pm])): ?>
<div class="search-results-group-container">
<h3><?= __d('controller', $pm, 2); ?></h3>
<ul class="search-results-group">

<?php foreach($vv_results[$pm] as $pkey => $matches): ?>
<?php
$url = [
'controller' => \Cake\Utility\Inflector::dasherize($pm),
'action' => 'edit',
$pkey
];
// The same entity can match on more than one searchable model
?>

<?php foreach($matches as $m => $entity): ?>
<?php
$displayField = $vv_supported_models[$m]['displayField'];
$displayLabel = __d('field', $displayField);
$displayString = $entity->$displayField;

// If we match on a related model (for example PersonRoles for People)
// indicate what actually matched
$matchInfo = __d('result', 'search.result.id', $pkey);

// Do we have a more informative string to render?
if(!empty($entity->person->primary_name->full_name)) {
$displayString = $entity->person->primary_name->full_name;

$matchInfo = __d('result', 'search.result.related', $displayLabel, $entity->$displayField, $pkey);
} elseif(!empty($entity->group->name)) {
$displayString = $entity->group->name;

$matchInfo = __d('result', 'search.result.related', $displayLabel, $displayString, $pkey);
}
?>
<li class="search-result">
<a href="<?= $this->Url->build($url) ?>">
<div class="search-result-name">
<?= $displayString ?>
</div>
<div class="search-result-match-info">
<?= filter_var($matchInfo, FILTER_SANITIZE_SPECIAL_CHARS) ?>
</div>
</a>
</li>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
<div id="search-results-<?= strtolower($pm) ?>" class="search-results-group-container accordion-item">
<div id="search-results-<?= strtolower($pm) ?>-header" class="search-results-group-title accordion-header">
<button class="accordion-button"
data-bs-toggle="collapse"
data-bs-target="#search-results-<?= strtolower($pm) ?>-body"
aria-expanded="true"
aria-controls="search-results-<?= strtolower($pm) ?>-body">
<?= __d('controller', $pm, 2); ?>
</button>
</div>
<div id="search-results-<?= strtolower($pm) ?>-body" class="accordion-collapse collapse show">
<div class="accordion-body">
<ul class="search-results-group">
<?php foreach($vv_results[$pm] as $pkey => $matches): ?>
<?php
$url = [
'controller' => \Cake\Utility\Inflector::dasherize($pm),
'action' => 'edit',
$pkey
];
// The same entity can match on more than one searchable model
?>

<?php foreach($matches as $m => $entity): ?>
<?php
$displayField = $vv_supported_models[$m]['displayField'];
$displayLabel = __d('field', $displayField);
$displayString = $entity->$displayField;

// If we match on a related model (for example PersonRoles for People)
// indicate what actually matched
$matchInfo = __d('result', 'search.result.id', $pkey);

// Do we have a more informative string to render?
if(!empty($entity->person->primary_name->full_name)) {
$displayString = $entity->person->primary_name->full_name;

$matchInfo = __d('result', 'search.result.related', $displayLabel, $entity->$displayField, $pkey);
} elseif(!empty($entity->group->name)) {
$displayString = $entity->group->name;

$matchInfo = __d('result', 'search.result.related', $displayLabel, $displayString, $pkey);
}
?>
<li class="search-result">
<a href="<?= $this->Url->build($url) ?>">
<div class="search-result-name">
<?= $displayString ?>
</div>
<div class="search-result-match-info">
<?= filter_var($matchInfo, FILTER_SANITIZE_SPECIAL_CHARS) ?>
</div>
</a>
</li>
<?php endforeach; ?>
<?php endforeach; ?>
</ul>
</div>
</div>
</div>
<?php endif; ?>
<?php endforeach; ?>
Expand Down
29 changes: 14 additions & 15 deletions app/templates/element/javascript.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,30 +53,29 @@

// SEARCH
// Persistent search bar form:
$('#global-search form').submit(function () {
// Disallow submit on blank
if($.trim($('#global-search-q').val()) == '') {
return false;
}
});
// Select search text on focus
$('#global-search-q').focus(function() {
$('#global-search-q').select();
});

// Search page form:
$('#search').submit(function () {
$('#global-search form').submit(function() {
// Disallow submit on blank
if($.trim($('#q').val()) == '') {
return false;
}
});
$('#search-clear').click(function () {
$('#global-search-clear').click(function(e) {
e.stopPropagation();
$('#q').val('');
$('#q').removeClass('hasValue');
$('#q').focus();
});
// Select search text on focus
$('#q').focus(function() {
$('#q').select();
$(this).select();
});
// Hide and reveal clear button
$('#q').on('input', function(e) {
if($(this).val() != '') {
$(this).addClass('hasValue');
} else {
$(this).removeClass('hasValue');
}
});

// TOP FILTER FORM
Expand Down
37 changes: 34 additions & 3 deletions app/templates/element/searchGlobal.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,11 +46,42 @@
<?php
print $this->Form->create(null, $options);
print $this->Form->hidden('co_id', ['default' => $vv_cur_co->id]);
print $this->Form->label('global-search-q', __d('field','search.placeholder'), ['class' => 'visually-hidden']);
print $this->Form->input('global-search-q',['id' => 'global-search-q', 'placeholder' => __d('field','search.placeholder')]);
print $this->Form->label(
'q',
__d('field','search.global'),
['class' => 'visually-hidden']
);
$globalSearchInputClass = '';
if(!empty($this->request->getData('q'))) {
$globalSearchInputClass = 'hasValue';
}
print $this->Form->input(
'q',
[
'id' => 'q',
'class' => $globalSearchInputClass,
'placeholder' => __d('field','search.placeholder')
]
);
print $this->Form->button(
'<span class="material-icons">close</span>',
[
'type' => 'button',
'escapeTitle' => false,
'id' => 'global-search-clear',
'class' => 'btn btn-link',
'aria-label' => __d('field','search.global.clear')
]
);
print $this->Form->button(
'<em class="material-icons">search</em>',
['type' => 'submit', 'escapeTitle' => false, 'id' => 'global-search-button', 'class' => 'btn btn-link btn-sm']
[
'type' => 'submit',
'escapeTitle' => false,
'id' => 'global-search-button',
'class' => 'btn btn-link btn-sm',
'aria-label' => __d('field','search.global.submit')
]
);
print $this->Form->end();
?>
Expand Down
Loading