{"id":23567031,"url":"https://github.com/sul-dlss/blacklight-hierarchy","last_synced_at":"2025-08-10T04:04:20.946Z","repository":{"id":3079338,"uuid":"4102929","full_name":"sul-dlss/blacklight-hierarchy","owner":"sul-dlss","description":"gem: Hierarchical Facet Plugin for Blacklight","archived":false,"fork":false,"pushed_at":"2025-04-16T20:55:21.000Z","size":988,"stargazers_count":10,"open_issues_count":5,"forks_count":8,"subscribers_count":13,"default_branch":"main","last_synced_at":"2025-04-17T07:48:43.922Z","etag":null,"topics":["access","gem","infrastructure"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sul-dlss.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2012-04-22T09:28:35.000Z","updated_at":"2025-04-16T20:55:24.000Z","dependencies_parsed_at":"2024-06-19T06:54:20.375Z","dependency_job_id":"2ee5fe7c-0f31-4dc0-ac29-d2f229f8acef","html_url":"https://github.com/sul-dlss/blacklight-hierarchy","commit_stats":{"total_commits":171,"total_committers":13,"mean_commits":"13.153846153846153","dds":0.7134502923976609,"last_synced_commit":"aab6288d3c2151cfbbaa8e64d3e3eb037c823646"},"previous_names":[],"tags_count":32,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sul-dlss%2Fblacklight-hierarchy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sul-dlss%2Fblacklight-hierarchy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sul-dlss%2Fblacklight-hierarchy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sul-dlss%2Fblacklight-hierarchy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sul-dlss","download_url":"https://codeload.github.com/sul-dlss/blacklight-hierarchy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250536242,"owners_count":21446699,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["access","gem","infrastructure"],"created_at":"2024-12-26T18:11:44.060Z","updated_at":"2025-08-10T04:04:20.899Z","avatar_url":"https://github.com/sul-dlss.png","language":"Ruby","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blacklight::Hierarchy\n[![Build Status](https://github.com/sul-dlss/blacklight-hierarchy/workflows/CI/badge.svg)](https://github.com/sul-dlss/blacklight-hierarchy/actions?query=branch%3Amain) [![Gem Version](https://badge.fury.io/rb/blacklight-hierarchy.svg)](http://badge.fury.io/rb/blacklight-hierarchy)\n\nThis plugin provides hierarchical facets for [Blacklight](https://github.com/projectblacklight/blacklight).\n\nPlease note this is does not directly follow any of the competing approaches of [Hierarchical Facets in Solr](http://wiki.apache.org/solr/HierarchicalFaceting), including Solr PivotFacets.\n\n## Usage\n\nAdd the plugin to your Blacklight app's Gemfile.\n\n```ruby\ngem 'blacklight-hierarchy'\n```\n\nIndex your hierarchies in a (colon-)separated list. For example, items in a \"processing\" queue with a \"copy\" action, might be indexed as:\n\n```xml\n\u003cdoc\u003e\n  \u003cfield name=\"id\"\u003efoo\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing:copy\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing:copy:waiting\u003c/field\u003e\n\u003c/doc\u003e\n\u003cdoc\u003e\n  \u003cfield name=\"id\"\u003ebar\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing:copy\u003c/field\u003e\n  \u003cfield name=\"queue_status_facet\"\u003eprocessing:copy:completed\u003c/field\u003e\n\u003c/doc\u003e\n```\n\nThat would cause the facet count to appear at all three levels:\n\n- [processing](#) (2)\n    - [copy](#) (2)\n        - [completed](#) (1)\n        - [waiting](#) (1)\n\nYou can skip as many levels as you'd like, as long as the \"leaf\" values are indexed. For example, if you didn't index the \"processing\" part alone, it will simply be a container, not a clickable/countable facet:\n\n- processing\n    - [copy](#) (2)\n        - [completed](#) (1)\n        - [waiting](#) (1)\n\n**Note**: If you use Solr's built-in [PathHierarchyTokenizerFactory](http://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.PathHierarchyTokenizerFactory), you can index the entire depth by supplying only the leaf nodes.  Otherwise you are expected to build the permutations yourself before loading.\n\nIn your Blacklight controller configuration (usually `CatalogController`), tell Blacklight to render the facet using the hierarchy component.\n\n\n```ruby\nconfig.add_facet_field 'queue_wps',   label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'queue_wsp',   label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'queue_swp',   label: 'Queue Status', component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'callnum_top', label: 'Callnumber',   component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'foo_trunk',   label: 'Foo L1',       component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'foo_branch',  label: 'Foo L2',       component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'foo_leaves',  label: 'Foo L3',       component: Blacklight::Hierarchy::FacetFieldListComponent\nconfig.add_facet_field 'tag_facet',   label: 'Tag',          component: Blacklight::Hierarchy::FacetFieldListComponent\n```\n\nAdd your hierarchy-specific options to the controller configuration:\n\n```ruby\nconfig.facet_display = {\n  :hierarchy =\u003e {\n    'queue'   =\u003e [['wps','wsp','swp'], ':'],       # values are arrays: 1st element is array, 2nd is delimiter string\n    'callnum' =\u003e [['top'], '/'],\n    'foo'     =\u003e [['trunk', 'branch', 'leaves']],  # implied default delimiter\n    'tag'     =\u003e [[nil]]                           # TODO: explain\n  }\n}\n```\n\nIn the above configuration, 'queue_status_facet' is the full Solr field name, and ':' is the delimiter within the field.  Note that suffixes ('facet' in the above example) should not contain underscores, since the methods that deal with the Solr fields and match them to the config assume the \"prefix\" ('queue_status' in the above example) will be everything up to the last underscore in the field name.  See the facet_tree method for further explanation and some relevant code, as well as the render_hierarchy method for relevant code.\n\nThe `[nil]` value is present in support of rotatable facet hierarchies, a totally undocumented feature.\n\nYou may optionally configure a custom facet item presenter, e.g.:\n\n```ruby\nconfig.facet_display = {\n  :hierarchy =\u003e {\n    'location_hierarchy' =\u003e [['f'], ':', MyApp::CustomFacetItemPresenter] # values are arrays: 1st element is array, 2nd is delimiter string, 3rd is a presenter\n  }\n}\n```\n\nFacet fields should be added for each permutation of hierarchy key and term values, joined by **_**.  Or, the output of:\n\n```ruby\nconfig.facet_display[:hierarchy].each{ |k,v| puts \"#{k}_#{v}\" }\n```\n### Sorting\nSorting for a hierarchical facet item list is configured just like a non-hierarchical Blacklight facet. By default, the list sorts by count. To specify alphabetical sorting, use `sort: 'alpha'` in `config.add_facet_field`, e.g.:\n\n```ruby\nconfig.add_facet_field 'tag_facet', sort: 'alpha', label: 'Tag', component: Blacklight::Hierarchy::FacetFieldListComponent\n```\n\n### Changing the icons\nWe store our closed/open icons as the CSS variables `--bl-h-closed-icon` and `--bl-h-closed-icon` in `hierarchy.css`. By default we use SVGs provided by the [Font Awesome](https://github.com/FortAwesome/Font-Awesome) library. To change the icon, reassign these CSS variables with new SVG code.\n\n```css\n  /* app/assets/stylesheets/blacklight/hierarchy/hierarchy.css */\n\n  /* plus sign */\n  --bl-h-closed-icon: url(\"data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 448 512'%3e%3c!--! Font Awesome Free 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free %28Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License%29 Copyright 2022 Fonticons, Inc. --%3e%3cpath d='M200 344V280H136C122.7 280 112 269.3 112 256C112 242.7 122.7 232 136 232H200V168C200 154.7 210.7 144 224 144C237.3 144 248 154.7 248 168V232H312C325.3 232 336 242.7 336 256C336 269.3 325.3 280 312 280H248V344C248 357.3 237.3 368 224 368C210.7 368 200 357.3 200 344zM0 96C0 60.65 28.65 32 64 32H384C419.3 32 448 60.65 448 96V416C448 451.3 419.3 480 384 480H64C28.65 480 0 451.3 0 416V96zM48 96V416C48 424.8 55.16 432 64 432H384C392.8 432 400 424.8 400 416V96C400 87.16 392.8 80 384 80H64C55.16 80 48 87.16 48 96z'/%3e%3c/svg%3e\");\n```\n\n\n### Aria Labels\nFor screen reader purposes we have used \"Toggle subgroup\" as the aria-label attribute of the button.  This is internationalized using rails' i18n feature.\n\nThe field name is used in the key to allow for facet specific aria labels or defaults back to the generic key/\"Toggle subgroup\" text.\n\n```yml\n# config/locales/en.yml\nen:\n  blacklight:\n    hierarchy:\n      format_ssim_toggle_aria_label: Toggle format section\n      toggle_aria_label: Toggle call number section\n```\n\n## Caveats\n\nThis code was ripped out of another project, and is still quite immature as a standalone project. Every effort has been made to make it as plug-and-play as possible, but it may stomp on Blacklight in unintended ways (e.g., ways that made sense in context of its former host app, but which aren't compatible with generic Blacklight). Proceed with caution, and report issues.\n\n## Release\n\nIn order to cut a new release you will need to publish simultaneously to NPM and RubyGems. Before you do that ensure that versions in `lib/blacklight/hierarchy/version.rb` and `package.json` match. Assuming you have the credentials to do it you can then:\n\n```\n$ rake release\n$ npm publish\n```\n\n## TODO\n\n- WRITE TESTS\n- Switch internal facet management from hack-y Hash to `Blacklight::Hierarchy::FacetGroup` class (already implemented, but not plumbed up)\n- Clarify when suffix is applied/required/etc.\n\n## Developing gem\n- Clone locally `git@github.com:sul-dlss/blacklight-hierarchy.git`\n- go into project directory `cd blacklight-hierarchy`\n- install dependencies `bundle install`\n- Create a test app to develop and test against `bundle exec rake engine_cart:generate\n- Run tests `bundle exec rspec`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsul-dlss%2Fblacklight-hierarchy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsul-dlss%2Fblacklight-hierarchy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsul-dlss%2Fblacklight-hierarchy/lists"}