diff --git a/app.rb b/app.rb index 80ce1da6..936f44c4 100644 --- a/app.rb +++ b/app.rb @@ -246,7 +246,7 @@ def login get "/email/record" do datastore, id = params["record"].split(",") - @record = Search::Presenters::Record.for_datastore(datastore: datastore, id: id, size: "brief") + @record = Search::Presenters::Record.for_datastore(datastore: datastore, id: id, size: "email") if params["content_type"] == "txt" content_type "text/plain" @@ -259,7 +259,7 @@ def login @records = Hash.new { |hash, key| hash[key] = [] } params["record"].map do |r| datastore, id = r.split(",") - @records[datastore.capitalize].push Search::Presenters::Record.for_datastore(datastore: datastore, id: id, size: "brief") + @records[datastore.capitalize].push Search::Presenters::Record.for_datastore(datastore: datastore, id: id, size: "email") end if params["content_type"] == "txt" diff --git a/assets/scripts/datastores/list/scripts.js b/assets/scripts/datastores/list/scripts.js index 87475126..e166e936 100644 --- a/assets/scripts/datastores/list/scripts.js +++ b/assets/scripts/datastores/list/scripts.js @@ -1,9 +1,11 @@ import { getTemporaryList, temporaryList } from './layout.js'; -import { shareForm, tabControl } from '../partials/_actions.js'; import { downloadTemporaryListRIS } from '../partials/actions/action/_ris.js'; +import { emailAction } from '../partials/actions/action/_email.js'; import { initializeCitations } from '../partials/actions/action/_citation.js'; import { removeSelected } from '../partials/actions/action/_remove-selected.js'; import { selectAll } from './partials/_select-all.js'; +import { tabControl } from '../partials/_actions.js'; +import { textAction } from '../partials/actions/action/_text.js'; // Get the temporary list from session storage const list = getTemporaryList(); @@ -12,10 +14,10 @@ const list = getTemporaryList(); tabControl('.actions'); // Email -shareForm('#actions__email--tabpanel'); +emailAction(); // Text -shareForm('#actions__text--tabpanel'); +textAction(); // Citations initializeCitations(); diff --git a/assets/scripts/datastores/partials/_actions.js b/assets/scripts/datastores/partials/_actions.js index 6034625b..3580bc6c 100644 --- a/assets/scripts/datastores/partials/_actions.js +++ b/assets/scripts/datastores/partials/_actions.js @@ -59,37 +59,6 @@ const disableActionTabs = () => { }); }; -const fetchFormResults = async (form) => { - const formData = new FormData(form); - - const response = await fetch(form.action, { - body: formData, - headers: { - Accept: 'application/json' - }, - method: form.method - }); - - return response; -}; - -const shareForm = (panel, formResults = fetchFormResults) => { - const form = document.querySelector(`${panel} form:not(.login__form)`); - - // Return if form not found because the user is not logged in - if (!form) { - return; - } - - form.addEventListener('submit', async (event) => { - event.preventDefault(); - changeAlert({ - alert: document.querySelector(`${panel} .alert`), - response: await formResults(form) - }); - }); -}; - const copyToClipboard = ({ alert, text }) => { if (alert) { alert.style.display = 'block'; @@ -101,9 +70,7 @@ export { changeAlert, copyToClipboard, disableActionTabs, - fetchFormResults, getTabPanel, isSelected, - shareForm, tabControl }; diff --git a/assets/scripts/datastores/partials/actions/action/_email.js b/assets/scripts/datastores/partials/actions/action/_email.js new file mode 100644 index 00000000..6b7311d8 --- /dev/null +++ b/assets/scripts/datastores/partials/actions/action/_email.js @@ -0,0 +1,52 @@ +import { changeAlert } from '../_alert.js'; +import { viewingFullRecord } from '../../../record/layout.js'; + +const responseBody = ({ elements }) => { + const params = new URLSearchParams(); + // Convert form elements to URL-encoded string + Array.from(elements).forEach((element) => { + if (element.name && !element.disabled) { + params.append(element.name, element.value); + } + }); + // Return the URL-encoded string + return params.toString(); +}; + +const fetchFormResponse = async ({ body = responseBody, form, isFullRecord = viewingFullRecord(), url }) => { + const { action, elements, method } = form; + return await fetch( + isFullRecord ? action : url, + { + body: body({ elements }), + headers: { + Accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded' + }, + method + } + ); +}; + +const emailAction = ({ emailResponse = fetchFormResponse, showAlert = changeAlert } = {}) => { + const form = document.querySelector('form.action__email--form'); + + // Return early if the form is not found because the user is not logged in + if (!form) { + return; + } + + form.addEventListener('submit', async (event) => { + event.preventDefault(); + showAlert({ + alert: document.querySelector('#actions__email--tabpanel .alert'), + response: await emailResponse({ form, url: '/everything/list/email' }) + }); + }); +}; + +export { + emailAction, + fetchFormResponse, + responseBody +}; diff --git a/assets/scripts/datastores/partials/actions/action/_text.js b/assets/scripts/datastores/partials/actions/action/_text.js new file mode 100644 index 00000000..e7d4082d --- /dev/null +++ b/assets/scripts/datastores/partials/actions/action/_text.js @@ -0,0 +1,21 @@ +import { changeAlert } from '../_alert.js'; +import { fetchFormResponse } from './_email.js'; + +const textAction = ({ showAlert = changeAlert, textResponse = fetchFormResponse } = {}) => { + const form = document.querySelector('form.action__text--form'); + + // Return early if the form is not found because the user is not logged in + if (!form) { + return; + } + + form.addEventListener('submit', async (event) => { + event.preventDefault(); + showAlert({ + alert: document.querySelector('#actions__text--tabpanel .alert'), + response: await textResponse({ form, url: '/everything/list/sms' }) + }); + }); +}; + +export { textAction }; diff --git a/assets/scripts/datastores/record/scripts.js b/assets/scripts/datastores/record/scripts.js index afbc78c9..d11b13fa 100644 --- a/assets/scripts/datastores/record/scripts.js +++ b/assets/scripts/datastores/record/scripts.js @@ -1,9 +1,11 @@ -import { shareForm, tabControl } from '../partials/_actions.js'; import { addToList } from '../list/partials/_add-to.js'; import copyLink from '../partials/actions/action/_link.js'; +import { emailAction } from '../partials/actions/action/_email.js'; import { getTemporaryList } from '../list/layout.js'; import { initializeCitations } from '../partials/actions/action/_citation.js'; import shelfBrowse from './partials/_shelf-browse.js'; +import { tabControl } from '../partials/_actions.js'; +import { textAction } from '../partials/actions/action/_text.js'; import toggleItems from '../partials/_toggle.js'; import toggleMARCData from './partials/_marc.js'; import toggleTruncatedText from './partials/_title.js'; @@ -15,10 +17,10 @@ const list = getTemporaryList(); tabControl('.actions'); // Email -shareForm('#actions__email--tabpanel'); +emailAction(); // Text -shareForm('#actions__text--tabpanel'); +textAction(); // Citations initializeCitations(); diff --git a/lib/search/email.rb b/lib/search/email.rb index 076cf538..97d92877 100644 --- a/lib/search/email.rb +++ b/lib/search/email.rb @@ -56,7 +56,7 @@ def self.for(id) end def initialize(id) - @record = Search::Presenters::Record.for_datastore(datastore: "catalog", id: id, size: "brief") + @record = Search::Presenters::Record.for_datastore(datastore: "catalog", id: id, size: "email") end def subject diff --git a/lib/search/models/record/catalog/holdings/hathi_trust.rb b/lib/search/models/record/catalog/holdings/hathi_trust.rb index 31b14ab3..ad3bdce3 100644 --- a/lib/search/models/record/catalog/holdings/hathi_trust.rb +++ b/lib/search/models/record/catalog/holdings/hathi_trust.rb @@ -7,12 +7,28 @@ def count @count ||= @hathi_trust_items.count end + def search_only_count + @search_only_count ||= search_only_items.count + end + + def full_text_count + @full_text_count ||= full_text_items.count + end + def has_description? @hathi_trust_items.any? { |x| x["description"].present? } end def items - @hathi_trust_items.map { |item| Item.new(item) } + @items ||= @hathi_trust_items.map { |item| Item.new(item) } + end + + def full_text_items + @full_text_items ||= items.select { |item| item.full_text? } + end + + def search_only_items + @search_only_items ||= items.select { |item| !item.full_text? } end class Item @@ -26,6 +42,10 @@ def initialize(item) end end + def full_text? + status.match?("Full text") + end + def url "http://hdl.handle.net/2027/#{id}" end diff --git a/lib/search/presenters/record/catalog.rb b/lib/search/presenters/record/catalog.rb index ff33b747..7879748d 100644 --- a/lib/search/presenters/record/catalog.rb +++ b/lib/search/presenters/record/catalog.rb @@ -111,6 +111,10 @@ def id @record.bib.id end + def url + "#{S.base_url}/catalog/record/#{id}" + end + def title result = [ OpenStruct.new(text: @record.bib.title.original.text, css_class: "title-primary") @@ -367,7 +371,7 @@ def to_h transliterated: f.values&.first&.transliterated&.text } end, - url: "#{S.base_url}/catalog/record/#{id}", + url: url, citation: { ris: ris, csl: csl @@ -414,3 +418,4 @@ def each(&block) end end end +require_relative "catalog/email" diff --git a/lib/search/presenters/record/catalog/email.rb b/lib/search/presenters/record/catalog/email.rb new file mode 100644 index 00000000..ff6764a6 --- /dev/null +++ b/lib/search/presenters/record/catalog/email.rb @@ -0,0 +1,12 @@ +module Search::Presenters::Record::Catalog + class Email < Full + METADATA_METHODS = [ + :main_author, + :published, + :series + ] + def holdings + EmailHoldings.new(@record) + end + end +end diff --git a/lib/search/presenters/record/catalog/email_holdings.rb b/lib/search/presenters/record/catalog/email_holdings.rb new file mode 100644 index 00000000..80e40bd5 --- /dev/null +++ b/lib/search/presenters/record/catalog/email_holdings.rb @@ -0,0 +1,50 @@ +class Search::Presenters::Record::Catalog::EmailHoldings + # + # + # + # @param [Search::Models::Record::Catalog] data is the catalog record model + # + def initialize(data) + @data = data + @holdings = Search::Presenters::Record::Catalog::Holdings.new(@data) + end + + def too_many? + non_ht_search_only_item_count > 3 || (non_ht_search_only_item_count == 0 && @holdings.hathi_trust.search_only_count > 3) + end + + def any? + list.any? + end + + def list + @list ||= [ + hathi_trust_list, + @holdings.online, + @holdings.finding_aids, + * @holdings.physical + ].reject { |x| x.empty? } + end + + private + + def hathi_trust_list + if non_ht_search_only_item_count == 0 + @holdings.hathi_trust + else + Search::Presenters::Record::Catalog::Holdings::HathiTrustFullText.new(@data.holdings.hathi_trust) + end + end + + def non_ht_search_only_item_count + @non_ht_search_only_item_count ||= + physical_item_count + + @holdings.online.count + + @holdings.finding_aids.count + + @holdings.hathi_trust.full_text_count + end + + def physical_item_count + @holdings.physical.map { |x| x.count }.sum + end +end diff --git a/lib/search/presenters/record/catalog/holdings.rb b/lib/search/presenters/record/catalog/holdings.rb index 369e8a54..d6aade7f 100644 --- a/lib/search/presenters/record/catalog/holdings.rb +++ b/lib/search/presenters/record/catalog/holdings.rb @@ -12,15 +12,15 @@ def initialize(data) def list [ # send the holding not the items - HathiTrust.new(@holdings.hathi_trust), - Online.new(@holdings), + hathi_trust, + online, finding_aids, * physical ].reject { |x| x.empty? } end def physical - if finding_aids.empty? + @physical ||= if finding_aids.empty? @holdings.physical.list.map do |holding| Physical.new(holding: holding, bib: @data.bib) end @@ -29,6 +29,14 @@ def physical end end + def hathi_trust + @hathi_trust ||= HathiTrust.new(@holdings.hathi_trust) + end + + def online + @online ||= Online.new(@holdings) + end + def finding_aids @finding_aids ||= FindingAids.new(@holdings.finding_aids) end @@ -41,15 +49,22 @@ class HathiTrust # def initialize(holding) @holding = holding - @items = holding.items end def count - @holding.count + items.count end def empty? - @holding.count == 0 + count == 0 + end + + def full_text_count + @holding.full_text_count + end + + def search_only_count + @holding.search_only_count end def heading @@ -84,13 +99,25 @@ def rows end def items - @items.map do |item| + @items ||= map_items(@holding.items) + end + + private + + def map_items(items) + items.map do |item| ElectronicItem.new(url: item.url, availability_text: item.status, description: item.description, source: item.source) end end end + class HathiTrustFullText < HathiTrust + def items + @items ||= map_items(@holding.items.select { |x| x.full_text? }) + end + end + class Online def initialize(holdings) @holdings = holdings @@ -274,3 +301,4 @@ def partial require_relative "physical_holdings" require_relative "finding_aids_holding" +require_relative "email_holdings" diff --git a/public/images/email/check_circle.png b/public/images/email/check_circle.png new file mode 100644 index 00000000..54374253 Binary files /dev/null and b/public/images/email/check_circle.png differ diff --git a/public/images/email/error.png b/public/images/email/error.png new file mode 100644 index 00000000..33aa0a71 Binary files /dev/null and b/public/images/email/error.png differ diff --git a/public/images/email/warning.png b/public/images/email/warning.png new file mode 100644 index 00000000..323bdd3b Binary files /dev/null and b/public/images/email/warning.png differ diff --git a/spec/factories.rb b/spec/factories.rb index 4522740a..c7bc6b61 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -13,13 +13,15 @@ def create(factory, opts = {}) when :catalog_record CatalogRecord.record(**opts) when :catalog_holdings - CatalogRecord.holdings + CatalogRecord.holdings(**opts) when :catalog_bib CatalogRecord.bib(**opts) when :single_script_paired_text_item CatalogRecord.single_script_paired_text_item when :hathi_trust_holdings CatalogRecord.hathi_trust_holdings + when :hathi_trust_item + CatalogRecord.hathi_trust_item when :physical_item CatalogRecord.physical_item when :shelf_browse_item diff --git a/spec/factories/catalog_record.rb b/spec/factories/catalog_record.rb index 4928e064..16d40fa2 100644 --- a/spec/factories/catalog_record.rb +++ b/spec/factories/catalog_record.rb @@ -86,8 +86,16 @@ class << self } - def record(bib_fields: [], other_fields: []) - result = instance_double(Search::Models::Record::Catalog, bib: bib(fields: bib_fields)) + HOLDINGS = { + hathi_trust: "hathi_trust_holdings", + alma_digital: "alma_digital_holdings", + electronic: "electronic_holdings", + finding_aids: "finding_aid_holding", + physical: "physical_holdings" + } + + def record(bib_fields: [], other_fields: [], holdings: []) + result = instance_double(Search::Models::Record::Catalog, bib: bib(fields: bib_fields), holdings: holdings(kinds: holdings)) other_fields.each do |f| allow(result).to receive(f).and_return(send(f)) end @@ -198,15 +206,42 @@ def citation instance_double(Search::Models::Record::Catalog::Citation) end - def holdings - instance_double(Search::Models::Record::Catalog::Holdings, hathi_trust: hathi_trust_holdings, - alma_digital: alma_digital_holdings, electronic: electronic_holdings, finding_aids: finding_aid_holding, - physical: physical_holdings) + def holdings(kinds: nil) + kinds = [:alma_digital, :hathi_trust, :electronic, :finding_aids, :physical] if kinds.nil? || kinds == :all + included_holdings = HOLDINGS.map do |h, method| + holding = if kinds.include?(h) + send(method) + elsif h == :physical + empty_physical_holding + elsif h == :hathi_trust + empty_hathi_trust_holding + else + empty_holding + end + [h, holding] + end.to_h + + # included_holdings = kinds.map { |h| [h, send(HOLDINGS[h])] }.to_h + instance_double(Search::Models::Record::Catalog::Holdings, **included_holdings) + end + + def empty_physical_holding + instance_double(Search::Models::Record::Catalog::Holdings::Physical, list: []) + end + + def empty_hathi_trust_holding + instance_double(Search::Models::Record::Catalog::Holdings::HathiTrust, items: [], count: 0, has_description?: false, full_text_count: 0, search_only_count: 0) + end + + def empty_holding + instance_double(Search::Models::Record::Catalog::Holdings::Electronic, + items: [], count: 0, + has_description?: false) end def hathi_trust_holdings instance_double(Search::Models::Record::Catalog::Holdings::HathiTrust, - items: [hathi_trust_item], count: 1, + items: [hathi_trust_item], count: 1, full_text_count: 1, search_only_count: 0, has_description?: true) end @@ -215,7 +250,8 @@ def hathi_trust_item url: Faker::Internet.url, source: Faker::Educator.university, description: Faker::Lorem.sentence, - status: "Full text") + status: "Full text", + full_text?: true) end def alma_digital_holdings diff --git a/spec/models/record/catalog/holdings/hathi_trust_spec.rb b/spec/models/record/catalog/holdings/hathi_trust_spec.rb index 976a8df7..0f8ec6ab 100644 --- a/spec/models/record/catalog/holdings/hathi_trust_spec.rb +++ b/spec/models/record/catalog/holdings/hathi_trust_spec.rb @@ -1,4 +1,31 @@ RSpec.describe Search::Models::Record::Catalog::Holdings::HathiTrust do + def search_only_item + { + "id" => "mdp.#{Faker::Barcode.ean}", + "rights" => "ic", + "description" => Faker::Lorem.sentence, + "collection_code" => "MIU", + "access" => false, + "source" => Faker::Educator.university, + "status" => "Search only (no full text)" + } + end + + def full_text_item + { + "id" => "mdp.#{Faker::Barcode.ean}", + "rights" => "pd", + "description" => Faker::Lorem.sentence, + "collection_code" => "MIU", + "access" => true, + "source" => Faker::Educator.university, + "status" => "Full text" + } + end + + let(:data) { + {"holdings" => {"hathi_trust_items" => []}} + } before(:each) do @data = { "holdings" => { @@ -18,23 +45,87 @@ end subject do - described_class.new(@data) + described_class.new(data) end context "#items" do it "passes an array of items containing the url and the other info from the api" do + item = search_only_item + data["holdings"]["hathi_trust_items"].push(item) + first_item = subject.items.first - expect(first_item.id).to eq("mdp.39015017893416") + expect(first_item.id).to eq(item["id"]) expect(first_item.rights).to eq("ic") - expect(first_item.description).to eq("description") + expect(first_item.description).to eq(item["description"]) expect(first_item.access).to eq(false) - expect(first_item.source).to eq("University of Michigan") + expect(first_item.source).to eq(item["source"]) expect(first_item.status).to eq("Search only (no full text)") expect(first_item.url).not_to be_nil end it "generates appropriate urls based on the hathi trust id" do + item = search_only_item + data["holdings"]["hathi_trust_items"].push(item) + first_item = subject.items.first - expect(first_item.url).to eq("http://hdl.handle.net/2027/mdp.39015017893416") + expect(first_item.url).to eq("http://hdl.handle.net/2027/#{item["id"]}") + end + + context "Item #full_text" do + it "generates appropriate urls based on the hathi trust id" do + item = search_only_item + data["holdings"]["hathi_trust_items"].push(item) + + first_item = subject.items.first + expect(first_item.full_text?).to eq(false) + end + it "generates appropriate urls based on the hathi trust id" do + item = full_text_item + data["holdings"]["hathi_trust_items"].push(item) + + first_item = subject.items.first + expect(first_item.full_text?).to eq(true) + end + end + end + context "#full_text_items" do + it "returns only the full text items" do + so_item = search_only_item + ft_item = full_text_item + data["holdings"]["hathi_trust_items"].push(so_item) + data["holdings"]["hathi_trust_items"].push(ft_item) + + expect(subject.full_text_items.count).to eq(1) + expect(subject.full_text_items.first.id).to eq(ft_item["id"]) + end + end + context "#search_only_items" do + it "returns only the full text items" do + so_item = search_only_item + ft_item = full_text_item + data["holdings"]["hathi_trust_items"].push(so_item) + data["holdings"]["hathi_trust_items"].push(ft_item) + + expect(subject.search_only_items.count).to eq(1) + expect(subject.search_only_items.first.id).to eq(so_item["id"]) + end + end + + context "#full_text_count" do + it "returns only the full text items" do + data["holdings"]["hathi_trust_items"].push(search_only_item) + data["holdings"]["hathi_trust_items"].push(full_text_item) + data["holdings"]["hathi_trust_items"].push(search_only_item) + + expect(subject.full_text_count).to eq(1) + end + end + context "#search_only_count" do + it "returns only the full text items" do + data["holdings"]["hathi_trust_items"].push(full_text_item) + data["holdings"]["hathi_trust_items"].push(search_only_item) + data["holdings"]["hathi_trust_items"].push(full_text_item) + + expect(subject.search_only_count).to eq(1) end end end diff --git a/spec/presenters/record/catalog/email_holdings_spec.rb b/spec/presenters/record/catalog/email_holdings_spec.rb new file mode 100644 index 00000000..b58fa174 --- /dev/null +++ b/spec/presenters/record/catalog/email_holdings_spec.rb @@ -0,0 +1,80 @@ +describe Search::Presenters::Record::Catalog::EmailHoldings do + def create_record(*holdings) + create(:catalog_record, holdings: holdings) + end + subject do + described_class.new(@record) + end + context "#too_many?" do + it "returns false when there is only one physical holding" do + @record = create_record(:physical) + expect(subject.too_many?).to eq(false) + end + it "is true when the item count for physical is greater than three" do + @record = create_record(:physical) + allow(@record.holdings.physical.list.first).to receive(:count).and_return(4) + expect(subject.too_many?).to eq(true) + end + it "is true when there is an online holding with 4 items" do + @record = create_record(:alma_digital, :electronic) + allow(@record.holdings.alma_digital).to receive(:count).and_return(2) + allow(@record.holdings.electronic).to receive(:count).and_return(2) + expect(subject.too_many?).to eq(true) + end + it "is true when there is one finding aid and 2 electronic and one phyiscal" do + @record = create_record(:alma_digital, :electronic, :finding_aids) + allow(@record.holdings.alma_digital).to receive(:count).and_return(2) + expect(subject.too_many?).to eq(true) + end + it "is true when there are 4 HT full text items" do + @record = create_record(:hathi_trust) + allow(@record.holdings.hathi_trust).to receive(:full_text_count).and_return(4) + expect(subject.too_many?).to eq(true) + end + it "is false when there are less than 4 HT search only items and nothing else" do + @record = create_record(:hathi_trust) + allow(@record.holdings.hathi_trust).to receive(:full_text_count).and_return(0) + allow(@record.holdings.hathi_trust).to receive(:search_only_count).and_return(3) + expect(subject.too_many?).to eq(false) + end + it "is true when there are more than 4 HT search only items and nothing else" do + @record = create_record(:hathi_trust) + allow(@record.holdings.hathi_trust).to receive(:full_text_count).and_return(0) + allow(@record.holdings.hathi_trust).to receive(:search_only_count).and_return(4) + expect(subject.too_many?).to eq(true) + end + it "is false when there are more than 3 HT search only items and one of any other item" do + @record = create_record(:hathi_trust, :physical) + allow(@record.holdings.hathi_trust).to receive(:search_only_count).and_return(4) + expect(subject.too_many?).to eq(false) + end + end + context "#list" do + it "sends only Full text items when there are any" do + @record = create_record(:alma_digital, :electronic) + full_text_ht = create(:hathi_trust_item) + so_ht = create(:hathi_trust_item) + allow(so_ht).to receive(:status).and_return("Search only (no full text)") + allow(so_ht).to receive(:full_text?).and_return(false) + allow(@record.holdings.hathi_trust).to receive(:search_only_count).and_return(1) + allow(@record.holdings.hathi_trust).to receive(:full_text_count).and_return(1) + allow(@record.holdings.hathi_trust).to receive(:items).and_return([so_ht, full_text_ht]) + + items = subject.list.first.items + expect(items.first.description.to_s).to eq(full_text_ht.description) + expect(items.count).to eq(1) + end + it "sends Search only items when that's all there is" do + @record = create_record(:hathi_trust) + so_ht = @record.holdings.hathi_trust.items.first + allow(so_ht).to receive(:status).and_return("Search only (no full text)") + allow(so_ht).to receive(:full_text?).and_return(false) + allow(@record.holdings.hathi_trust).to receive(:search_only_count).and_return(1) + allow(@record.holdings.hathi_trust).to receive(:full_text_count).and_return(0) + + items = subject.list.first.items + expect(items.first.description.to_s).to eq(so_ht.description) + expect(items.count).to eq(1) + end + end +end diff --git a/spec/presenters/record/catalog/holdings_spec.rb b/spec/presenters/record/catalog/holdings_spec.rb index 0ed5c335..573c6014 100644 --- a/spec/presenters/record/catalog/holdings_spec.rb +++ b/spec/presenters/record/catalog/holdings_spec.rb @@ -1,6 +1,6 @@ RSpec.describe Search::Presenters::Record::Catalog::Holdings do let(:record) do - create(:catalog_record, other_fields: [:holdings]) + create(:catalog_record, holdings: [:alma_digital, :hathi_trust, :electronic, :finding_aids, :physical]) end let(:ht_holdings) do record.holdings.hathi_trust @@ -25,7 +25,7 @@ expect(subject.list.first.heading).to eq("HathiTrust Digital Library") end it "does not include HathiTrust when it does not have items" do - allow(ht_holdings).to receive(:count).and_return(0) + allow(ht_holdings).to receive(:items).and_return([]) expect(subject.list.first&.heading).not_to eq("HathiTrust Digital Library") end it "includes Online when there are online items" do @@ -73,7 +73,7 @@ context "#empty?" do it "is true when there are no items" do - allow(hathi_trust_holdings).to receive(:count).and_return(0) + allow(hathi_trust_holdings).to receive(:items).and_return([]) expect(subject.empty?).to eq(true) end it "is false when there are items" do diff --git a/spec/presenters/record/catalog/physical_holdings_spec.rb b/spec/presenters/record/catalog/physical_holdings_spec.rb index 257defc9..e9b99d7a 100644 --- a/spec/presenters/record/catalog/physical_holdings_spec.rb +++ b/spec/presenters/record/catalog/physical_holdings_spec.rb @@ -1,6 +1,6 @@ RSpec.describe Search::Presenters::Record::Catalog::Holdings::Physical do let(:record) do - create(:catalog_record, other_fields: [:holdings]) + create(:catalog_record, holdings: [:physical]) end let(:physical_holding) do record.holdings.physical.list.first diff --git a/spec/presenters/record/catalog_spec.rb b/spec/presenters/record/catalog_spec.rb index a38d5eef..014b9168 100644 --- a/spec/presenters/record/catalog_spec.rb +++ b/spec/presenters/record/catalog_spec.rb @@ -339,7 +339,13 @@ end end describe Search::Presenters::Record::Catalog::Brief do - let(:record) { create(:catalog_record, bib_fields: [:title, :main_author, :published, :series], other_fields: [:citation, :holdings]) } + let(:record) { + create(:catalog_record, + bib_fields: [:title, :main_author, :published, :series], + other_fields: [:citation], + holdings: [:alma_digital, :hathi_trust, :electronic, :finding_aids, + :physical]) + } subject do described_class.new(record) end diff --git a/spec/sms_spec.rb b/spec/sms_spec.rb index ba565a4d..f6b30cb3 100644 --- a/spec/sms_spec.rb +++ b/spec/sms_spec.rb @@ -1,6 +1,6 @@ describe Search::SMS::Catalog do before(:each) do - @record = create(:catalog_record, bib_fields: [:title], other_fields: [:holdings]) + @record = create(:catalog_record, bib_fields: [:title], holdings: [:physical]) end subject do diff --git a/test/scripts/datastores/partials/_actions.spec.js b/test/scripts/datastores/partials/_actions.spec.js index ac38b53b..acabe759 100644 --- a/test/scripts/datastores/partials/_actions.spec.js +++ b/test/scripts/datastores/partials/_actions.spec.js @@ -1,4 +1,4 @@ -import { copyToClipboard, disableActionTabs, getTabPanel, isSelected, shareForm, tabControl } from '../../../../assets/scripts/datastores/partials/_actions.js'; +import { copyToClipboard, disableActionTabs, getTabPanel, isSelected, tabControl } from '../../../../assets/scripts/datastores/partials/_actions.js'; import { getCheckboxes, someCheckboxesChecked } from '../../../../assets/scripts/datastores/list/partials/list-item/_checkbox.js'; import { expect } from 'chai'; import { JSDOM } from 'jsdom'; @@ -9,7 +9,6 @@ describe('actions', function () { let firstTab = null; let secondTab = null; let getAlert = null; - let getForm = null; beforeEach(function () { // Apply HTML to the body @@ -25,10 +24,6 @@ describe('actions', function () {
This is a warning.
-
- - -
Tab Panel 2 @@ -48,10 +43,6 @@ describe('actions', function () { return document.querySelector('.alert'); }; - getForm = () => { - return document.querySelector('form'); - }; - // Make sure the first tab is selected expect(firstTab().getAttribute('aria-selected'), 'Tab 1 should be selected.').to.equal('true'); }); @@ -60,7 +51,6 @@ describe('actions', function () { firstTab = null; secondTab = null; getAlert = null; - getForm = null; }); describe('isSelected()', function () { @@ -211,67 +201,6 @@ describe('actions', function () { }); }); - describe('fetchFormResults()', function () { - // - }); - - describe('shareForm()', function () { - beforeEach(function () { - // Apply HTML to the body - document.body.innerHTML = ` -
-
- We're sorry. Something went wrong. Please use Ask a Librarian for help. -
-
- - -
-
- `; - }); - - it('should prevent the default form submission and call shareForm', async function () { - const response = Response.json({ message: 'Record sent successfully.' }, { status: 200 }); - - const fetchFormFake = sinon.fake.resolves(response); - shareForm('#actions__record--tabpanel', fetchFormFake); - - // Simulate form submission - const submitEvent = new window.Event('submit', { - bubbles: true, - cancelable: true - }); - getForm().dispatchEvent(submitEvent); - // Wait until the async calls resolve - await new Promise((resolve) => { - setTimeout(resolve, 10); - }); - - expect(getAlert().textContent).to.include('Record sent successfully.'); - }); - - it('should show an error on submission', async function () { - const response = Response.json({ message: 'Please enter a valid email address (e.g. uniqname@umich.edu)' }, { status: 500 }); - - const fetchFormFake = sinon.fake.returns(response); - shareForm('#actions__record--tabpanel', fetchFormFake); - - // Simulate form submission - const submitEvent = new window.Event('submit', { - bubbles: true, - cancelable: true - }); - getForm().dispatchEvent(submitEvent); - // Wait until the async calls resolve - await new Promise((resolve) => { - setTimeout(resolve, 10); - }); - - expect(getAlert().textContent).to.include('Please enter a valid email address (e.g. uniqname@umich.edu)'); - }); - }); - describe('copyToClipboard()', function () { let getText = null; let clipboardSpy = null; diff --git a/test/scripts/datastores/partials/actions/action/_email.spec.js b/test/scripts/datastores/partials/actions/action/_email.spec.js new file mode 100644 index 00000000..e7b5a9c5 --- /dev/null +++ b/test/scripts/datastores/partials/actions/action/_email.spec.js @@ -0,0 +1,241 @@ +import { + emailAction, + fetchFormResponse, + responseBody +} from '../../../../../../assets/scripts/datastores/partials/actions/action/_email.js'; +import { expect } from 'chai'; +import sinon from 'sinon'; + +describe('email', function () { + let getAlert = null; + let getForm = null; + let getInput = null; + + beforeEach(function () { + // Apply HTML to the body + document.body.innerHTML = ` +
+
+ +
+ `; + + getAlert = () => { + return document.querySelector('.alert'); + }; + + getForm = () => { + return document.querySelector('form'); + }; + + getInput = () => { + return getForm().querySelector('input'); + }; + }); + + afterEach(function () { + getAlert = null; + getForm = null; + getInput = null; + }); + + describe('responseBody()', function () { + let response = null; + + beforeEach(function () { + // Call the function + response = responseBody({ elements: getForm().elements }); + }); + + afterEach(function () { + response = null; + }); + + it('should return a string', function () { + expect(response).to.be.a('string'); + }); + + it('should return a URL-encoded string', function () { + expect(response).to.equal(`${getInput().name}=${encodeURIComponent(getInput().value)}`); + }); + }); + + describe('fetchFormResponse()', function () { + let responseBodyStub = null; + let args = null; + let fetchStub = null; + + beforeEach(function () { + responseBodyStub = sinon.stub().returns(responseBody({ elements: getForm().elements })); + args = { + body: responseBodyStub, + form: getForm(), + isFullRecord: false, + url: '/everything/list/email' + }; + fetchStub = sinon.stub(global, 'fetch').resolves('mocked-fetch-response'); + }); + + afterEach(function () { + responseBodyStub = null; + args = null; + fetchStub = null; + }); + + it('should call `fetch` once', async function () { + // Call the function + await fetchFormResponse(args); + + // Check that `fetch` was called once + expect(fetchStub.calledOnce, '`fetch` was not called once').to.be.true; + }); + + describe('URL', function () { + it('should fetch the `url` argument when `isFullRecord` is `false`', async function () { + // Check that `isFullRecord` is `false` + expect(args.isFullRecord, '`isFullRecord` is not `false`').to.be.false; + + // Call the function + await fetchFormResponse(args); + + // Check that `fetch` was called with the `url` argument + expect(fetchStub.args[0][0], '`fetch` was not called with the `url` argument').to.equal(args.url); + }); + + it('should fetch the form `action` when `isFullRecord` is `true`', async function () { + // Check that `isFullRecord` is `true` + args.isFullRecord = true; + expect(args.isFullRecord, '`isFullRecord` is not `true`').to.be.true; + + // Call the function + await fetchFormResponse(args); + + // Check that `fetch` was called with the form `action` + expect(fetchStub.args[0][0], '`fetch` was not called with the form `action`').to.equal(getForm().action); + }); + }); + + describe('fetch options', function () { + let fetchArgs = null; + + beforeEach(async function () { + // Call the function + await fetchFormResponse(args); + + [[, fetchArgs]] = fetchStub.args; + }); + + afterEach(function () { + fetchArgs = null; + }); + + it('should call `body` with the correct arguments', function () { + expect(responseBodyStub.args[0][0], '`body` was not called with the correct arguments').to.deep.equal({ elements: getForm().elements }); + }); + + it('`body` should equal the result of `responseBody`', function () { + expect(fetchArgs.body, '`body` should equal the result of `responseBody`').to.deep.equal(responseBodyStub()); + }); + + it('`headers` should equal the correct headers', function () { + expect(fetchArgs.headers, '`headers` should equal the correct headers').to.deep.equal({ + Accept: 'application/json', + 'Content-Type': 'application/x-www-form-urlencoded' + }); + }); + + it('`method` should equal the form `method`', function () { + expect(fetchArgs.method, '`method` should equal the form `method`').to.equal(getForm().method); + }); + }); + }); + + describe('emailAction()', function () { + let submitEvent = null; + let preventDefaultSpy = null; + let mockResponse = null; + let fetchFormResponseStub = null; + let changeAlertStub = null; + let args = null; + + beforeEach(function () { + submitEvent = new window.Event('submit', { + bubbles: true, + cancelable: true + }); + preventDefaultSpy = sinon.spy(submitEvent, 'preventDefault'); + mockResponse = { + json: () => { + return { message: 'Sending your email.' }; + }, + ok: true + }; + fetchFormResponseStub = sinon.stub().resolves(mockResponse); + changeAlertStub = sinon.stub(); + args = { + emailResponse: fetchFormResponseStub, + showAlert: changeAlertStub + }; + }); + + afterEach(function () { + submitEvent = null; + preventDefaultSpy = null; + fetchFormResponseStub = null; + changeAlertStub = null; + args = null; + }); + + describe('form not found', function () { + beforeEach(function () { + // Apply HTML to the body + document.body.innerHTML = ``; + + // Check that the form does not exist + expect(getForm(), 'the form should not be found').to.be.null; + + // Call the function + emailAction(args); + }); + + it('should not call `fetchFormResponse`', function () { + expect(fetchFormResponseStub.called, '`fetchFormResponse` should have not been called').to.be.false; + }); + + it('should not call `showAlert`', function () { + expect(changeAlertStub.called, '`showAlert` should have not been called').to.be.false; + }); + }); + + describe('submit event handler', function () { + beforeEach(async function () { + // Call the function + emailAction(args); + + // Submit the form + getForm().dispatchEvent(submitEvent); + + // Wait for the event handler to complete + await Promise.resolve(); + }); + + it('should call `preventDefault` on the submit event', function () { + expect(preventDefaultSpy.called, '`preventDefault` was not called').to.be.true; + }); + + it('should call `showAlert` with the correct arguments', function () { + expect(changeAlertStub.calledWithExactly({ + alert: getAlert(), + response: mockResponse + }), '`showAlert` was not called with the correct arguments').to.be.true; + }); + + it('should call `fetchFormResponse` with the correct arguments', function () { + expect(fetchFormResponseStub.calledWithExactly({ form: getForm(), url: '/everything/list/email' }), '`fetchFormResponse` was not called with the correct arguments').to.be.true; + }); + }); + }); +}); diff --git a/test/scripts/datastores/partials/actions/action/_text.spec.js b/test/scripts/datastores/partials/actions/action/_text.spec.js new file mode 100644 index 00000000..38657753 --- /dev/null +++ b/test/scripts/datastores/partials/actions/action/_text.spec.js @@ -0,0 +1,120 @@ +import { expect } from 'chai'; +import sinon from 'sinon'; +import { textAction } from '../../../../../../assets/scripts/datastores/partials/actions/action/_text.js'; + +describe('text', function () { + let getAlert = null; + let getForm = null; + + beforeEach(function () { + // Apply HTML to the body + document.body.innerHTML = ` +
+
+
+ + +
+
+ `; + + getAlert = () => { + return document.querySelector('.alert'); + }; + + getForm = () => { + return document.querySelector('form'); + }; + }); + + afterEach(function () { + getAlert = null; + getForm = null; + }); + + describe('textAction()', function () { + let submitEvent = null; + let preventDefaultSpy = null; + let mockResponse = null; + let fetchFormResponseStub = null; + let changeAlertStub = null; + let args = null; + + beforeEach(function () { + submitEvent = new window.Event('submit', { + bubbles: true, + cancelable: true + }); + preventDefaultSpy = sinon.spy(submitEvent, 'preventDefault'); + mockResponse = { + json: () => { + return { message: 'Sending your text.' }; + }, + ok: true + }; + fetchFormResponseStub = sinon.stub().resolves(mockResponse); + changeAlertStub = sinon.stub(); + args = { + showAlert: changeAlertStub, + textResponse: fetchFormResponseStub + }; + }); + + afterEach(function () { + submitEvent = null; + preventDefaultSpy = null; + fetchFormResponseStub = null; + changeAlertStub = null; + args = null; + }); + + describe('form not found', function () { + beforeEach(function () { + // Apply HTML to the body + document.body.innerHTML = ``; + + // Check that the form does not exist + expect(getForm(), 'the form should not be found').to.be.null; + + // Call the function + textAction(args); + }); + + it('should not call `fetchFormResponse`', function () { + expect(fetchFormResponseStub.called, '`fetchFormResponse` should have not been called').to.be.false; + }); + + it('should not call `showAlert`', function () { + expect(changeAlertStub.called, '`showAlert` should have not been called').to.be.false; + }); + }); + + describe('submit event handler', function () { + beforeEach(async function () { + // Call the function + textAction(args); + + // Submit the form + getForm().dispatchEvent(submitEvent); + + // Wait for the event handler to complete + await Promise.resolve(); + }); + + it('should call `preventDefault` on the submit event', function () { + expect(preventDefaultSpy.called, '`preventDefault` was not called').to.be.true; + }); + + it('should call `showAlert` with the correct arguments', function () { + expect(changeAlertStub.calledWithExactly({ + alert: getAlert(), + response: mockResponse + }), '`showAlert` was not called with the correct arguments').to.be.true; + }); + + it('should call `fetchFormResponse` with the correct arguments', function () { + expect(fetchFormResponseStub.calledWithExactly({ form: getForm(), url: '/everything/list/sms' }), '`fetchFormResponse` was not called with the correct arguments').to.be.true; + }); + }); + }); +}); diff --git a/views/email/list.erb b/views/email/list.erb index abd39f0c..29e59886 100644 --- a/views/email/list.erb +++ b/views/email/list.erb @@ -12,7 +12,7 @@ <%= datastore %> <% @records[datastore].each_with_index do |record, index| %> - <%= erb :"/email/partials/_list-item", locals: { show_index: index + 1, record: record.to_h } %> + <%= erb :"/email/partials/_list-item", locals: { show_index: index + 1, record: record } %> <% end %> <% end %> diff --git a/views/email/list/txt.erb b/views/email/list/txt.erb index 4bee377a..8d6d98fa 100644 --- a/views/email/list/txt.erb +++ b/views/email/list/txt.erb @@ -5,7 +5,7 @@ <% @records.keys.each do |datastore| %> ## <%= datastore %> <% @records[datastore].each_with_index do |record, index| %> -<%= erb :"/email/partials/list-item/_txt", locals: { show_index: index + 1, record: record.to_h } %> +<%= erb :"/email/partials/list-item/_txt", locals: { show_index: index + 1, record: record } %> <% end %> <% end %> diff --git a/views/email/partials/_border.erb b/views/email/partials/_border.erb new file mode 100644 index 00000000..95a0c20f --- /dev/null +++ b/views/email/partials/_border.erb @@ -0,0 +1,7 @@ +<%# START TOP BORDER %> + + + + +
 
+<%# END TOP BORDER %> diff --git a/views/email/partials/_footer.erb b/views/email/partials/_footer.erb index f2bbbb9b..330ddcdc 100644 --- a/views/email/partials/_footer.erb +++ b/views/email/partials/_footer.erb @@ -1,13 +1,7 @@
- <%# START TOP BORDER %> - - - - -
 
- <%# END TOP BORDER %> + <%= erb :"email/partials/_border", locals: { color: "#e4e4e4", width: 2 } %> <%# START CONTENT CONTAINER %> diff --git a/views/email/partials/_list-item.erb b/views/email/partials/_list-item.erb index 7094dc6a..ccca085e 100644 --- a/views/email/partials/_list-item.erb +++ b/views/email/partials/_list-item.erb @@ -13,15 +13,15 @@
- <%= erb :"/email/partials/list-item/_title", locals: { show_index: show_index, title: record[:title], url: record[:url] } %> - <%= erb :"/email/partials/list-item/_metadata", locals: { metadata: record[:metadata] } %> + <%= erb :"/email/partials/list-item/_title", locals: { show_index: show_index, title: record.title, url: record.url } %> + <%= erb :"/email/partials/list-item/_metadata", locals: { metadata: record.metadata } %>
- <%= erb :"/email/partials/list-item/_holdings", locals: { holdings: record[:holdings] } %> + <%= erb :"/email/partials/list-item/_holdings", locals: { holdings: record.holdings } %>
diff --git a/views/email/partials/list-item/_holdings.erb b/views/email/partials/list-item/_holdings.erb index d1b4d971..13d570fd 100644 --- a/views/email/partials/list-item/_holdings.erb +++ b/views/email/partials/list-item/_holdings.erb @@ -1,46 +1,50 @@ -<%# If holdings %> -<%# START TOP BORDER %> - - - - -
 
-<%# END TOP BORDER %> - - - - - - <%# If holdings.length <= 3 %> - - - -
- <%# If holdings.length > 3 %> - - There are multiple items, locations or volumes associated with this record; please see the catalog record for full details. - - <%# Else %> - Online Resources -
+<% + summary_attributes = "bgcolor=\"#f7f8f9\" style=\"background: #f7f8f9; background-color: #f7f8f9; padding: 12px 16px; text-align: left;\"" +%> +<% if holdings.any? %> + <% if holdings.too_many? %> + <%= erb :"email/partials/_border" %> + + + + +
> + + There are multiple items, locations or volumes associated with this record; please see the catalog record for full details. + +
+ <% else %> + <% holdings.list.each do |holding| %> + <%= erb :"email/partials/_border" %> - - <% ["Link", "Description", "Source"].each do |field| %> - - <% end %> + + - - <% [ - link_to(body: "Available Online", url: "https://example.com"), - "Available from 2001.", - "Miscellaneous Ejournals. Miscellaneous Ejournals. Open access for all users. Authorized U-M users (+ guests in U-M Libraries)" - ].each do |data| %> - - <% end %> + +
- <%= field %> -
> + <%= holding.heading %> +
- <%= data %> -
+ + + <% holding.table_headings.each do |heading| %> + + <% end %> + + <% holding.rows.each do |row| %> + + <% row.each do |cell| %> + + <% end %> + + <% end %> +
+ <%= heading %> +
+ <%= erb :"email/partials/list-item/holdings/_#{cell.partial}", locals: {value: cell} %> +
+
-
\ No newline at end of file + <% end %> + <% end %> +<% end %> diff --git a/views/email/partials/list-item/_metadata.erb b/views/email/partials/list-item/_metadata.erb index e2a0412f..11cc4bcf 100644 --- a/views/email/partials/list-item/_metadata.erb +++ b/views/email/partials/list-item/_metadata.erb @@ -1,14 +1,29 @@ <% metadata.each do |data| %> - - <% end %> diff --git a/views/email/partials/list-item/_title.erb b/views/email/partials/list-item/_title.erb index b2820f4e..ae29f96f 100644 --- a/views/email/partials/list-item/_title.erb +++ b/views/email/partials/list-item/_title.erb @@ -1,7 +1,7 @@ <% heading_style = "color: #6e6e6e; font-size: 20px; font-weight: 700; margin: 0px; font-family: 'Noto Sans', Tahoma, Verdana, Arial, sans-serif; font-weight: 700; line-height: 1.5;" - link = link_to(body: title[:original], url: url) - transliterated = "#{title[:transliterated]}" + link = link_to(body: title.first.text, url: url) + transliterated = title[1] ? "#{title[1].text}" : "" %> <% if show_index %> diff --git a/views/email/partials/list-item/_txt.erb b/views/email/partials/list-item/_txt.erb index 0db9f12b..7106bbe7 100644 --- a/views/email/partials/list-item/_txt.erb +++ b/views/email/partials/list-item/_txt.erb @@ -1,4 +1,4 @@ -<%= erb :"/email/partials/list-item/title/_txt", locals: { show_index: show_index, title: record[:title], url: record[:url] } %> -<%= erb :"/email/partials/list-item/metadata/_txt", locals: { metadata: record[:metadata] } %> -<%= erb :"/email/partials/list-item/holdings/_txt", locals: { holdings: record[:holdings] } %> +<%= erb :"/email/partials/list-item/title/_txt", locals: { show_index: show_index, title: record.title, url: record.url } %> +<%= erb :"/email/partials/list-item/metadata/_txt", locals: { metadata: record.metadata } %> +<%= erb :"/email/partials/list-item/holdings/_txt", locals: { holdings: record.holdings } %> \ No newline at end of file diff --git a/views/email/partials/list-item/holdings/_link_to.erb b/views/email/partials/list-item/holdings/_link_to.erb new file mode 100644 index 00000000..9e881969 --- /dev/null +++ b/views/email/partials/list-item/holdings/_link_to.erb @@ -0,0 +1 @@ +<%= link_to(body: value.text, url: value.url) %> diff --git a/views/email/partials/list-item/holdings/_plain_text.erb b/views/email/partials/list-item/holdings/_plain_text.erb new file mode 100644 index 00000000..481e883c --- /dev/null +++ b/views/email/partials/list-item/holdings/_plain_text.erb @@ -0,0 +1 @@ +<%= value.text %> diff --git a/views/email/partials/list-item/holdings/_status.erb b/views/email/partials/list-item/holdings/_status.erb new file mode 100644 index 00000000..b7f65c4d --- /dev/null +++ b/views/email/partials/list-item/holdings/_status.erb @@ -0,0 +1,9 @@ +<% + color = case value.intent + when 'success' then '#057c42' + when 'warning' then '#aa5600' + when 'danger' then '#c53b26' + else 'inherit' + end +%> +<%= value.icon.gsub('_', ' ') %> icon<%= value.text %> diff --git a/views/email/partials/list-item/holdings/_txt.erb b/views/email/partials/list-item/holdings/_txt.erb index 286496f5..79cc48e6 100644 --- a/views/email/partials/list-item/holdings/_txt.erb +++ b/views/email/partials/list-item/holdings/_txt.erb @@ -1,11 +1,12 @@ +<% if holdings.too_many? %> [*There are multiple items, locations or volumes associated with this record; please see the catalog record for full details.*] - - **Online Resources** - * [Available Online](https://search.lib.umich.edu/everything/) - - Access requires institutional login. Authorized U-M users (no guest access). - * [Available Online](https://search.lib.umich.edu/everything/) - - Available from 2001. - - Miscellaneous Ejournals. Miscellaneous Ejournals. Open access for all users. Authorized U-M users (+ guests in U-M Libraries) +<% else %> + <% holdings.list.each do |holding| %> + **<%= holding.heading %>** + <% holding.rows.each do |row| %> + <% row.each_with_index do |cell, index| %> + <%= index === 0 ? "* " : " " %><%= erb :"email/partials/list-item/holdings/#{cell.partial}/_txt", locals: {value: cell} %> + <% end %> + <% end %> + <% end %> +<% end %> diff --git a/views/email/partials/list-item/holdings/link_to/_txt.erb b/views/email/partials/list-item/holdings/link_to/_txt.erb new file mode 100644 index 00000000..8b070100 --- /dev/null +++ b/views/email/partials/list-item/holdings/link_to/_txt.erb @@ -0,0 +1 @@ +[<%= value.text %>](<%= value.url %>) diff --git a/views/email/partials/list-item/holdings/plain_text/_txt.erb b/views/email/partials/list-item/holdings/plain_text/_txt.erb new file mode 100644 index 00000000..481e883c --- /dev/null +++ b/views/email/partials/list-item/holdings/plain_text/_txt.erb @@ -0,0 +1 @@ +<%= value.text %> diff --git a/views/email/partials/list-item/holdings/status/_txt.erb b/views/email/partials/list-item/holdings/status/_txt.erb new file mode 100644 index 00000000..481e883c --- /dev/null +++ b/views/email/partials/list-item/holdings/status/_txt.erb @@ -0,0 +1 @@ +<%= value.text %> diff --git a/views/email/partials/list-item/metadata/_academic_discipline.erb b/views/email/partials/list-item/metadata/_academic_discipline.erb new file mode 100644 index 00000000..f0eb9402 --- /dev/null +++ b/views/email/partials/list-item/metadata/_academic_discipline.erb @@ -0,0 +1,5 @@ +
    + <% value.disciplines.each_with_index do |discipline, index| %> +
  1. <%= index != 0 ? " " : "" %><%= link_to(body: discipline.text, url: discipline.url) %>
  2. + <% end %> +
diff --git a/views/email/partials/list-item/metadata/_browse.erb b/views/email/partials/list-item/metadata/_browse.erb new file mode 100644 index 00000000..39fbb33e --- /dev/null +++ b/views/email/partials/list-item/metadata/_browse.erb @@ -0,0 +1 @@ +<%= value %> diff --git a/views/email/partials/list-item/metadata/_format.erb b/views/email/partials/list-item/metadata/_format.erb new file mode 100644 index 00000000..481e883c --- /dev/null +++ b/views/email/partials/list-item/metadata/_format.erb @@ -0,0 +1 @@ +<%= value.text %> diff --git a/views/email/partials/list-item/metadata/_link_to.erb b/views/email/partials/list-item/metadata/_link_to.erb new file mode 100644 index 00000000..ae0bdec7 --- /dev/null +++ b/views/email/partials/list-item/metadata/_link_to.erb @@ -0,0 +1 @@ +<%= link_to(body: value, url: value.url) %> diff --git a/views/email/partials/list-item/metadata/_plain_text.erb b/views/email/partials/list-item/metadata/_plain_text.erb new file mode 100644 index 00000000..39fbb33e --- /dev/null +++ b/views/email/partials/list-item/metadata/_plain_text.erb @@ -0,0 +1 @@ +<%= value %> diff --git a/views/email/partials/list-item/metadata/_txt.erb b/views/email/partials/list-item/metadata/_txt.erb index 7e3d62af..89d81b4a 100644 --- a/views/email/partials/list-item/metadata/_txt.erb +++ b/views/email/partials/list-item/metadata/_txt.erb @@ -1,3 +1,9 @@ <% metadata.each do |data| %> - * **<%= data[:field] %>:** <%= data[:original]%><% if data[:transliterated] %> | <%= data[:transliterated]%><% end %> + **<%= data.field %>:** <% data.each do |value| %><% if !value.paired? %> + <%= erb :"email/partials/list-item/metadata/#{data.partial}/_txt", locals: {value: value.respond_to?(:original) ? value.original : value} %> + <% else %> + <%= erb :"email/partials/list-item/metadata/#{data.partial}/_txt", locals: { value: value.original } %> + <%= erb :"email/partials/list-item/metadata/#{data.partial}/_txt", locals: { value: value.transliterated } %> + <% end %> + <% end %> <% end %> diff --git a/views/email/partials/list-item/metadata/academic_discipline/_txt.erb b/views/email/partials/list-item/metadata/academic_discipline/_txt.erb new file mode 100644 index 00000000..ee0eeb1f --- /dev/null +++ b/views/email/partials/list-item/metadata/academic_discipline/_txt.erb @@ -0,0 +1,3 @@ +<% value.disciplines.each_with_index do |discipline, index| %> + <%= index != 0 ? "> " : "" %>[<%= discipline.text %>](<%= discipline.url %>) +<% end %> diff --git a/views/email/partials/list-item/metadata/browse/_txt.erb b/views/email/partials/list-item/metadata/browse/_txt.erb new file mode 100644 index 00000000..39fbb33e --- /dev/null +++ b/views/email/partials/list-item/metadata/browse/_txt.erb @@ -0,0 +1 @@ +<%= value %> diff --git a/views/email/partials/list-item/metadata/format/_txt.erb b/views/email/partials/list-item/metadata/format/_txt.erb new file mode 100644 index 00000000..481e883c --- /dev/null +++ b/views/email/partials/list-item/metadata/format/_txt.erb @@ -0,0 +1 @@ +<%= value.text %> diff --git a/views/email/partials/list-item/metadata/link_to/_txt.erb b/views/email/partials/list-item/metadata/link_to/_txt.erb new file mode 100644 index 00000000..8b070100 --- /dev/null +++ b/views/email/partials/list-item/metadata/link_to/_txt.erb @@ -0,0 +1 @@ +[<%= value.text %>](<%= value.url %>) diff --git a/views/email/partials/list-item/metadata/plain_text/_txt.erb b/views/email/partials/list-item/metadata/plain_text/_txt.erb new file mode 100644 index 00000000..39fbb33e --- /dev/null +++ b/views/email/partials/list-item/metadata/plain_text/_txt.erb @@ -0,0 +1 @@ +<%= value %> diff --git a/views/email/partials/list-item/title/_txt.erb b/views/email/partials/list-item/title/_txt.erb index a62ea560..52d23876 100644 --- a/views/email/partials/list-item/title/_txt.erb +++ b/views/email/partials/list-item/title/_txt.erb @@ -1,4 +1,4 @@ -<% if show_index %><%= "#{show_index}." %> ##<% end %># [<%= title[:original] %>](<%= url%>) -<% if title[:transliterated] %> - <%= title[:transliterated] %> +<% if show_index %><%= "#{show_index}." %> ##<% end %># [<%= title.first.text %>](<%= url%>) +<% if title[1] %> + <%= title[1].text %> <% end %> diff --git a/views/email/record.erb b/views/email/record.erb index 1a08a3dd..d8974fab 100644 --- a/views/email/record.erb +++ b/views/email/record.erb @@ -4,7 +4,7 @@
+ <%= data.field %> +
    + <% data.each do |value| %> +
  • + <% if value.paired? %> +
      +
    • + <%= erb :"email/partials/list-item/metadata/_#{data.partial}", locals: { value: value.original } %> +
    • +
    • + <%= erb :"email/partials/list-item/metadata/_#{data.partial}", locals: { value: value.transliterated } %> +
    • +
    + <% else %> + <% my_value = value.respond_to?(:original) ? value.original : value %> + <%= erb :"email/partials/list-item/metadata/_#{data.partial}", locals: {value: my_value} %> + <% end %> +
  • + <% end %> +
- <%= erb :"/email/partials/_list-item", locals: { show_index: nil, record: @record.to_h } %> + <%= erb :"/email/partials/_list-item", locals: { show_index: nil, record: @record } %>
diff --git a/views/email/record/txt.erb b/views/email/record/txt.erb index 9ba7a9c6..a0d8b042 100644 --- a/views/email/record/txt.erb +++ b/views/email/record/txt.erb @@ -1,5 +1,5 @@ <%= erb :"/email/partials/header/_txt" %> -<%= erb :"/email/partials/list-item/_txt", locals: { show_index: nil, record: @record.to_h } %> +<%= erb :"/email/partials/list-item/_txt", locals: { show_index: nil, record: @record } %> <%= erb :"/email/partials/ask-a-librarian/_txt" %>