blacklight-spotlight 5.3.0 → 5.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +18 -1
- data/app/assets/javascripts/spotlight/spotlight.esm.js +1696 -1229
- data/app/assets/javascripts/spotlight/spotlight.esm.js.map +1 -1
- data/app/assets/javascripts/spotlight/spotlight.js +1718 -1232
- data/app/assets/javascripts/spotlight/spotlight.js.map +1 -1
- data/app/assets/stylesheets/spotlight/_multi_up_item_grid.scss +1 -10
- data/app/assets/stylesheets/spotlight/_nestable.scss +18 -1
- data/app/assets/stylesheets/spotlight/_pages.scss +3 -3
- data/app/components/spotlight/analytics/aggregation_component.html.erb +1 -1
- data/app/components/spotlight/document_admin_table_component.html.erb +2 -2
- data/app/components/spotlight/edit_view_links_component.html.erb +1 -1
- data/app/components/spotlight/header_component.html.erb +1 -1
- data/app/components/spotlight/tag_list_form_component.html.erb +1 -1
- data/app/components/spotlight/tag_selector_component.html.erb +2 -2
- data/app/components/spotlight/translations/subheading_component.html.erb +1 -1
- data/app/controllers/spotlight/resources_controller.rb +1 -1
- data/app/javascript/spotlight/admin/add_another.js +22 -15
- data/app/javascript/spotlight/admin/add_image_selector.js +27 -25
- data/app/javascript/spotlight/admin/add_new_button.js +47 -43
- data/app/javascript/spotlight/admin/blacklight_configuration.js +52 -38
- data/app/javascript/spotlight/admin/block_mixins/autocompleteable.js +68 -60
- data/app/javascript/spotlight/admin/block_mixins/formable.js +55 -47
- data/app/javascript/spotlight/admin/block_mixins/plustextable.js +19 -20
- data/app/javascript/spotlight/admin/blocks/block.js +20 -16
- data/app/javascript/spotlight/admin/blocks/browse_block.js +42 -37
- data/app/javascript/spotlight/admin/blocks/browse_group_categories_block.js +33 -31
- data/app/javascript/spotlight/admin/blocks/iframe_block.js +14 -11
- data/app/javascript/spotlight/admin/blocks/link_to_search_block.js +4 -7
- data/app/javascript/spotlight/admin/blocks/oembed_block.js +13 -10
- data/app/javascript/spotlight/admin/blocks/pages_block.js +20 -13
- data/app/javascript/spotlight/admin/blocks/resources_block.js +150 -117
- data/app/javascript/spotlight/admin/blocks/rule_block.js +11 -10
- data/app/javascript/spotlight/admin/blocks/search_result_block.js +16 -17
- data/app/javascript/spotlight/admin/blocks/solr_documents_base_block.js +123 -64
- data/app/javascript/spotlight/admin/blocks/solr_documents_block.js +8 -8
- data/app/javascript/spotlight/admin/blocks/solr_documents_carousel_block.js +63 -43
- data/app/javascript/spotlight/admin/blocks/solr_documents_embed_block.js +9 -9
- data/app/javascript/spotlight/admin/blocks/solr_documents_features_block.js +17 -16
- data/app/javascript/spotlight/admin/blocks/solr_documents_grid_block.js +6 -7
- data/app/javascript/spotlight/admin/blocks/uploaded_items_block.js +84 -64
- data/app/javascript/spotlight/admin/crop.js +203 -156
- data/app/javascript/spotlight/admin/croppable.js +4 -4
- data/app/javascript/spotlight/admin/croppable_modal.js +59 -37
- data/app/javascript/spotlight/admin/edit_in_place.js +50 -47
- data/app/javascript/spotlight/admin/exhibits.js +52 -41
- data/app/javascript/spotlight/admin/form_observer.js +59 -53
- data/app/javascript/spotlight/admin/iiif.js +26 -25
- data/app/javascript/spotlight/admin/index.js +44 -47
- data/app/javascript/spotlight/admin/locks.js +14 -14
- data/app/javascript/spotlight/admin/multi_image_selector.js +127 -111
- data/app/javascript/spotlight/admin/pages.js +21 -21
- data/app/javascript/spotlight/admin/progress_monitor.js +67 -65
- data/app/javascript/spotlight/admin/readonly_checkbox.js +3 -3
- data/app/javascript/spotlight/admin/search_typeahead.js +55 -43
- data/app/javascript/spotlight/admin/select_related_input.js +17 -17
- data/app/javascript/spotlight/admin/sir-trevor/block_controls.js +100 -84
- data/app/javascript/spotlight/admin/sir-trevor/block_limits.js +36 -31
- data/app/javascript/spotlight/admin/sir-trevor/locales.js +52 -39
- data/app/javascript/spotlight/admin/spotlight_nestable.js +126 -91
- data/app/javascript/spotlight/admin/tabs.js +19 -3
- data/app/javascript/spotlight/admin/translation_progress.js +13 -7
- data/app/javascript/spotlight/admin/users.js +41 -41
- data/app/javascript/spotlight/admin/visibility_toggle.js +4 -4
- data/app/javascript/spotlight/controllers/clipboard_controller.js +14 -0
- data/app/javascript/spotlight/controllers/index.js +4 -2
- data/app/javascript/spotlight/controllers/tag_selector_controller.js +116 -79
- data/app/javascript/spotlight/core.js +18 -15
- data/app/javascript/spotlight/index.js +4 -4
- data/app/javascript/spotlight/user/browse_group_categories.js +24 -22
- data/app/javascript/spotlight/user/carousel.js +23 -19
- data/app/javascript/spotlight/user/clear_form_button.js +15 -15
- data/app/javascript/spotlight/user/index.js +4 -4
- data/app/javascript/spotlight/user/zpr_links.js +18 -18
- data/app/models/spotlight/analytics/ga.rb +0 -1
- data/app/models/spotlight/resources/iiif_manifest_v3.rb +2 -2
- data/app/services/spotlight/exhibit_import_export_service.rb +0 -2
- data/app/views/blacklight/nav/_bookmark.html.erb +1 -1
- data/app/views/catalog/_remove_tags.html.erb +1 -1
- data/app/views/layouts/spotlight/base.html.erb +1 -1
- data/app/views/shared/_header_navbar.html.erb +1 -1
- data/app/views/shared/_masthead.html.erb +2 -2
- data/app/views/shared/_site_sidebar.html.erb +1 -1
- data/app/views/shared/_user_util_links.html.erb +2 -2
- data/app/views/spotlight/about_pages/_contacts.html.erb +1 -1
- data/app/views/spotlight/accessibility/alt_text.html.erb +1 -1
- data/app/views/spotlight/admin_users/index.html.erb +11 -9
- data/app/views/spotlight/appearances/edit.html.erb +1 -1
- data/app/views/spotlight/browse/_search_box.html.erb +1 -1
- data/app/views/spotlight/bulk_updates/_download.html.erb +1 -1
- data/app/views/spotlight/bulk_updates/_progress_panel.html.erb +6 -6
- data/app/views/spotlight/bulk_updates/edit.html.erb +1 -1
- data/app/views/spotlight/catalog/_admin_header.html.erb +1 -1
- data/app/views/spotlight/catalog/_admin_index_header_default.html.erb +1 -1
- data/app/views/spotlight/catalog/_curation_mode_toggle_default.html.erb +1 -1
- data/app/views/spotlight/catalog/_document.html.erb +2 -2
- data/app/views/spotlight/catalog/_document_admin_table.html.erb +1 -1
- data/app/views/spotlight/catalog/_edit_sidecar.html.erb +1 -1
- data/app/views/spotlight/catalog/_index_compact_default.html.erb +1 -1
- data/app/views/spotlight/catalog/_reindex_progress_panel.html.erb +6 -6
- data/app/views/spotlight/catalog/select_image.html.erb +1 -1
- data/app/views/spotlight/contact_mailer/report_problem.html.erb +2 -2
- data/app/views/spotlight/exhibits/_contact.html.erb +2 -2
- data/app/views/spotlight/exhibits/_delete.html.erb +2 -2
- data/app/views/spotlight/exhibits/_exhibit_card.html.erb +1 -1
- data/app/views/spotlight/exhibits/_export.html.erb +1 -1
- data/app/views/spotlight/exhibits/_form.html.erb +2 -2
- data/app/views/spotlight/exhibits/_languages.html.erb +7 -7
- data/app/views/spotlight/exhibits/_missing_exhibits.html.erb +1 -1
- data/app/views/spotlight/locks/_lock.html.erb +2 -2
- data/app/views/spotlight/metadata_configurations/edit.html.erb +1 -1
- data/app/views/spotlight/pages/_order_pages.html.erb +3 -3
- data/app/views/spotlight/pages/preview.html.erb +1 -1
- data/app/views/spotlight/pages/show.html.erb +2 -2
- data/app/views/spotlight/resources/_form.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 +5 -5
- data/app/views/spotlight/search_configurations/_search_fields.html.erb +1 -1
- data/app/views/spotlight/search_configurations/edit.html.erb +1 -1
- data/app/views/spotlight/searches/index.html.erb +2 -2
- data/app/views/spotlight/shared/_configuration_sidebar.html.erb +1 -1
- data/app/views/spotlight/shared/_curation_sidebar.html.erb +1 -1
- data/app/views/spotlight/shared/_dd3_item.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/_sir_trevor_block_array.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_browse_block.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/_featured_pages_block.html.erb +2 -2
- data/app/views/spotlight/sir_trevor/blocks/_link_to_search_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_rule_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_search_results_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/_solr_documents_features_block.html.erb +1 -1
- data/app/views/spotlight/sir_trevor/blocks/_solr_documents_grid_block.html.erb +1 -1
- data/app/views/spotlight/sites/edit_exhibits.html.erb +3 -3
- data/app/views/spotlight/translations/_browse_categories.html.erb +2 -2
- data/app/views/spotlight/translations/_general.html.erb +21 -21
- data/app/views/spotlight/translations/_groups.html.erb +1 -1
- data/app/views/spotlight/translations/_metadata.html.erb +8 -8
- data/app/views/spotlight/translations/_pages_table.html.erb +2 -2
- data/app/views/spotlight/translations/_search_fields.html.erb +13 -13
- data/app/views/spotlight/translations/edit.html.erb +5 -5
- data/config/importmap.rb +0 -1
- data/lib/generators/spotlight/assets/propshaft_generator.rb +0 -1
- data/lib/generators/spotlight/templates/solr/conf/admin-extra.html +31 -31
- data/lib/spotlight/version.rb +1 -1
- data/spec/factories/contact_images.rb +1 -1
- data/spec/factories/exhibit_thumbnails.rb +1 -1
- data/spec/factories/featured_images.rb +1 -1
- data/spec/support/features/test_features_helpers.rb +41 -1
- metadata +4 -61
- data/app/javascript/spotlight/admin/copy_email_addresses.js +0 -7
- data/vendor/assets/javascripts/jquery.waitforimages.min.js +0 -2
|
@@ -1,39 +1,44 @@
|
|
|
1
|
-
import Core from
|
|
1
|
+
import Core from "spotlight/core"
|
|
2
2
|
|
|
3
|
-
Core.BlockLimits = function(editor) {
|
|
4
|
-
this.editor = editor
|
|
5
|
-
}
|
|
3
|
+
Core.BlockLimits = function (editor) {
|
|
4
|
+
this.editor = editor
|
|
5
|
+
}
|
|
6
6
|
|
|
7
|
-
Core.BlockLimits.prototype.enforceLimits = function(editor) {
|
|
8
|
-
this.addEditorCallbacks(editor)
|
|
9
|
-
this.checkGlobalBlockTypeLimit()()
|
|
10
|
-
}
|
|
7
|
+
Core.BlockLimits.prototype.enforceLimits = function (editor) {
|
|
8
|
+
this.addEditorCallbacks(editor)
|
|
9
|
+
this.checkGlobalBlockTypeLimit()()
|
|
10
|
+
}
|
|
11
11
|
|
|
12
|
-
Core.BlockLimits.prototype.addEditorCallbacks = function(
|
|
13
|
-
SirTrevor.EventBus.on(
|
|
14
|
-
SirTrevor.EventBus.on(
|
|
15
|
-
}
|
|
12
|
+
Core.BlockLimits.prototype.addEditorCallbacks = function (_editor) {
|
|
13
|
+
SirTrevor.EventBus.on("block:create:new", this.checkBlockTypeLimitOnAdd())
|
|
14
|
+
SirTrevor.EventBus.on("block:remove", this.checkGlobalBlockTypeLimit())
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
Core.BlockLimits.prototype.checkBlockTypeLimitOnAdd = function() {
|
|
18
|
-
var editor = this.editor
|
|
17
|
+
Core.BlockLimits.prototype.checkBlockTypeLimitOnAdd = function () {
|
|
18
|
+
var editor = this.editor
|
|
19
19
|
|
|
20
|
-
return function(block) {
|
|
21
|
-
var control = $(
|
|
20
|
+
return function (block) {
|
|
21
|
+
var control = $(
|
|
22
|
+
".st-block-controls__button[data-type='" + block.type + "']",
|
|
23
|
+
editor.blockControls.el,
|
|
24
|
+
)
|
|
22
25
|
|
|
23
|
-
control.prop("disabled", !editor.blockManager.canCreateBlock(block.class()))
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
+
control.prop("disabled", !editor.blockManager.canCreateBlock(block.class()))
|
|
27
|
+
}
|
|
28
|
+
}
|
|
26
29
|
|
|
27
|
-
Core.BlockLimits.prototype.checkGlobalBlockTypeLimit = function() {
|
|
30
|
+
Core.BlockLimits.prototype.checkGlobalBlockTypeLimit = function () {
|
|
28
31
|
// we don't know what type of block was created or removed.. So, try them all.
|
|
29
|
-
var editor = this.editor
|
|
30
|
-
|
|
31
|
-
return function() {
|
|
32
|
-
$.each(editor.blockManager.blockTypes, function(i, type) {
|
|
33
|
-
var block_type = SirTrevor.Blocks[type].prototype
|
|
34
|
-
|
|
35
|
-
var control = $(editor.blockControls.el).find(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
32
|
+
var editor = this.editor
|
|
33
|
+
|
|
34
|
+
return function () {
|
|
35
|
+
$.each(editor.blockManager.blockTypes, function (i, type) {
|
|
36
|
+
var block_type = SirTrevor.Blocks[type].prototype
|
|
37
|
+
|
|
38
|
+
var control = $(editor.blockControls.el).find(
|
|
39
|
+
".st-block-controls__button[data-type='" + block_type.type + "']",
|
|
40
|
+
)
|
|
41
|
+
control.prop("disabled", !editor.blockManager.canCreateBlock(type))
|
|
42
|
+
})
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -1,111 +1,123 @@
|
|
|
1
1
|
SirTrevor.Locales.en.blocks = $.extend(SirTrevor.Locales.en.blocks, {
|
|
2
2
|
autocompleteable: {
|
|
3
|
-
placeholder: "Enter a title..."
|
|
3
|
+
placeholder: "Enter a title...",
|
|
4
4
|
},
|
|
5
5
|
|
|
6
6
|
browse: {
|
|
7
7
|
title: "Browse Categories",
|
|
8
|
-
description:
|
|
9
|
-
|
|
8
|
+
description:
|
|
9
|
+
"This widget highlights browse categories. Each highlighted category links to the corresponding browse category results page.",
|
|
10
|
+
item_counts: "Include item counts?",
|
|
10
11
|
},
|
|
11
12
|
|
|
12
13
|
browse_group_categories: {
|
|
13
14
|
autocomplete: "Enter a browse group title...",
|
|
14
15
|
title: "Browse Group Categories",
|
|
15
|
-
description:
|
|
16
|
-
|
|
16
|
+
description:
|
|
17
|
+
"This widget displays all browse categories associated with a selected browse group as a horizontally-scrolling row. Each selected browse group is displayed as a separate row. Each displayed category in a group links to the corresponding browse category results page.",
|
|
18
|
+
item_counts: "Include category item counts?",
|
|
17
19
|
},
|
|
18
20
|
|
|
19
21
|
link_to_search: {
|
|
20
22
|
title: "Saved Searches",
|
|
21
|
-
description:
|
|
22
|
-
|
|
23
|
+
description:
|
|
24
|
+
"This widget highlights saved searches. Each highlighted saved search links to the search results page generated by the saved search parameters. Any saved search listed on the Curation > Browse categories page, whether published or not, can be highlighted as a saved search.",
|
|
25
|
+
item_counts: "Include item counts?",
|
|
23
26
|
},
|
|
24
27
|
|
|
25
28
|
iframe: {
|
|
26
|
-
title:
|
|
29
|
+
title: "IFrame",
|
|
27
30
|
description: "This widget embeds iframe-based embed code into pages",
|
|
28
|
-
placeholder: "Enter embed code here. It should begin with e.g. '<iframe'"
|
|
31
|
+
placeholder: "Enter embed code here. It should begin with e.g. '<iframe'",
|
|
29
32
|
},
|
|
30
33
|
|
|
31
34
|
oembed: {
|
|
32
35
|
title: "Embed + Text",
|
|
33
|
-
description:
|
|
36
|
+
description:
|
|
37
|
+
"This widget embeds an oEmbed-supported web resource and a text block to the left or right of it. Examples of oEmbed-supported resources include those from YouTube, Twitter, Flickr, and SlideShare.",
|
|
34
38
|
url: "URL",
|
|
35
39
|
},
|
|
36
40
|
|
|
37
41
|
uploaded_items: {
|
|
38
42
|
title: "Uploaded Item Row",
|
|
39
|
-
description:
|
|
40
|
-
|
|
41
|
-
|
|
43
|
+
description:
|
|
44
|
+
"This widget displays uploaded items in a horizontal row. Optionally, you can add a heading and/or text to be displayed adjacent to the items. The item caption and link URL fields are also optional.",
|
|
45
|
+
caption: "Caption",
|
|
46
|
+
link: "Link URL",
|
|
42
47
|
},
|
|
43
48
|
|
|
44
49
|
featured_pages: {
|
|
45
|
-
title:
|
|
46
|
-
description:
|
|
50
|
+
title: "Pages",
|
|
51
|
+
description:
|
|
52
|
+
"This widget highlights pages from this exhibit. Each highlighted item links to the corresponding page.",
|
|
47
53
|
},
|
|
48
54
|
|
|
49
55
|
resources: {
|
|
50
56
|
panel: {
|
|
51
57
|
drag: "Drag",
|
|
52
58
|
display: "Display?",
|
|
53
|
-
remove: "Remove"
|
|
59
|
+
remove: "Remove",
|
|
54
60
|
},
|
|
55
61
|
alt_text: {
|
|
56
62
|
decorative: "Decorative",
|
|
57
63
|
alternative_text: "Alternative text",
|
|
58
|
-
placeholder: "Enter alt text for this item..."
|
|
59
|
-
}
|
|
64
|
+
placeholder: "Enter alt text for this item...",
|
|
65
|
+
},
|
|
60
66
|
},
|
|
61
67
|
|
|
62
68
|
rule: {
|
|
63
|
-
title: "Horizontal Rule"
|
|
69
|
+
title: "Horizontal Rule",
|
|
64
70
|
},
|
|
65
71
|
|
|
66
72
|
search_results: {
|
|
67
73
|
title: "Search Results",
|
|
68
|
-
description:
|
|
74
|
+
description:
|
|
75
|
+
"This widget displays a set of search results on a page. Specify a search result set by selecting an existing browse category. You can also select the view types that are available to the user when viewing the result set.",
|
|
69
76
|
},
|
|
70
77
|
|
|
71
78
|
solr_documents: {
|
|
72
79
|
title: "Item Row",
|
|
73
|
-
description:
|
|
80
|
+
description:
|
|
81
|
+
"This widget displays exhibit items in a horizontal row. Optionally, you can add a heading and/or text to be displayed adjacent to the items.",
|
|
74
82
|
caption: {
|
|
75
83
|
placeholder: "Select...",
|
|
76
84
|
primary: "Primary caption",
|
|
77
|
-
secondary: "Secondary caption"
|
|
85
|
+
secondary: "Secondary caption",
|
|
78
86
|
},
|
|
79
87
|
zpr: {
|
|
80
|
-
title: 'Offer "View larger" option'
|
|
81
|
-
}
|
|
88
|
+
title: 'Offer "View larger" option',
|
|
89
|
+
},
|
|
82
90
|
},
|
|
83
91
|
|
|
84
92
|
solr_documents_carousel: {
|
|
85
93
|
title: "Item Carousel",
|
|
86
|
-
description:
|
|
94
|
+
description:
|
|
95
|
+
"This widget displays exhibit items in a carousel. You can configure the item captions, how the images are cycled, and the size of the carousel.",
|
|
87
96
|
interval: {
|
|
88
97
|
title: "Automatically cycle images",
|
|
89
|
-
placeholder: "Select..."
|
|
98
|
+
placeholder: "Select...",
|
|
90
99
|
},
|
|
91
100
|
height: {
|
|
92
|
-
title: "Maximum carousel height"
|
|
93
|
-
}
|
|
101
|
+
title: "Maximum carousel height",
|
|
102
|
+
},
|
|
94
103
|
},
|
|
95
104
|
|
|
96
105
|
solr_documents_embed: {
|
|
97
106
|
title: "Item Embed",
|
|
98
|
-
description:
|
|
107
|
+
description:
|
|
108
|
+
"This widget embeds an exhibit item in a viewer on a page. Optionally, you can add a heading to be displayed above the viewer and/or text to be displayed adjacent to the viewer.",
|
|
99
109
|
},
|
|
100
110
|
|
|
101
111
|
solr_documents_features: {
|
|
102
112
|
title: "Item Slideshow",
|
|
103
|
-
description:
|
|
113
|
+
description:
|
|
114
|
+
"This widget displays exhibit items in a static slideshow. The user will move between items in the slideshow using the field you select as the primary caption.",
|
|
104
115
|
},
|
|
105
116
|
|
|
106
117
|
solr_documents_grid: {
|
|
107
118
|
title: "Item Grid",
|
|
108
|
-
description:
|
|
119
|
+
description:
|
|
120
|
+
"This widget displays exhibit items in a multi-row grid. Optionally, you can add a heading and/or text to be displayed adjacent to the items.",
|
|
109
121
|
},
|
|
110
122
|
|
|
111
123
|
textable: {
|
|
@@ -114,18 +126,19 @@ SirTrevor.Locales.en.blocks = $.extend(SirTrevor.Locales.en.blocks, {
|
|
|
114
126
|
align: {
|
|
115
127
|
title: "Display text on:",
|
|
116
128
|
left: "Left",
|
|
117
|
-
right: "Right"
|
|
118
|
-
}
|
|
129
|
+
right: "Right",
|
|
130
|
+
},
|
|
119
131
|
},
|
|
120
132
|
|
|
121
133
|
group: {
|
|
122
134
|
undefined: "Standard widgets",
|
|
123
|
-
items: "Exhibit item widgets"
|
|
135
|
+
items: "Exhibit item widgets",
|
|
124
136
|
},
|
|
125
137
|
|
|
126
138
|
alt_text_guidelines: {
|
|
127
|
-
intro:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
139
|
+
intro:
|
|
140
|
+
"For each item, please enter alternative text or appropriately check the decorative box. ",
|
|
141
|
+
link_label: "Guidelines for writing alt text.",
|
|
142
|
+
link_url: "https://www.w3.org/WAI/tutorials/images/",
|
|
143
|
+
},
|
|
144
|
+
})
|
|
@@ -1,68 +1,86 @@
|
|
|
1
|
-
import Sortable from
|
|
1
|
+
import Sortable from "sortablejs"
|
|
2
2
|
|
|
3
|
-
const Module = (function() {
|
|
4
|
-
const nestableContainerSelector = '[data-behavior="nestable"]'
|
|
3
|
+
const Module = (function () {
|
|
4
|
+
const nestableContainerSelector = '[data-behavior="nestable"]'
|
|
5
5
|
const sortableOptions = {
|
|
6
6
|
animation: 150,
|
|
7
|
-
draggable:
|
|
8
|
-
handle:
|
|
7
|
+
draggable: ".dd-item",
|
|
8
|
+
handle: ".dd-handle",
|
|
9
9
|
fallbackOnBody: true,
|
|
10
10
|
swapThreshold: 0.65,
|
|
11
|
-
|
|
11
|
+
// 0 turns off SortableJS's "drop near an empty list" check. The .dd-nesting drop
|
|
12
|
+
// zones in _nestable.scss decide nesting, so a vertical drag past an item's edge
|
|
13
|
+
// does not nest it by accident.
|
|
14
|
+
emptyInsertThreshold: 0,
|
|
12
15
|
onStart: onStartHandler,
|
|
13
16
|
onEnd: onEndHandler,
|
|
14
17
|
onMove: onMoveHandler,
|
|
15
18
|
}
|
|
16
|
-
const draggableClass =
|
|
17
|
-
const nestedSortableClass =
|
|
18
|
-
const nestedSortableSelector =
|
|
19
|
-
const nestedSortableNodeName =
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
const
|
|
24
|
-
const
|
|
25
|
-
const
|
|
26
|
-
|
|
19
|
+
const draggableClass = "dd-item"
|
|
20
|
+
const nestedSortableClass = "dd-list"
|
|
21
|
+
const nestedSortableSelector = ".dd-list"
|
|
22
|
+
const nestedSortableNodeName = "ol"
|
|
23
|
+
const nestingClass = "dd-nesting"
|
|
24
|
+
const findNode = (id, container) =>
|
|
25
|
+
container.querySelector(`[data-id="${id}"]`)
|
|
26
|
+
const setWeight = (node, weight) => (weightField(node).value = weight)
|
|
27
|
+
const setParent = (node, parentId) => (parentPageField(node).value = parentId)
|
|
28
|
+
const weightField = (node) => findProperty(node, "weight")
|
|
29
|
+
const parentPageField = (node) => findProperty(node, "parent_page")
|
|
30
|
+
const findProperty = (node, property) =>
|
|
31
|
+
node.querySelector(`input[data-property="${property}"]`)
|
|
32
|
+
let nestedId = 0
|
|
27
33
|
|
|
28
34
|
return {
|
|
29
|
-
init: function(nestedContainers) {
|
|
35
|
+
init: function (nestedContainers) {
|
|
30
36
|
if (nestedContainers === undefined) {
|
|
31
|
-
nestedContainers = document.querySelectorAll(nestableContainerSelector)
|
|
37
|
+
nestedContainers = document.querySelectorAll(nestableContainerSelector)
|
|
32
38
|
}
|
|
33
39
|
|
|
34
40
|
// nestedContainers could be a jQuery selector result, normalize to an array.
|
|
35
|
-
const containersToInit = Array.from(nestedContainers)
|
|
41
|
+
const containersToInit = Array.from(nestedContainers)
|
|
36
42
|
containersToInit.forEach((container) => {
|
|
37
43
|
// Sir Trevor listens for drag and drop events and will error on Sortable events.
|
|
38
44
|
// Don't let them bubble past the Sortable wrapper.
|
|
39
|
-
container.addEventListener(
|
|
40
|
-
|
|
45
|
+
container.addEventListener("drop", stopPropagationHandler)
|
|
46
|
+
|
|
41
47
|
const nestedSortables = [
|
|
42
48
|
...(container.matches(nestedSortableSelector) ? [container] : []),
|
|
43
|
-
...Array.from(container.querySelectorAll(nestedSortableSelector))
|
|
44
|
-
]
|
|
45
|
-
const group = `nested-${nestedId++}
|
|
46
|
-
|
|
47
|
-
nestedSortables.forEach(sortable => {
|
|
48
|
-
new Sortable(sortable, { ...sortableOptions, group: group })
|
|
49
|
-
})
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
|
-
}
|
|
49
|
+
...Array.from(container.querySelectorAll(nestedSortableSelector)),
|
|
50
|
+
]
|
|
51
|
+
const group = `nested-${nestedId++}`
|
|
52
|
+
|
|
53
|
+
nestedSortables.forEach((sortable) => {
|
|
54
|
+
new Sortable(sortable, { ...sortableOptions, group: group })
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
},
|
|
58
|
+
}
|
|
53
59
|
|
|
54
60
|
function stopPropagationHandler(evt) {
|
|
55
|
-
evt.stopPropagation()
|
|
61
|
+
evt.stopPropagation()
|
|
56
62
|
}
|
|
57
63
|
|
|
58
64
|
function onStartHandler(evt) {
|
|
59
|
-
|
|
65
|
+
const nestableContainer = getNestableContainer(evt.item)
|
|
66
|
+
makeEmptyChildSortablesForEligibleParents(
|
|
67
|
+
nestableContainer,
|
|
68
|
+
getMaxNestingLevelSetting(evt.item),
|
|
69
|
+
)
|
|
70
|
+
// Size the drop zone below each child list to match the dragged item, so that
|
|
71
|
+
// a drag straight to the right lands in the list of the item above.
|
|
72
|
+
nestableContainer.style.setProperty(
|
|
73
|
+
"--dd-nesting-zone-height",
|
|
74
|
+
`${evt.item.querySelector(sortableOptions.handle).offsetHeight}px`,
|
|
75
|
+
)
|
|
76
|
+
nestableContainer.classList.add(nestingClass)
|
|
60
77
|
}
|
|
61
78
|
|
|
62
79
|
function onEndHandler(evt) {
|
|
63
|
-
const nestableContainer = getNestableContainer(evt.item)
|
|
64
|
-
|
|
65
|
-
|
|
80
|
+
const nestableContainer = getNestableContainer(evt.item)
|
|
81
|
+
nestableContainer.classList.remove(nestingClass)
|
|
82
|
+
removeEmptySortables(nestableContainer)
|
|
83
|
+
updateWeightsAndRelationships(nestableContainer)
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
function onMoveHandler(evt) {
|
|
@@ -70,122 +88,139 @@ const Module = (function() {
|
|
|
70
88
|
// E.g., data-max-depth=2 allows for one level of nesting.
|
|
71
89
|
// evt.dragged is a draggable in a Sortable (e.g., a dd-item)
|
|
72
90
|
// evt.to is the Sortable to insert into (e.g., a dd-list)
|
|
73
|
-
const maxAllowedDepth = getMaxNestingLevelSetting(evt.to) - 1
|
|
74
|
-
const newDepth = getSortableDepth(evt.to) + getHeight(evt.dragged)
|
|
91
|
+
const maxAllowedDepth = getMaxNestingLevelSetting(evt.to) - 1
|
|
92
|
+
const newDepth = getSortableDepth(evt.to) + getHeight(evt.dragged)
|
|
75
93
|
|
|
76
94
|
// Be careful here. Returning true is different than returning nothing in SortableJS.
|
|
77
95
|
if (newDepth > maxAllowedDepth) {
|
|
78
|
-
return false
|
|
96
|
+
return false
|
|
79
97
|
}
|
|
80
98
|
}
|
|
81
99
|
|
|
82
100
|
// Get the depth of the sortable element from the root container
|
|
83
101
|
function getSortableDepth(sortableElement) {
|
|
84
|
-
const originatingGroup = Sortable.get(sortableElement).options.group.name
|
|
85
|
-
let depth = 0
|
|
86
|
-
let parentSortableElement = sortableElement
|
|
87
|
-
|
|
88
|
-
while (
|
|
89
|
-
|
|
102
|
+
const originatingGroup = Sortable.get(sortableElement).options.group.name
|
|
103
|
+
let depth = 0
|
|
104
|
+
let parentSortableElement = sortableElement
|
|
105
|
+
|
|
106
|
+
while (
|
|
107
|
+
(parentSortableElement = parentSortableElement.parentElement.closest(
|
|
108
|
+
nestedSortableSelector,
|
|
109
|
+
))
|
|
110
|
+
) {
|
|
111
|
+
const parentSortable = Sortable.get(parentSortableElement)
|
|
90
112
|
if (parentSortable?.options.group.name === originatingGroup) {
|
|
91
|
-
depth
|
|
113
|
+
depth++
|
|
92
114
|
}
|
|
93
115
|
}
|
|
94
116
|
|
|
95
|
-
return depth
|
|
117
|
+
return depth
|
|
96
118
|
}
|
|
97
119
|
|
|
98
120
|
// Find the max child depth in the tree, starting from the draggableElement
|
|
99
121
|
function findMaxDepth(draggableElement) {
|
|
100
|
-
const childSortableElement = draggableElement.querySelector(
|
|
122
|
+
const childSortableElement = draggableElement.querySelector(
|
|
123
|
+
nestedSortableSelector,
|
|
124
|
+
)
|
|
101
125
|
if (!childSortableElement) {
|
|
102
|
-
return 1
|
|
126
|
+
return 1
|
|
103
127
|
}
|
|
104
128
|
|
|
105
|
-
const children = childSortableElement.querySelectorAll(`.${draggableClass}`)
|
|
106
|
-
const childDepths = Array.from(children).map(findMaxDepth)
|
|
107
|
-
return 1 + Math.max(0, ...childDepths)
|
|
129
|
+
const children = childSortableElement.querySelectorAll(`.${draggableClass}`)
|
|
130
|
+
const childDepths = Array.from(children).map(findMaxDepth)
|
|
131
|
+
return 1 + Math.max(0, ...childDepths)
|
|
108
132
|
}
|
|
109
133
|
|
|
110
134
|
function getHeight(draggableElement) {
|
|
111
|
-
return findMaxDepth(draggableElement) - 1
|
|
135
|
+
return findMaxDepth(draggableElement) - 1
|
|
112
136
|
}
|
|
113
137
|
|
|
114
138
|
function getNestableContainer(element) {
|
|
115
|
-
return element.closest(nestableContainerSelector)
|
|
139
|
+
return element.closest(nestableContainerSelector)
|
|
116
140
|
}
|
|
117
141
|
|
|
118
142
|
function getMaxNestingLevelSetting(element) {
|
|
119
|
-
return getNestableContainer(element).getAttribute(
|
|
143
|
+
return getNestableContainer(element).getAttribute("data-max-depth") || 1
|
|
120
144
|
}
|
|
121
145
|
|
|
122
146
|
// Create empty child sortables for all potential parents as appropriate for the given nesting level
|
|
123
147
|
function makeEmptyChildSortablesForEligibleParents(container, nestingLevel) {
|
|
124
148
|
if (nestingLevel <= 1) {
|
|
125
|
-
return
|
|
149
|
+
return
|
|
126
150
|
}
|
|
127
151
|
|
|
128
|
-
const sortableElement = container.querySelector(nestedSortableSelector)
|
|
129
|
-
const sortable = Sortable.get(sortableElement)
|
|
152
|
+
const sortableElement = container.querySelector(nestedSortableSelector)
|
|
153
|
+
const sortable = Sortable.get(sortableElement)
|
|
130
154
|
if (!sortable) {
|
|
131
|
-
return
|
|
155
|
+
return
|
|
132
156
|
}
|
|
133
157
|
|
|
134
|
-
const group = sortable.options.group.name
|
|
135
|
-
const draggableElements = Array.from(sortableElement.children)
|
|
136
|
-
|
|
158
|
+
const group = sortable.options.group.name
|
|
159
|
+
const draggableElements = Array.from(sortableElement.children).filter(
|
|
160
|
+
(child) => child.classList.contains(draggableClass),
|
|
161
|
+
)
|
|
137
162
|
|
|
138
|
-
draggableElements.forEach(draggableElement => {
|
|
163
|
+
draggableElements.forEach((draggableElement) => {
|
|
139
164
|
if (!draggableElement.querySelector(nestedSortableSelector)) {
|
|
140
|
-
const emptySortableElement = document.createElement(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
165
|
+
const emptySortableElement = document.createElement(
|
|
166
|
+
nestedSortableNodeName,
|
|
167
|
+
)
|
|
168
|
+
emptySortableElement.className = nestedSortableClass
|
|
169
|
+
draggableElement.appendChild(emptySortableElement)
|
|
170
|
+
new Sortable(emptySortableElement, {
|
|
171
|
+
...sortableOptions,
|
|
172
|
+
group: group,
|
|
173
|
+
})
|
|
144
174
|
}
|
|
145
|
-
makeEmptyChildSortablesForEligibleParents(
|
|
146
|
-
|
|
175
|
+
makeEmptyChildSortablesForEligibleParents(
|
|
176
|
+
draggableElement,
|
|
177
|
+
nestingLevel - 1,
|
|
178
|
+
)
|
|
179
|
+
})
|
|
147
180
|
}
|
|
148
181
|
|
|
149
182
|
// Remove any empty sortables within the container. They could be empty lists, which are invalid for accessibility.
|
|
150
183
|
function removeEmptySortables(container) {
|
|
151
|
-
const sortableElements = container.querySelectorAll(nestedSortableSelector)
|
|
152
|
-
sortableElements.forEach(sortableElement => {
|
|
153
|
-
if (sortableElement.innerHTML.trim() ===
|
|
154
|
-
const sortable = Sortable.get(sortableElement)
|
|
184
|
+
const sortableElements = container.querySelectorAll(nestedSortableSelector)
|
|
185
|
+
sortableElements.forEach((sortableElement) => {
|
|
186
|
+
if (sortableElement.innerHTML.trim() === "") {
|
|
187
|
+
const sortable = Sortable.get(sortableElement)
|
|
155
188
|
if (sortable) {
|
|
156
|
-
sortable.destroy()
|
|
157
|
-
sortableElement.remove()
|
|
189
|
+
sortable.destroy()
|
|
190
|
+
sortableElement.remove()
|
|
158
191
|
}
|
|
159
192
|
}
|
|
160
|
-
})
|
|
193
|
+
})
|
|
161
194
|
}
|
|
162
195
|
|
|
163
196
|
// Traverse all sortables within a container and update the weight and parent_page inputs
|
|
164
197
|
function updateWeightsAndRelationships(container) {
|
|
165
|
-
const sortableElement = container.matches(nestedSortableSelector)
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
const
|
|
169
|
-
|
|
198
|
+
const sortableElement = container.matches(nestedSortableSelector)
|
|
199
|
+
? container
|
|
200
|
+
: container.querySelector(nestedSortableSelector)
|
|
201
|
+
const nestingLevelSetting = getMaxNestingLevelSetting(sortableElement)
|
|
202
|
+
const sortable = Sortable.get(sortableElement)
|
|
203
|
+
const stack = [{ nodes: sortable.toArray(), parentId: "" }]
|
|
204
|
+
let weight = 0
|
|
170
205
|
|
|
171
206
|
while (stack.length > 0) {
|
|
172
|
-
const {nodes, parentId} = stack.pop()
|
|
207
|
+
const { nodes, parentId } = stack.pop()
|
|
173
208
|
|
|
174
209
|
nodes.forEach((nodeId) => {
|
|
175
|
-
const node = findNode(nodeId, container)
|
|
176
|
-
setWeight(node, weight++)
|
|
210
|
+
const node = findNode(nodeId, container)
|
|
211
|
+
setWeight(node, weight++)
|
|
177
212
|
|
|
178
213
|
if (nestingLevelSetting > 1) {
|
|
179
|
-
setParent(node, parentId)
|
|
180
|
-
const children = node.querySelector(nestedSortableSelector)
|
|
214
|
+
setParent(node, parentId)
|
|
215
|
+
const children = node.querySelector(nestedSortableSelector)
|
|
181
216
|
if (children) {
|
|
182
|
-
const sortableElement = Sortable.get(children)
|
|
183
|
-
stack.push({nodes: sortableElement.toArray(), parentId: nodeId})
|
|
217
|
+
const sortableElement = Sortable.get(children)
|
|
218
|
+
stack.push({ nodes: sortableElement.toArray(), parentId: nodeId })
|
|
184
219
|
}
|
|
185
220
|
}
|
|
186
|
-
})
|
|
221
|
+
})
|
|
187
222
|
}
|
|
188
223
|
}
|
|
189
|
-
})()
|
|
224
|
+
})()
|
|
190
225
|
|
|
191
226
|
export default Module
|
|
@@ -1,8 +1,24 @@
|
|
|
1
|
+
import * as bootstrap from "bootstrap"
|
|
2
|
+
|
|
3
|
+
// Bootstrap's ESM build exports Tab by name; CDN-converted UMD builds (e.g. ga.jspm.io) only have a default export
|
|
4
|
+
const Tab = bootstrap.Tab ?? bootstrap.default?.Tab
|
|
5
|
+
|
|
1
6
|
export default class {
|
|
2
7
|
connect() {
|
|
3
|
-
if (
|
|
4
|
-
|
|
5
|
-
|
|
8
|
+
if (document.querySelector("[role=tabpanel]") && window.location.hash) {
|
|
9
|
+
const targetId = window.location.hash.substring(1)
|
|
10
|
+
const targetElement = document.getElementById(targetId)
|
|
11
|
+
if (!targetElement) return
|
|
12
|
+
|
|
13
|
+
const tabpanel = targetElement.closest("[role=tabpanel]")
|
|
14
|
+
if (!tabpanel) return
|
|
15
|
+
|
|
16
|
+
const tabElement = document.querySelector(
|
|
17
|
+
`a[role=tab][href="#${tabpanel.id}"]`,
|
|
18
|
+
)
|
|
19
|
+
if (!tabElement) return
|
|
20
|
+
|
|
21
|
+
Tab.getOrCreateInstance(tabElement).show()
|
|
6
22
|
}
|
|
7
23
|
}
|
|
8
24
|
}
|
|
@@ -4,13 +4,19 @@
|
|
|
4
4
|
// present (indicated by data attributes) in each tab's content
|
|
5
5
|
export default class {
|
|
6
6
|
connect() {
|
|
7
|
-
$('[data-behavior="translation-progress"]').each(function(){
|
|
8
|
-
var currentTab = $(this)
|
|
9
|
-
var tabName = $(this).attr(
|
|
10
|
-
var translationFields = $(
|
|
11
|
-
|
|
7
|
+
$('[data-behavior="translation-progress"]').each(function () {
|
|
8
|
+
var currentTab = $(this)
|
|
9
|
+
var tabName = $(this).attr("aria-controls")
|
|
10
|
+
var translationFields = $("#" + tabName).find(
|
|
11
|
+
'[data-translation-progress-item="true"]',
|
|
12
|
+
)
|
|
13
|
+
var completedTranslations = $("#" + tabName).find(
|
|
14
|
+
'[data-translation-present="true"]',
|
|
15
|
+
)
|
|
12
16
|
|
|
13
|
-
currentTab
|
|
17
|
+
currentTab
|
|
18
|
+
.find("span")
|
|
19
|
+
.text(completedTranslations.length + "/" + translationFields.length)
|
|
14
20
|
})
|
|
15
21
|
}
|
|
16
|
-
}
|
|
22
|
+
}
|