blacklight-spotlight 4.7.1 → 5.0.0.pre.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +30 -12
- data/Rakefile +8 -1
- data/app/assets/javascripts/spotlight/application.js +0 -1
- data/app/assets/javascripts/spotlight/spotlight.esm.js +3620 -3847
- data/app/assets/javascripts/spotlight/spotlight.esm.js.map +1 -1
- data/app/assets/javascripts/spotlight/spotlight.js +3620 -3852
- data/app/assets/javascripts/spotlight/spotlight.js.map +1 -1
- data/app/assets/stylesheets/spotlight/_accessibility.scss +0 -9
- data/app/assets/stylesheets/spotlight/_autocomplete.scss +49 -0
- data/app/assets/stylesheets/spotlight/_blacklight_configuration.scss +0 -1
- data/app/assets/stylesheets/spotlight/_blacklight_overrides.scss +1 -6
- data/app/assets/stylesheets/spotlight/_browse.scss +2 -2
- data/app/assets/stylesheets/spotlight/_catalog.scss +40 -41
- data/app/assets/stylesheets/spotlight/_curation.scss +1 -1
- data/app/assets/stylesheets/spotlight/_exhibit_admin.scss +7 -0
- data/app/assets/stylesheets/spotlight/_exhibits_index.scss +8 -5
- data/app/assets/stylesheets/spotlight/_featured_browse_categories_block.scss +3 -3
- data/app/assets/stylesheets/spotlight/_header.scss +13 -0
- data/app/assets/stylesheets/spotlight/_mixins.scss +3 -4
- data/app/assets/stylesheets/spotlight/_nestable.scss +2 -12
- data/app/assets/stylesheets/spotlight/_pages.scss +11 -9
- data/app/assets/stylesheets/spotlight/_report_a_problem.scss +1 -3
- data/app/assets/stylesheets/spotlight/_sir-trevor_overrides.scss +2 -2
- data/app/assets/stylesheets/spotlight/_spotlight.scss +2 -1
- data/app/assets/stylesheets/spotlight/_tag_selector.scss +34 -0
- data/app/assets/stylesheets/spotlight/_variables.scss +0 -8
- data/app/components/spotlight/analytics/dashboard_component.html.erb +3 -3
- data/app/components/spotlight/breadcrumbs_component.html.erb +13 -19
- data/app/components/spotlight/bulk_action_component.rb +1 -1
- data/app/components/spotlight/document_component.rb +1 -1
- data/app/components/spotlight/save_search_component.rb +1 -1
- data/app/components/spotlight/select_image_component.html.erb +17 -0
- data/app/components/spotlight/select_image_component.rb +24 -0
- data/app/components/spotlight/skip_link_component.rb +16 -0
- data/app/components/spotlight/tag_selector_component.html.erb +40 -0
- data/app/components/spotlight/tag_selector_component.rb +41 -0
- data/app/components/spotlight/tag_selector_component.yml +6 -0
- data/app/components/spotlight/title_component.html.erb +8 -0
- data/app/components/spotlight/title_component.rb +22 -0
- data/app/controllers/spotlight/accessibility_controller.rb +2 -2
- data/app/controllers/spotlight/catalog_controller.rb +7 -2
- data/app/controllers/spotlight/contact_email_controller.rb +8 -2
- data/app/controllers/spotlight/languages_controller.rb +9 -4
- data/app/helpers/spotlight/application_helper.rb +7 -0
- data/app/helpers/spotlight/crop_helper.rb +4 -0
- data/app/helpers/spotlight/meta_helper.rb +59 -36
- data/app/javascript/spotlight/admin/blacklight_configuration.js +1 -1
- data/app/javascript/spotlight/admin/block_mixins/autocompleteable.js +70 -34
- data/app/javascript/spotlight/admin/blocks/block.js +1 -0
- data/app/javascript/spotlight/admin/blocks/browse_block.js +8 -12
- data/app/javascript/spotlight/admin/blocks/browse_group_categories_block.js +14 -18
- data/app/javascript/spotlight/admin/blocks/pages_block.js +6 -10
- data/app/javascript/spotlight/admin/blocks/resources_block.js +33 -15
- data/app/javascript/spotlight/admin/blocks/solr_documents_base_block.js +11 -6
- data/app/javascript/spotlight/admin/blocks/solr_documents_embed_block.js +1 -0
- data/app/javascript/spotlight/admin/blocks/uploaded_items_block.js +4 -3
- data/app/javascript/spotlight/admin/copy_email_addresses.js +2 -0
- data/app/javascript/spotlight/admin/crop.js +45 -17
- data/app/javascript/spotlight/admin/croppable.js +8 -1
- data/app/javascript/spotlight/admin/croppable_modal.js +68 -0
- data/app/javascript/spotlight/admin/exhibits.js +15 -10
- data/app/javascript/spotlight/admin/form_observer.js +1 -1
- data/app/javascript/spotlight/admin/index.js +0 -10
- data/app/javascript/spotlight/admin/locks.js +15 -5
- data/app/javascript/spotlight/admin/pages.js +1 -1
- data/app/javascript/spotlight/admin/search_typeahead.js +62 -55
- data/app/javascript/spotlight/admin/spotlight_nestable.js +173 -50
- data/app/javascript/spotlight/admin/visibility_toggle.js +1 -11
- data/app/javascript/spotlight/controllers/index.js +8 -0
- data/app/javascript/spotlight/controllers/tag_selector_controller.js +203 -0
- data/app/javascript/spotlight/core.js +4 -6
- data/app/javascript/spotlight/index.js +2 -0
- data/app/javascript/spotlight/user/browse_group_categories.js +2 -0
- data/app/javascript/spotlight/user/carousel.js +3 -1
- data/app/javascript/spotlight/user/index.js +0 -2
- data/app/models/sir_trevor_rails/block.rb +5 -4
- data/app/models/sir_trevor_rails/blocks/solr_documents_block.rb +1 -1
- data/app/models/sir_trevor_rails/blocks/solr_documents_embed_block.rb +1 -1
- data/app/models/sir_trevor_rails/blocks/uploaded_items_block.rb +1 -1
- data/app/models/spotlight/page_configurations.rb +1 -1
- data/app/views/catalog/_add_tags.html.erb +2 -2
- data/app/views/catalog/_change_visibility.html.erb +1 -1
- data/app/views/catalog/_remove_tags.html.erb +2 -2
- data/app/views/layouts/spotlight/base.html.erb +24 -13
- data/app/views/layouts/spotlight/spotlight.html.erb +6 -6
- data/app/views/shared/_masthead.html.erb +4 -31
- data/app/views/shared/_site_sidebar.html.erb +1 -1
- data/app/views/shared/_user_util_links.html.erb +3 -1
- data/app/views/spotlight/accessibility/alt_text.html.erb +2 -2
- data/app/views/spotlight/admin_users/index.html.erb +3 -3
- data/app/views/spotlight/appearances/edit.html.erb +1 -1
- data/app/views/spotlight/browse/_search_box.html.erb +8 -8
- data/app/views/spotlight/browse/show.html.erb +1 -1
- data/app/views/spotlight/bulk_updates/_download.html.erb +1 -1
- data/app/views/spotlight/bulk_updates/_upload.html.erb +1 -1
- data/app/views/spotlight/catalog/_admin_header.html.erb +1 -1
- data/app/views/spotlight/catalog/_edit_default.html.erb +2 -1
- data/app/views/spotlight/catalog/select_image.html.erb +1 -0
- data/app/views/spotlight/contacts/_form.html.erb +1 -1
- data/app/views/spotlight/exhibits/_contact.html.erb +5 -6
- data/app/views/spotlight/exhibits/_delete.html.erb +1 -1
- data/app/views/spotlight/exhibits/_languages.html.erb +3 -2
- data/app/views/spotlight/featured_images/_form.html.erb +6 -2
- data/app/views/spotlight/featured_images/_upload_form.html.erb +1 -1
- data/app/views/spotlight/metadata_configurations/_metadata_field.html.erb +1 -1
- data/app/views/spotlight/metadata_configurations/edit.html.erb +6 -6
- data/app/views/spotlight/pages/show.html.erb +1 -1
- data/app/views/spotlight/resources/csv_upload/_form.html.erb +1 -1
- data/app/views/spotlight/resources/upload/_form.html.erb +1 -1
- data/app/views/spotlight/roles/index.html.erb +1 -1
- data/app/views/spotlight/searches/_form.html.erb +1 -1
- data/app/views/spotlight/shared/_dd3_item.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_browse_group_categories_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_solr_documents_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_solr_documents_carousel_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_uploaded_items_block.html.erb +1 -1
- data/app/views/spotlight/tags/index.html.erb +2 -3
- data/app/views/spotlight/translations/_import.html.erb +2 -2
- data/config/importmap.rb +5 -0
- data/config/locales/spotlight.en.yml +2 -0
- data/config/routes.rb +5 -3
- data/lib/generators/spotlight/assets/generator_common_utilities.rb +36 -0
- data/lib/generators/spotlight/assets/importmap_generator.rb +87 -0
- data/lib/generators/spotlight/assets/propshaft_generator.rb +96 -0
- data/lib/generators/spotlight/assets_generator.rb +22 -0
- data/lib/generators/spotlight/install_generator.rb +8 -36
- data/lib/generators/spotlight/scaffold_resource_generator.rb +1 -1
- data/lib/generators/spotlight/templates/assets/spotlight.scss +6 -0
- data/lib/generators/spotlight/templates/javascript/jquery-shim.js +1 -0
- data/lib/spotlight/engine.rb +7 -6
- data/lib/spotlight/version.rb +1 -1
- data/spec/support/features/capybara_wait_metadata_helper.rb +13 -0
- data/spec/support/features/test_features_helpers.rb +16 -30
- data/vendor/assets/javascripts/tiny-slider.js +3 -0
- metadata +35 -87
- data/app/assets/stylesheets/spotlight/#_accessibility.scss# +0 -12
- data/app/javascript/spotlight/admin/checkbox_submit.js +0 -75
- data/app/javascript/spotlight/admin/exhibit_tag_autocomplete.js +0 -39
- data/app/javascript/spotlight/user/report_a_problem.js +0 -30
- data/app/views/spotlight/browse/_tophat.html.erb +0 -1
- data/app/views/spotlight/catalog/_tophat_default.html.erb +0 -1
- data/app/views/spotlight/home_pages/_tophat.html.erb +0 -2
- data/app/views/spotlight/pages/_tophat.html.erb +0 -1
- data/lib/generators/spotlight/templates/spotlight.js +0 -1
- data/lib/generators/spotlight/templates/spotlight.scss +0 -5
- data/spec/support/features/capybara_default_max_wait_metadata_helper.rb +0 -20
- data/vendor/assets/javascripts/bootstrap-tagsinput.js +0 -530
- data/vendor/assets/javascripts/jquery.serializejson.js +0 -234
- data/vendor/assets/javascripts/nestable.js +0 -645
- data/vendor/assets/javascripts/sir-trevor.js +0 -23508
- data/vendor/assets/javascripts/typeahead.bundle.min.js +0 -7
- data/vendor/assets/stylesheets/bootstrap-tagsinput.css +0 -46
@@ -8,30 +8,26 @@ SirTrevor.Blocks.BrowseGroupCategories = (function(){
|
|
8
8
|
return Core.Block.Resources.extend({
|
9
9
|
type: "browse_group_categories",
|
10
10
|
icon_name: "browse",
|
11
|
-
bloodhoundOptions: function() {
|
12
|
-
var that = this;
|
13
|
-
return {
|
14
|
-
prefetch: {
|
15
|
-
url: this.autocomplete_url(),
|
16
|
-
ttl: 0,
|
17
|
-
filter: function(response) {
|
18
|
-
// Let the dom know that the response has been returned
|
19
|
-
$(that.inner).attr('data-browse-groups-fetched', true);
|
20
|
-
return response;
|
21
|
-
}
|
22
|
-
}
|
23
|
-
};
|
24
|
-
},
|
25
11
|
|
26
12
|
autocomplete_control: function() {
|
27
|
-
|
13
|
+
const autocompleteID = this.blockID + '-autocomplete';
|
14
|
+
return `<auto-complete src="${this.autocomplete_url()}" for="${autocompleteID}-popup" fetch-on-empty>
|
15
|
+
<input type="text" name="${autocompleteID}" placeholder="${i18n.t("blocks:browse_group_categories:autocomplete")}" data-default-typeahead>
|
16
|
+
<ul id="${autocompleteID}-popup"></ul>
|
17
|
+
<div id="${autocompleteID}-popup-feedback" class="sr-only visually-hidden"></div>
|
18
|
+
</auto-complete>`
|
28
19
|
},
|
29
20
|
autocomplete_template: function(obj) {
|
30
21
|
return `<div class="autocomplete-item${!obj.published ? ' blacklight-private' : ''}">
|
31
|
-
<span class="autocomplete-title">${obj.title}</span><br/></div>`
|
22
|
+
<span class="autocomplete-title">${this.highlight(obj.title)}</span><br/></div>`
|
32
23
|
},
|
33
24
|
|
34
|
-
autocomplete_url: function() {
|
25
|
+
autocomplete_url: function() {
|
26
|
+
return document.getElementById(this.instanceID).closest('form[data-autocomplete-exhibit-browse-groups-path]').dataset.autocompleteExhibitBrowseGroupsPath;
|
27
|
+
},
|
28
|
+
autocomplete_fetch: function(url) {
|
29
|
+
return this.fetchOnceAndFilterLocalResults(url);
|
30
|
+
},
|
35
31
|
_itemPanel: function(data) {
|
36
32
|
var index = "item_" + this.globalIndex++;
|
37
33
|
var checked;
|
@@ -42,7 +38,7 @@ SirTrevor.Blocks.BrowseGroupCategories = (function(){
|
|
42
38
|
}
|
43
39
|
var resource_id = data.slug || data.id;
|
44
40
|
var markup = `
|
45
|
-
<li class="field
|
41
|
+
<li class="field dd-item dd3-item" data-resource-id="${resource_id}" data-id="${index}" id="${this.formId(index)}">
|
46
42
|
<input type="hidden" name="item[${index}][id]" value="${resource_id}" />
|
47
43
|
<input type="hidden" name="item[${index}][title]" value="${data.title}" />
|
48
44
|
<input data-property="weight" type="hidden" name="item[${index}][weight]" value="${data.weight}" />
|
@@ -7,20 +7,16 @@ SirTrevor.Blocks.FeaturedPages = (function(){
|
|
7
7
|
|
8
8
|
icon_name: "pages",
|
9
9
|
|
10
|
-
autocomplete_url: function() { return
|
10
|
+
autocomplete_url: function() { return document.getElementById(this.instanceID).closest('form[data-autocomplete-exhibit-pages-path]').dataset.autocompleteExhibitPagesPath; },
|
11
|
+
autocomplete_fetch: function(url) {
|
12
|
+
return this.fetchOnceAndFilterLocalResults(url);
|
13
|
+
},
|
11
14
|
autocomplete_template: function(obj) {
|
15
|
+
const description = obj.description ? `<small> ${obj.description}</small>` : '';
|
12
16
|
const thumbnail = obj.thumbnail_image_url ? `<div class="document-thumbnail"><img class="img-thumbnail" src="${obj.thumbnail_image_url}" /></div>` : ''
|
13
17
|
return `<div class="autocomplete-item${!obj.published ? ' blacklight-private' : ''}">${thumbnail}
|
14
|
-
<span class="autocomplete-title">${obj.title}</span><br
|
18
|
+
<span class="autocomplete-title">${this.highlight(obj.title)}</span><br/>${description}</div>`
|
15
19
|
},
|
16
|
-
bloodhoundOptions: function() {
|
17
|
-
return {
|
18
|
-
prefetch: {
|
19
|
-
url: this.autocomplete_url(),
|
20
|
-
ttl: 0
|
21
|
-
}
|
22
|
-
};
|
23
|
-
}
|
24
20
|
});
|
25
21
|
|
26
22
|
})();
|
@@ -8,11 +8,12 @@ Core.Block.Resources = (function(){
|
|
8
8
|
formable: true,
|
9
9
|
autocompleteable: true,
|
10
10
|
show_heading: true,
|
11
|
+
show_image_selection: true,
|
11
12
|
title: function() { return i18n.t("blocks:" + this.type + ":title"); },
|
12
13
|
description: function() { return i18n.t("blocks:" + this.type + ":description"); },
|
13
14
|
alt_text_guidelines: function() {
|
14
15
|
if (this.showAltText()) {
|
15
|
-
return i18n.t("blocks:alt_text_guidelines:intro");
|
16
|
+
return i18n.t("blocks:alt_text_guidelines:intro");
|
16
17
|
}
|
17
18
|
return "";
|
18
19
|
},
|
@@ -20,7 +21,7 @@ Core.Block.Resources = (function(){
|
|
20
21
|
if (this.showAltText()) {
|
21
22
|
var link_url = i18n.t("blocks:alt_text_guidelines:link_url");
|
22
23
|
var link_label = i18n.t("blocks:alt_text_guidelines:link_label");
|
23
|
-
return '<a target="_blank" href="' + link_url + '">' + link_label + '</a>';
|
24
|
+
return '<a target="_blank" href="' + link_url + '">' + link_label + '</a>';
|
24
25
|
}
|
25
26
|
return "";
|
26
27
|
},
|
@@ -59,7 +60,16 @@ Core.Block.Resources = (function(){
|
|
59
60
|
.map(word => word.charAt(0).toUpperCase() + word.slice(1))
|
60
61
|
.join('');
|
61
62
|
},
|
62
|
-
|
63
|
+
_itemSelectImageLink: function(block_item_id, doc_id, index) {
|
64
|
+
// If image selection is not possible for this block, then do not show
|
65
|
+
// image selection link
|
66
|
+
if (!this.show_image_selection) return ``;
|
67
|
+
var url = $('form[data-exhibit-path]').data('exhibit-path') + '/select_image?';
|
68
|
+
var markup = `
|
69
|
+
<a name="selectimage" href="${url}block_item_id=${block_item_id}&index_id=${index}" data-blacklight-modal="trigger">Select image area</a>
|
70
|
+
`;
|
71
|
+
return markup;
|
72
|
+
},
|
63
73
|
_itemPanel: function(data) {
|
64
74
|
var index = "item_" + this.globalIndex++;
|
65
75
|
var checked;
|
@@ -69,8 +79,9 @@ Core.Block.Resources = (function(){
|
|
69
79
|
checked = "";
|
70
80
|
}
|
71
81
|
var resource_id = data.slug || data.id;
|
82
|
+
var block_item_id = this.formId(index);
|
72
83
|
var markup = `
|
73
|
-
<li class="field
|
84
|
+
<li class="field dd-item dd3-item" data-cropper="select_image_${block_item_id}" data-resource-id="${resource_id}" data-id="${index}" id="${block_item_id}" data-input-prefix="item[${index}]">
|
74
85
|
<input type="hidden" name="item[${index}][id]" value="${resource_id}" />
|
75
86
|
<input type="hidden" name="item[${index}][title]" value="${data.title}" />
|
76
87
|
${this._itemPanelIiifFields(index, data)}
|
@@ -79,13 +90,20 @@ Core.Block.Resources = (function(){
|
|
79
90
|
<div class="dd-handle dd3-handle">${i18n.t("blocks:resources:panel:drag")}</div>
|
80
91
|
<div class="card-header item-grid">
|
81
92
|
<div class="d-flex">
|
82
|
-
<div class="
|
83
|
-
<
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
93
|
+
<div class="d-inline-block">
|
94
|
+
<div class="d-flex">
|
95
|
+
<div class="checkbox">
|
96
|
+
<input name="item[${index}][display]" type="hidden" value="false" />
|
97
|
+
<input name="item[${index}][display]" id="${this.formId(this.display_checkbox + '_' + data.id)}" type="checkbox" ${checked} class="item-grid-checkbox" value="true" />
|
98
|
+
<label class="sr-only visually-hidden" for="${this.formId(this.display_checkbox + '_' + data.id)}">${i18n.t("blocks:resources:panel:display")}</label>
|
99
|
+
</div>
|
100
|
+
<div class="pic">
|
101
|
+
<img class="img-thumbnail" src="${(data.thumbnail_image_url || ((data.iiif_tilesource || "").replace("/info.json", "/full/!100,100/0/default.jpg")))}" />
|
102
|
+
</div>
|
103
|
+
</div>
|
104
|
+
<div class="d-inline-block">
|
105
|
+
${this._itemSelectImageLink(block_item_id,data.id, index)}
|
106
|
+
</div>
|
89
107
|
</div>
|
90
108
|
<div class="main">
|
91
109
|
<div class="title card-title">${data.title}</div>
|
@@ -118,7 +136,7 @@ Core.Block.Resources = (function(){
|
|
118
136
|
},
|
119
137
|
|
120
138
|
afterPanelRender: function(data, panel) {
|
121
|
-
|
139
|
+
|
122
140
|
},
|
123
141
|
|
124
142
|
afterPanelDelete: function() {
|
@@ -183,7 +201,7 @@ Core.Block.Resources = (function(){
|
|
183
201
|
<div class="me-2 mr-2">
|
184
202
|
<label class="col-form-label pb-0 pt-1" for="${this.formId(this.alt_text_textarea + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:alternative_text")}</label>
|
185
203
|
<div class="form-check mb-1 justify-content-end">
|
186
|
-
<input class="form-check-input" type="checkbox"
|
204
|
+
<input class="form-check-input" type="checkbox"
|
187
205
|
id="${this.formId(this.decorative_checkbox + '_' + data.id)}" name="item[${index}][decorative]" ${isDecorative ? 'checked' : ''}>
|
188
206
|
<label class="form-check-label" for="${this.formId(this.decorative_checkbox + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:decorative")}</label>
|
189
207
|
</div>
|
@@ -223,7 +241,6 @@ Core.Block.Resources = (function(){
|
|
223
241
|
|
224
242
|
onBlockRender: function() {
|
225
243
|
SpotlightNestable.init($('[data-behavior="nestable"]', this.inner));
|
226
|
-
|
227
244
|
$('[data-input-select-target]', this.inner).selectRelatedInput();
|
228
245
|
},
|
229
246
|
|
@@ -232,7 +249,8 @@ Core.Block.Resources = (function(){
|
|
232
249
|
$.each(Object.keys(data.item || {}).map(function(k) { return data.item[k]}).sort(function(a,b) { return a.weight - b.weight; }), function(index, item) {
|
233
250
|
context.createItemPanel(item);
|
234
251
|
});
|
235
|
-
|
252
|
+
|
253
|
+
}
|
236
254
|
});
|
237
255
|
|
238
256
|
})();
|
@@ -5,11 +5,11 @@ SirTrevor.Blocks.SolrDocumentsBase = (function(){
|
|
5
5
|
|
6
6
|
return Core.Block.Resources.extend({
|
7
7
|
plustextable: true,
|
8
|
-
autocomplete_url: function() { return this.$instance().closest('form[data-autocomplete-exhibit-catalog-path]').data('autocomplete-exhibit-catalog-path')
|
8
|
+
autocomplete_url: function() { return this.$instance().closest('form[data-autocomplete-exhibit-catalog-path]').data('autocomplete-exhibit-catalog-path') },
|
9
9
|
autocomplete_template: function(obj) {
|
10
10
|
const thumbnail = obj.thumbnail ? `<div class="document-thumbnail"><img class="img-thumbnail" src="${obj.thumbnail}" /></div>` : ''
|
11
11
|
return `<div class="autocomplete-item${obj.private ? ' blacklight-private' : ''}">${thumbnail}
|
12
|
-
<span class="autocomplete-title">${obj.title}</span><br/><small> ${obj.description}</small></div>`
|
12
|
+
<span class="autocomplete-title">${this.highlight(obj.title)}</span><br/><small> ${this.highlight(obj.description)}</small></div>`
|
13
13
|
},
|
14
14
|
transform_autocomplete_results: function(response) {
|
15
15
|
return $.map(response['docs'], function(doc) {
|
@@ -50,16 +50,21 @@ SirTrevor.Blocks.SolrDocumentsBase = (function(){
|
|
50
50
|
|
51
51
|
// Sets the first version of the IIIF information from autocomplete data.
|
52
52
|
_itemPanelIiifFields: function(index, autocomplete_data) {
|
53
|
-
|
54
|
-
// '<input type="hidden" name="item[' + index + '][iiif_region]" value="' + (data.iiif_region) + '"/>',
|
55
|
-
// for legacy compatiblity:
|
53
|
+
var iiifFields = [
|
56
54
|
'<input type="hidden" name="item[' + index + '][thumbnail_image_url]" value="' + (autocomplete_data.thumbnail_image_url || autocomplete_data.thumbnail || "") + '"/>',
|
57
55
|
'<input type="hidden" name="item[' + index + '][full_image_url]" value="' + (autocomplete_data.full_image_url || autocomplete_data.thumbnail_image_url || autocomplete_data.thumbnail || "") + '"/>',
|
58
56
|
'<input type="hidden" name="item[' + index + '][iiif_tilesource]" value="' + (autocomplete_data.iiif_tilesource) + '"/>',
|
59
57
|
'<input type="hidden" name="item[' + index + '][iiif_manifest_url]" value="' + (autocomplete_data.iiif_manifest_url) + '"/>',
|
60
58
|
'<input type="hidden" name="item[' + index + '][iiif_canvas_id]" value="' + (autocomplete_data.iiif_canvas_id) + '"/>',
|
61
59
|
'<input type="hidden" name="item[' + index + '][iiif_image_id]" value="' + (autocomplete_data.iiif_image_id) + '"/>',
|
62
|
-
]
|
60
|
+
];
|
61
|
+
|
62
|
+
// The region input is required for widgets that enable image cropping but not otherwise
|
63
|
+
if(this.show_image_selection) {
|
64
|
+
iiifFields.push('<input type="hidden" name="item[' + index + '][iiif_region]" value="' + (autocomplete_data.iiif_region || "") + '"/>');
|
65
|
+
}
|
66
|
+
|
67
|
+
return iiifFields.join("\n");
|
63
68
|
},
|
64
69
|
// Overwrites the hidden inputs from _itemPanelIiifFields with data from the
|
65
70
|
// manifest. Called by afterPanelRender - the manifest_data here is built
|
@@ -6,7 +6,8 @@ SirTrevor.Blocks.UploadedItems = (function(){
|
|
6
6
|
plustextable: true,
|
7
7
|
uploadable: true,
|
8
8
|
autocompleteable: false,
|
9
|
-
|
9
|
+
show_image_selection: false,
|
10
|
+
|
10
11
|
id_key: 'file',
|
11
12
|
|
12
13
|
type: 'uploaded_items',
|
@@ -70,7 +71,7 @@ SirTrevor.Blocks.UploadedItems = (function(){
|
|
70
71
|
var dataUrl = data.url || data.file.url;
|
71
72
|
|
72
73
|
var markup = `
|
73
|
-
<li class="field
|
74
|
+
<li class="field dd-item dd3-item" data-id="${index}" id="${this.formId(index)}">
|
74
75
|
<input type="hidden" name="item[${index}][id]" value="${dataId}" />
|
75
76
|
<input type="hidden" name="item[${index}][title]" value="${dataTitle}" />
|
76
77
|
<input type="hidden" name="item[${index}][url]" data-item-grid-thumbnail="true" value="${dataUrl}"/>
|
@@ -152,7 +153,7 @@ SirTrevor.Blocks.UploadedItems = (function(){
|
|
152
153
|
<div class="col-lg-3 ps-md-2 pl-md-2">
|
153
154
|
<label class="col-form-label text-nowrap pb-0 pt-1 justify-content-md-start justify-content-lg-end d-flex" for="${this.formId(this.alt_text_textarea + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:alternative_text")}</label>
|
154
155
|
<div class="form-check d-flex justify-content-md-start justify-content-lg-end">
|
155
|
-
<input class="form-check-input" type="checkbox"
|
156
|
+
<input class="form-check-input" type="checkbox"
|
156
157
|
id="${this.formId(this.decorative_checkbox + '_' + data.id)}" name="item[${index}][decorative]" ${isDecorative ? 'checked' : ''}>
|
157
158
|
<label class="form-check-label" for="${this.formId(this.decorative_checkbox + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:decorative")}</label>
|
158
159
|
</div>
|
@@ -2,22 +2,37 @@ import { addImageSelector } from 'spotlight/admin/add_image_selector'
|
|
2
2
|
import Core from 'spotlight/core'
|
3
3
|
|
4
4
|
export default class Crop {
|
5
|
-
constructor(cropArea) {
|
5
|
+
constructor(cropArea, preserveAspectRatio = true) {
|
6
6
|
this.cropArea = cropArea;
|
7
7
|
this.cropArea.data('iiifCropper', this);
|
8
|
+
// This element will also have the IIIF input elements contained
|
9
|
+
// There may be multiple elements with data-cropper attributes, but
|
10
|
+
// there should only one element with this data-cropper attribute value.
|
8
11
|
this.cropSelector = '[data-cropper="' + cropArea.data('cropperKey') + '"]';
|
9
12
|
this.cropTool = $(this.cropSelector);
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
this.
|
14
|
-
|
15
|
-
this.
|
16
|
-
|
13
|
+
// Exhibit and masthead cropping requires the ratio between image width and height
|
14
|
+
// to be consistent, whereas item widget cropping allows any combination of
|
15
|
+
// image width and height.
|
16
|
+
this.preserveAspectRatio = preserveAspectRatio;
|
17
|
+
// Get the IIIF input elements used to store/reference IIIF information
|
18
|
+
this.inputPrefix = this.cropTool.data('input-prefix');
|
19
|
+
this.iiifUrlField = this.iiifInputElement(this.inputPrefix, 'iiif_tilesource', this.cropTool);
|
20
|
+
this.iiifRegionField = this.iiifInputElement(this.inputPrefix, 'iiif_region', this.cropTool);
|
21
|
+
this.iiifManifestField = this.iiifInputElement(this.inputPrefix, 'iiif_manifest_url', this.cropTool);
|
22
|
+
this.iiifCanvasField = this.iiifInputElement(this.inputPrefix, 'iiif_canvas_id', this.cropTool);
|
23
|
+
this.iiifImageField = this.iiifInputElement(this.inputPrefix, 'iiif_image_id', this.cropTool);
|
24
|
+
// Get the closest form element
|
17
25
|
this.form = cropArea.closest('form');
|
18
26
|
this.tileSource = null;
|
19
27
|
}
|
20
28
|
|
29
|
+
// Return the iiif input element based on the fieldname.
|
30
|
+
// Multiple input fields with the same name on the page may be related
|
31
|
+
// to a cropper. We thus need to pass in a parent element.
|
32
|
+
iiifInputElement(inputPrefix, fieldName, inputParentElement) {
|
33
|
+
return $('input[name="' + inputPrefix + '[' + fieldName + ']"]', inputParentElement);
|
34
|
+
}
|
35
|
+
|
21
36
|
// Render the cropper environment and add hooks into the autocomplete and upload forms
|
22
37
|
render() {
|
23
38
|
this.setupAutoCompletes();
|
@@ -152,15 +167,21 @@ export default class Crop {
|
|
152
167
|
if (this.cropperMap) {
|
153
168
|
return;
|
154
169
|
}
|
155
|
-
|
170
|
+
|
171
|
+
var cropperOptions = {
|
156
172
|
editable: true,
|
157
173
|
center: [0, 0],
|
158
174
|
crs: L.CRS.Simple,
|
159
|
-
zoom: 0
|
160
|
-
|
175
|
+
zoom: 0
|
176
|
+
}
|
177
|
+
|
178
|
+
if(this.preserveAspectRatio) {
|
179
|
+
cropperOptions['editOptions'] = {
|
161
180
|
rectangleEditorClass: this.aspectRatioPreservingRectangleEditor(this.aspectRatio())
|
162
|
-
}
|
163
|
-
}
|
181
|
+
};
|
182
|
+
}
|
183
|
+
|
184
|
+
this.cropperMap = L.map(this.cropArea.attr('id'), cropperOptions);
|
164
185
|
this.invalidateMapSizeOnTabToggle();
|
165
186
|
}
|
166
187
|
|
@@ -228,9 +249,12 @@ export default class Crop {
|
|
228
249
|
}
|
229
250
|
|
230
251
|
var input = $('[data-behavior="autocomplete"]', this.cropTool);
|
231
|
-
|
232
|
-
|
233
|
-
|
252
|
+
|
253
|
+
// Not every page which uses this module has autocomplete linked directly to the cropping tool
|
254
|
+
if(input.length) {
|
255
|
+
var panel = $(input.data('target-panel'));
|
256
|
+
addImageSelector(input, panel, this.iiifManifestField.val(), !this.iiifImageField.val());
|
257
|
+
}
|
234
258
|
}
|
235
259
|
|
236
260
|
invalidateMapSizeOnTabToggle() {
|
@@ -280,7 +304,11 @@ export default class Crop {
|
|
280
304
|
}
|
281
305
|
|
282
306
|
setUploadId(id) {
|
283
|
-
|
307
|
+
// This input is currently used for exhibit masthead or thumbnail image upload.
|
308
|
+
// The name should be sufficient in this case, as we don't use this part of the
|
309
|
+
// code for solr document widgets where we enable cropping.
|
310
|
+
// If we require more specificity, we can scope this to this.cropTool.
|
311
|
+
$('input[name="' + this.inputPrefix + '[upload_id]"]').val(id);
|
284
312
|
}
|
285
313
|
|
286
314
|
aspectRatioPreservingRectangleEditor(aspect) {
|
@@ -1,10 +1,17 @@
|
|
1
1
|
import Crop from 'spotlight/admin/crop';
|
2
|
+
import CroppableModal from 'spotlight/admin/croppable_modal';
|
2
3
|
|
3
|
-
export default class {
|
4
|
+
export default class Croppable {
|
4
5
|
connect() {
|
6
|
+
// For exhibit masthead or thumbnail pages, where
|
7
|
+
// the div exists on page load
|
5
8
|
$('[data-behavior="iiif-cropper"]').each(function() {
|
6
9
|
var cropElement = $(this)
|
7
10
|
new Crop(cropElement).render()
|
8
11
|
})
|
12
|
+
|
13
|
+
// In the case of individual document thumbnails, selection
|
14
|
+
// of the image is through a modal. Here we attach the event
|
15
|
+
new CroppableModal().attachModalHandlers();
|
9
16
|
}
|
10
17
|
}
|
@@ -0,0 +1,68 @@
|
|
1
|
+
import Crop from 'spotlight/admin/crop';
|
2
|
+
|
3
|
+
export default class CroppableModal {
|
4
|
+
|
5
|
+
attachModalHandlers() {
|
6
|
+
// Attach handler for when modal first loads, to show the cropper
|
7
|
+
this.attachModalLoadBehavior();
|
8
|
+
// Attach handler for save by checking if clicking in the modal is on a save button
|
9
|
+
this.attachModalSaveHandler();
|
10
|
+
}
|
11
|
+
|
12
|
+
attachModalLoadBehavior() {
|
13
|
+
// Listen for event thrown when modal is displayed with content
|
14
|
+
document.addEventListener('loaded.blacklight.blacklight-modal', function(e) {
|
15
|
+
var dataCropperDiv = $('#blacklight-modal [data-behavior="iiif-cropper"]');
|
16
|
+
|
17
|
+
if(dataCropperDiv) {
|
18
|
+
new Crop(dataCropperDiv, false).render();
|
19
|
+
}
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
// Field names are of the format item[item_0][iiif_image_id]
|
24
|
+
iiifInputField(itemIndex, fieldName, parentElement) {
|
25
|
+
var itemPrefix = 'item[' + itemIndex + ']';
|
26
|
+
var selector = 'input[name="' + itemPrefix + '[' + fieldName + ']"]';
|
27
|
+
return $(selector, parentElement);
|
28
|
+
}
|
29
|
+
|
30
|
+
attachModalSaveHandler() {
|
31
|
+
var context = this;
|
32
|
+
|
33
|
+
document.addEventListener('show.blacklight.blacklight-modal', function(e) {
|
34
|
+
$('#save-cropping-selection').on('click', () => {
|
35
|
+
context.saveCroppedRegion();
|
36
|
+
});
|
37
|
+
});
|
38
|
+
}
|
39
|
+
|
40
|
+
saveCroppedRegion() {
|
41
|
+
//On hitting "save changes", we need to copy over the value
|
42
|
+
//to the iiif thumbnail url input field as well as the image source itself
|
43
|
+
var context = this;
|
44
|
+
var dataCropperDiv = $('#blacklight-modal [data-behavior="iiif-cropper"]');
|
45
|
+
|
46
|
+
if(dataCropperDiv) {
|
47
|
+
var dataCropperKey = dataCropperDiv.data("cropper-key");
|
48
|
+
var itemIndex = dataCropperDiv.data("index-id");
|
49
|
+
// Get the element on the main edit page whose select image link opened up the modal
|
50
|
+
var itemElement = $('[data-cropper="' + dataCropperKey + '"]');
|
51
|
+
// Get the hidden input field on the main edit page corresponding to this item
|
52
|
+
var thumbnailSaveField = context.iiifInputField(itemIndex, 'thumbnail_image_url', itemElement);
|
53
|
+
var fullimageSaveField = context.iiifInputField(itemIndex, 'full_image_url', itemElement);
|
54
|
+
var iiifTilesource = context.iiifInputField(itemIndex, 'iiif_tilesource', itemElement).val();
|
55
|
+
var regionValue = context.iiifInputField(itemIndex, 'iiif_region', itemElement).val();
|
56
|
+
// Extract the region string to incorporate into the thumbnail URL
|
57
|
+
var urlPrefix = iiifTilesource.substring(0, iiifTilesource.lastIndexOf('/info.json'));
|
58
|
+
var thumbnailUrl = urlPrefix + '/' + regionValue + '/!400,400/0/default.jpg';
|
59
|
+
// Set the hidden input value to the thumbnail URL
|
60
|
+
// Also set the full image - which is used by widgets like carousel or slideshow
|
61
|
+
thumbnailSaveField.val(thumbnailUrl);
|
62
|
+
fullimageSaveField.val(urlPrefix + '/' + regionValue + '/!800,800/0/default.jpg');
|
63
|
+
// Also change img url for thumbnail image
|
64
|
+
var itemImage = $('img.img-thumbnail', itemElement);
|
65
|
+
itemImage.attr('src', thumbnailUrl);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
}
|
@@ -41,21 +41,26 @@ export default class {
|
|
41
41
|
$(inputContainer).insertAfter(contacts.last());
|
42
42
|
});
|
43
43
|
|
44
|
-
|
45
|
-
|
46
|
-
}
|
47
|
-
|
48
|
-
$('.contact-email-delete').on('ajax:error', function(event, _xhr, _status, error) {
|
49
|
-
var errSpan = $(this).closest('.contact').find('.contact-email-delete-error');
|
50
|
-
errSpan.show();
|
51
|
-
errSpan.find('.error-msg').first().text(error || event.detail[1]);
|
52
|
-
});
|
44
|
+
if (document.getElementById('another-email')) {
|
45
|
+
document.addEventListener('turbo:submit-end', this.contactToDeleteNotFoundHandler);
|
46
|
+
}
|
53
47
|
|
54
|
-
|
48
|
+
if ($.fn.tooltip) {
|
49
|
+
$('.btn-with-tooltip').tooltip();
|
50
|
+
}
|
55
51
|
|
56
52
|
// Put focus in saved search title input when Save this search modal is shown
|
57
53
|
$('#save-modal').on('shown.bs.modal', function () {
|
58
54
|
$('#search_title').focus();
|
59
55
|
});
|
60
56
|
}
|
57
|
+
|
58
|
+
contactToDeleteNotFoundHandler(e) {
|
59
|
+
const contact = e.detail.formSubmission?.delegate?.element?.querySelector('.contact')
|
60
|
+
if (contact && e.detail?.fetchResponse?.response?.status === 404) {
|
61
|
+
const error = contact.querySelector('.contact-email-delete-error');
|
62
|
+
error.style.display = 'block';
|
63
|
+
error.querySelector('.error-msg').textContent = 'Not Found';
|
64
|
+
}
|
65
|
+
}
|
61
66
|
}
|
@@ -68,7 +68,7 @@ export default class {
|
|
68
68
|
connect() {
|
69
69
|
// Instantiate the singleton SerializedForm plugin
|
70
70
|
var serializedForm = $.SerializedForm();
|
71
|
-
$(window).on('beforeunload page:before-change turbolinks:before-visit', function(event) {
|
71
|
+
$(window).on('beforeunload page:before-change turbolinks:before-visit turbo:before-visit', function(event) {
|
72
72
|
// Don't handle the same event twice #turbolinks
|
73
73
|
if (event.handled !== true) {
|
74
74
|
if ( serializedForm.observedFormsStatusHasChanged() ) {
|
@@ -1,18 +1,9 @@
|
|
1
|
-
// These scripts are in the vendor directory
|
2
|
-
import 'nestable'
|
3
|
-
import 'bootstrap-tagsinput'
|
4
|
-
import 'jquery.serializejson'
|
5
|
-
import 'leaflet-iiif'
|
6
|
-
import 'Leaflet.Editable'
|
7
|
-
import 'Path.Drag'
|
8
|
-
|
9
1
|
import AddAnother from 'spotlight/admin/add_another'
|
10
2
|
import AddNewButton from 'spotlight/admin/add_new_button'
|
11
3
|
import BlacklightConfiguration from 'spotlight/admin/blacklight_configuration'
|
12
4
|
import CopyEmailAddress from 'spotlight/admin/copy_email_addresses'
|
13
5
|
import Croppable from 'spotlight/admin/croppable'
|
14
6
|
import EditInPlace from 'spotlight/admin/edit_in_place'
|
15
|
-
import ExhibitTagAutocomplete from 'spotlight/admin/exhibit_tag_autocomplete'
|
16
7
|
import Exhibits from 'spotlight/admin/exhibits'
|
17
8
|
import FormObserver from 'spotlight/admin/form_observer'
|
18
9
|
import Locks from 'spotlight/admin/locks'
|
@@ -62,7 +53,6 @@ export default class {
|
|
62
53
|
new CopyEmailAddress().connect()
|
63
54
|
new Croppable().connect()
|
64
55
|
new EditInPlace().connect()
|
65
|
-
new ExhibitTagAutocomplete().connect()
|
66
56
|
new Exhibits().connect()
|
67
57
|
new FormObserver().connect()
|
68
58
|
new Locks().connect()
|
@@ -1,12 +1,22 @@
|
|
1
1
|
export default class {
|
2
2
|
delete_lock(el) {
|
3
|
-
|
4
|
-
|
3
|
+
const csrfToken = document.querySelector('meta[name="csrf-token"]')?.content;
|
4
|
+
|
5
|
+
fetch(el.dataset.lock, {
|
6
|
+
method: 'DELETE',
|
7
|
+
headers: {
|
8
|
+
'X-CSRF-Token': csrfToken
|
9
|
+
}
|
10
|
+
});
|
11
|
+
|
12
|
+
el.removeAttribute('data-lock');
|
5
13
|
}
|
6
14
|
|
7
15
|
connect() {
|
8
|
-
|
9
|
-
|
10
|
-
|
16
|
+
document.querySelectorAll('[data-lock]').forEach(element => {
|
17
|
+
element.addEventListener('click', (e) => {
|
18
|
+
this.delete_lock(e.target);
|
19
|
+
});
|
20
|
+
});
|
11
21
|
}
|
12
22
|
}
|
@@ -5,7 +5,7 @@ import Core from 'spotlight/core'
|
|
5
5
|
export default class {
|
6
6
|
connect(){
|
7
7
|
SirTrevor.setDefaults({
|
8
|
-
iconUrl: Spotlight.sirTrevorIcon
|
8
|
+
iconUrl: Spotlight.sirTrevorIcon,
|
9
9
|
uploadUrl: $('[data-attachment-endpoint]').data('attachment-endpoint'),
|
10
10
|
ajaxOptions: {
|
11
11
|
headers: {
|