diff --git a/css/ding_availability.css b/css/ding_availability.css index c85cd49..c944039 100644 --- a/css/ding_availability.css +++ b/css/ding_availability.css @@ -1,24 +1,20 @@ -.pending { - color: #696a69; -} - -/* Not available or reservable */ -/* Note: This applies to online resources as well. However, it's possible to style these, based on material type */ +.availability.pending, .availability.processed { - color: #ed1e88; -} - -.availability.available { - color: #0072bc; + color: #959595; /* Grey */ } .availability.reservable { - color: #ea9123; + color: #f0cb28; /* Yellow */ } /* Available and reservable */ +.availability.available, .availability.available.reservable { - color: #4c9f45; + color: #528c10; /* Green */ } +/* Available, but not reservable */ +.availability.available.not-reservable { + color: #a32e10; /* Red */ +} diff --git a/css/ding_availability_legend.css b/css/ding_availability_legend.css index 5e4e687..0e39d9c 100644 --- a/css/ding_availability_legend.css +++ b/css/ding_availability_legend.css @@ -22,23 +22,21 @@ } .availability-legend-item.available img { - background-color: #4c9f45; + background-color: #528c10; /* Green */ } .availability-legend-item.on-loan img { - background-color: #ea9123; + background-color: #f0cb28; /* Yellow */ } .availability-legend-item.unavailable img { - background-color: #ED1E88; + background-color: #a32e10; /* Red */ } .availability-legend-item.unavailable.netdokument img { - background-color: #2e2e2e; + background-color: #a32e10; /* Red */ } .availability-legend-item.unreservable img { - background-color: #0072bc; + background-color: #a32e10; /* Red */ } - - diff --git a/ding_availability.admin.inc b/ding_availability.admin.inc new file mode 100644 index 0000000..09074a8 --- /dev/null +++ b/ding_availability.admin.inc @@ -0,0 +1,50 @@ + 'fieldset', + '#title' => t('Update from datawell'), + '#description' => t('Update the lists of known types and sources by asking the datawell for all types and sorces.'), + ); + + $form['update']['update'] = array( + '#type' => 'submit', + '#value' => t('Update'), + '#submit' => array('ting_admin_reservable_settings_update'), + ); + + // Get available types. + $types = variable_get('ting_well_types', array()); + + $form['ding_availability_holdings'] = array( + '#type' => 'fieldset', + '#title' => t('Holdings information'), + '#tree' => FALSE, + '#description' => t("Which ting object types should display provider holdings information in the holding field e.g. on the ting object view"), + ); + + $form['ding_availability_holdings']['ding_availability_holdings_types'] = array( + '#type' => 'checkboxes', + '#title' => t('Types'), + '#options' => drupal_map_assoc(array_keys($types)), + '#default_value' => variable_get('ding_availability_holdings_types', _ding_availability_holdings_default_types()), + ); + // Save us the trouble of running array_filter. + $form['array_filter'] = array('#type' => 'value', '#value' => TRUE); + + return system_settings_form($form); +} diff --git a/ding_availability.field.inc b/ding_availability.field.inc index 5b8672b..cef7bee 100644 --- a/ding_availability.field.inc +++ b/ding_availability.field.inc @@ -57,7 +57,7 @@ function ding_availability_field_formatter_info() { 'label' => t('Default'), 'field types' => array( 'ding_availability_item', - 'ding_availability_holdings' + 'ding_availability_holdings', ), ), 'ding_availability_type' => array( @@ -66,8 +66,8 @@ function ding_availability_field_formatter_info() { 'ting_type', ), ), - 'ding_availability_types' => array( - 'label' => t('With availability information'), + 'ding_availability_with_labels' => array( + 'label' => t('Availability information with labels'), 'field types' => array( 'ting_collection_types', ), @@ -80,49 +80,91 @@ function ding_availability_field_formatter_info() { */ function ding_availability_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) { $element = array(); + $online_types = array_filter(variable_get('ting_online_types', _ting_default_online_types())); + $reservable_sources = array_filter(variable_get('ting_reservable_sources', _ting_default_reservable_sources())); + + // Attach front-end style and JS to the element. foreach ($items as $delta => $item) { $attached = array( - 'js' => array( - drupal_get_path('module', 'ding_availability') . '/js/ding_availability.js' => array( - 'type' => 'file', - ), - ), 'css' => array( - drupal_get_path('module', 'ding_availability') . '/css/ding_availability.css' + drupal_get_path('module', 'ding_availability') . '/css/ding_availability.css', ), ); - switch ($field['type']) { - case 'ding_availability_holdings': + + // Extract records' source. + if ($field['type'] != 'ting_collection_types') { + $ac_source = $entity->reply->record['ac:source'][''][0]; + } + + switch ($display['type']) { + case 'ding_availability_default': // Generate an unique id. $id = drupal_html_id('holdings-' . $entity->id); - $attached['js'][1] = array( - 'data' => array( - 'ding_availability_mode' => 'holdings', - 'ding_availability' => array( - $id => array($entity->localId), + + // Add javascript. + $attached['js'] = array( + drupal_get_path('module', 'ding_availability') . '/js/ding_availability.js', + ); + + // If item is of type 'library materials' (where we can lookup holding + // data), prepare to check holding on the item. + $holding_types = variable_get('ding_availability_holdings_types', _ding_availability_holdings_default_types()); + if (in_array(strtolower($ac_source), $reservable_sources) && in_array(strtolower($entity->type), $holding_types)) { + $attached['js'][] = array( + 'data' => array( + 'ding_availability_mode' => 'holdings', + 'ding_availability' => array( + $id => array($entity->localId), + ), ), - ), 'type' => 'setting'); + 'type' => 'setting', + ); + + $element[$delta] = array( + // @todo: move this into tpl file. + '#markup' => '

' . t('Fetching holdings information.') . '

', + '#attached' => $attached, + ); + } + + break; - $element[$delta] = array( - '#markup' => '
', - '#attached' => $attached, - ); - break; case 'ding_availability_item': + // Add javascript. + $attached['js'] = array( + drupal_get_path('module', 'ding_availability') . '/js/ding_availability.js', + ); + $element[$delta] = array( '#markup' => '
', '#attached' => $attached, ); break; - case 'ting_type': + + case 'ding_availability_type': // Generate an unique id. $id = drupal_html_id('availability-' . $entity->id); - $attached['js'][1] = array( - 'data' => array( - 'ding_availability' => array( - $id => array($entity->localId), + + // Mark as available if it is an online resource, + $available_online = (in_array(drupal_strtolower($entity->type), $online_types)) ? 'available' : 'not-available-online'; + + // Add javascript. + $attached['js'] = array( + drupal_get_path('module', 'ding_availability') . '/js/ding_availability.js', + ); + + // If item is of type 'library materials' (where we can lookup holding + // data), prepare to check holding on the item. + if (in_array(strtolower($ac_source), $reservable_sources)) { + $attached['js'][1] = array( + 'data' => array( + 'ding_availability' => array( + $id => array($entity->localId), + ), ), - ), 'type' => 'setting'); + 'type' => 'setting', + ); + } $element[$delta] = array( '#theme' => 'item_list', @@ -131,44 +173,129 @@ function ding_availability_field_formatter_view($entity_type, $entity, $field, $ array( 'data' => $entity->type, 'id' => $id, - 'class' => array('availability', drupal_html_class($entity->type)), - ) + 'class' => array( + 'availability', + drupal_html_class($entity->type), + $available_online, + 'pending', + ), + ), ), ); break; - case 'ting_collection_types': + + case 'ding_availability_with_labels': $id_mapping = array(); $typed_entities = array(); + // Sort entities into type -> ids. foreach ($entity->entities as $ent) { - $typed_entities[$ent->type][] = $ent->localId; + $typed_entities[$ent->type][] = $ent; } + // Build basic output render array. + $output = array( + '#theme' => 'ding_availability_types', + '#types' => array(), + '#attached' => $attached, + ); + + // Loop over the different material types. foreach ($typed_entities as $type => $entities) { // Generate an unique id. - $id = drupal_html_id('availability-' . $entity->id . '-' . $type); - // Create a list element for each type. - $types[] = array( - 'data' => $type, - 'id' => $id, - 'class' => array('availability', drupal_html_class($type)), - ); - // Map the HTML id to the list of entity ids. - $id_mapping[$id] = $entities; + $id = drupal_html_id('availability-' . $entities[0]->id . '-' . $type); + + // Extract records' source. + $ac_source = $entities[0]->reply->record['ac:source'][''][0]; + + // Get link to first element in the collection of the current type. + // If more than one exists link to the collection. + if (count($entities) == 1) { + $url = entity_uri('ting_object', $entities[0]); + } + else { + $url = entity_uri('ting_collection', $entities[0]); + } + + // Mark as available if it is an online resource. + if (in_array(drupal_strtolower($type), $online_types) || $entities[0]->getOnline_url(FALSE)) { + if (!isset($output['#types']['online'])) { + // Add label "online" to output. + $output['#types']['online'] = array( + '#theme' => 'ding_availability_type', + '#class' => 'js-online', + '#label' => t('Online'), + '#links' => array(), + ); + } + // Add it to the online label. + $output['#types']['online']['#links'][] = array( + 'status' => 'available', + 'type' => $type, + 'link' => array( + // The online url can't be used with l(), has it will encode + // it. + '#markup' => '' . check_plain($type) . '', + ), + ); + } + else { + if (!isset($output['#types']['pending'])) { + // Add label "Pending" to output as in waiting for information. + $output['#types']['pending'] = array( + '#theme' => 'ding_availability_type', + '#class' => 'js-pending', + '#label' => t('Pending availability'), + '#links' => array(), + ); + } + $output['#types']['pending']['#links'][] = array( + 'status' => 'pending', + 'type' => $type, + 'link' => array( + '#theme' => 'link', + '#text' => check_plain($type), + '#path' => $url['path'], + '#options' => array( + 'attributes' => array( + 'class' => array( + 'search-result--availability-link', + 'availability', + 'pending', + ), + 'id' => $id, + ), + 'html' => FALSE, + ), + ), + ); + } + + // If item is of type 'library materials' (where we can lookup + // availability data), map the HTML id to the list of entity ids. + // This is for the current material type group (book, cd, etc.). + if (in_array(strtolower($ac_source), $reservable_sources) && !in_array(drupal_strtolower($type), $online_types)) { + $id_mapping[$id] = array(); + foreach ($entities as $object_entity) { + $id_mapping[$id][] = $object_entity->localId; + } + } } - $attached['js'][1] = array( + // Prepare to check holding on the item. + // It's important that this is attached even if empty, else javascript + // will fail because it gets an empty object. + $output['#attached']['js'][] = array( 'data' => array( 'ding_availability' => $id_mapping, - ), 'type' => 'setting'); - - $element[$delta] = array( - '#theme' => 'item_list', - '#attached' => $attached, - '#items' => $types, + ), 'type' => 'setting', ); + $output['#attached']['js'][] = drupal_get_path('module', 'ding_availability') . '/js/ding_availability_labels.js'; + + $element[$delta] = $output; break; } } + return $element; } diff --git a/ding_availability.info b/ding_availability.info index 26c04e2..59ed159 100644 --- a/ding_availability.info +++ b/ding_availability.info @@ -5,4 +5,5 @@ version = "7.x-0.14" core = 7.x files[] = ding_availability.module dependencies[] = ding_provider -dependencies[] = blackhole +dependencies[] = virtual_field +dependencies[] = ting diff --git a/ding_availability.install b/ding_availability.install index e270bfd..a19876b 100644 --- a/ding_availability.install +++ b/ding_availability.install @@ -14,7 +14,7 @@ function ding_availability_ding_entity_fields() { 'field' => array( 'locked' => TRUE, 'storage' => array( - 'type' => 'blackhole', + 'type' => 'virtual_field', ), ), 'instance' => array( @@ -23,3 +23,16 @@ function ding_availability_ding_entity_fields() { ), ); } + +/** + * Convert blackhole field storage to virtual field. + */ +function ding_availability_update_7000() { + return db_update('field_config') + ->fields(array( + 'storage_type' => 'virtual_field', + 'storage_module' => 'virtual_field', + )) + ->condition('module', 'ding_availability') + ->execute(); +} diff --git a/ding_availability.make b/ding_availability.make index 0720fa8..4d3a7c2 100644 --- a/ding_availability.make +++ b/ding_availability.make @@ -1,11 +1,15 @@ api = 2 core = 7.x +; contrib + +projects[virtual_field][subdir] = "contrib" +projects[virtual_field][version] = "1.2" + +; Ding2 + projects[ding_provider][type] = "module" projects[ding_provider][download][type] = "git" projects[ding_provider][download][url] = "git@github.com:ding2/ding_provider.git" -projects[ding_provider][download][tag] = "7.x-0.13" +projects[ding_provider][download][branch] = "master" -projects[blackhole][type] = "module" -projects[blackhole][download][type] = "git" -projects[blackhole][download][url] = "git@github.com:xendk/blackhole.git" diff --git a/ding_availability.module b/ding_availability.module index 90e5f3e..5bd2276 100644 --- a/ding_availability.module +++ b/ding_availability.module @@ -11,6 +11,8 @@ module_load_include('inc', 'ding_availability', 'ding_availability.field'); * Implements hook_menu(). */ function ding_availability_menu() { + $items = array(); + $items['ding_availability/items'] = array( 'title' => 'Availability status', 'page callback' => 'ding_availability_js', @@ -25,6 +27,15 @@ function ding_availability_menu() { 'type' => MENU_CALLBACK, ); + $items['admin/config/ting/holdings'] = array( + 'title' => 'Provider availability holdings', + 'description' => 'Configure which ting object types should try to fetch provider holdings information.', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('ding_availability_admin_holdings_settings'), + 'access arguments' => array('administer ting settings'), + 'file' => 'ding_availability.admin.inc', + ); + return $items; } @@ -41,21 +52,67 @@ function ding_availability_ding_provider_user() { } /** + * Implements hook_theme(). + */ +function ding_availability_theme($existing, $type, $theme, $path) { + return array( + 'ding_holdings' => array( + 'template' => 'ding-holdings', + 'variables' => array( + 'holdings' => NULL, + 'total_count' => NULL, + 'reserved_count' => NULL, + 'total_plus_ordered_count' => NULL, + ), + 'path' => $path . '/templates', + ), + 'ding_availability_types' => array( + 'template' => 'ding-availability-types', + 'variables' => array( + 'types' => array(), + ), + 'path' => $path . '/templates', + ), + 'ding_availability_type' => array( + 'template' => 'ding-availability-type', + 'variables' => array( + 'class' => NULL, + 'label' => NULL, + 'links' => array(), + ), + 'path' => $path . '/templates', + ), + ); +} + +/** + * Output the availability information as json. * + * @param array $provider_ids + * Providers ID's to fetch availability information for. */ function ding_availability_js($provider_ids) { drupal_json_output(ding_availability_items(explode(',', $provider_ids))); } /** + * Output holdings information as json. * + * @param array $provider_ids + * Providers ID's to fetch holdings information for. */ function ding_availability_holdings_js($provider_ids) { drupal_json_output(ding_availability_holdings(explode(',', $provider_ids))); } /** + * Get availability from the provider. * + * @param array $provider_ids + * ID's to fetch data for. + * + * @return array + * Availability information. */ function ding_availability_items($provider_ids) { if (ding_provider_implements('availability', 'items')) { @@ -68,6 +125,12 @@ function ding_availability_items($provider_ids) { 'reservable' => FALSE, 'available' => FALSE, ); + + // Marks internet resources as available. + if (isset($item['is_internet']) && $item['is_internet']) { + $item['available'] = TRUE; + } + _ding_availability_text($item); } } @@ -79,7 +142,13 @@ function ding_availability_items($provider_ids) { } /** + * Get holdings from the provider. * + * @param array $provider_ids + * ID's to fetch data for. + * + * @return array + * Holdings information. */ function ding_availability_holdings($provider_ids) { $items = ding_provider_invoke('availability', 'holdings', $provider_ids); @@ -91,18 +160,98 @@ function ding_availability_holdings($provider_ids) { 'reservable' => FALSE, 'available' => FALSE, 'holdings' => array(), + 'ordered_count' => 0, ); + + // Marks internet resources as available. + if ($item['is_internet']) { + $item['available'] = TRUE; + } + _ding_availability_text($item); + + // Support for creating the html here instead of in the provider. + // The provider contains a location array, total_count, available_count, + // reserved_count, reservable_count, ordered_count. + // We assume that the provider supports this, if it didn't deliver html. + if (!isset($item['html'])) { + $header = array( + 'placement' => t('Placement'), + 'copies' => t('Copies'), + 'available' => t('At home'), + ); + + $attributes = array( + 'class' => array('availability-holdings-table'), + ); + + // check if there are items in acquisition + foreach ($item['holdings'] as $holding) { + $item['ordered_count'] += (isset($holding['ordered_count'])) ? (int) $holding['ordered_count'] : 0; + } + // if yes, add a column + if ($item['ordered_count']) { + $header['acquisition'] = t('In acquisition'); + } + + $rows = array(); + foreach ($item['holdings'] as $holding) { + $rows[] = ding_availability_holdings_row($holding, $item['ordered_count']); + } + + // Theme the output. + $item['html'] = theme('ding_holdings', array( + 'holdings' => array( + '#theme' => 'table', + '#header' => $header, + '#rows' => $rows, + '#attributes' => $attributes, + ), + 'total_count' => (int) $item['total_count'], + 'reserved_count' => (int) $item['reserved_count'], + 'ordered_count' => (int) $item['ordered_count'], + 'total_plus_ordered_count' => (int) $item['total_count'] + (int) $item['ordered_count'], + )); + } } return $items; } +/** + * @param $holding + * @param $show_ordered_count + * + * @return array + */ +function ding_availability_holdings_row($holding, $show_ordered_count) { + $row = array(); + + // Create placement string. + $row['placement'] = implode(' > ', $holding['placement']); + + // Library copies. + $row['copies'] = isset($holding['total_count']) ? (int) $holding['total_count'] : 0; + + // Calculate copies home. + $row['available'] = isset($holding['available_count']) ? (int) $holding['available_count'] : 0; + $row['available'] += isset($holding['reference_count']) ? (int) $holding['reference_count'] : 0; + + // copies in acquisition. + if ($show_ordered_count) { + $ordered_count = isset($holding['ordered_count']) ? (int) $holding['ordered_count'] : 0; + $row['copies'] += $ordered_count; + $row['ordered_count'] = $ordered_count; + } + + return $row; +} + /** * Adds the human readable status text of an item. */ function _ding_availability_text(&$item) { - if ($item['available'] && $item['reservable']) { + if ($item['available'] || (isset($item['is_internet']) && $item['is_internet'])) { $item['status'] = t('available'); } elseif (!$item['available'] && $item['reservable']) { @@ -119,6 +268,7 @@ function _ding_availability_text(&$item) { /** * Implements hook_block_info(). + * * Define availability legend block. */ function ding_availability_block_info() { @@ -132,9 +282,11 @@ function ding_availability_block_info() { /** * Implements hook_block_view(). + * * Define availability legend block. */ -function ding_availability_block_view($delta = '') { +function ding_availability_block_view($delta) { + $block = array(); $block['subject'] = t('Ding availability legend'); $block['content'] = ding_availability_render_legend(); return $block; @@ -147,29 +299,28 @@ function ding_availability_render_legend() { drupal_add_css(drupal_get_path('module', 'ding_availability') . '/css/ding_availability_legend.css'); - // construct the image's path (.gif stored in a module subdir) + // Construct the image's path (.gif stored in a module subdir). $image_path = drupal_get_path('module', 'ding_availability') . '/images/blank.gif'; - // make some text, image's alt & title tags (SEO, accessibility) + // Make some text, image's alt & title tags (SEO, accessibility). $availability_legend['available'] = t('Available'); $availability_legend['on-loan'] = t('On loan'); $availability_legend['unavailable'] = t('Unavailable'); $availability_legend['unreservable'] = t('Not reservable'); - // render image html using theme_image (returns NULL if file doesn't exist) - foreach ( $availability_legend as $key => $val ) { + // Render image html using theme_image (returns NULL if file doesn't exist). + foreach ($availability_legend as $key => $val) { $format_label = '' . $val . ''; - $format_image = theme('image', array('path'=>$image_path, 'alt'=>$val, 'title'=>$val)); + $format_image = theme('image', array('path' => $image_path, 'alt' => $val, 'title' => $val)); $format_items[] = '
' . $format_image . $format_label . '
'; }; $format_items[] = '
'; return '
' . implode($format_items) . '
'; - } /** - * ting_object_entities preprocessor. + * Implements hook_preprocessor_ting_object_entities(). */ function ding_availability_preprocess_ting_object_entities(&$variables) { if (!empty($variables['content']) && function_exists('ding_availability_render_legend')) { @@ -180,3 +331,71 @@ function ding_availability_preprocess_ting_object_entities(&$variables) { } } +/** + * The defaults types that should display provider holdings information. + * + * @return array + * List of data well types that should be fetched holdings information if they + * have the library material or catalog source. + */ +function _ding_availability_holdings_default_types() { + return array( + 'bog', + 'cd (musik)', + 'node', + 'dvd', + 'billedbog', + 'lydbog (cd)', + 'lydbog (bånd)', + 'tegneserie', + 'cd', + 'sammensat materiale', + 'lydbog (cd-mp3)', + 'video', + 'bog stor skrift', + 'årbog', + 'cd-rom', + 'periodikum', + 'pc-spil', + 'blu-ray', + 'playstation 3', + 'playstation 2', + 'wii', + 'xbox 360', + 'nintendo ds', + 'graphic novel', + 'grafisk blad', + 'dvd-rom', + 'kort', + 'plakat', + 'gameboy advance', + 'xbox', + 'grammofonplade', + 'wii u', + 'serie', + 'avis', + 'spil', + 'playstation', + 'mikroform', + 'bånd', + 'originalkunst', + 'puslespil', + 'laborativt materiale', + 'øvelsesmodel', + 'foto', + 'maleri', + 'teaterdukke', + 'kassettelydbånd', + 'transparent', + 'billedkort', + 'diskette', + 'legetøj', + 'gameboy', + 'punktskrift', + 'akvarel', + 'arkitekturtegning', + 'emnekasse', + 'spolelydbånd', + 'udstillingsmontage', + ); +} diff --git a/js/ding_availability.js b/js/ding_availability.js index 5d8d35e..c3944f8 100644 --- a/js/ding_availability.js +++ b/js/ding_availability.js @@ -4,14 +4,18 @@ */ (function($) { + "use strict"; // Cache of fetched availability information. Drupal.DADB = {}; - Drupal.behaviors.dingAvailabilityAttach = { - attach: function(context, settings) { - var ids = []; - var html_ids = []; + $(document).ready(function() { + var settings = Drupal.settings; + var ids = []; + var html_ids = []; + + // Extract entity ids and add them to the settings array. + if (settings.hasOwnProperty('ding_availability')) { $.each(settings.ding_availability, function(id, entity_ids) { $.each(entity_ids, function(index, entity_id) { if (Drupal.DADB[entity_id] === undefined) { @@ -21,105 +25,133 @@ } }); }); + } - $.each(html_ids, function(index, id) { - $('#' + id).addClass('pending'); + $.each(html_ids, function(index, id) { + $('#' + id).addClass('pending'); + }); + + // Fetch availability. + if (ids.length > 0) { + var mode = settings.ding_availability_mode ? settings.ding_availability_mode : 'items'; + var path = settings.basePath + 'ding_availability/' + mode + '/' + ids.join(','); + $.ajax({ + dataType: "json", + url: path, + success: function(data) { + $.each(data, function(id, item) { + // Update cache. + Drupal.DADB[id] = item; + }); + + $.each(settings.ding_availability, function(id, entity_ids) { + if (id.match(/^availability-/)) { + // Update availability indicators. + ding_availability_update_availability(id, entity_ids); + } + else { + // Update holding information. + ding_availability_update_holdings(id, entity_ids); + } + }); + } }); - - // Fetch availability. - if (ids.length > 0) { - $.getJSON(settings.basePath + 'ding_availability/' + (settings.ding_availability_mode ? settings.ding_availability_mode: 'items') + '/' + ids.join(','), {}, update); - } - else { - // Apply already fetched availability + } + else { + // Apply already fetched availability, if any. + if (settings.hasOwnProperty('ding_availability')) { $.each(settings.ding_availability, function(id, entity_ids) { - updateAvailability(id, entity_ids); + ding_availability_update_availability(id, entity_ids); }); } + } + }); + + + /** + * Update availability information. + * + * Add classes to reservation texts and display reservation button based on + * availability information + * + * @param id + * HTML id of the availability to update. + * @param entity_ids + * Entity id for which to update availability information. + */ + function ding_availability_update_availability(id, entity_ids) { + var available = false; + var reservable = false; + var is_internet = false; + var element = $('#' + id); + element.removeClass('pending').addClass('processed'); + + $.each(entity_ids, function(index, entity_id) { + // Reserve button + var reserver_btn = element.parents('.ting-object:first, .material-item:first').find('a[id$=' + entity_id + '].reserve-button'); + + if (Drupal.DADB[entity_id]) { + available = available || Drupal.DADB[entity_id]['available']; + reservable = reservable || Drupal.DADB[entity_id]['reservable']; + is_internet = is_internet || Drupal.DADB[entity_id]['is_internet']; - function update(data, textData) { - $.each(data, function(id, item) { - // Update cache. - Drupal.DADB[id] = item; - }); - - $.each(settings.ding_availability, function(id, entity_ids) { - if (id.match(/^availability-/)) { - // Update availability indicators. - updateAvailability(id, entity_ids); - } - else { - // Update holding information. - updateHoldings(id, entity_ids); - } - }); - } + if (available) { + element.addClass('available'); - function updateAvailability(id, entity_ids) { - var available = false; - var reservable = false; - $.each(entity_ids, function(index, entity_id) { - if (Drupal.DADB[entity_id]) { - available = available || Drupal.DADB[entity_id]['available']; - reservable = reservable || Drupal.DADB[entity_id]['reservable']; + // Add class to reserve button + if (reserver_btn.length) { + reserver_btn.addClass('available'); } - }); - - $('#' + id).removeClass('pending'); - $('#' + id).addClass('processed'); - - if (available) { - $('#' + id).addClass('available'); - } - if (reservable) { - $('#' + id).addClass('reservable'); } + else { + element.addClass('unavailable'); - if (available && reservable) { - $('#' + id).attr('title', Drupal.t('available')); - } - else if (!available && reservable) { - $('#' + id).attr('title', Drupal.t('on loan')); - } - else if (available && ! reservable) { - $('#' + id).attr('title', Drupal.t('not reservable')); - } - else if (!available && ! reservable) { - $('#' + id).attr('title', Drupal.t('unavailable')); + // Add class to reserve button + if (reserver_btn.length) { + reserver_btn.addClass('unavailable'); + } } - } - function updateHoldings(id, entity_ids) { - var entity_id = entity_ids.pop(); - if (Drupal.DADB[entity_id] && (Drupal.DADB[entity_id]['holdings'] || Drupal.DADB[entity_id]['holdings_available'])) { - var holdings; - var length; + if (reservable) { + element.addClass('reservable'); - // Use holdings_available, if set and entity is not a periodical. - if (Drupal.DADB[entity_id]['holdings_available'] && !Drupal.DADB[entity_id]['is_periodical'] ) { - holdings = Drupal.DADB[entity_id]['holdings_available']; - length = holdings.length; - } - else { - holdings = Drupal.DADB[entity_id]['holdings']; - //holdings is an object - not array - length = Object.keys(holdings).length; + // Add class to reserve button + if (reserver_btn.length) { + reserver_btn.addClass('reservable'); } + } + else { + element.addClass('not-reservable'); - - if (length > 0) { - $('#' + id).append('

' + Drupal.t('Holdings available on the shelf') + '

'); - $('#' + id).append('