umlaut 3.0.0alpha1
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.
- data/LICENSE +7 -0
- data/README.md +49 -0
- data/Rakefile +37 -0
- data/app/assets/images/error.gif +0 -0
- data/app/assets/images/export_bg_bot.gif +0 -0
- data/app/assets/images/export_bg_mid.gif +0 -0
- data/app/assets/images/export_bg_top.gif +0 -0
- data/app/assets/images/famfamfam/book_open.png +0 -0
- data/app/assets/images/famfamfam/cross.png +0 -0
- data/app/assets/images/famfamfam/page_sound.gif +0 -0
- data/app/assets/images/famfamfam/page_text.gif +0 -0
- data/app/assets/images/famfamfam/page_up.gif +0 -0
- data/app/assets/images/famfamfam/page_white.png +0 -0
- data/app/assets/images/famfamfam/readme.html +1495 -0
- data/app/assets/images/famfamfam/tiny_cross.png +0 -0
- data/app/assets/images/frame_remove.gif +0 -0
- data/app/assets/images/ico_go.gif +0 -0
- data/app/assets/images/jhu_findit.gif +0 -0
- data/app/assets/images/list_closed.png +0 -0
- data/app/assets/images/list_open.png +0 -0
- data/app/assets/images/more_info.gif +0 -0
- data/app/assets/images/rails.png +0 -0
- data/app/assets/images/request.gif +0 -0
- data/app/assets/images/spinner.gif +0 -0
- data/app/assets/javascripts/umlaut/ajax_windows.js +35 -0
- data/app/assets/javascripts/umlaut/ensure_window_size.js.erb +34 -0
- data/app/assets/javascripts/umlaut/expand_contract_toggle.js +25 -0
- data/app/assets/javascripts/umlaut/search_autocomplete.js +46 -0
- data/app/assets/javascripts/umlaut/simple_visible_toggle.js +8 -0
- data/app/assets/javascripts/umlaut/update_html.js +152 -0
- data/app/assets/javascripts/umlaut.js +17 -0
- data/app/assets/stylesheets/umlaut.css +857 -0
- data/app/controllers/application_controller.rb +14 -0
- data/app/controllers/export_email_controller.rb +123 -0
- data/app/controllers/js_helper_controller.rb +10 -0
- data/app/controllers/link_router_controller.rb +87 -0
- data/app/controllers/open_search_controller.rb +9 -0
- data/app/controllers/resolve_controller.rb +288 -0
- data/app/controllers/resource_controller.rb +83 -0
- data/app/controllers/search_controller.rb +328 -0
- data/app/controllers/search_methods/sfx3.rb +148 -0
- data/app/controllers/search_methods/sfx4.rb +257 -0
- data/app/controllers/search_methods/sfx_api.rb +47 -0
- data/app/controllers/store_controller.rb +64 -0
- data/app/controllers/umlaut/controller_behavior.rb +20 -0
- data/app/controllers/umlaut/controller_logic.rb +96 -0
- data/app/controllers/umlaut/error_handling.rb +48 -0
- data/app/controllers/umlaut_controller.rb +112 -0
- data/app/helpers/application_helper.rb +4 -0
- data/app/helpers/emailer_helper.rb +43 -0
- data/app/helpers/export_email_helper.rb +34 -0
- data/app/helpers/open_search_helper.rb +7 -0
- data/app/helpers/resolve_helper.rb +225 -0
- data/app/helpers/search_helper.rb +50 -0
- data/app/helpers/umlaut/footer_helper.rb +64 -0
- data/app/helpers/umlaut/helper.rb +62 -0
- data/app/helpers/umlaut/html_head_helper.rb +37 -0
- data/app/helpers/umlaut/url_generation.rb +77 -0
- data/app/mailers/emailer.rb +48 -0
- data/app/models/clickthrough.rb +2 -0
- data/app/models/collection.rb +259 -0
- data/app/models/crossref_lookup.rb +2 -0
- data/app/models/dispatched_service.rb +58 -0
- data/app/models/permalink.rb +29 -0
- data/app/models/referent.rb +473 -0
- data/app/models/referent_value.rb +14 -0
- data/app/models/request.rb +449 -0
- data/app/models/service_response.rb +179 -0
- data/app/models/service_store.rb +59 -0
- data/app/models/service_type_value.rb +58 -0
- data/app/models/service_wave.rb +150 -0
- data/app/models/sfx_db/az_additional_title.rb +11 -0
- data/app/models/sfx_db/az_letter_group.rb +11 -0
- data/app/models/sfx_db/az_title.rb +38 -0
- data/app/models/sfx_db/az_title_v2.rb +34 -0
- data/app/models/sfx_db/isbn.rb +12 -0
- data/app/models/sfx_db/issn.rb +12 -0
- data/app/models/sfx_db/object.rb +35 -0
- data/app/models/sfx_db/object_portfolio.rb +6 -0
- data/app/models/sfx_db/publisher.rb +10 -0
- data/app/models/sfx_db/sfx_db_base.rb +54 -0
- data/app/models/sfx_db/target.rb +9 -0
- data/app/models/sfx_db/target_service.rb +10 -0
- data/app/models/sfx_db/title.rb +10 -0
- data/app/models/sfx_db.rb +10 -0
- data/app/models/sfx_url.rb +35 -0
- data/app/views/emailer/citation.text.erb +28 -0
- data/app/views/emailer/short_citation.text.erb +8 -0
- data/app/views/export_email/_email.html.erb +25 -0
- data/app/views/export_email/_send_email.html.erb +3 -0
- data/app/views/export_email/_send_txt.html.erb +3 -0
- data/app/views/export_email/_txt.html.erb +62 -0
- data/app/views/export_email/email.html.erb +3 -0
- data/app/views/export_email/send_email.html.erb +1 -0
- data/app/views/export_email/send_txt.html.erb +1 -0
- data/app/views/export_email/txt.html.erb +3 -0
- data/app/views/js_helper/loader.erb.js +13 -0
- data/app/views/layouts/umlaut.html.erb +52 -0
- data/app/views/open_search/index.html.erb +9 -0
- data/app/views/resolve/_api_in_progress.xml.erb +21 -0
- data/app/views/resolve/_background_progress.html.erb +51 -0
- data/app/views/resolve/_background_updater.html.erb +38 -0
- data/app/views/resolve/_citation.html.erb +87 -0
- data/app/views/resolve/_coins.html.erb +1 -0
- data/app/views/resolve/_compact_citation.html.erb +33 -0
- data/app/views/resolve/_cover_image.html.erb +35 -0
- data/app/views/resolve/_fulltext.html.erb +55 -0
- data/app/views/resolve/_help.html.erb +17 -0
- data/app/views/resolve/_holding.html.erb +91 -0
- data/app/views/resolve/_related_items.html.erb +35 -0
- data/app/views/resolve/_search_inside.html.erb +62 -0
- data/app/views/resolve/_section_display.html.erb +49 -0
- data/app/views/resolve/_service_errors.html.erb +29 -0
- data/app/views/resolve/_standard_response_item.html.erb +89 -0
- data/app/views/resolve/api.xml.builder +72 -0
- data/app/views/resolve/background_status.html.erb +26 -0
- data/app/views/resolve/index.html.erb +73 -0
- data/app/views/resolve/partial_html_sections.xml.erb +30 -0
- data/app/views/search/_a_to_z.html.erb +6 -0
- data/app/views/search/_citation.html.erb +94 -0
- data/app/views/search/_pager.html.erb +60 -0
- data/app/views/search/books.html.erb +103 -0
- data/app/views/search/journal_search.html.erb +90 -0
- data/app/views/search/journals.html.erb +167 -0
- data/app/views/search/opensearch_description.rxml +10 -0
- data/app/views/testing/index.html.erb +1 -0
- data/app/views/umlaut/README +5 -0
- data/app/views/umlaut/error.html.erb +45 -0
- data/db/migrate/01_umlaut_init.rb +113 -0
- data/db/orig_fixed_data/service_type_values.yml +120 -0
- data/db/seeds.rb +7 -0
- data/lib/CronTab.rb +192 -0
- data/lib/aws_product_sign.rb +146 -0
- data/lib/exlibris/aleph/patron.rb +64 -0
- data/lib/exlibris/aleph/record.rb +54 -0
- data/lib/exlibris/aleph/rest_api.rb +29 -0
- data/lib/exlibris/primo/holding.rb +192 -0
- data/lib/exlibris/primo/rsrc.rb +17 -0
- data/lib/exlibris/primo/searcher.rb +276 -0
- data/lib/exlibris/primo/source/aleph.rb +46 -0
- data/lib/exlibris/primo/source/distribution/nyu_aleph.rb +323 -0
- data/lib/exlibris/primo/toc.rb +17 -0
- data/lib/exlibris/primo_ws.rb +140 -0
- data/lib/generators/templates/umlaut_services.yml +237 -0
- data/lib/generators/umlaut/asset_hooks_generator.rb +44 -0
- data/lib/generators/umlaut/install_generator.rb +110 -0
- data/lib/hip3/bib.rb +291 -0
- data/lib/hip3/bib_searcher.rb +302 -0
- data/lib/hip3/custom_field_lookup.rb +44 -0
- data/lib/hip3/holding.rb +50 -0
- data/lib/hip3/item.rb +65 -0
- data/lib/hip3/receipt.rb +7 -0
- data/lib/hip3/serial_copy.rb +82 -0
- data/lib/holding.rb +32 -0
- data/lib/marc_helper.rb +254 -0
- data/lib/metadata_helper.rb +312 -0
- data/lib/opensearch_feed.rb +398 -0
- data/lib/opensearch_query.rb +98 -0
- data/lib/referent_filter.rb +16 -0
- data/lib/referent_filters/dissertation_catch.rb +45 -0
- data/lib/section_renderer.rb +503 -0
- data/lib/service.rb +336 -0
- data/lib/service_adaptors/ajax_export.rb +37 -0
- data/lib/service_adaptors/amazon.rb +412 -0
- data/lib/service_adaptors/blacklight.rb +327 -0
- data/lib/service_adaptors/book_finder.rb +40 -0
- data/lib/service_adaptors/bx.rb +51 -0
- data/lib/service_adaptors/cover_thing.rb +73 -0
- data/lib/service_adaptors/elsevier_cover.rb +57 -0
- data/lib/service_adaptors/email_export.rb +10 -0
- data/lib/service_adaptors/ezproxy.rb +171 -0
- data/lib/service_adaptors/google_book_search.rb +442 -0
- data/lib/service_adaptors/gpo.rb +124 -0
- data/lib/service_adaptors/hathi_trust.rb +308 -0
- data/lib/service_adaptors/hip3_service.rb +150 -0
- data/lib/service_adaptors/hip_holding_search.rb +237 -0
- data/lib/service_adaptors/internet_archive.rb +488 -0
- data/lib/service_adaptors/isbn_db.rb +86 -0
- data/lib/service_adaptors/isi.rb +258 -0
- data/lib/service_adaptors/jcr.rb +146 -0
- data/lib/service_adaptors/opac.rb +351 -0
- data/lib/service_adaptors/open_library.rb +316 -0
- data/lib/service_adaptors/open_library_cover.rb +73 -0
- data/lib/service_adaptors/primo_service.rb +392 -0
- data/lib/service_adaptors/primo_source.rb +78 -0
- data/lib/service_adaptors/pubmed.rb +133 -0
- data/lib/service_adaptors/request_to_fixture.rb +68 -0
- data/lib/service_adaptors/scopus.rb +295 -0
- data/lib/service_adaptors/sfx-new.rb +557 -0
- data/lib/service_adaptors/sfx.rb +566 -0
- data/lib/service_adaptors/sfx_backchannel_record.rb +69 -0
- data/lib/service_adaptors/txt_holding_export.rb +32 -0
- data/lib/service_adaptors/ulrichs_cover.rb +57 -0
- data/lib/service_adaptors/ulrichs_link.rb +47 -0
- data/lib/service_adaptors/worldcat.rb +116 -0
- data/lib/service_adaptors/worldcat_identities.rb +591 -0
- data/lib/tasks/umlaut.rake +134 -0
- data/lib/umlaut/default_configuration.rb +5 -0
- data/lib/umlaut/routes.rb +136 -0
- data/lib/umlaut/version.rb +3 -0
- data/lib/umlaut.rb +37 -0
- data/lib/umlaut_configurable.rb +343 -0
- data/lib/umlaut_http.rb +100 -0
- data/lib/xml_schema_helper.rb +109 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/umlaut_controller.rb +112 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database-jhu.yml +44 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +34 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +61 -0
- data/test/dummy/config/umlaut_services.yml +237 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20111228211210_umlaut_init.rb +113 -0
- data/test/dummy/db/schema.rb +124 -0
- data/test/dummy/log/development.log +12981 -0
- data/test/dummy/log/production.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/dummy/tmp/cache/assets/C5F/340/sprockets%2F99692920160b7a279b86a80415b79db7 +0 -0
- data/test/dummy/tmp/cache/assets/C70/4D0/sprockets%2F034ad2036e623081bd352800786dfe80 +0 -0
- data/test/dummy/tmp/cache/assets/C73/920/sprockets%2Fd371318f22900492fd180f17c5e2a504 +9268 -0
- data/test/dummy/tmp/cache/assets/C80/980/sprockets%2Fc94807409c1523d43e18d25f35d93c41 +0 -0
- data/test/dummy/tmp/cache/assets/C8F/780/sprockets%2Fe47e28558116fb5f8038754e60d1961d +11769 -0
- data/test/dummy/tmp/cache/assets/CAA/EB0/sprockets%2F1d179210e8b76f1ea63c802688a015e4 +9271 -0
- data/test/dummy/tmp/cache/assets/CBB/9C0/sprockets%2F706f28923fb754cad04b9107c89986a1 +0 -0
- data/test/dummy/tmp/cache/assets/CBF/B60/sprockets%2F08ca89671549936265dcb673bf02e36f +0 -0
- data/test/dummy/tmp/cache/assets/CC9/9F0/sprockets%2F306166316e2cafd13c15e62b51a2339d +0 -0
- data/test/dummy/tmp/cache/assets/CF6/F20/sprockets%2F5b2ffa1103079dfd555197838f87a99f +0 -0
- data/test/dummy/tmp/cache/assets/CF7/2B0/sprockets%2F25a7c73655bd3598173b39d9f98bcd46 +862 -0
- data/test/dummy/tmp/cache/assets/CFE/080/sprockets%2F37fe9f4255baddbd549a659914929398 +0 -0
- data/test/dummy/tmp/cache/assets/D22/060/sprockets%2F9aec77b768e91a802d284271c58e2f7e +21357 -0
- data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/D33/6D0/sprockets%2F500129c57f1146e556ec3aacd6cd38c1 +0 -0
- data/test/dummy/tmp/cache/assets/D33/FD0/sprockets%2F2ba0b4e6334a77b923e5f770381bb2bf +0 -0
- data/test/dummy/tmp/cache/assets/D42/C20/sprockets%2Fbcf14e437b1582bf93b77670acf8e090 +21353 -0
- data/test/dummy/tmp/cache/assets/D50/A30/sprockets%2F7d8b294ac433db5d056538f8cf7c66b9 +0 -0
- data/test/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +872 -0
- data/test/dummy/tmp/cache/assets/D65/590/sprockets%2Fc1bb92fc3406a126b7dd302edc96d629 +0 -0
- data/test/dummy/tmp/cache/assets/D71/6B0/sprockets%2Fde558b71b494cf09b1bf055c8dff0353 +0 -0
- data/test/dummy/tmp/cache/assets/D72/610/sprockets%2Fa8c708eeb30ef93de34d755d4f45d023 +859 -0
- data/test/dummy/tmp/cache/assets/D76/AD0/sprockets%2Fe2158cde93188cf5ab6457bc6d6602ec +0 -0
- data/test/dummy/tmp/cache/assets/D7A/E40/sprockets%2F9622ffcc499a57627cd1bb18fe31b8e4 +11772 -0
- data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +0 -0
- data/test/dummy/tmp/cache/assets/D9B/770/sprockets%2F8aacf02eb7dbb0949704b28f27b87e0b +0 -0
- data/test/dummy/tmp/cache/assets/DA6/A80/sprockets%2F92e26d8e58d5bcc8b8f6c25d1b05b9c1 +0 -0
- data/test/dummy/tmp/cache/assets/DE8/790/sprockets%2Fd1333bde2b9aafcc712d11dd09ab35d8 +0 -0
- data/test/dummy/tmp/cache/assets/DF7/F30/sprockets%2F7bc16c4109b17fabe29f8ddbbf732d1c +374 -0
- data/test/dummy/tmp/cache/assets/E03/570/sprockets%2F493bdc0ac14cd4f57fdfe4253f992bde +0 -0
- data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/E0B/4B0/sprockets%2F7988df51a61c81ce6ede4a2d4c8cce4f +377 -0
- data/test/dummy/tmp/cache/assets/E5F/960/sprockets%2Fdc007b6cad5c7ef08e33ec28cfff0ef6 +0 -0
- data/test/fixtures/dispatched_services.yml +5 -0
- data/test/fixtures/permalinks.yml +5 -0
- data/test/fixtures/referent_values.yml +1734 -0
- data/test/fixtures/referents.yml +156 -0
- data/test/fixtures/requests.yml +284 -0
- data/test/fixtures/service_responses.yml +5 -0
- data/test/fixtures/sfx_urls.yml +4 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +10 -0
- data/test/umlaut_test.rb +7 -0
- data/test/unit/aleph_patron_test.rb +39 -0
- data/test/unit/aleph_record_benchmarks.rb +28 -0
- data/test/unit/aleph_record_test.rb +30 -0
- data/test/unit/aws_product_sign_test.rb +93 -0
- data/test/unit/collection_test.rb +76 -0
- data/test/unit/google_book_search_test.rb +101 -0
- data/test/unit/primo_searcher_test.rb +403 -0
- data/test/unit/primo_service_test.rb +939 -0
- data/test/unit/primo_ws_test.rb +131 -0
- data/test/unit/service_response_test.rb +9 -0
- data/test/unit/service_test.rb +33 -0
- metadata +580 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
# Kind of analagous to SFX "source parser". Takes ContextObjects
|
2
|
+
# passed in, and filters/mutates them.
|
3
|
+
#
|
4
|
+
# specific subclasses in lib/context_object_filters
|
5
|
+
#
|
6
|
+
# configured to apply in environment.rb
|
7
|
+
|
8
|
+
class ReferentFilter
|
9
|
+
|
10
|
+
# input: Referent object
|
11
|
+
# will mutate/modify it.
|
12
|
+
def filter(referent)
|
13
|
+
# implement in subclass
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
class DissertationCatch < ReferentFilter
|
2
|
+
include MetadataHelper
|
3
|
+
|
4
|
+
@@da_issns = ['00959154', '00993123', '04194209', '04194217', '0420073X', '00993123', '10427279', '03076075']
|
5
|
+
|
6
|
+
# input: ropenurl ContextObject
|
7
|
+
# Is this a citation to a Dissertation Abstracts
|
8
|
+
# issn, or do we otherwise think it's a dissertation citation? Then change
|
9
|
+
# it to a dissertation citation.
|
10
|
+
def filter(referent)
|
11
|
+
issn = get_identifier(:urn, "issn", referent)
|
12
|
+
|
13
|
+
return unless issn
|
14
|
+
|
15
|
+
# normalize removing hyphen
|
16
|
+
issn.gsub!('-', '')
|
17
|
+
|
18
|
+
if ( @@da_issns.find { |i| i == issn } )
|
19
|
+
# || lc($jtitle) =~ /dissertation/i || lc($jtitle2) =~ /dissertation/i)
|
20
|
+
|
21
|
+
referent.enhance_referent("genre", "dissertation")
|
22
|
+
|
23
|
+
metadata = referent.metadata
|
24
|
+
# Reset it's title to the dissertation title
|
25
|
+
title = metadata['atitle'] || metadata['title']
|
26
|
+
referent.enhance_referent("btitle", title)
|
27
|
+
referent.enhance_referent("title", title, true, false, :overwrite => true)
|
28
|
+
# Now erase titles that do not apply
|
29
|
+
referent.remove_value("atitle")
|
30
|
+
referent.remove_value("jtitle")
|
31
|
+
referent.remove_value("stitle")
|
32
|
+
# issn or isbn are wrong, probably point to Dissertation Abstracts
|
33
|
+
referent.remove_value("issn")
|
34
|
+
referent.remove_value("isbn")
|
35
|
+
# Same with all article level metadata
|
36
|
+
referent.remove_value("volume")
|
37
|
+
referent.remove_value("issue")
|
38
|
+
referent.remove_value("issue_start")
|
39
|
+
referent.remove_value("spage")
|
40
|
+
referent.remove_value("epage")
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,503 @@
|
|
1
|
+
# = The Section Architecture
|
2
|
+
#
|
3
|
+
# Umlaut has what could be considered a 'domain specific language' for
|
4
|
+
# describing the display individual sections of content on the resolve menu
|
5
|
+
# page. These sections often correspond to a ServiceTypeValue, like "fulltext".
|
6
|
+
# But sometimes may include multiple ServiceTypeValues (eg related_items section
|
7
|
+
# includes cited_by and similar_items), or no ServiceTypeValue at all (eg
|
8
|
+
# section to display a COinS).
|
9
|
+
#
|
10
|
+
# A description of a section is simply a hash with certain conventional
|
11
|
+
# keys describing various aspects of the contents and display of that section.
|
12
|
+
# These hashes are listed in the resolve_sections application configuration
|
13
|
+
# variable, initialized in the resolve_views.rb initializer, and customized
|
14
|
+
# or over-ridden in the local resolve_views.rb initializer.
|
15
|
+
#
|
16
|
+
# One benefit of describing a section through configuration is that section
|
17
|
+
# display can often by changed at configure time without requiring a code
|
18
|
+
# time. Another is that the description of the section can be used not
|
19
|
+
# only to generate the initial HTML page; but also by the javascript that
|
20
|
+
# update the sections with new background content as available; and by the
|
21
|
+
# partial_html_sections api that delivers HTML fragments for sections in an
|
22
|
+
# XML or JSON container.
|
23
|
+
#
|
24
|
+
# A description of a section is simply a hash, suitable for passing to
|
25
|
+
# SectionRenderer.new, detailed below. Plus some additional variables
|
26
|
+
# specifying _where_ to display the section, documented in the resolve_views.rb
|
27
|
+
# initializer.
|
28
|
+
#
|
29
|
+
# = The SectionRenderer
|
30
|
+
# A SectionRenderer object provides logic for displaying a specific section
|
31
|
+
# on the Umlaut resolve menu page. It is initialized with a hash describing
|
32
|
+
# the details -- or significantly, with simply a pointer to such a hash
|
33
|
+
# already existing in the resolve_sections config variable.
|
34
|
+
#
|
35
|
+
# A SectionRenderer is typically created by the ResolveHelper#render_section
|
36
|
+
# method, which then passes the SectionRender object to the
|
37
|
+
# _section_display.erb.html that does the actual rendering, using
|
38
|
+
# the SectionRenderer for logic and hashes to pass to render calls in
|
39
|
+
# the partial.
|
40
|
+
#
|
41
|
+
#
|
42
|
+
# == Section Options
|
43
|
+
#
|
44
|
+
# Section options are typically configured in hashes in the application
|
45
|
+
# config variable resolve_sections, which is expected to be a list of hashes.
|
46
|
+
# That hash is suitable to be passed to a SectionRenderer.new() as configuration
|
47
|
+
# options for the section. The various ways these options can be used
|
48
|
+
# is documented below.
|
49
|
+
#
|
50
|
+
# === Simplest Case, Defaults
|
51
|
+
#
|
52
|
+
# As is common in ruby, SectionRenderer will make a lot of conventional
|
53
|
+
# assumptions, allowing you to be very concise for the basic simple case:
|
54
|
+
#
|
55
|
+
# { :div_id => "fulltext", :html_area => :main }
|
56
|
+
#
|
57
|
+
# This means that:
|
58
|
+
# * this section is assumed to be contained within a <div id="fulltext">. The
|
59
|
+
# div won't be automatically rendered, it's the containing pages
|
60
|
+
# responsibility to put in a div with this id.
|
61
|
+
#
|
62
|
+
# * this section is assumed to contain responses of type
|
63
|
+
# ServiceTypeValue["fulltext"]
|
64
|
+
#
|
65
|
+
# * The section will be displayed with stock heading block including a title
|
66
|
+
# constructed from the display_name of ServiceTypeValue["fulltext"], or
|
67
|
+
# in general the display_name of the first ServiceTypeValue included
|
68
|
+
# in this section.
|
69
|
+
#
|
70
|
+
# * The section will include a stock 'spinner' if there are potential background
|
71
|
+
# results being gathered for the ServiceTypeValue(s) contained.
|
72
|
+
#
|
73
|
+
# * The actual ServiceResponses collected for the ServiceTypeValue included
|
74
|
+
# will be rendered with a _standard_response_item
|
75
|
+
# partial, using render :collection.
|
76
|
+
#
|
77
|
+
# * The section will be displayed whether or not there are any actual
|
78
|
+
# responses included. If there are no responses, a message will be displayed
|
79
|
+
# to that effect.
|
80
|
+
#
|
81
|
+
# The display of a section can be customized via configuration parameters to
|
82
|
+
# a large degree, including supplying your own partial to take over almost
|
83
|
+
# all display of the section.
|
84
|
+
#
|
85
|
+
# === Customizing ServiceTypeValues
|
86
|
+
#
|
87
|
+
# You can specifically supply the ServiceTypeValues contained in this
|
88
|
+
# section, to a different type than would be guessed from the div_id:
|
89
|
+
#
|
90
|
+
# {:div_id => "my_area", :service_type_values => ["fulltext"]}
|
91
|
+
#
|
92
|
+
# Or specify multiple types included in one section:
|
93
|
+
#
|
94
|
+
# {:div_id => "related_items", :service_type_values => ['cited_by', 'similar]}
|
95
|
+
#
|
96
|
+
# Or a section that isn't used for displaying service responses at all,
|
97
|
+
# and has no service type:
|
98
|
+
#
|
99
|
+
# {:div_id => "coins", :partial => "coins", :service_type_values => []}
|
100
|
+
#
|
101
|
+
# Note that a custom partial needs to be supplied if there are no service_type_values supplied.
|
102
|
+
#
|
103
|
+
# === Customizing heading display
|
104
|
+
#
|
105
|
+
# You can supply a title for the section that's different than what would
|
106
|
+
# be guessed from it's ServiceTypeValues. You can also supply a prompt.
|
107
|
+
#
|
108
|
+
# {:div_id =>"excerpts", :section_title=>"Lots of good stuff", :section_prompt => "Limited previes and excerpts."}
|
109
|
+
#
|
110
|
+
# You can also suppress display of the stock section heading at all:
|
111
|
+
# {:show_heading => false, ...}
|
112
|
+
#
|
113
|
+
# This may be becuase you don't want a heading, or because you are supplying
|
114
|
+
# a custom partial that will take care of the heading in a custom way.
|
115
|
+
#
|
116
|
+
# === Customizing spinner display
|
117
|
+
#
|
118
|
+
# You can also suppress display of the stock spinner, because you don't
|
119
|
+
# want a spinner, or because your custom partial will be taking care of it.
|
120
|
+
# {:show_spinner => false, ...}
|
121
|
+
#
|
122
|
+
# By default, the spinner displays what type of thing it's waiting on, guessing
|
123
|
+
# from the ServiceTypeValue configured. If you want to specify this item name:
|
124
|
+
# {:item_name_plural => "Related Items", ...}
|
125
|
+
#
|
126
|
+
# === Customizing visibility of section
|
127
|
+
#
|
128
|
+
# By default, a section will simply be displayed regardless of whether
|
129
|
+
# there are any actual responses to display. However, the 'visibility'
|
130
|
+
# argument can be used to customize this in many ways.
|
131
|
+
# visibilty:
|
132
|
+
# [*true*]
|
133
|
+
# Default, always show section.
|
134
|
+
# [*false*]
|
135
|
+
# Never show section. (Not sure why you'd want this).
|
136
|
+
# [<b>:any_services</b>]
|
137
|
+
# Show section if and only if there are any configured
|
138
|
+
# services that generate the ServiceTypeValues included
|
139
|
+
# in this section, regardless of whether in this case
|
140
|
+
# they have or not.
|
141
|
+
# [<b>:in_progress</b>]
|
142
|
+
# Show the section if responses exist, OR if any services
|
143
|
+
# are currently in progress that are capable of generating
|
144
|
+
# responses of the right type for this section.
|
145
|
+
# [<b>:responses_exist</b>]
|
146
|
+
# Show the section if and only if some responses
|
147
|
+
# have actually been generated of the types contained
|
148
|
+
# in this section.
|
149
|
+
# [<b>:complete_with_responses</b>]
|
150
|
+
# Show the section only if there are responses
|
151
|
+
# generated, AND all services supplying
|
152
|
+
# responses of the type contained in section
|
153
|
+
# have completed, no more responses are possible.
|
154
|
+
# [<b>(lambda object)</b>]
|
155
|
+
# Most flexibly of all, you can supply your own lambda
|
156
|
+
# supplying custom logic to determine whether to show
|
157
|
+
# the section, based on current context. The lambda
|
158
|
+
# will be passed the SectionRenderer object as an argument,
|
159
|
+
# providing access to the Umlaut Request with context.
|
160
|
+
# eg:
|
161
|
+
# :visibility => lambda do |renderer|
|
162
|
+
# renderer.request.something == something
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# === List with limit
|
166
|
+
#
|
167
|
+
# You can have the section automatically use the ResolveHelper#list_with_limit
|
168
|
+
# helper to limit the number of items initially displayed, with the rest behind
|
169
|
+
# a 'more' expand/contract widget.
|
170
|
+
#
|
171
|
+
# { :div_id => "highlighted_link",
|
172
|
+
# :list_visible_limit => 1,
|
173
|
+
# :visibility => :in_progress, ... }
|
174
|
+
#
|
175
|
+
# === Custom partial display
|
176
|
+
#
|
177
|
+
# By default, the SectionRenderer assumes that all the ServiceResposnes included
|
178
|
+
# are capable of being displayed by the standard_item_response, and displays
|
179
|
+
# them simply by render standard_item_response with a \:colection. Sometimes
|
180
|
+
# this assumption isn't true, or you want custom display for other reasons.
|
181
|
+
# You can supply your own partial that the renderer will use to display
|
182
|
+
# the content.
|
183
|
+
#
|
184
|
+
# { :div_id => "my_div", :partial => "my_partial", ... }
|
185
|
+
#
|
186
|
+
# The partial so supplied should live in resolve/_my_partial.html.erb
|
187
|
+
#
|
188
|
+
# When this partial is called, it will have local variables set
|
189
|
+
# to give it the data it needs in order to create a display:
|
190
|
+
#
|
191
|
+
# [*responses_by_type*]
|
192
|
+
# a hash keyed by ServiceTypeValue name, with the
|
193
|
+
# the value being an array of the respective ServiceType
|
194
|
+
# objects.
|
195
|
+
# [*responses*] a flattened list of all ServiceTypes included in
|
196
|
+
# this section, of varying ServiceTypeValues. Most
|
197
|
+
# useful when the section only includes one
|
198
|
+
# ServiceTypeValue
|
199
|
+
# [*renderer*] The SectionRenderer object itself, from which
|
200
|
+
# the current umlaut request can be obtained,
|
201
|
+
# among other things.
|
202
|
+
#
|
203
|
+
# You can supply additional static local arguments to the partial
|
204
|
+
# in the SectionRenderer setup:
|
205
|
+
#
|
206
|
+
# {:div_id=> "foo", :partial=>"my_partial", :partial_locals => {:mode => "big"}, ... }
|
207
|
+
#
|
208
|
+
# the :partial_locals argument can be used with the standard_response_item
|
209
|
+
# too:
|
210
|
+
# {:div_id => "highlighted_link", :partial_locals => {:show_source => true}}
|
211
|
+
#
|
212
|
+
# Note that your custom partial will still be displayed with stock
|
213
|
+
# header and possibly spinner surrounding it. You can suppress these elements:
|
214
|
+
#
|
215
|
+
# {:div_id => "cover_image", :partial => "cover_image", :show_heading => false, :show_spinner => false}
|
216
|
+
#
|
217
|
+
# But even so, some 'wrapping' html is rendered surrounding your partial.
|
218
|
+
# If you want to disable even this, becuase your partial will take care of it
|
219
|
+
# itself, you can do so with \:show_partial_only => true
|
220
|
+
# {:div_id => "search_inside", :partial => "search_inside", :show_partial_only => true}
|
221
|
+
class SectionRenderer
|
222
|
+
include ActionView::Helpers::TagHelper
|
223
|
+
@@bg_update_sections = @@partial_update_sections = nil
|
224
|
+
|
225
|
+
# First argument is the current umlaut Request object.
|
226
|
+
# Second argument is a session description hash. See class overview
|
227
|
+
# for an overview. Recognized keys of session description hash:
|
228
|
+
# * [id] SessionRenderer will look up session description hash in
|
229
|
+
# resolve_views finding one with :div_id == id
|
230
|
+
# * [div_id] The id of the <div> the section lives in. Also used
|
231
|
+
# generally as unique ID for the section.
|
232
|
+
# * [service_type_values] ServiceTypeValue's that this section contains.
|
233
|
+
# defaults to [ServiceTypeValue[div_id]]
|
234
|
+
# * [section_title] Title for the section. Defaults to
|
235
|
+
# service_type_values.first.display_name
|
236
|
+
# * [section_prompt] Prompt. Default nil.
|
237
|
+
# * [show_heading] Show the heading section at all. Default true.
|
238
|
+
# * [show_spinner] Show a stock spinner for bg action for service_type_values.
|
239
|
+
# default true.
|
240
|
+
# * [item_name_plural] Pluralized name of the objects included, used in
|
241
|
+
# spinner message. Default
|
242
|
+
# service_type_values.first.display_name_pluralize
|
243
|
+
# * [visibilty] What logic to use to decide whether to show the section at
|
244
|
+
# all. true|false|:any_services|:in_progress|:responses_exist|:complete_with_responses|(lambda object)
|
245
|
+
# * [list_visible_limit] Use list_with_limit to limit initially displayed
|
246
|
+
# items to value. Default nil, meaning don't use
|
247
|
+
# list_with_limit.
|
248
|
+
# * [partial] Use a custom partial to display this section, instead of
|
249
|
+
# using render("standard_response_item", :collection => [all responses]) as default.
|
250
|
+
# * [show_partial_only] Display custom partial without any of the usual
|
251
|
+
# standardized wrapping HTML. Custom partial will
|
252
|
+
# take care of it itself.
|
253
|
+
def initialize(a_umlaut_request, section_def = {})
|
254
|
+
@umlaut_request = a_umlaut_request
|
255
|
+
|
256
|
+
@section_id = section_def[:id] || section_def[:div_id]
|
257
|
+
raise Exception.new("SectionRenderer needs an :id passed in arguments hash") unless @section_id
|
258
|
+
|
259
|
+
# Merge in default arguments for this section from config.
|
260
|
+
construct_options(section_def)
|
261
|
+
|
262
|
+
end
|
263
|
+
|
264
|
+
# Returns all ServiceTypeValue objects contained in this section, as
|
265
|
+
# configured. Lazy caches result for perfomance.
|
266
|
+
def service_type_values
|
267
|
+
@service_type_values ||=
|
268
|
+
@options[:service_type_values].collect do |s|
|
269
|
+
s.kind_of?(ServiceTypeValue)? s : ServiceTypeValue[s]
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# Whether any services that generate #service_type_values are
|
274
|
+
# currently in progress. Lazy caches result for efficiency.
|
275
|
+
def services_in_progress?
|
276
|
+
# cache for efficiency
|
277
|
+
@services_in_progress ||=
|
278
|
+
@umlaut_request.service_types_in_progress?(service_type_values)
|
279
|
+
end
|
280
|
+
|
281
|
+
# Hash of ServiceType objects (join obj
|
282
|
+
# representing individual reponse data) included in this
|
283
|
+
# section. Keyed by string ServiceTypeValue id, value is array
|
284
|
+
# of ServiceTypes
|
285
|
+
def responses
|
286
|
+
unless (@responses)
|
287
|
+
@responses = {}
|
288
|
+
service_type_values.each do |st|
|
289
|
+
@responses[st.name] = @umlaut_request.get_service_type(st)
|
290
|
+
end
|
291
|
+
end
|
292
|
+
@responses
|
293
|
+
end
|
294
|
+
|
295
|
+
# All the values from #responses, flattened into a simple Array.
|
296
|
+
def responses_list
|
297
|
+
responses.values.flatten
|
298
|
+
end
|
299
|
+
|
300
|
+
def responses_empty?
|
301
|
+
responses_list.empty?
|
302
|
+
end
|
303
|
+
|
304
|
+
def request
|
305
|
+
return @umlaut_request
|
306
|
+
end
|
307
|
+
|
308
|
+
def div_id
|
309
|
+
return @section_id
|
310
|
+
end
|
311
|
+
|
312
|
+
def show_heading?
|
313
|
+
(! show_partial_only?) && @options[:show_heading]
|
314
|
+
end
|
315
|
+
|
316
|
+
def render_heading
|
317
|
+
content_tag(:div, :class=>"section_heading")
|
318
|
+
|
319
|
+
output = ''
|
320
|
+
|
321
|
+
output <<= '<div class="section_heading">'
|
322
|
+
(output <<= '<h3>' << CGI::escapeHTML(section_title) << '</h3>') if section_title
|
323
|
+
(output <<= '<p class="section_prompt">' << CGI::escapeHTML(section_prompt) << '</p>') if section_prompt
|
324
|
+
output <<= '</div>'
|
325
|
+
|
326
|
+
output.html_safe
|
327
|
+
end
|
328
|
+
|
329
|
+
def show_spinner?
|
330
|
+
(! show_partial_only?) && @options[:show_spinner] &&
|
331
|
+
@umlaut_request.service_types_in_progress?(service_type_values)
|
332
|
+
end
|
333
|
+
|
334
|
+
# A hash suitable to be passed to Rails render(), to render
|
335
|
+
# a spinner for this section. Called by section_display partial,
|
336
|
+
# nobody else should need to call it.
|
337
|
+
def spinner_render_hash
|
338
|
+
{ :partial => "background_progress",
|
339
|
+
:locals =>{ :svc_types => service_type_values,
|
340
|
+
:div_id => "progress_#{@section_id}",
|
341
|
+
:current_set_empty => responses_empty?,
|
342
|
+
:item_name => @options[:item_name_plural]}
|
343
|
+
}
|
344
|
+
end
|
345
|
+
|
346
|
+
def show_partial_only?
|
347
|
+
@options[:show_partial_only]
|
348
|
+
end
|
349
|
+
|
350
|
+
def custom_partial?
|
351
|
+
! @options[:partial].nil?
|
352
|
+
end
|
353
|
+
|
354
|
+
# A hash suitable to be passed to Rails render() to render the
|
355
|
+
# inner content portion of the section. Called by the section_display
|
356
|
+
# partial, nobody else should need to call this. You may be looking
|
357
|
+
# for ResolveHelper#render_section instead.
|
358
|
+
def content_render_hash
|
359
|
+
if custom_partial?
|
360
|
+
{:partial => @options[:partial].to_s,
|
361
|
+
:object => responses_list,
|
362
|
+
:locals => @options[:partial_locals].merge(
|
363
|
+
{:responses_by_type => responses,
|
364
|
+
:responses => responses_list,
|
365
|
+
:umlaut_request => request,
|
366
|
+
:renderer => self})}
|
367
|
+
else
|
368
|
+
{:partial => @options[:item_partial].to_s,
|
369
|
+
:collection => responses_list,
|
370
|
+
:locals => @options[:partial_locals].clone}
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
# used only with with list_with_limit functionality in section_display
|
375
|
+
# partial.
|
376
|
+
def item_render_hash(item)
|
377
|
+
# need to clone @options[:partial_locals], because
|
378
|
+
# Rails will modify it to add the 'object' to it. Bah!
|
379
|
+
{:partial => @options[:item_partial],
|
380
|
+
:object => item,
|
381
|
+
:locals => @options[:partial_locals].clone}
|
382
|
+
end
|
383
|
+
|
384
|
+
# Is the section visible according to it's settings calculated in current
|
385
|
+
# context?
|
386
|
+
def visible?
|
387
|
+
case @options[:visibility]
|
388
|
+
when true, false
|
389
|
+
@options[:visibility]
|
390
|
+
when :any_services
|
391
|
+
# do any services exist which even potentially generate our types, even
|
392
|
+
# if they've completed without doing so?.
|
393
|
+
nil != @umlaut_request.dispatched_services.to_a.find do |ds|
|
394
|
+
! (service_type_values & ds.service.service_types_generated ).empty?
|
395
|
+
end
|
396
|
+
when :in_progress
|
397
|
+
# Do we have any of our types generated, or any services in progress
|
398
|
+
# that might generate them?
|
399
|
+
(! responses_empty?) || services_in_progress?
|
400
|
+
when :responses_exist
|
401
|
+
# Have any responses of our type actually been generated?
|
402
|
+
! responses_empty?
|
403
|
+
when :complete_with_responses
|
404
|
+
(! responses.empty?) && ! (services_in_progress?)
|
405
|
+
when Proc
|
406
|
+
# It's a lambda, which takes @umlaut_request as an arg
|
407
|
+
@options[:visibility].call(self)
|
408
|
+
else true
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
def list_visible_limit
|
413
|
+
@options[:list_visible_limit]
|
414
|
+
end
|
415
|
+
|
416
|
+
def section_title
|
417
|
+
@options[:section_title]
|
418
|
+
end
|
419
|
+
|
420
|
+
def section_prompt
|
421
|
+
@options[:section_prompt]
|
422
|
+
end
|
423
|
+
|
424
|
+
|
425
|
+
# Convenience method for re-ordering sections in local resolve_views
|
426
|
+
# initializer.
|
427
|
+
# Swaps elements if necessary to ensure they are in the specified order.
|
428
|
+
# For example, make sure holding comes before document_delivery:
|
429
|
+
# SectionRenderer.ensureOrder("holding", "document_delivery")
|
430
|
+
# Maybe in the future we'll expand this to take variable arguments.
|
431
|
+
def self.swap_if_needed!(first, second)
|
432
|
+
|
433
|
+
list = AppConfig.param("resolve_sections")
|
434
|
+
return unless list
|
435
|
+
|
436
|
+
index1 = find_index(list) {|s| s[:div_id] == first}
|
437
|
+
index2 = find_index(list) {|s| s[:div_id] == second}
|
438
|
+
|
439
|
+
(list[index1], list[index2] = list[index2], list[index1]) if index1 && index2 && (index1 > index2)
|
440
|
+
|
441
|
+
list
|
442
|
+
end
|
443
|
+
|
444
|
+
# helper for swap_if_needed! and ensure_order!
|
445
|
+
def self.find_index(array, &block)
|
446
|
+
array.each_with_index do |value, index|
|
447
|
+
return index if block.call(value)
|
448
|
+
end
|
449
|
+
return nil
|
450
|
+
end
|
451
|
+
|
452
|
+
|
453
|
+
protected
|
454
|
+
|
455
|
+
def construct_options(arguments)
|
456
|
+
|
457
|
+
# Fill in static defaults
|
458
|
+
@options = {:show_spinner => true,
|
459
|
+
:show_heading => true,
|
460
|
+
:visibility => true,
|
461
|
+
:show_partial_only => false,
|
462
|
+
:partial_locals => {}}.merge!(arguments)
|
463
|
+
|
464
|
+
|
465
|
+
# service type value default to same name as section_id
|
466
|
+
@options[:service_type_values] ||= [@section_id]
|
467
|
+
|
468
|
+
|
469
|
+
# Fill in calculatable-defaults
|
470
|
+
if (service_type_values.length > 0)
|
471
|
+
@options = {:section_title =>
|
472
|
+
service_type_values.first.display_name
|
473
|
+
}.merge(@options)
|
474
|
+
end
|
475
|
+
|
476
|
+
# Partials to display. Default to _standard_response_item item partial.
|
477
|
+
if ( @options[:partial] == true)
|
478
|
+
@options[:partial] = @section_id
|
479
|
+
end
|
480
|
+
if (@options[:partial].blank?)
|
481
|
+
@options[:item_partial] =
|
482
|
+
case @options[:item_partial]
|
483
|
+
when true then @section_id + "_item"
|
484
|
+
when String then options[:item_partial]
|
485
|
+
else "standard_response_item"
|
486
|
+
end
|
487
|
+
end
|
488
|
+
|
489
|
+
# sanity check
|
490
|
+
if ( @options[:show_partial_only] && ! @options[:partial])
|
491
|
+
raise Exception.new("SectionRenderer: You must supply a :partial argument if :show_partial_only is set true")
|
492
|
+
end
|
493
|
+
|
494
|
+
return @options
|
495
|
+
end
|
496
|
+
|
497
|
+
|
498
|
+
|
499
|
+
|
500
|
+
|
501
|
+
|
502
|
+
|
503
|
+
end
|