Skip to content

Commit

Permalink
HYC-1003 - Text Formatting for Abstracts (#1123)
Browse files Browse the repository at this point in the history
* save tinymce content to textarea

* tinymce saves on change

* validate metadata on change for rich text fields

* assert tinymce content in test
  • Loading branch information
davidcam-src authored Oct 22, 2024
1 parent 0be6a5c commit 5219bbd
Show file tree
Hide file tree
Showing 16 changed files with 217 additions and 19 deletions.
117 changes: 117 additions & 0 deletions app/assets/javascripts/hyrax/editor.es6
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import RelationshipsControl from 'hyrax/relationships/control'
import SaveWorkControl from 'hyrax/save_work/save_work_control'
import AdminSetWidget from 'hyrax/editor/admin_set_widget'
import ControlledVocabulary from 'hyrax/editor/controlled_vocabulary'
import Autocomplete from 'hyrax/autocomplete'
import AuthoritySelect from 'hyrax/authority_select'

export default class {
/**
* initialize the editor behaviors
* @param {jQuery} element - The form that has a data-param-key attribute
*/
constructor(element) {
this.element = element
this.paramKey = element.data('paramKey') // The work type
this.adminSetWidget = new AdminSetWidget(element.find('select[id$="_admin_set_id"]'))
this.sharingTabElement = $('#tab-share')
}

init() {
this.autocomplete()
this.controlledVocabularies()
this.sharingTab()
this.relationshipsControl()
this.saveWorkControl()
this.saveWorkFixed()
this.authoritySelect()
this.formInProgress()
}

// Immediate feedback after work creation, editing.
formInProgress() {
$('[data-behavior~=work-form]').on('submit', function(event){
$('.card-footer.save-progress').removeAttr("hidden");
});
}

// Used when you have a linked data field that can have terms from multiple
// authorities.
authoritySelect() {
$("[data-authority-select]").each(function() {
let authoritySelect = $(this).data().authoritySelect
let options = {selectBox: 'select.' + authoritySelect,
inputField: 'input.' + authoritySelect}
new AuthoritySelect(options);
})
}

// Autocomplete fields for the work edit form (based_near, subject, language, child works)
autocomplete() {
var autocomplete = new Autocomplete()

$('[data-autocomplete]').each((function() {
var elem = $(this)
autocomplete.setup(elem, elem.data('autocomplete'), elem.data('autocompleteUrl'))
elem.parents('.multi_value.form-group').manage_fields({
add: function(e, element) {
var elem = $(element)
// Don't mark an added element as readonly even if previous element was
// Enable before initializing, as otherwise LinkedData fields remain disabled
elem.attr('readonly', false)
autocomplete.setup(elem, elem.data('autocomplete'), elem.data('autocompleteUrl'))
}
})
}))
}

// initialize any controlled vocabulary widgets
controlledVocabularies() {
this.element.find('.controlled_vocabulary.form-group').each((_idx, controlled_field) =>
new ControlledVocabulary(controlled_field, this.paramKey)
)
}

// Display the sharing tab if they select an admin set that permits sharing
sharingTab() {
if(this.adminSetWidget && !this.adminSetWidget.isEmpty()) {
this.adminSetWidget.on('change', () => this.sharingTabVisiblity(this.adminSetWidget.isSharing()))
this.sharingTabVisiblity(this.adminSetWidget.isSharing())
}
}

sharingTabVisiblity(visible) {
if (visible)
this.sharingTabElement.removeAttr("hidden")
else
this.sharingTabElement.attr("hidden","")
}

relationshipsControl() {
let collections = this.element.find('[data-behavior="collection-relationships"]')
collections.each((_idx, element) =>
new RelationshipsControl(element,
collections.data('members'),
collections.data('paramKey'),
'member_of_collections_attributes',
'tmpl-collection').init())

let works = this.element.find('[data-behavior="child-relationships"]')
works.each((_idx, element) =>
new RelationshipsControl(element,
works.data('members'),
works.data('paramKey'),
'work_members_attributes',
'tmpl-child-work').init())
}
// [hyc-override] Store saveWorkControl instance in a global variable to enable tinymce to call it
// This is necessary for requirement checks to update when rich text fields are edited
saveWorkControl() {
window.saveWorkControlInstance = new SaveWorkControl(this.element.find("#form-progress"), this.adminSetWidget)
}

saveWorkFixed() {
// Fixedsticky will polyfill position:sticky
this.element.find('#savewidget').fixedsticky()
}
}
30 changes: 30 additions & 0 deletions app/renderers/hyrax/renderers/formatted_text_renderer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# frozen_string_literal: true
module Hyrax
module Renderers
class FormattedTextRenderer < AttributeRenderer
private
def attribute_value_to_html(value)
sanitized_value = get_sanitized_string(value)
if microdata_value_attributes(field).present?
"<span#{html_attributes(microdata_value_attributes(field))}>#{sanitized_value}</span>"
else
li_value(sanitized_value)
end
end

# Sanitize the value, allowing only safe HTML tags and attributes
def get_sanitized_string(string)
# Define allowed tags and attributes
allowed_tags = %w[strong em b i u p br small mark sub sup a ul ol li dl dt dd div span h1 h2 h3 h4 h5 h6]
allowed_attributes = %w[href]
sanitize(string, tags: allowed_tags, attributes: allowed_attributes)
end

# Same as attribute renderer override, but without escaping the value
def li_value(value)
field_value = find_language(value) || value
auto_link((field_value))
end
end
end
end
2 changes: 1 addition & 1 deletion app/views/hyrax/articles/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%= presenter.attribute_to_html(:alternative_title, html_dl: true, label: "Alternate title") %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:translator_display, label: 'Translator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/artworks/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:description, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:note, html_dl: true) %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/hyrax/data_sets/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<%= presenter.attribute_to_html(:last_modified_date, render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:contributor_display, label: 'Contributor', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:methodology, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:methodology, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/dissertations/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<%= presenter.attribute_to_html(:date_modified, label: 'Last Modified', render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:contributor_display, label: 'Contributor', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
4 changes: 2 additions & 2 deletions app/views/hyrax/generals/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:contributor_display, label: 'Contributor', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:translator_display, label: 'Translator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:description, html_dl: true) %>
<%= presenter.attribute_to_html(:table_of_contents, html_dl: true) %>
<%= presenter.attribute_to_html(:methodology, html_dl: true) %>
<%= presenter.attribute_to_html(:methodology, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/honors_theses/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<%= presenter.attribute_to_html(:alternative_title, html_dl: true, label: 'Alternate title') %>
<%= presenter.attribute_to_html(:date_modified, label: 'Last Modified', render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/journals/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= presenter.attribute_to_html(:alternative_title, html_dl: true, label: "Alternate title") %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/masters_papers/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= presenter.attribute_to_html(:date_modified, label: 'Last Modified', render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: 'Date of publication') %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/multimeds/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= presenter.attribute_to_html(:date_modified, label: 'Last Modified', render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
<%= presenter.attribute_to_html(:subject, render_as: :faceted, html_dl: true) %>
Expand Down
2 changes: 1 addition & 1 deletion app/views/hyrax/scholarly_works/_attribute_rows.html.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<%= presenter.attribute_to_html(:date_modified, label: 'Last Modified', render_as: :date, html_dl: true) %>
<%= presenter.attribute_to_html(:creator_display, label: 'Creator', render_as: :person, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, html_dl: true) %>
<%= presenter.attribute_to_html(:abstract, render_as: :formatted_text, html_dl: true) %>
<%= presenter.attribute_to_html(:description, html_dl: true) %>
<%= presenter.attribute_to_html(:date_issued, html_dl: true, label: "Date of publication") %>
<%= presenter.attribute_to_html(:keyword, render_as: :faceted, html_dl: true) %>
Expand Down
8 changes: 5 additions & 3 deletions app/views/records/edit_fields/_abstract.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<% if f.object.multiple? key %>
<%= f.input :abstract, as: :multi_value, input_html: { rows: '14', type: 'textarea'}, required: f.object.required?(key) %>
<%= f.input :abstract, as: :multi_value, input_html: { rows: '14', type: 'textarea', class: 'tinymce'}, required: f.object.required?(key) %>
<% else %>
<%= f.input :abstract, as: :text, input_html: { rows: '14' }, required: f.object.required?(key) %>
<% end %>
<%= f.input :abstract, as: :text, input_html: { rows: '14', class: 'tinymce' }, required: f.object.required?(key) %>
<% end %>
<!-- [hyc-override] Include JS for TinyMCE with rich_text configuration. Enables rich text editing. -->
<%= tinymce :rich_text %>
8 changes: 5 additions & 3 deletions app/views/records/edit_fields/_methodology.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<% if f.object.multiple? key %>
<%= f.input :methodology, as: :multi_value, input_html: { rows: '14', type: 'textarea'}, required: f.object.required?(key) %>
<%= f.input :methodology, as: :multi_value, input_html: { rows: '14', type: 'textarea', class: 'tinymce' }, required: f.object.required?(key) %>
<% else %>
<%= f.input :methodology, as: :text, input_html: { rows: '14' }, required: f.object.required?(key) %>
<% end %>
<%= f.input :methodology, as: :text, input_html: { rows: '14', class: 'tinymce' }, required: f.object.required?(key) %>
<% end %>
<!-- [hyc-override] Include JS for TinyMCE with rich_text configuration. Enables rich text editing. -->
<%= tinymce :rich_text %>
44 changes: 44 additions & 0 deletions config/tinymce.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,49 @@ content_block:
- table
- fullscreen
- image
rich_text:
menubar: false
toolbar:
- "undo redo | bold italic underline | alignleft aligncenter alignright | link | numlist bullist outdent indent | blockquote | code"
plugins:
- "link lists code"
style_formats:
- title: "Inline"
items:
- title: "Bold"
inline: "b"
- title: "Italic"
inline: "i"
- title: "Underline"
inline: "u"
- title: "Strikethrough"
inline: "strike"
- title: "Blocks"
items:
- title: "Paragraph"
block: "p"
- title: "Blockquote"
block: "blockquote"
- title: "Alignments"
items:
- title: "Left"
block: ""
classes: "align-left"
- title: "Center"
block: ""
classes: "align-center"
- title: "Right"
block: ""
classes: "align-right"
setup: |
function (editor) {
editor.on('change', function () {
tinymce.triggerSave();
if (window.saveWorkControlInstance) {
window.saveWorkControlInstance.validateMetadata();
}
});
}
custom:
<<: *default
5 changes: 4 additions & 1 deletion spec/features/edit_sage_ingested_works_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,10 @@
expect(page).to have_field('Creator #2', with: 'Zhang, Xi')
expect(page).to have_field('Additional affiliation (Creator #1)', with: 'Department of Family and Community Medicine, University of California, San Francisco, CA, USA')
expect(page).to have_field('ORCID (Creator #1)', with: 'https://orcid.org/0000-0001-6833-8372')
expect(page).to have_field('Abstract', with: /Efforts to increase education opportunities, provide insurance/)
# Assert content within an iframe to check the abstract. Tinymce rich text editors confuse Capybara assertions.
within_frame(find('iframe#article_abstract_ifr')) do
expect(page).to have_content('Efforts to increase education opportunities, provide insurance')
end

# Javascript execution is inconsistent in the test environment, so rather than expanding the rest
# of the form elements, checking for the remainder of the elements whether they are visible or not.
Expand Down

0 comments on commit 5219bbd

Please sign in to comment.