umlaut 3.0.0alpha1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (293) hide show
  1. data/LICENSE +7 -0
  2. data/README.md +49 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/images/error.gif +0 -0
  5. data/app/assets/images/export_bg_bot.gif +0 -0
  6. data/app/assets/images/export_bg_mid.gif +0 -0
  7. data/app/assets/images/export_bg_top.gif +0 -0
  8. data/app/assets/images/famfamfam/book_open.png +0 -0
  9. data/app/assets/images/famfamfam/cross.png +0 -0
  10. data/app/assets/images/famfamfam/page_sound.gif +0 -0
  11. data/app/assets/images/famfamfam/page_text.gif +0 -0
  12. data/app/assets/images/famfamfam/page_up.gif +0 -0
  13. data/app/assets/images/famfamfam/page_white.png +0 -0
  14. data/app/assets/images/famfamfam/readme.html +1495 -0
  15. data/app/assets/images/famfamfam/tiny_cross.png +0 -0
  16. data/app/assets/images/frame_remove.gif +0 -0
  17. data/app/assets/images/ico_go.gif +0 -0
  18. data/app/assets/images/jhu_findit.gif +0 -0
  19. data/app/assets/images/list_closed.png +0 -0
  20. data/app/assets/images/list_open.png +0 -0
  21. data/app/assets/images/more_info.gif +0 -0
  22. data/app/assets/images/rails.png +0 -0
  23. data/app/assets/images/request.gif +0 -0
  24. data/app/assets/images/spinner.gif +0 -0
  25. data/app/assets/javascripts/umlaut/ajax_windows.js +35 -0
  26. data/app/assets/javascripts/umlaut/ensure_window_size.js.erb +34 -0
  27. data/app/assets/javascripts/umlaut/expand_contract_toggle.js +25 -0
  28. data/app/assets/javascripts/umlaut/search_autocomplete.js +46 -0
  29. data/app/assets/javascripts/umlaut/simple_visible_toggle.js +8 -0
  30. data/app/assets/javascripts/umlaut/update_html.js +152 -0
  31. data/app/assets/javascripts/umlaut.js +17 -0
  32. data/app/assets/stylesheets/umlaut.css +857 -0
  33. data/app/controllers/application_controller.rb +14 -0
  34. data/app/controllers/export_email_controller.rb +123 -0
  35. data/app/controllers/js_helper_controller.rb +10 -0
  36. data/app/controllers/link_router_controller.rb +87 -0
  37. data/app/controllers/open_search_controller.rb +9 -0
  38. data/app/controllers/resolve_controller.rb +288 -0
  39. data/app/controllers/resource_controller.rb +83 -0
  40. data/app/controllers/search_controller.rb +328 -0
  41. data/app/controllers/search_methods/sfx3.rb +148 -0
  42. data/app/controllers/search_methods/sfx4.rb +257 -0
  43. data/app/controllers/search_methods/sfx_api.rb +47 -0
  44. data/app/controllers/store_controller.rb +64 -0
  45. data/app/controllers/umlaut/controller_behavior.rb +20 -0
  46. data/app/controllers/umlaut/controller_logic.rb +96 -0
  47. data/app/controllers/umlaut/error_handling.rb +48 -0
  48. data/app/controllers/umlaut_controller.rb +112 -0
  49. data/app/helpers/application_helper.rb +4 -0
  50. data/app/helpers/emailer_helper.rb +43 -0
  51. data/app/helpers/export_email_helper.rb +34 -0
  52. data/app/helpers/open_search_helper.rb +7 -0
  53. data/app/helpers/resolve_helper.rb +225 -0
  54. data/app/helpers/search_helper.rb +50 -0
  55. data/app/helpers/umlaut/footer_helper.rb +64 -0
  56. data/app/helpers/umlaut/helper.rb +62 -0
  57. data/app/helpers/umlaut/html_head_helper.rb +37 -0
  58. data/app/helpers/umlaut/url_generation.rb +77 -0
  59. data/app/mailers/emailer.rb +48 -0
  60. data/app/models/clickthrough.rb +2 -0
  61. data/app/models/collection.rb +259 -0
  62. data/app/models/crossref_lookup.rb +2 -0
  63. data/app/models/dispatched_service.rb +58 -0
  64. data/app/models/permalink.rb +29 -0
  65. data/app/models/referent.rb +473 -0
  66. data/app/models/referent_value.rb +14 -0
  67. data/app/models/request.rb +449 -0
  68. data/app/models/service_response.rb +179 -0
  69. data/app/models/service_store.rb +59 -0
  70. data/app/models/service_type_value.rb +58 -0
  71. data/app/models/service_wave.rb +150 -0
  72. data/app/models/sfx_db/az_additional_title.rb +11 -0
  73. data/app/models/sfx_db/az_letter_group.rb +11 -0
  74. data/app/models/sfx_db/az_title.rb +38 -0
  75. data/app/models/sfx_db/az_title_v2.rb +34 -0
  76. data/app/models/sfx_db/isbn.rb +12 -0
  77. data/app/models/sfx_db/issn.rb +12 -0
  78. data/app/models/sfx_db/object.rb +35 -0
  79. data/app/models/sfx_db/object_portfolio.rb +6 -0
  80. data/app/models/sfx_db/publisher.rb +10 -0
  81. data/app/models/sfx_db/sfx_db_base.rb +54 -0
  82. data/app/models/sfx_db/target.rb +9 -0
  83. data/app/models/sfx_db/target_service.rb +10 -0
  84. data/app/models/sfx_db/title.rb +10 -0
  85. data/app/models/sfx_db.rb +10 -0
  86. data/app/models/sfx_url.rb +35 -0
  87. data/app/views/emailer/citation.text.erb +28 -0
  88. data/app/views/emailer/short_citation.text.erb +8 -0
  89. data/app/views/export_email/_email.html.erb +25 -0
  90. data/app/views/export_email/_send_email.html.erb +3 -0
  91. data/app/views/export_email/_send_txt.html.erb +3 -0
  92. data/app/views/export_email/_txt.html.erb +62 -0
  93. data/app/views/export_email/email.html.erb +3 -0
  94. data/app/views/export_email/send_email.html.erb +1 -0
  95. data/app/views/export_email/send_txt.html.erb +1 -0
  96. data/app/views/export_email/txt.html.erb +3 -0
  97. data/app/views/js_helper/loader.erb.js +13 -0
  98. data/app/views/layouts/umlaut.html.erb +52 -0
  99. data/app/views/open_search/index.html.erb +9 -0
  100. data/app/views/resolve/_api_in_progress.xml.erb +21 -0
  101. data/app/views/resolve/_background_progress.html.erb +51 -0
  102. data/app/views/resolve/_background_updater.html.erb +38 -0
  103. data/app/views/resolve/_citation.html.erb +87 -0
  104. data/app/views/resolve/_coins.html.erb +1 -0
  105. data/app/views/resolve/_compact_citation.html.erb +33 -0
  106. data/app/views/resolve/_cover_image.html.erb +35 -0
  107. data/app/views/resolve/_fulltext.html.erb +55 -0
  108. data/app/views/resolve/_help.html.erb +17 -0
  109. data/app/views/resolve/_holding.html.erb +91 -0
  110. data/app/views/resolve/_related_items.html.erb +35 -0
  111. data/app/views/resolve/_search_inside.html.erb +62 -0
  112. data/app/views/resolve/_section_display.html.erb +49 -0
  113. data/app/views/resolve/_service_errors.html.erb +29 -0
  114. data/app/views/resolve/_standard_response_item.html.erb +89 -0
  115. data/app/views/resolve/api.xml.builder +72 -0
  116. data/app/views/resolve/background_status.html.erb +26 -0
  117. data/app/views/resolve/index.html.erb +73 -0
  118. data/app/views/resolve/partial_html_sections.xml.erb +30 -0
  119. data/app/views/search/_a_to_z.html.erb +6 -0
  120. data/app/views/search/_citation.html.erb +94 -0
  121. data/app/views/search/_pager.html.erb +60 -0
  122. data/app/views/search/books.html.erb +103 -0
  123. data/app/views/search/journal_search.html.erb +90 -0
  124. data/app/views/search/journals.html.erb +167 -0
  125. data/app/views/search/opensearch_description.rxml +10 -0
  126. data/app/views/testing/index.html.erb +1 -0
  127. data/app/views/umlaut/README +5 -0
  128. data/app/views/umlaut/error.html.erb +45 -0
  129. data/db/migrate/01_umlaut_init.rb +113 -0
  130. data/db/orig_fixed_data/service_type_values.yml +120 -0
  131. data/db/seeds.rb +7 -0
  132. data/lib/CronTab.rb +192 -0
  133. data/lib/aws_product_sign.rb +146 -0
  134. data/lib/exlibris/aleph/patron.rb +64 -0
  135. data/lib/exlibris/aleph/record.rb +54 -0
  136. data/lib/exlibris/aleph/rest_api.rb +29 -0
  137. data/lib/exlibris/primo/holding.rb +192 -0
  138. data/lib/exlibris/primo/rsrc.rb +17 -0
  139. data/lib/exlibris/primo/searcher.rb +276 -0
  140. data/lib/exlibris/primo/source/aleph.rb +46 -0
  141. data/lib/exlibris/primo/source/distribution/nyu_aleph.rb +323 -0
  142. data/lib/exlibris/primo/toc.rb +17 -0
  143. data/lib/exlibris/primo_ws.rb +140 -0
  144. data/lib/generators/templates/umlaut_services.yml +237 -0
  145. data/lib/generators/umlaut/asset_hooks_generator.rb +44 -0
  146. data/lib/generators/umlaut/install_generator.rb +110 -0
  147. data/lib/hip3/bib.rb +291 -0
  148. data/lib/hip3/bib_searcher.rb +302 -0
  149. data/lib/hip3/custom_field_lookup.rb +44 -0
  150. data/lib/hip3/holding.rb +50 -0
  151. data/lib/hip3/item.rb +65 -0
  152. data/lib/hip3/receipt.rb +7 -0
  153. data/lib/hip3/serial_copy.rb +82 -0
  154. data/lib/holding.rb +32 -0
  155. data/lib/marc_helper.rb +254 -0
  156. data/lib/metadata_helper.rb +312 -0
  157. data/lib/opensearch_feed.rb +398 -0
  158. data/lib/opensearch_query.rb +98 -0
  159. data/lib/referent_filter.rb +16 -0
  160. data/lib/referent_filters/dissertation_catch.rb +45 -0
  161. data/lib/section_renderer.rb +503 -0
  162. data/lib/service.rb +336 -0
  163. data/lib/service_adaptors/ajax_export.rb +37 -0
  164. data/lib/service_adaptors/amazon.rb +412 -0
  165. data/lib/service_adaptors/blacklight.rb +327 -0
  166. data/lib/service_adaptors/book_finder.rb +40 -0
  167. data/lib/service_adaptors/bx.rb +51 -0
  168. data/lib/service_adaptors/cover_thing.rb +73 -0
  169. data/lib/service_adaptors/elsevier_cover.rb +57 -0
  170. data/lib/service_adaptors/email_export.rb +10 -0
  171. data/lib/service_adaptors/ezproxy.rb +171 -0
  172. data/lib/service_adaptors/google_book_search.rb +442 -0
  173. data/lib/service_adaptors/gpo.rb +124 -0
  174. data/lib/service_adaptors/hathi_trust.rb +308 -0
  175. data/lib/service_adaptors/hip3_service.rb +150 -0
  176. data/lib/service_adaptors/hip_holding_search.rb +237 -0
  177. data/lib/service_adaptors/internet_archive.rb +488 -0
  178. data/lib/service_adaptors/isbn_db.rb +86 -0
  179. data/lib/service_adaptors/isi.rb +258 -0
  180. data/lib/service_adaptors/jcr.rb +146 -0
  181. data/lib/service_adaptors/opac.rb +351 -0
  182. data/lib/service_adaptors/open_library.rb +316 -0
  183. data/lib/service_adaptors/open_library_cover.rb +73 -0
  184. data/lib/service_adaptors/primo_service.rb +392 -0
  185. data/lib/service_adaptors/primo_source.rb +78 -0
  186. data/lib/service_adaptors/pubmed.rb +133 -0
  187. data/lib/service_adaptors/request_to_fixture.rb +68 -0
  188. data/lib/service_adaptors/scopus.rb +295 -0
  189. data/lib/service_adaptors/sfx-new.rb +557 -0
  190. data/lib/service_adaptors/sfx.rb +566 -0
  191. data/lib/service_adaptors/sfx_backchannel_record.rb +69 -0
  192. data/lib/service_adaptors/txt_holding_export.rb +32 -0
  193. data/lib/service_adaptors/ulrichs_cover.rb +57 -0
  194. data/lib/service_adaptors/ulrichs_link.rb +47 -0
  195. data/lib/service_adaptors/worldcat.rb +116 -0
  196. data/lib/service_adaptors/worldcat_identities.rb +591 -0
  197. data/lib/tasks/umlaut.rake +134 -0
  198. data/lib/umlaut/default_configuration.rb +5 -0
  199. data/lib/umlaut/routes.rb +136 -0
  200. data/lib/umlaut/version.rb +3 -0
  201. data/lib/umlaut.rb +37 -0
  202. data/lib/umlaut_configurable.rb +343 -0
  203. data/lib/umlaut_http.rb +100 -0
  204. data/lib/xml_schema_helper.rb +109 -0
  205. data/test/dummy/Rakefile +7 -0
  206. data/test/dummy/app/assets/javascripts/application.js +13 -0
  207. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  208. data/test/dummy/app/controllers/application_controller.rb +3 -0
  209. data/test/dummy/app/controllers/umlaut_controller.rb +112 -0
  210. data/test/dummy/app/helpers/application_helper.rb +2 -0
  211. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  212. data/test/dummy/config/application.rb +45 -0
  213. data/test/dummy/config/boot.rb +10 -0
  214. data/test/dummy/config/database-jhu.yml +44 -0
  215. data/test/dummy/config/database.yml +25 -0
  216. data/test/dummy/config/environment.rb +5 -0
  217. data/test/dummy/config/environments/development.rb +34 -0
  218. data/test/dummy/config/environments/production.rb +60 -0
  219. data/test/dummy/config/environments/test.rb +39 -0
  220. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  221. data/test/dummy/config/initializers/inflections.rb +10 -0
  222. data/test/dummy/config/initializers/mime_types.rb +5 -0
  223. data/test/dummy/config/initializers/secret_token.rb +7 -0
  224. data/test/dummy/config/initializers/session_store.rb +8 -0
  225. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  226. data/test/dummy/config/locales/en.yml +5 -0
  227. data/test/dummy/config/routes.rb +61 -0
  228. data/test/dummy/config/umlaut_services.yml +237 -0
  229. data/test/dummy/config.ru +4 -0
  230. data/test/dummy/db/migrate/20111228211210_umlaut_init.rb +113 -0
  231. data/test/dummy/db/schema.rb +124 -0
  232. data/test/dummy/log/development.log +12981 -0
  233. data/test/dummy/log/production.log +0 -0
  234. data/test/dummy/public/404.html +26 -0
  235. data/test/dummy/public/422.html +26 -0
  236. data/test/dummy/public/500.html +26 -0
  237. data/test/dummy/public/favicon.ico +0 -0
  238. data/test/dummy/script/rails +6 -0
  239. data/test/dummy/tmp/cache/assets/C5F/340/sprockets%2F99692920160b7a279b86a80415b79db7 +0 -0
  240. data/test/dummy/tmp/cache/assets/C70/4D0/sprockets%2F034ad2036e623081bd352800786dfe80 +0 -0
  241. data/test/dummy/tmp/cache/assets/C73/920/sprockets%2Fd371318f22900492fd180f17c5e2a504 +9268 -0
  242. data/test/dummy/tmp/cache/assets/C80/980/sprockets%2Fc94807409c1523d43e18d25f35d93c41 +0 -0
  243. data/test/dummy/tmp/cache/assets/C8F/780/sprockets%2Fe47e28558116fb5f8038754e60d1961d +11769 -0
  244. data/test/dummy/tmp/cache/assets/CAA/EB0/sprockets%2F1d179210e8b76f1ea63c802688a015e4 +9271 -0
  245. data/test/dummy/tmp/cache/assets/CBB/9C0/sprockets%2F706f28923fb754cad04b9107c89986a1 +0 -0
  246. data/test/dummy/tmp/cache/assets/CBF/B60/sprockets%2F08ca89671549936265dcb673bf02e36f +0 -0
  247. data/test/dummy/tmp/cache/assets/CC9/9F0/sprockets%2F306166316e2cafd13c15e62b51a2339d +0 -0
  248. data/test/dummy/tmp/cache/assets/CF6/F20/sprockets%2F5b2ffa1103079dfd555197838f87a99f +0 -0
  249. data/test/dummy/tmp/cache/assets/CF7/2B0/sprockets%2F25a7c73655bd3598173b39d9f98bcd46 +862 -0
  250. data/test/dummy/tmp/cache/assets/CFE/080/sprockets%2F37fe9f4255baddbd549a659914929398 +0 -0
  251. data/test/dummy/tmp/cache/assets/D22/060/sprockets%2F9aec77b768e91a802d284271c58e2f7e +21357 -0
  252. data/test/dummy/tmp/cache/assets/D32/A10/sprockets%2F13fe41fee1fe35b49d145bcc06610705 +0 -0
  253. data/test/dummy/tmp/cache/assets/D33/6D0/sprockets%2F500129c57f1146e556ec3aacd6cd38c1 +0 -0
  254. data/test/dummy/tmp/cache/assets/D33/FD0/sprockets%2F2ba0b4e6334a77b923e5f770381bb2bf +0 -0
  255. data/test/dummy/tmp/cache/assets/D42/C20/sprockets%2Fbcf14e437b1582bf93b77670acf8e090 +21353 -0
  256. data/test/dummy/tmp/cache/assets/D50/A30/sprockets%2F7d8b294ac433db5d056538f8cf7c66b9 +0 -0
  257. data/test/dummy/tmp/cache/assets/D54/ED0/sprockets%2F71c9fa01091d432b131da3bb73faf3d4 +872 -0
  258. data/test/dummy/tmp/cache/assets/D65/590/sprockets%2Fc1bb92fc3406a126b7dd302edc96d629 +0 -0
  259. data/test/dummy/tmp/cache/assets/D71/6B0/sprockets%2Fde558b71b494cf09b1bf055c8dff0353 +0 -0
  260. data/test/dummy/tmp/cache/assets/D72/610/sprockets%2Fa8c708eeb30ef93de34d755d4f45d023 +859 -0
  261. data/test/dummy/tmp/cache/assets/D76/AD0/sprockets%2Fe2158cde93188cf5ab6457bc6d6602ec +0 -0
  262. data/test/dummy/tmp/cache/assets/D7A/E40/sprockets%2F9622ffcc499a57627cd1bb18fe31b8e4 +11772 -0
  263. data/test/dummy/tmp/cache/assets/D84/210/sprockets%2Fabd0103ccec2b428ac62c94e4c40b384 +0 -0
  264. data/test/dummy/tmp/cache/assets/D9B/770/sprockets%2F8aacf02eb7dbb0949704b28f27b87e0b +0 -0
  265. data/test/dummy/tmp/cache/assets/DA6/A80/sprockets%2F92e26d8e58d5bcc8b8f6c25d1b05b9c1 +0 -0
  266. data/test/dummy/tmp/cache/assets/DE8/790/sprockets%2Fd1333bde2b9aafcc712d11dd09ab35d8 +0 -0
  267. data/test/dummy/tmp/cache/assets/DF7/F30/sprockets%2F7bc16c4109b17fabe29f8ddbbf732d1c +374 -0
  268. data/test/dummy/tmp/cache/assets/E03/570/sprockets%2F493bdc0ac14cd4f57fdfe4253f992bde +0 -0
  269. data/test/dummy/tmp/cache/assets/E04/890/sprockets%2F2f5173deea6c795b8fdde723bb4b63af +0 -0
  270. data/test/dummy/tmp/cache/assets/E0B/4B0/sprockets%2F7988df51a61c81ce6ede4a2d4c8cce4f +377 -0
  271. data/test/dummy/tmp/cache/assets/E5F/960/sprockets%2Fdc007b6cad5c7ef08e33ec28cfff0ef6 +0 -0
  272. data/test/fixtures/dispatched_services.yml +5 -0
  273. data/test/fixtures/permalinks.yml +5 -0
  274. data/test/fixtures/referent_values.yml +1734 -0
  275. data/test/fixtures/referents.yml +156 -0
  276. data/test/fixtures/requests.yml +284 -0
  277. data/test/fixtures/service_responses.yml +5 -0
  278. data/test/fixtures/sfx_urls.yml +4 -0
  279. data/test/performance/browsing_test.rb +9 -0
  280. data/test/test_helper.rb +10 -0
  281. data/test/umlaut_test.rb +7 -0
  282. data/test/unit/aleph_patron_test.rb +39 -0
  283. data/test/unit/aleph_record_benchmarks.rb +28 -0
  284. data/test/unit/aleph_record_test.rb +30 -0
  285. data/test/unit/aws_product_sign_test.rb +93 -0
  286. data/test/unit/collection_test.rb +76 -0
  287. data/test/unit/google_book_search_test.rb +101 -0
  288. data/test/unit/primo_searcher_test.rb +403 -0
  289. data/test/unit/primo_service_test.rb +939 -0
  290. data/test/unit/primo_ws_test.rb +131 -0
  291. data/test/unit/service_response_test.rb +9 -0
  292. data/test/unit/service_test.rb +33 -0
  293. 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