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

Convert range limit views + helpers to presenters + components #179

Merged
merged 16 commits into from
May 5, 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
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ This will install some asset references in your application.js and application.c
You have at least one solr field you want to display as a range limit, that's why you've installed this plugin. In your CatalogController, the facet configuration should look like:

```ruby
config.add_facet_field 'pub_date', label: 'Publication Year', range: true
config.add_facet_field 'pub_date', label: 'Publication Year', **default_range_config
```

You should now get range limit display. More complicated configuration is available if desired, see Range Facet Configuration below.
Expand Down Expand Up @@ -138,11 +138,11 @@ is probably the best touch UI anyway, if it can be made to work well.
There are two main types of JavaScript implemented for BlacklightRangeLimit:
- Initialization and refresh of Range Limit plugin based off of events
- Range Limit plugin functionality called from event listeners

The second class of range limit functionality is customizable in your local application by overriding the specified function.

A simple example of this is overriding the display ratio used to create the histogram

```javascript
BlacklightRangeLimit.display_ratio = 1
```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/**
* Closure functions in this file are mainly concerned with initializing, resizing, and updating
* range limit functionality based off of page load, facet opening, page resizing, and otherwise
* events.
* events.
*/

Blacklight.onLoad(function() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ BlacklightRangeLimit.turnIntoPlot = function turnIntoPlot(container, wait_for_vi
}
}

BlacklightRangeLimit.parseSegment = function parseSegment(el) {
if ($(el).find("span.single").first().data('blrlSingle')) {
var val = BlacklightRangeLimit.parseNum($(el).find("span.single").first().data('blrlSingle'));

return [val, val];
} else {
var from = BlacklightRangeLimit.parseNum($(el).find("span.from").first().data('blrlBegin'));
var to = BlacklightRangeLimit.parseNum($(el).find("span.to").first().data('blrlEnd'));

return [from, to];
}
}

// Takes a div holding a ul of distribution segments produced by
// blacklight_range_limit/_range_facets and makes it into
// a flot area chart.
Expand All @@ -45,15 +58,16 @@ BlacklightRangeLimit.areaChart = function areaChart(container) {
var series_data = new Array();
var pointer_lookup = new Array();
var x_ticks = new Array();
var min = BlacklightRangeLimit.parseNum($(container).find("ul li:first-child span.from").first().data('blrlBegin'));
var max = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").first().data('blrlEnd'));
var min = BlacklightRangeLimit.parseSegment($(container).find("ul li:first-child").first())[0];
var max = BlacklightRangeLimit.parseSegment($(container).find("ul li:last-child").first())[1];

$(container).find("ul li").each(function() {
var from = BlacklightRangeLimit.parseNum($(this).find("span.from").first().data('blrlBegin'));
var to = BlacklightRangeLimit.parseNum($(this).find("span.to").first().data('blrlEnd'));
var count = BlacklightRangeLimit.parseNum($(this).find("span.count").text());
var avg = (count / (to - from + 1));
var segment = BlacklightRangeLimit.parseSegment(this);
var from = segment[0];
var to = segment[1];

var count = BlacklightRangeLimit.parseNum($(this).find("span.facet-count,span.count").text());
var avg = (count / (to - from + 1));

//We use the avg as the y-coord, to make the area of each
//segment proportional to how many documents it holds.
Expand All @@ -62,12 +76,10 @@ BlacklightRangeLimit.areaChart = function areaChart(container) {

x_ticks.push(from);

pointer_lookup.push({'from': from, 'to': to, 'count': count, 'label': $(this).find(".facet_select").html() });
pointer_lookup.push({'from': from, 'to': to, 'count': count, 'label': $(this).find(".facet-select,.facet_select").html() });
});
var max_plus_one = BlacklightRangeLimit.parseNum($(container).find("ul li:last-child span.to").text())+1;
x_ticks.push( max_plus_one );


x_ticks.push( max + 1 );

var plot;
var config = $(container).closest('.blrl-plot-config').data('plot-config') || $(container).closest('.facet-limit').data('plot-config') || {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Blacklight.onLoad(function() {
// returns two element array min/max as numbers. If there is a limit applied,
// it's boundaries are are limits. Otherwise, min/max in current result
// set as sniffed from HTML. Pass in a DOM element for a div.range
// Will return NaN as min or max in case of error or other weirdness.
// Will return NaN as min or max in case of error or other weirdness.
BlacklightRangeLimit.min_max = function min_max(range_element) {
var current_limit = $(range_element).closest(".limit_content.range_limit").find(".current")

Expand Down Expand Up @@ -117,7 +117,7 @@ BlacklightRangeLimit.buildSlider = function buildSlider(thisContext) {
begin_el.change(function() {
var val = BlacklightRangeLimit.parseNum($(thisContext).val());
if (isNaN(val) || val < min) {
//for weird data, set slider at min
//for weird data, set slider at min
val = min;
}
var values = placeholder_input.data("slider").getValue();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<%= render(@layout.new(facet_field: @facet_field)) do |component| %>
<% component.label do %>
<%= @facet_field.label %>
<% end %>

<% component.body do %>
<div class="limit_content range_limit <%= @facet_field.key %>-config blrl-plot-config">
<% if @facet_field.selected_range_facet_item %>
<%= render BlacklightRangeLimit::RangeSegmentsComponent.new(facet_field: @facet_field, facet_items: [@facet_field.selected_range_facet_item], classes: ['current']) %>
<% end %>

<!-- no results profile if missing is selected -->
<% unless @facet_field.missing_selected? %>
<!-- you can hide this if you want, but it has to be on page if you want
JS slider and calculated facets to show up, JS sniffs it. -->
<div class="profile">
<% if (min = @facet_field.min) &&
(max = @facet_field.max) %>

<% if range_config[:segments] != false %>
<div class="distribution subsection <%= 'chart_js' unless range_config[:chart_js] == false %>">
<!-- if we already fetched segments from solr, display them
here. Otherwise, display a link to fetch them, which JS
will AJAX fetch. -->
<% if @facet_field.range_queries.any? %>
<%= render BlacklightRangeLimit::RangeSegmentsComponent.new(facet_field: @facet_field) %>
<% else %>
<%= link_to(t('blacklight.range_limit.view_distribution'), range_limit_url(range_start: min, range_end: max), class: "load_distribution") %>
<% end %>
</div>
<% end %>
<p class="range subsection <%= "slider_js" unless range_config[:slider_js] == false %>">
<%= t('blacklight.range_limit.results_range_html', min: min, max: max) %>
</p>
<% end %>
</div>

<%= render BlacklightRangeLimit::RangeFormComponent.new(facet_field: @facet_field, classes: @classes) %>

<%= more_link(key: @facet_field.key, label: @facet_field.label) unless @facet_field.in_modal? %>

<% if @facet_field.missing_facet_item && !request.xhr? %>
<%= render BlacklightRangeLimit::RangeSegmentsComponent.new(facet_field: @facet_field, facet_items: [@facet_field.missing_facet_item], classes: ['missing', 'subsection']) %>
<% end %>
<% end %>
</div>
<% end %>
<% end %>
29 changes: 29 additions & 0 deletions app/components/blacklight_range_limit/range_facet_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# frozen_string_literal: true

module BlacklightRangeLimit
class RangeFacetComponent < ::ViewComponent::Base
renders_one :more_link, ->(key:, label:) do
tag.div class: 'more_facets' do
link_to t('blacklight.range_limit.view_larger', field_name: label),
search_facet_path(id: key),
data: { blacklight_modal: 'trigger' }
end
end

delegate :search_action_path, :search_facet_path, to: :helpers

def initialize(facet_field:, layout: nil, classes: BlacklightRangeLimit.classes)
@facet_field = facet_field
@layout = layout == false ? Blacklight::FacetFieldNoLayoutComponent : Blacklight::FacetFieldComponent
@classes = classes
end

def range_config
@facet_field.range_config
end

def range_limit_url(options = {})
helpers.main_app.url_for(@facet_field.search_state.to_h.merge(range_field: @facet_field.key, action: 'range_limit').merge(options))
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<%= form_tag search_action_path, method: :get, class: [@classes[:form], "range_#{@facet_field.key} d-flex justify-content-center"].join(' ') do %>
<%= render Blacklight::HiddenSearchStateComponent.new(params: @facet_field.search_state.params_for_search.except(:utf8, :page)) %>

<div class="input-group input-group-sm mb-3 flex-nowrap range-limit-input-group">
<%= render_range_input(:begin, begin_label) %>
<%= render_range_input(:end, end_label) %>
<div class="input-group-append visually-hidden">
<%= submit_tag t('blacklight.range_limit.submit_limit'), class: @classes[:submit] %>
</div>
<%= submit_tag t('blacklight.range_limit.submit_limit'), class: @classes[:submit] + " sr-only", "aria-hidden": "true" %>
</div>
<% end %>
46 changes: 46 additions & 0 deletions app/components/blacklight_range_limit/range_form_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# frozen_string_literal: true

module BlacklightRangeLimit
class RangeFormComponent < ::ViewComponent::Base
delegate :search_action_path, to: :helpers

def initialize(facet_field:, classes: BlacklightRangeLimit.classes)
@facet_field = facet_field
@classes = classes
end

def begin_label
range_config[:input_label_range_begin] || t("blacklight.range_limit.range_begin", field_label: @facet_field.label)
end

def end_label
range_config[:input_label_range_end] || t("blacklight.range_limit.range_end", field_label: @facet_field.label)
end

def maxlength
range_config[:maxlength]
end

# type is 'begin' or 'end'
def render_range_input(type, input_label = nil, maxlength_override = nil)
type = type.to_s

default = if @facet_field.selected_range.is_a?(Range)
case type
when 'begin' then @facet_field.selected_range.first
when 'end' then @facet_field.selected_range.last
end
end

html = number_field_tag("range[#{@facet_field.key}][#{type}]", default, maxlength: maxlength_override || maxlength, class: "form-control text-center range_#{type}")
html += label_tag("range[#{@facet_field.key}][#{type}]", input_label, class: 'sr-only visually-hidden') if input_label.present?
html
end

private

def range_config
@facet_field.range_config
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<ul class="facet-values list-unstyled <%= @classes.join(' ') %>">
<%= render @item_component.with_collection(facet_item_presenters) %>
</ul>
26 changes: 26 additions & 0 deletions app/components/blacklight_range_limit/range_segments_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# frozen_string_literal: true

module BlacklightRangeLimit
class RangeSegmentsComponent < ::ViewComponent::Base
def initialize(facet_field:, facet_items: nil, item_component: nil, classes: [])
super

@facet_field = facet_field
@facet_items = facet_items || facet_field.try(:range_queries) || []
@item_component = facet_field.facet_field.item_component || Blacklight::FacetItemComponent
@classes = classes
end

def facet_item_presenters
@facet_items.map { |item| facet_item_presenter(item) }
end

def facet_item_presenter(facet_item)
facet_config.item_presenter.new(facet_item, facet_config, helpers, @facet_field.key)
end

def facet_config
@facet_field.facet_field
end
end
end
Loading