app/assets/javascripts/spotlight/spotlight.js in blacklight-spotlight-4.2.0 vs app/assets/javascripts/spotlight/spotlight.js in blacklight-spotlight-4.3.0

- old
+ new

@@ -5139,10 +5139,11 @@ $this.data('scrollTimeout', setTimeout(callback, 250, self)); }); }; // Place all the behaviors and hooks related to the matching controller here. + // All this logic will automatically be available in application.js. class Pages { connect(){ SirTrevor.setDefaults({ iconUrl: Spotlight.sirTrevorIcon, @@ -5605,11 +5606,13 @@ } } } // Visibility toggle for items in an exhibit, based on Blacklight's bookmark toggle + // See: https://github.com/projectblacklight/blacklight/blob/main/app/javascript/blacklight/bookmark_toggle.js + const VisibilityToggle = (e) => { if (e.target.matches('[data-checkboxsubmit-target="checkbox"]')) { const form = e.target.closest('form'); if (form) { new CheckboxSubmit(form).clicked(e); @@ -5931,30 +5934,53 @@ return Spotlight$1.Block.extend({ type: "resources", formable: true, autocompleteable: true, show_heading: true, + show_alt_text: true, title: function() { return i18n.t("blocks:" + this.type + ":title"); }, description: function() { return i18n.t("blocks:" + this.type + ":description"); }, - + alt_text_guidelines: function() { + if (this.show_alt_text) { + return i18n.t("blocks:alt_text_guidelines:intro"); + } + return ""; + }, + alt_text_guidelines_link: function() { + if (this.show_alt_text) { + var link_url = i18n.t("blocks:alt_text_guidelines:link_url"); + var link_label = i18n.t("blocks:alt_text_guidelines:link_label"); + return '<a target="_blank" href="' + link_url + '">' + link_label + '</a>'; + } + return ""; + }, icon_name: "resources", blockGroup: function() { return i18n.t("blocks:group:items") }, primary_field_key: "primary-caption-field", show_primary_field_key: "show-primary-caption", secondary_field_key: "secondary-caption-field", show_secondary_field_key: "show-secondary-caption", display_checkbox: "display-checkbox", + decorative_checkbox: "decorative-checkbox", + alt_text_textarea: "alt-text-textarea", globalIndex: 0, _itemPanelIiifFields: function(index, data) { return []; }, + _altTextFieldsHTML: function(index, data) { + if (this.show_alt_text) { + return this.altTextHTML(index, data); + } + return ""; + }, + _itemPanel: function(data) { var index = "item_" + this.globalIndex++; var checked; if (data.display == "true") { checked = "checked='checked'"; @@ -5981,10 +6007,11 @@ <img class="img-thumbnail" src="${(data.thumbnail_image_url || ((data.iiif_tilesource || "").replace("/info.json", "/full/!100,100/0/default.jpg")))}" /> </div> <div class="main"> <div class="title card-title">${data.title}</div> <div>${(data.slug || data.id)}</div> + ${this._altTextFieldsHTML(index, data)} </div> <div class="remove float-right float-end"> <a data-item-grid-panel-remove="true" href="#">${i18n.t("blocks:resources:panel:remove")}</a> </div> </div> @@ -6017,10 +6044,11 @@ }, createItemPanel: function(data) { var panel = this._itemPanel(data); + this.attachAltTextHandlers(panel); $(panel).appendTo($('.panels > ol', this.inner)); $('[data-behavior="nestable"]', this.inner).trigger('change'); }, item_options: function() { return ""; }, @@ -6049,15 +6077,71 @@ editorHTML: function() { return `<div class="form resources-admin clearfix"> <div class="widget-header"> ${this.description()} + ${this.alt_text_guidelines()} + ${this.alt_text_guidelines_link()} </div> ${this.content()} </div>` }, + _altTextData: function(data) { + const isDecorative = data.decorative; + const altText = isDecorative ? '' : (data.alt_text || ''); + const altTextBackup = data.alt_text_backup || ''; + const placeholderAttr = isDecorative ? '' : `placeholder="${i18n.t("blocks:resources:alt_text:placeholder")}"`; + const disabledAttr = isDecorative ? 'disabled' : ''; + + return { isDecorative, altText, altTextBackup, placeholderAttr, disabledAttr }; + }, + + altTextHTML: function(index, data) { + const { isDecorative, altText, altTextBackup, placeholderAttr, disabledAttr } = this._altTextData(data); + return `<div class="mt-2 pt-2 d-flex"> + <div class="me-2 mr-2"> + <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> + <div class="form-check mb-1 justify-content-end"> + <input class="form-check-input" type="checkbox" + id="${this.formId(this.decorative_checkbox + '_' + data.id)}" name="item[${index}][decorative]" ${isDecorative ? 'checked' : ''}> + <label class="form-check-label" for="${this.formId(this.decorative_checkbox + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:decorative")}</label> + </div> + </div> + <div class="flex-grow-1 flex-fill d-flex"> + <input type="hidden" name="item[${index}][alt_text_backup]" value="${altTextBackup}" /> + <textarea class="form-control w-100" rows="2" ${placeholderAttr} + id="${this.formId(this.alt_text_textarea + '_' + data.id)}" name="item[${index}][alt_text]" ${disabledAttr}>${altText}</textarea> + </div> + </div>` + }, + + attachAltTextHandlers: function(panel) { + if (this.show_alt_text) { + const decorativeCheckbox = $('input[name$="[decorative]"]', panel); + const altTextInput = $('textarea[name$="[alt_text]"]', panel); + const altTextBackupInput = $('input[name$="[alt_text_backup]"]', panel); + + decorativeCheckbox.on('change', function() { + const isDecorative = this.checked; + if (isDecorative) { + altTextBackupInput.val(altTextInput.val()); + altTextInput.val(''); + } else { + altTextInput.val(altTextBackupInput.val()); + } + altTextInput + .prop('disabled', isDecorative) + .attr('placeholder', isDecorative ? '' : i18n.t("blocks:resources:alt_text:placeholder")); + }); + + altTextInput.on('input', function() { + $(this).data('lastValue', $(this).val()); + }); + } + }, + onBlockRender: function() { Module.init($('[data-behavior="nestable"]', this.inner)); $('[data-input-select-target]', this.inner).selectRelatedInput(); }, @@ -6243,11 +6327,11 @@ return panel; }, item_options: function() { return ` - '<label> + <label> <input type="hidden" name="display-item-counts" value="false" /> <input type="checkbox" name="display-item-counts" value="true" checked /> ${i18n.t("blocks:browse_group_categories:item_counts")} </label>` }, @@ -6678,11 +6762,11 @@ SirTrevor.Blocks.SolrDocumentsEmbed = (function(){ return SirTrevor.Blocks.SolrDocumentsBase.extend({ type: "solr_documents_embed", - + show_alt_text: false, icon_name: "item_embed", item_options: function() { return "" }, afterPreviewLoad: function(options) { @@ -6842,10 +6926,11 @@ </div> <div class="field row mr-3 me-3"> <label for="${this.formId('link_' + dataId)}" class="col-form-label col-md-3">${i18n.t("blocks:uploaded_items:link")}</label> <input type="text" class="form-control col" id="${this.formId('link_' + dataId)}" name="item[${index}][link]" data-field="link"/> </div> + ${this._altTextFieldsHTML(index, data)} </div> <div class="remove float-right float-end"> <a data-item-grid-panel-remove="true" href="#">${i18n.t("blocks:resources:panel:remove")}</a> </div> </div> @@ -6869,10 +6954,12 @@ editorHTML: function() { return `<div class="form oembed-text-admin clearfix"> <div class="widget-header"> ${this.description()} + ${this.alt_text_guidelines()} + ${this.alt_text_guidelines_link()} </div> <div class="row"> <div class="form-group mb-3 col-md-8"> <div class="panels dd nestable-item-grid" data-behavior="nestable" data-max-depth="1"> <ol class="dd-list"> @@ -6888,10 +6975,28 @@ </div> ${this.text_area()} </div>` }, + altTextHTML: function(index, data) { + const { isDecorative, altText, altTextBackup, placeholderAttr, disabledAttr } = this._altTextData(data); + return ` + <div class="field row mr-3 me-3"> + <div class="col-lg-3 ps-md-2 pl-md-2"> + <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> + <div class="form-check d-flex justify-content-md-start justify-content-lg-end"> + <input class="form-check-input" type="checkbox" + id="${this.formId(this.decorative_checkbox + '_' + data.id)}" name="item[${index}][decorative]" ${isDecorative ? 'checked' : ''}> + <label class="form-check-label" for="${this.formId(this.decorative_checkbox + '_' + data.id)}">${i18n.t("blocks:resources:alt_text:decorative")}</label> + </div> + </div> + <input type="hidden" name="item[${index}][alt_text_backup]" value="${altTextBackup}" /> + <textarea class="col-lg-9" rows="2" ${placeholderAttr} + id="${this.formId(this.alt_text_textarea + '_' + data.id)}" name="item[${index}][alt_text]" ${disabledAttr}>${altText}</textarea> + </div>` + }, + zpr_key: 'zpr_link' }); })(); (function() { @@ -7098,10 +7203,15 @@ resources: { panel: { drag: "Drag", display: "Display?", remove: "Remove" + }, + alt_text: { + decorative: "Decorative", + alternative_text: "Alternative text", + placeholder: "Enter alt text for this item..." } }, rule: { title: "Horizontal Rule" @@ -7163,9 +7273,15 @@ }, group: { undefined: "Standard widgets", items: "Exhibit item widgets" + }, + + alt_text_guidelines: { + intro: 'For each item, please enter alternative text or appropriately check the decorative box. ', + link_label: 'Guidelines for writing alt text.', + link_url: 'https://www.w3.org/WAI/tutorials/images/' } }); // These scripts are in the vendor directory