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('');
- var container = $('#' + id + ' ul');
- $.each(holdings, function(i, holding) {
- container.append('- ' + holding + '
');
- });
+ // Add class to reserve button
+ if (reserver_btn.length) {
+ reserver_btn.addClass('not-reservable');
}
}
}
+ else {
+ reserver_btn.addClass('not-reservable');
+ }
+ });
+ }
+
+ /**
+ * Update availability holdings information.
+ *
+ * Insert HTML with information about where the entities are located.
+ *
+ * @param id
+ * HTML id of the availability to update.
+ * @param entity_ids
+ * Entity id for which to update availability holdings information.
+ */
+ function ding_availability_update_holdings(id, entity_ids) {
+ var entity_id = entity_ids.pop();
+ if (Drupal.DADB[entity_id] && (Drupal.DADB[entity_id]['holdings'])) {
+ // Show status for material.
+ $('#' + id).html(Drupal.DADB[entity_id].html);
}
- };
+ }
})(jQuery);
-
diff --git a/js/ding_availability_labels.js b/js/ding_availability_labels.js
new file mode 100644
index 0000000..862493d
--- /dev/null
+++ b/js/ding_availability_labels.js
@@ -0,0 +1,205 @@
+/**
+ * @file
+ * JavaScript behaviours for fetching and displaying availability information
+ * on TingEntities.
+ */
+(function($) {
+ "use strict";
+
+ // Cache of fetched availability information.
+ Drupal.DADB = {};
+
+ Drupal.behaviors.dingAvailabilityAttach = {
+ attach: function(context, settings) {
+ var ids = [];
+ var html_ids = [];
+
+ // Extract entity ids from Drupal 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) {
+ Drupal.DADB[entity_id] = null;
+ ids.push(entity_id);
+ html_ids.push(id);
+ }
+ });
+ });
+ }
+
+ // 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.
+ update_availability(id, entity_ids);
+ }
+ });
+ update_availability_remove_pending();
+ }
+ });
+ }
+ else {
+ // Apply already fetched availability, if any.
+ if (settings.hasOwnProperty('ding_availability')) {
+ $.each(settings.ding_availability, function(id, entity_ids) {
+ update_availability(id, entity_ids);
+ });
+ update_availability_remove_pending();
+ }
+ }
+
+ /**
+ * Update availability on the page.
+ *
+ * The array of entity_ids is an array as we only show one availability
+ * label per material type. So if one of these have an available status
+ * the label have to reflect this.
+ *
+ * @param id
+ * The element id that this should target.
+ * @param entity_ids
+ * Array of entities.
+ */
+ function update_availability(id, entity_ids) {
+ // Default the status to not available and not reservable.
+ var status = {
+ available: false,
+ reservable: false
+ };
+
+ // Loop over the entity ids and if one has available or reservable
+ // true save that value.
+ $.each(entity_ids, function(index, entity_id) {
+ if (Drupal.DADB[entity_id]) {
+ status.available = status.available || Drupal.DADB[entity_id]['available'];
+ status.reservable = status.reservable || Drupal.DADB[entity_id]['reservable'];
+ }
+ });
+
+ var element = $('#' + id);
+ element.removeClass('pending').addClass('processed');
+
+ // Get hold of the reserve button (it hidden as default, so we may need
+ // to show it).
+ var reserver_btn = element.parents('.ting-object:first').find('[id^=ding-reservation-reserve-form]');
+
+ update_availability_elements(element, reserver_btn, status);
+ }
+
+ /**
+ * Helper function to crate labels groups and move the materials based on
+ * availability.
+ *
+ * @param element
+ * The target element (material that should be moved).
+ * @param status
+ * Structure with available and reservable state.
+ */
+ function update_availability_type(element, status) {
+ var groups_wrapper = element.closest('.search-result--availability');
+ var reservable = status['reservable'];
+ var available = status['available'];
+
+ var group = null;
+ if ($('.js-online', groups_wrapper).length !== 0) {
+ group = $('.js-online', groups_wrapper);
+ }
+ else if (available) {
+ group = $('.js-available', groups_wrapper);
+
+ if (group.length === 0) {
+ group = $('' + Drupal.t('Available') + ':
');
+ groups_wrapper.append(group);
+ }
+ }
+ else if (reservable) {
+ group = $('.js-reservable', groups_wrapper);
+ if (group.length === 0) {
+ group = $('' + Drupal.t('Reservable') + ':
');
+ groups_wrapper.append(group);
+ }
+ }
+ else {
+ group = $('.js-unavailable', groups_wrapper);
+
+ if (group.length === 0) {
+ group = $('' + Drupal.t('Not available') + ':
');
+ groups_wrapper.append(group);
+ }
+ }
+
+ // Move the element into that type.
+ group.append(element);
+ }
+
+ /**
+ * Removes js-pending groups (labels) if they are empty or changes the
+ * label to "Can be obtained". This should be called as the last function
+ * in updating availability information and see as a clean-up function.
+ */
+ function update_availability_remove_pending() {
+ // Loop over all pending availability groups.
+ $('.js-pending').each(function() {
+ var elm = $(this);
+ var children = elm.children();
+ if (children.length) {
+ // Change the label from pending.
+ var label = elm.contents().first()[0];
+ label.nodeValue = Drupal.t('Can be obtained') + ': ';
+ }
+ else {
+ // The current pending group is empty, so simply remove it.
+ elm.remove();
+ }
+ });
+ }
+
+ /**
+ * Add class to both an element and the reservation button.
+ *
+ * @param element
+ * jQuery availability element to add the class to.
+ * @param btn
+ * Reservation button to add the class to.
+ * @param status
+ * Structure with available and reservable state.
+ */
+ function update_availability_elements(element, btn, status) {
+ var class_name = null;
+
+ for (var i in status) {
+ if (status[i] === true) {
+ class_name = i;
+ }
+ else {
+ if (i === 'available') {
+ class_name = 'un' + i;
+ }
+ else if (i === 'reservable') {
+ class_name = 'not-' + i;
+ }
+ }
+
+ element.addClass(class_name);
+ if (btn.length) {
+ btn.addClass(class_name);
+ }
+ }
+
+ update_availability_type(element, status);
+ }
+ }
+ };
+})(jQuery);
diff --git a/templates/ding-availability-type.tpl.php b/templates/ding-availability-type.tpl.php
new file mode 100644
index 0000000..55be665
--- /dev/null
+++ b/templates/ding-availability-type.tpl.php
@@ -0,0 +1,14 @@
+
+:
+
+
+
diff --git a/templates/ding-availability-types.tpl.php b/templates/ding-availability-types.tpl.php
new file mode 100644
index 0000000..0e4b9c3
--- /dev/null
+++ b/templates/ding-availability-types.tpl.php
@@ -0,0 +1,12 @@
+
+
+
+
diff --git a/templates/ding-holdings.tpl.php b/templates/ding-holdings.tpl.php
new file mode 100644
index 0000000..56ebbea
--- /dev/null
+++ b/templates/ding-holdings.tpl.php
@@ -0,0 +1,22 @@
+ $ordered_count));
+}
+$total_text = format_plural($total_plus_ordered_count, 'We have 1 copy.', 'We have @count copies.', array('@count' => $total_plus_ordered_count));
+?>
+
+