From fe2090dd2b8c2b7d32de04df3a019fc9a3e559cb Mon Sep 17 00:00:00 2001 From: Ioannis Igoumenos <ioigoume@gmail.com> Date: Fri, 3 May 2024 17:25:51 +0300 Subject: [PATCH] Refactored filter.php.Created elements and FilterHelper. (#190) --- app/src/View/Helper/FieldHelper.php | 21 +- app/src/View/Helper/FilterHelper.php | 160 +++++++++++++ app/templates/Standard/index.php | 8 +- app/templates/element/filter/checkboxes.php | 63 +++++ app/templates/element/filter/dateSingle.php | 64 +++++ ...{dateTimeFilters.php => datetimeGroup.php} | 20 +- app/templates/element/filter/default.php | 61 +++++ app/templates/element/filter/filter.php | 220 +++--------------- .../element/filter/footerButtons.php | 79 +++++++ .../{topFiltersToggle.php => legend.php} | 13 +- .../filter/{filterOptions.php => options.php} | 2 + .../{activeTopButton.php => topButtons.php} | 2 + 12 files changed, 504 insertions(+), 209 deletions(-) create mode 100644 app/src/View/Helper/FilterHelper.php create mode 100644 app/templates/element/filter/checkboxes.php create mode 100644 app/templates/element/filter/dateSingle.php rename app/templates/element/filter/{dateTimeFilters.php => datetimeGroup.php} (86%) create mode 100644 app/templates/element/filter/default.php create mode 100644 app/templates/element/filter/footerButtons.php rename app/templates/element/filter/{topFiltersToggle.php => legend.php} (90%) rename app/templates/element/filter/{filterOptions.php => options.php} (99%) rename app/templates/element/filter/{activeTopButton.php => topButtons.php} (98%) diff --git a/app/src/View/Helper/FieldHelper.php b/app/src/View/Helper/FieldHelper.php index 60355b63c..958d17005 100644 --- a/app/src/View/Helper/FieldHelper.php +++ b/app/src/View/Helper/FieldHelper.php @@ -172,9 +172,8 @@ public function calculateLabelAndDescription(string $fieldName): array * Emit a date/time form control. * This is a wrapper function for $this->control() * - * @param string $fieldName Form field - * @param string $dateType Standard, DateOnly, FromTime, ThroughTime - * @param array|null $queryParams Request Query parameters used by the filtering Blocks to get the date values + * @param string $fieldName Form field + * @param string $dateType Standard, DateOnly, FromTime, ThroughTime * @param string|null $label * * @return string HTML element @@ -183,24 +182,16 @@ public function calculateLabelAndDescription(string $fieldName): array public function dateField(string $fieldName, string $dateType=DateTypeEnum::Standard, - array $queryParams=null, string $label=null): string { // Initialize $dateFormat = $dateType === DateTypeEnum::DateOnly ? 'yyyy-MM-dd' : 'yyyy-MM-dd HH:mm:ss'; $dateTitle = $dateType === DateTypeEnum::DateOnly ? 'datepicker.enterDate' : 'datepicker.enterDateTime'; $datePattern = $dateType === DateTypeEnum::DateOnly ? '\d{4}-\d{2}-\d{2}' : '\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}'; - $date_object = null; - - if(isset($queryParams)) { - if(!empty($queryParams[$fieldName])) { - $date_object = FrozenTime::parse($queryParams[$fieldName]); - } - } else { - // This is an entity view. We are getting the data from the object - $entity = $this->getView()->get('vv_obj'); - $date_object = $entity->$fieldName; - } + $queryParams = $this->getView()->getRequest()->getQueryParams(); + $date_object = !empty($queryParams[$fieldName]) + ? FrozenTime::parse($queryParams[$fieldName]) + : $this->getEntity()?->$fieldName; // Create the options array for the (text input) form control $coptions = []; diff --git a/app/src/View/Helper/FilterHelper.php b/app/src/View/Helper/FilterHelper.php new file mode 100644 index 000000000..1cd59b602 --- /dev/null +++ b/app/src/View/Helper/FilterHelper.php @@ -0,0 +1,160 @@ +<?php +/** + * COmanage Registry Filter Helper + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.0.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + +declare(strict_types = 1); + +namespace App\View\Helper; + +use Cake\Collection\Collection; +use Cake\Utility\{Inflector, Hash}; +use Cake\View\Helper; + +class FilterHelper extends Helper +{ + /** + * Calculate Form Default Field Options + * + * @param string $columnName + * @param string $label + * + * @return array + */ + public function calculateFieldParams(string $columnName, string $label): array{ + $queryParameters = $this->getView()->getRequest()->getQueryParams(); + $searchableAttributesExtras = $this->getView()->get('vv_searchable_attributes_extras') ?? []; + $populatedVarData = $this->getView()->get( + // The populated variables are in plural while the column names are singular + // Convention: It is a prerequisite that the vvar should be the plural of the column name + lcfirst(Inflector::pluralize(Inflector::camelize($columnName))) + ); + + // Field options + $formParams = [ + 'label' => $label, + 'type' => isset($populatedVarData) ? 'select' : 'text', + // Options will be ignored for non-select fields + 'options' => $populatedVarData, + 'value' => $queryParameters[$columnName] ?? '', + 'required' => false, + 'class' => 'form-control', + // Empty will be ignored for non-select fields + 'empty' => true + ]; + + // Custom/Additional option items defined in the ModelTable::initialize::setFilterConfig + // Example: CousTable + if(isset($searchableAttributesExtras[$columnName]['options'])) { + // Flatten the custom options + $customOptionsFlattened = Hash::flatten($searchableAttributesExtras[$columnName]['options']); + // Get the key of the placeholder string + $dataKey = array_search('@DATA@', $customOptionsFlattened, true); + if($dataKey !== false) { + $customOptionsFlattened[$dataKey] = $formParams['options']; + $formParams['options'] = Hash::expand($customOptionsFlattened); + } + } + + return $formParams; + } + + /** + * + * @return array[] [search_params, $field_booleans_columns, $field_datetime_columns, $field_generic_columns] + */ + public function explodeFieldsByType(): array + { + // Get the query string and separate the search params from the non-search params + $queryParameters = $this->getView()->getRequest()->getQueryParams(); + $searchableAttributes = $this->getView()->get('vv_searchable_attributes') ?? []; + + // Filter the search params and take params with aliases into consideration + $search_params = []; + $field_booleans_columns = []; + $field_datetime_columns = []; + $field_generic_columns = []; + foreach ($searchableAttributes as $attr => $value) { + if($value['type'] == 'boolean') { + $field_booleans_columns[$attr] = $value; + } elseif ($value['type'] == 'timestamp') { + $field_datetime_columns[$attr] = $value; + } else { + $field_generic_columns[$attr] = $value; + } + + if(isset($queryParameters[$attr])) { + $search_params[$attr] = $queryParameters[$attr]; + continue; + } + + if(isset($value['alias']) && is_array($value['alias'])) { + foreach ($value['alias'] as $alias_key) { + if(isset($queryParameters[$alias_key])) { + $search_params[$attr][$alias_key] = $queryParameters[$alias_key]; + } + } + } + } + + return [ + $search_params, + $field_booleans_columns, + $field_datetime_columns, + $field_generic_columns, + ]; + } + + /** + * Return an array of the Form hidden fields and values + * + * @return array + */ + public function getHiddenFields(): array + { + // Get the query string and separate the search params from the non-search params + $queryParameters = $this->getView()->getRequest()->getQueryParams(); + $searchableAttributes = $this->getView()->get('vv_searchable_attributes') ?? []; + + // Search attributes collection + $alias_params = (new Collection($searchableAttributes)) + ->filter(fn ($val, $attr) => (\is_array($val) && \array_key_exists('alias', $val)) ) + ->extract('alias') + ->unfold() + ->toArray(); + + // For the non-search params, we need to search the alias params as well + $searchable_parameters = [ + ...array_keys($searchableAttributes), + ...$alias_params + ]; + + // Pass back the non-search params as hidden fields, but always exclude the page parameter + // because we need to start new searches on-page one (or we're likely to end up with a 404). + return (new Collection($queryParameters)) + ->filter(fn($value, $key) => !\in_array($key, $searchable_parameters, true) && $key != 'page') + ->toArray(); + } +} \ No newline at end of file diff --git a/app/templates/Standard/index.php b/app/templates/Standard/index.php index a262d8d08..d29a64b71 100644 --- a/app/templates/Standard/index.php +++ b/app/templates/Standard/index.php @@ -50,14 +50,18 @@ $linkActions = ['edit', 'view']; // $vv_template_path will be set for plugins -$templatePath = $vv_template_path ?? ROOT . DS . "templates" . DS . $modelsName; +$templatePath = $vv_template_path ?? ROOT . DS . 'templates' . DS . $modelsName; // Read the index configuration ($indexColumns) and the associated actions for this model -$incFile = $templatePath . DS . "columns.inc"; +$incFile = $templatePath . DS . 'columns.inc'; + if(!is_readable($incFile)) { throw new \InvalidArgumentException("$incFile is not readable"); } include($incFile); +if(isset($indexColumns)) { + $this->set('vv_indexColumns', $indexColumns); +} // $linkFilter is used for models that belong to a specific parent model (eg: co_id) $linkFilter = []; diff --git a/app/templates/element/filter/checkboxes.php b/app/templates/element/filter/checkboxes.php new file mode 100644 index 000000000..d39d6f4a9 --- /dev/null +++ b/app/templates/element/filter/checkboxes.php @@ -0,0 +1,63 @@ +<?php +/** + * COmanage Registry Top Filters Checkboxes + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.0.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + + +/* + * Parameters: + * $field_booleans_columns : array, required + */ + +declare(strict_types = 1); + +// Get the query string and separate the search params from the non-search params +$query = $this->request->getQueryParams(); + +?> + + +<?php if(!empty($field_booleans_columns)): ?> + <div class="top-filters-checkboxes input"> + <div class="top-filters-checkbox-fields"> + <?php foreach($field_booleans_columns as $key => $options): ?> + <div class="filter-boolean <?= empty($options['active']) ? 'filter-inactive' : 'filter-active' ?>"> + <div class="form-check form-check-inline"> + <?php + print $this->Form->label($options['label'] ?? $key); + print $this->Form->checkbox($key, [ + 'id' => str_replace("_", "-", $key), + 'class' => 'form-check-input', + 'checked' => $query[$key] ?? 0, + 'hiddenField' => false, + 'required' => false + ]); + ?> + </div> + </div> + <?php endforeach; ?> + </div> + </div> +<?php endif; ?> diff --git a/app/templates/element/filter/dateSingle.php b/app/templates/element/filter/dateSingle.php new file mode 100644 index 000000000..dc1aa11bb --- /dev/null +++ b/app/templates/element/filter/dateSingle.php @@ -0,0 +1,64 @@ +<?php +/** + * COmanage Registry Top Filters Checkboxes + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.0.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + + +/* + * Parameters: + * $columns : array, required + * $key : string, required + * $options : array, required + * $query : array, required + */ + +declare(strict_types = 1); + +use Cake\Utility\Inflector; +use App\Lib\Enum\DateTypeEnum; + +// $columns = the passed parameter $indexColumns as found in columns.inc; +// provides overrides for labels and sorting. +$columns = $vv_indexColumns; + +$wrapperCssClass = 'filter-active'; +if(empty($options['active'])) { + $wrapperCssClass = 'filter-inactive'; +} + +$label = Inflector::humanize( + Inflector::underscore( + $options['label'] ?? $columns[$key]['label'] + ) +); + +?> + +<div class="top-filters-fields-date filter-standard <?= $wrapperCssClass ?>"> + <?= $this->Form->label($key, $label) ?> + <div class="d-flex"> + <?= $this->Field->dateField($key, DateTypeEnum::DateOnly) ?> + </div> +</div> diff --git a/app/templates/element/filter/dateTimeFilters.php b/app/templates/element/filter/datetimeGroup.php similarity index 86% rename from app/templates/element/filter/dateTimeFilters.php rename to app/templates/element/filter/datetimeGroup.php index fb38f0f50..29fcc95de 100644 --- a/app/templates/element/filter/dateTimeFilters.php +++ b/app/templates/element/filter/datetimeGroup.php @@ -25,12 +25,24 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ +/* + * Parameters: + * $field_datetime_columns : array, required + */ + +declare(strict_types = 1); + + use App\Lib\Enum\DateTypeEnum; use Cake\Utility\Inflector; +// $columns = the passed parameter $indexColumns as found in columns.inc; +// provides overrides for labels and sorting. +$columns = $vv_indexColumns; + ?> -<div class="top-filters-fields-subgroups"> +<?php if(!empty($field_datetime_columns)): ?> <?php foreach($field_datetime_columns as $key => $options): ?> <div class="input"> <div class="top-search-date-label"> @@ -42,7 +54,7 @@ <?php // Create a text field to hold our value. print $this->Form->label("{$key}_starts_at", __d('field', 'starts_at'), ['class' => 'filter-datepicker-lbl']); - print $this->Field->dateField("{$key}_starts_at", DateTypeEnum::DateOnly, $query); + print $this->Field->dateField("{$key}_starts_at", DateTypeEnum::DateOnly); ?> </div> <!-- Ends at --> @@ -50,10 +62,10 @@ <?php // Create a text field to hold our value. print $this->Form->label("{$key}_ends_at", __d('field','ends_at'), ['class' => 'filter-datepicker-lbl']); - print $this->Field->dateField("{$key}_ends_at", DateTypeEnum::DateOnly, $query); + print $this->Field->dateField("{$key}_ends_at", DateTypeEnum::DateOnly); ?> </div> </div> </div> <?php endforeach; ?> -</div> +<?php endif; ?> diff --git a/app/templates/element/filter/default.php b/app/templates/element/filter/default.php new file mode 100644 index 000000000..40aa654df --- /dev/null +++ b/app/templates/element/filter/default.php @@ -0,0 +1,61 @@ +<?php +/** + * COmanage Registry Top Filters Checkboxes + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.0.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + + +/* + * Parameters: + * $columns : array, required + * $key : string, required + * $options : array, required + */ + +declare(strict_types = 1); + +use Cake\Utility\{Inflector}; + +// $columns = the passed parameter $indexColumns as found in columns.inc; provides overrides for labels and sorting. +$columns = $vv_indexColumns; + +$wrapperCssClass = 'filter-active'; +if(empty($options['active'])) { + $wrapperCssClass = 'filter-inactive'; +} + +$label = Inflector::humanize( + Inflector::underscore( + $options['label'] ?? $columns[$key]['label'] + ) +); + +// Get the Field configuration +$formParams = $this->Filter->calculateFieldParams($key, $label); + +?> + +<div class="filter-standard <?= $wrapperCssClass ?>"> + <?= $this->Form->control($key, $formParams) ?> +</div> \ No newline at end of file diff --git a/app/templates/element/filter/filter.php b/app/templates/element/filter/filter.php index f0df46ea6..aba4149e8 100644 --- a/app/templates/element/filter/filter.php +++ b/app/templates/element/filter/filter.php @@ -24,51 +24,22 @@ * @since COmanage Registry v5.0.0 * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ -use Cake\Collection\Collection; -use Cake\Utility\{Inflector, Hash}; -use App\Lib\Enum\DateTypeEnum; + +declare(strict_types = 1); + +use Cake\Utility\Inflector; // $this->name = Models $modelsName = $this->name; // $modelName = Model $modelName = Inflector::singularize($modelsName); -// $columns = the passed parameter $indexColumns as found in columns.inc; provides overrides for labels and sorting. -$columns = $indexColumns; - -// Get the query string and separate the search params from the non-search params -$query = $this->request->getQueryParams(); -// Search attributes collection -$search_attributes_collection = new Collection($vv_searchable_attributes); -$alias_params = $search_attributes_collection->filter(fn ($val, $attr) => (is_array($val) && array_key_exists('alias', $val)) ) - ->extract('alias') - ->unfold() - ->toArray(); -// For the non search params we need to search the alias params as well -$searchable_parameters = [ - ...array_keys($vv_searchable_attributes), - ...$alias_params - ]; -$non_search_params = (new Collection($query))->filter( fn($value, $key) => !in_array($key, $searchable_parameters) ) - ->toArray(); -// Filter the search params and take params with aliases into consideration -$search_params = []; -foreach ($vv_searchable_attributes as $attr => $value) { - if(isset($query[$attr])) { - $search_params[$attr] = $query[$attr]; - continue; - } - - if(isset($value['alias']) - && is_array($value['alias'])) { - foreach ($value['alias'] as $alias_key) { - if(isset($query[$alias_key])) { - $search_params[$attr][$alias_key] = $query[$alias_key]; - } - } - } -} +// Group Fields by Type +[ $search_params, + $field_booleans_columns, + $field_datetime_columns, + $field_generic_columns ] = $this->Filter->explodeFieldsByType(); // Begin the form print $this->Form->create(null, [ @@ -76,171 +47,50 @@ 'type' => 'get' ]); -// Pass back the non-search params as hidden fields, but always exclude the page parameter -// because we need to start new searches on page one (or we're likely to end up with a 404). -if(!empty($non_search_params)) { - foreach($non_search_params as $param => $value) { - if($param != 'page') { - print $this->Form->hidden(filter_var($param, FILTER_SANITIZE_SPECIAL_CHARS), array('default' => filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS))) . "\n"; - } - } +// Hidden Form fields +foreach($this->Filter->getHiddenFields() as $param => $value) { + print $this->Form->hidden( + filter_var($param, FILTER_SANITIZE_SPECIAL_CHARS), + array('default' => filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS))) . PHP_EOL; } -// Boolean to distinguish between search filters and sort parameters -$hasActiveFilters = false; ?> <div id="<?= $modelName . ucfirst($this->request->getParam('action')) ?>Search" class="top-filters"> <fieldset> - <!-- Top Filters toggle legend --> - <?= $this->element('filter/topFiltersToggle', compact('search_params')) ?> + <!-- Filter Legend --> + <?= $this->element('filter/legend', compact('search_params')) ?> + + <!-- Search TextBoxes/DropDowns/e.t.c. --> <div id="top-filters-fields"> + <!-- Single Search Fields --> <div class="top-filters-fields-subgroups"> <?php - $field_booleans_columns = []; - $field_datetime_columns = []; - - $inactiveFiltersCount = 0; // for re-balancing the columns and submit buttons - - foreach($vv_searchable_attributes as $key => $options) { - if($options['type'] == 'boolean') { - $field_booleans_columns[$key] = $options; - continue; - } elseif ($options['type'] == 'timestamp') { - $field_datetime_columns[$key] = $options; - continue; - } - - $wrapperCssClass = 'filter-active'; - if(empty($options['active'])) { - $wrapperCssClass = 'filter-inactive'; - $inactiveFiltersCount++; - } - - - $label = Inflector::humanize( - Inflector::underscore( - $options['label'] ?? $columns[$key]['label'] - ) - ); - - if($options['type'] == 'date') { - // Create a text field to hold our date value. - print '<div class="top-filters-fields-date filter-standard ' . $wrapperCssClass . '">'; - print $this->Form->label($key, $label); - print '<div class="d-flex">'; - print $this->Field->dateField($key, DateTypeEnum::DateOnly, $query); - print '</div>'; - print '</div>'; - } else { - // text input - $formParams = [ - 'label' => $label, - // The default type is text, but we might convert to select below - 'type' => 'text', - 'value' => (!empty($query[$key]) ? $query[$key] : ''), - 'required' => false, - 'class' => 'form-control' - ]; - } - - // The populated variables are in plural while the column names are singular - // Convention: It is a prerequisite that the vvar should be the plural of the column name - $populated_vvar = lcfirst(Inflector::pluralize(Inflector::camelize($key))); - if(isset($$populated_vvar)) { - // If we have an AutoViewVar matching the name of this key, - // convert to a select - $formParams['type'] = 'select'; - $formParams['options'] = $$populated_vvar; - if(isset($vv_searchable_attributes_extras[$key]['options'])) { - // Flatten the custom options - $customOptionsFlattened = Hash::flatten($vv_searchable_attributes_extras[$key]['options']); - // Get the key of the place holder string - $dataKey = array_search('@DATA@', $customOptionsFlattened, true); - if($dataKey !== false) { - $customOptionsFlattened[$dataKey] = $formParams['options']; - $formParams['options'] = Hash::expand($customOptionsFlattened); - } - } - // Allow empty so a filter doesn't require (eg) SOR - $formParams['empty'] = true; - } - - if($options['type'] != 'date') { - print '<div class="filter-standard ' . $wrapperCssClass . '">'; - print $this->Form->control($key, $formParams); - print '</div>'; - } + foreach($field_generic_columns as $key => $options) { + $elementArguments = compact('options', 'key'); + print match($options['type']) { + 'date' => $this->element('filter/dateSingle', $elementArguments), + default => $this->element('filter/default', $elementArguments), + }; } ?> - <?php if(!empty($field_booleans_columns)): ?> - <div class="top-filters-checkboxes input"> - <div class="top-filters-checkbox-fields"> - <?php foreach($field_booleans_columns as $key => $options): ?> - <div class="filter-boolean <?= empty($options['active']) ? 'filter-inactive' : 'filter-active' ?>"> - <div class="form-check form-check-inline"> - <?php - print $this->Form->label($options['label'] ?? $key); - print $this->Form->checkbox($key, [ - 'id' => str_replace("_", "-", $key), - 'class' => 'form-check-input', - 'checked' => $query[$key] ?? 0, - 'hiddenField' => false, - 'required' => false - ]); - ?> - </div> - </div> - <?php endforeach; ?> - </div> - </div> - <?php endif; ?> + + <!-- Checkboxes --> + <?= $this->element('filter/checkboxes', compact('field_booleans_columns')) ?> </div> - <?php - // Date Time filtering block - if (!empty($field_datetime_columns)) { - print $this->element( - 'filter/dateTimeFilters', - compact('field_datetime_columns', 'query') - ); - } + <!-- Date/ Time search textboxes Group --> + <div class="top-filters-fields-subgroups"> + <?= $this->element('filter/datetimeGroup', compact('field_datetime_columns')) ?> + </div> - <?php $rebalanceColumns = (((count($vv_searchable_attributes) - $inactiveFiltersCount) % 2 == 1) && empty($field_booleans_columns)) ? ' class="tss-rebalance"' : ''; ?> - <div id="top-filters-submit"<?= $rebalanceColumns ?>> - - <?php - // Order of the submitted buttons is important here: the Enter key will submit the first (and we want the tab order to follow suit). - // We reverse the visual order of all these buttons with CSS (flex-direction: row-reverse;). - - // search button (submit) - $args = array(); - $args['id'] = 'top-filters-filter-button'; - $args['aria-label'] = __d('operation', 'filter'); - $args['class'] = 'submit-button spin btn btn-primary'; - print $this->Form->submit(__d('operation', 'filter'),$args); - - // clear button - $args = array(); - $args['id'] = 'top-filters-clear'; - $args['class'] = 'clear-button spin btn btn-default'; - $args['aria-label'] = __d('operation', 'clear'); - $args['onclick'] = 'clearTopSearch(this.form)'; - print $this->Form->button(__d('operation', 'clear'),$args); - - // Options dropdown list - if(!empty($vv_searchable_attributes)) { - print $this->element( - 'filter/filterOptions', - compact('vv_searchable_attributes', 'field_booleans_columns') - ); - } + <!-- Footer / Submit Buttons --> + <?= $this->element('filter/footerButtons', compact('field_booleans_columns')) ?> - </div> </div> </fieldset> </div> -<?= $this->Form->end(); ?> +<?= $this->Form->end() ?> diff --git a/app/templates/element/filter/footerButtons.php b/app/templates/element/filter/footerButtons.php new file mode 100644 index 000000000..168895bcb --- /dev/null +++ b/app/templates/element/filter/footerButtons.php @@ -0,0 +1,79 @@ +<?php +/** + * COmanage Registry Top Filters Submit area buttons Element + * + * Portions licensed to the University Corporation for Advanced Internet + * Development, Inc. ("UCAID") under one or more contributor license agreements. + * See the NOTICE file distributed with this work for additional information + * regarding copyright ownership. + * + * UCAID licenses this file to you under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @link https://www.internet2.edu/comanage COmanage Project + * @package registry + * @since COmanage Registry v5.0.0 + * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) + */ + + +/* + * Parameters: + * $field_booleans_columns : array, required + */ + +declare(strict_types = 1); + +use Cake\Collection\Collection; + +$classes = ''; +$inactiveFiltersCount = (new Collection($vv_searchable_attributes))->filter(fn($col) => boolval($col['active']) === false) + ->count(); +if ((count($vv_searchable_attributes) - $inactiveFiltersCount) % 2 === 1 + && + empty($field_booleans_columns) +) { + $classes .= ' class="tss-rebalance'; +} + +?> + +<div id="top-filters-submit"<?= $classes ?>> + + <?php + // Order of the submitted buttons is important here: the Enter key will submit the first (and we want the tab order to follow suit). + // We reverse the visual order of all these buttons with CSS (flex-direction: row-reverse;). + + // search button (submit) + $args = array(); + $args['id'] = 'top-filters-filter-button'; + $args['aria-label'] = __d('operation', 'filter'); + $args['class'] = 'submit-button spin btn btn-primary'; + print $this->Form->submit(__d('operation', 'filter'), $args); + + // clear button + $args = array(); + $args['id'] = 'top-filters-clear'; + $args['class'] = 'clear-button spin btn btn-default'; + $args['aria-label'] = __d('operation', 'clear'); + $args['onclick'] = 'clearTopSearch(this.form)'; + print $this->Form->button(__d('operation', 'clear'), $args); + + // Options dropdown list + if(!empty($vv_searchable_attributes)) { + print $this->element( + 'filter/options', + compact('field_booleans_columns') + ); + } + ?> +</div> \ No newline at end of file diff --git a/app/templates/element/filter/topFiltersToggle.php b/app/templates/element/filter/legend.php similarity index 90% rename from app/templates/element/filter/topFiltersToggle.php rename to app/templates/element/filter/legend.php index 442b474e4..06a84d9c8 100644 --- a/app/templates/element/filter/topFiltersToggle.php +++ b/app/templates/element/filter/legend.php @@ -25,7 +25,14 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ -// $search_params passed as a parameter + +/* + * Parameters: + * $search_params : array, required + */ + +declare(strict_types = 1); + $hasActiveFilters = false; @@ -44,12 +51,12 @@ foreach($search_params as $key => $params) { // We have active filters - not just a sort. $hasActiveFilters = true; - print $this->element('filter/activeTopButton', compact('key', 'params')); + print $this->element('filter/topButtons', compact('key', 'params')); } ?> <?php if($hasActiveFilters): ?> <button id="top-filters-clear-all-button" class="filter-clear-all-button spin btn" type="button" aria-controls="top-filters-clear" onclick="event.stopPropagation()"> - <?= __d('operation', 'clear.filters',[2]); ?> + <?= __d('operation', 'clear.filters',[2]) ?> </button> <?php endif; ?> </span> diff --git a/app/templates/element/filter/filterOptions.php b/app/templates/element/filter/options.php similarity index 99% rename from app/templates/element/filter/filterOptions.php rename to app/templates/element/filter/options.php index 327f456db..0337d5f6b 100644 --- a/app/templates/element/filter/filterOptions.php +++ b/app/templates/element/filter/options.php @@ -25,6 +25,8 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ +declare(strict_types = 1); + ?> <div id="top-filters-options-container"> diff --git a/app/templates/element/filter/activeTopButton.php b/app/templates/element/filter/topButtons.php similarity index 98% rename from app/templates/element/filter/activeTopButton.php rename to app/templates/element/filter/topButtons.php index 2c3895d95..93baf9a05 100644 --- a/app/templates/element/filter/activeTopButton.php +++ b/app/templates/element/filter/topButtons.php @@ -25,6 +25,8 @@ * @license Apache License, Version 2.0 (http://www.apache.org/licenses/LICENSE-2.0) */ +declare(strict_types = 1); + use Cake\Utility\{Inflector, Hash}; // Construct aria-controls string