umlaut 3.0.0alpha1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|