You are here

biblio.module in Bibliography Module 7

Bibliography Module for Drupal.

File

biblio.module
View source
<?php

/**
 * @file
 * Bibliography Module for Drupal.
 */

/**
 *
 */
function _biblio_get_auth_types($auth_category, $biblio_type) {
  static $auth_types = array();
  if (empty($auth_types)) {
    $db_res = db_query("SELECT * FROM {biblio_contributor_type}");
    foreach ($db_res as $row) {
      $auth_types[$row->auth_category][$row->biblio_type][] = $row->auth_type;
    }
  }

  // Fall back to defaults, if no author types are defined for this biblio_type.
  $result = isset($auth_types[$auth_category][$biblio_type]) ? $auth_types[$auth_category][$biblio_type] : $auth_types[$auth_category][0];
  return $result;
}

/**
 *
 */
function _biblio_get_auth_type($auth_category, $biblio_type) {
  $result = (array) _biblio_get_auth_types($auth_category, $biblio_type);

  // Return first element of the array.
  return empty($result) ? NULL : current($result);
}

/**
 * Translate field titles and hints through the interface translation system, if
 * the i18nstrings module is enabled.
 */
function _biblio_localize_fields(&$fields) {
  if (function_exists('i18n_string')) {
    foreach ($fields as $key => $row) {
      $fields[$key]['title'] = i18n_string("biblio:field:{$row['ftdid']}:title", $fields[$key]['title']);
      $fields[$key]['hint'] = i18n_string("biblio:field:{$row['ftdid']}:hint", $fields[$key]['hint']);
    }
  }
}

/**
 * Translate a publication type through the interface translation system, if
 * the i18nstrings module is enabled.
 *
 * @param int $tid
 *   The biblio publication type identifier.
 *
 * @param string $value
 *   The string to translate.
 *
 * @param string $field
 *   The publication type field to translate (either 'name' or 'description').
 *
 * @return
 *   Translated value.
 */
function _biblio_localize_type($tid, $value, $field = 'name') {
  if (function_exists('i18n_string')) {
    return i18n_string("biblio:type:{$tid}:{$field}", $value);
  }
  return $value;
}

/**
 * Implements hook_locale().
 */
function biblio_locale($op = 'groups', $group = NULL) {
  switch ($op) {
    case 'groups':
      return array(
        'biblio' => t('Biblio'),
      );
    case 'refresh':
      if ($group == 'biblio') {
        biblio_locale_refresh_fields();
        biblio_locale_refresh_types();
      }
      break;
  }
}

/**
 * Refresh all translatable field strings.
 *
 * @param int $tid
 *   Biblio publication type id whose field strings are to be refreshed. If not
 *   specified, strings for all fields will be refreshed.
 */
function biblio_locale_refresh_fields($tid = NULL) {
  if (function_exists('i18n_string')) {
    if (isset($tid)) {
      $result = db_query('SELECT d.* FROM {biblio_field_type} b INNER JOIN {biblio_field_type_data} d ON b.ftdid = d.ftdid WHERE tid = :tid', array(
        ':tid' => $tid,
      ));
    }
    else {
      $result = db_query('SELECT * FROM {biblio_field_type_data}');
    }
    $options = array(
      'translate' => FALSE,
      'update' => TRUE,
    );
    foreach ($result as $row) {
      i18n_string("biblio:field:{$row->ftdid}:title", $row->title, $options);
      i18n_string("biblio:field:{$row->ftdid}:hint", $row->hint, $options);
    }
  }
}

/**
 * Refresh all publication type strings.
 *
 * @param int $tid
 *   Biblio publication type id whose field strings are to be refreshed. If not
 *   specified, strings for all fields will be refreshed.
 */
function biblio_locale_refresh_types($tid = NULL) {
  if (function_exists('i18n_string')) {
    if (isset($tid)) {
      $result = db_query('SELECT * FROM {biblio_types} WHERE tid = :tid', array(
        ':tid' => $tid,
      ));
    }
    else {
      $result = db_query('SELECT * FROM {biblio_types} WHERE tid > 0');
    }
    $options = array(
      'translate' => FALSE,
      'update' => TRUE,
    );
    foreach ($result as $row) {
      i18n_string("biblio:type:{$row->tid}:name", $row->name, $options);
      i18n_string("biblio:type:{$row->tid}:description", $row->description, $options);
    }
  }
}

/**
 * Implements hook_init().
 */
function biblio_init() {
  global $user, $conf;
  drupal_add_css(drupal_get_path('module', 'biblio') . '/biblio.css');

  // Prevent caching of biblio pages for anonymous users so session
  // variables work and thus filering works.
  if ($user->uid === 0 && variable_get('biblio_prevent_anon_cache', TRUE)) {
    $base = variable_get('biblio_base', 'biblio');
    if (drupal_match_path($_GET['q'], "{$base}\n{$base}/*")) {
      $conf['cache'] = FALSE;
    }
  }
}

/**
 * Implements hook_cron().
 */
function biblio_cron() {
  $path = drupal_get_path('module', 'biblio');
  require_once $path . '/includes/biblio.contributors.inc';
  require_once $path . '/includes/biblio.keywords.inc';

  // Defaults to once per day.
  $interval = variable_get('biblio_orphan_clean_interval', 24 * 60 * 60);
  if (time() >= variable_get('biblio_orphan_clean_next_execution', 0)) {
    biblio_delete_orphan_authors();
    biblio_delete_orphan_keywords();
    variable_set('biblio_orphan_clean_next_execution', time() + $interval);
  }
}

/**
 * Implements hook_theme().
 */
function biblio_theme($existing, $type, $theme, $path) {
  return array(
    'biblio_alpha_line' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'type' => 'author',
        'current' => NULL,
        'path' => NULL,
      ),
    ),
    'biblio_admin_keyword_edit_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_author_types_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_type_mapper_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_io_mapper_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_io_mapper_add_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_field_mapper_form' => array(
      'file' => 'includes/biblio.admin.inc',
      'render element' => 'form',
    ),
    'biblio_admin_types_edit_form' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_admin_types_form' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_field_tab' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_admin_author_edit_form' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_admin_author_edit_merge_table' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_openurl' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'openURL',
      ),
    ),
    'biblio_style' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node' => NULL,
        'style_name' => 'classic',
      ),
    ),
    'biblio_long' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node' => NULL,
        'base' => 'biblio',
        'style_name' => 'classic',
      ),
    ),
    'biblio_tabular' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node' => NULL,
        'base' => 'biblio',
        'teaser' => FALSE,
      ),
    ),
    'biblio_entry' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node',
        'style_name' => 'classic',
      ),
    ),
    'biblio_format_authors' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'contributors' => NULL,
        'options' => array(),
      ),
    ),
    'biblio_page_number' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'orig_page_info' => NULL,
        'page_range_delim' => "-",
        'single_page_prefix' => '',
        'page_range_prefix' => '',
        'total_pages_prefix' => '',
        'single_page_suffix' => '',
        'page_range_suffix' => '',
        'total_pages_suffix' => '',
        'shorten_page_range_end' => FALSE,
      ),
    ),
    'biblio_author_link' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'author',
      ),
    ),
    'biblio_filters' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'form_filter' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_export_links' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node' => NULL,
        'filter' => array(),
      ),
    ),
    'biblio_download_links' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node',
      ),
    ),
    'google_scholar_link' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(
        'node',
      ),
    ),
    'biblio_contributors' => array(
      'file' => 'includes/biblio_theme.inc',
      'render element' => 'form',
    ),
    'biblio_sort_tabs' => array(
      'file' => 'includes/biblio_theme.inc',
      'variables' => array(),
    ),
  );
}

/**
 * Page callback for autocompletion. Outputs JSON of autocomplete options.
 *
 * @param string $field
 *   The field to search.
 * @param string $string
 *   The string to search for.
 */
function biblio_autocomplete($field = NULL, $string = '') {
  $matches = array();
  switch ($field) {
    case 'contributor':
    case 'a':
      $result = db_query_range("SELECT name FROM {biblio_contributor_data} WHERE LOWER(lastname) LIKE LOWER(:name) OR LOWER(firstname) LIKE LOWER(:firstname) ORDER BY lastname ASC ", 0, 10, array(
        ':name' => $string . '%',
        ':firstname' => $string . '%',
      ));
      foreach ($result as $data) {
        $matches[$data->name] = check_plain($data->name);
      }
      break;
    case 'biblio_keywords':
    case 'k':
      $sep = check_plain(variable_get('biblio_keyword_sep', ','));

      // Find the last separator.
      $sep_pos = strrpos($string, $sep);

      // First part of the string upto the last separator.
      $start = trim(drupal_substr($string, 0, $sep_pos));
      $end_sep = $sep_pos ? $sep_pos + 1 : $sep_pos;

      // Part of the string after the last separator.
      $end = trim(drupal_substr($string, $end_sep)) . '%';
      $result = db_query_range("SELECT * FROM {biblio_keyword_data} WHERE LOWER(word) LIKE LOWER(:end) ORDER BY word ASC ", 0, 10, array(
        ':end' => $end,
      ));
      foreach ($result as $data) {

        // Now glue the word found onto the end of the original string...
        $keywords = $sep_pos ? $start . ', ' . check_plain($data->word) : check_plain($data->word);
        $matches[$keywords] = $keywords;
      }
      break;
    default:
      if (!$field) {
        break;
      }
      $field = drupal_strtolower($field);
      $string = '%' . drupal_strtolower($string) . '%';
      $query = db_select('biblio', 'b')
        ->fields('b', array(
        $field,
      ))
        ->condition($field, $string, 'LIKE')
        ->orderBy($field, 'ASC')
        ->range(0, 10);
      $result = $query
        ->execute();
      foreach ($result as $data) {
        $matches[$data->{$field}] = check_plain($data->{$field});
      }
  }
  print drupal_json_output($matches);
  drupal_exit();
}

/**
 *
 */
function biblio_help_page() {
  $base = variable_get('biblio_base', 'biblio');
  $text = "<h3>" . t('General:') . "</h3>";
  $text .= "<p>" . t('By default, the !url page will list all of the entries in the database sorted by Year in descending order. If you wish to sort by "Title" or "Type",  you may do so by clicking on the appropriate links at the top of the page.  To reverse the sort order, simply click the link a second time.', array(
    '!url' => l('', $base),
  )) . "</p>";
  $text .= "<h3>" . t('Filtering Search Results:') . "</h3>";
  $text .= "<p>" . t('If you wish to filter the results, click on the "Filter" tab at the top of the page.  To add a filter, click the radio button to the left of the filter type you wish to apply, then select the filter criteria from the drop down list on the right, then click the filter button.') . "</p>";
  $text .= "<p>" . t('It is possible to create complex filters by returning to the <i>Filter</i> tab and adding additional filters.  Simply follow the steps outlined above and press the "Refine" button.') . "</p>";
  $text .= "<p>" . t('All filters can be removed by clicking the <i>Clear All Filters</i> link at the top of the result page, or on the <i>Filter</i> tab they can be removed one at a time using the <i>Undo</i> button, or you can remove them all using the <i>Clear All</i> button.') . "</p>";
  $text .= "<p>" . t('You may also construct URLs which filter.  For example, /biblio/year/2005 will show all of the entries for 2005.  /biblio/year/2005/author/smith will show all of entries from 2005 for smith.') . "</p>";
  $text .= "<h3>" . t('Exporting Search Results:') . "</h3>";
  $text .= "<p>" . t('Assuming this option has been enabled by the administrator, you can export search results directly into EndNote.  The link at the top of the result page will export all of the search results, and the links on individual entries will export the information related to that single entry.') . "</p>";
  $text .= "<p>" . t('The information is exported in EndNote "Tagged" format similar to this...') . "<pre>" . t('
                  %0  Book
                  %A  John Smith
                  %D  1959
                  %T  The Works of John Smith
                  ...') . '</pre></p>';
  $text .= "<p>" . t('Clicking on one of the export links should cause your browser to ask you whether you want to Open, or Save To Disk, the file endnote.enw.  If you choose to open it, Endnote should start and ask you which library you would like store the results in.  Alternatively, you can save the file to disk and manually import it into EndNote.') . "</p>";
  return $text;
}

/**
 * Implements hook_help().
 *
 * Throughout Drupal, hook_help() is used to display help text at the top of
 * pages. Some other parts of Drupal pages get explanatory text from these hooks
 * as well. We use it here to provide a description of the module on the
 * module administration page.
 */
function biblio_help($path, $arg) {
  switch ($path) {
    case 'admin/help#biblio':
      return biblio_help_page();
    case 'admin/modules#description':

      // This description is shown in the listing at admin/modules.
      return t('Manages a list of scholarly papers on your site');
    case 'node/add#biblio':

      // This description shows up when users click "create content.".
      return t('This allows you to add a bibliographic entry to the database');
  }
}

/**
 *
 */
function biblio_node_info() {
  return array(
    'biblio' => array(
      'name' => t('Biblio'),
      'base' => 'biblio',
      'description' => t('Use Biblio for scholarly content, such as journal papers and books.'),
    ),
  );
}

/**
 *
 */
function biblio_node_access($node, $op, $account) {
  if (is_string($node)) {
    return NODE_ACCESS_IGNORE;
  }

  // We only care about biblio nodes.
  if ($node->type != 'biblio') {
    return NODE_ACCESS_IGNORE;
  }
  switch ($op) {
    case 'view':
      if (variable_get('biblio_view_only_own', 0) && $account->uid != $node->uid || !user_access('access biblio content')) {
        return NODE_ACCESS_DENY;
      }
      break;
    case 'update':
    case 'delete':
      if (user_access('edit by all biblio authors') && isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
        foreach ($node->biblio_contributors as $key => $author) {
          if (isset($author['drupal_uid']) && $author['drupal_uid'] == $account->uid || isset($account->data['biblio_contributor_id']) && $author['cid'] == $account->data['biblio_contributor_id']) {
            return NODE_ACCESS_ALLOW;
          }
        }
      }
      break;
    default:
  }
  return NODE_ACCESS_IGNORE;
}

/**
 *
 */
function biblio_access($op, $node = '') {
  global $user;
  switch ($op) {
    case 'admin':
      return user_access('administer biblio');
    case 'import':
      return user_access('import from file');
    case 'export':
      return user_access('show export links');
    case 'edit_author':
      if (user_access('administer biblio') || user_access('edit biblio authors')) {
        return NODE_ACCESS_ALLOW;
      }
      break;
    case 'download':
      if (user_access('show download links') || user_access('show own download links') && $user->uid == $node->uid) {
        return NODE_ACCESS_ALLOW;
      }
      break;
    case 'rss':
      return variable_get('biblio_rss', 0);
    default:
  }
  return NODE_ACCESS_IGNORE;
}

/**
 * Implements hook_permission().
 *
 * Since we are limiting the ability to create new nodes to certain users,
 * we need to define what those permissions are here. We also define a permission
 * to allow users to edit the nodes they created.
 */
function biblio_permission() {
  return array(
    'administer biblio' => array(
      'title' => t('Administer Biblio'),
      'description' => t('Allows full control (create, update, delete) of all Biblio nodes'),
    ),
    'access biblio content' => array(
      'title' => t('Access Biblio content'),
      'description' => t('Allows the user to view Biblio nodes'),
    ),
    // @code
    // 'create biblio' => array(
    //   'title' => t('Create Biblio'),
    //   'description' => t('Allows the user to create new Biblio nodes'),
    //  ),
    //  'edit all biblio entries' => array(
    //    'title' => t('Edit all Biblio entries'),
    //    'description' => t('Allows the user to edit ALL biblio entries regardless of who "owns" them, otherwise they are restricted to on'),
    //  ),
    // @endcode
    'edit by all biblio authors' => array(
      'title' => t('Edit by all Biblio authors'),
      'description' => t('Allows any/all of the authors associated with a biblio entry to edit the biblio entry. This requires the Drupal UserID be mapped to a Biblio author ID'),
    ),
    'edit biblio authors' => array(
      'title' => t('Edit Biblio authors'),
      'description' => t('Allows the user to edit author information'),
    ),
    'import from file' => array(
      'title' => t('Import from file'),
      'description' => t('Allows the user to import bibliographic data from files such as BibTeX, RIS, EndNote'),
    ),
    'show export links' => array(
      'title' => t('Show export links'),
      'description' => t('Allows users to see links which allow export of bibliographic data for an individual entry or the entire result set'),
    ),
    'show download links' => array(
      'title' => t('Show download links'),
      'description' => t('Allows users to see links to any attachements associated with the Biblio entry'),
    ),
    'show own download links' => array(
      'title' => t('Show own download links'),
      'description' => t('Allows user to only see download links on entries for which they are the owner.'),
    ),
    'show filter tab' => array(
      'title' => t('Show filter tab'),
      'description' => t('This determines if the "Filter" tab on the Biblio list page will be shown to the user'),
    ),
    'show sort links' => array(
      'title' => t('Show sort links'),
      'description' => t('This determines if the "Sort" links on the Biblio list page will be shown to the user'),
    ),
    'view full text' => array(
      'title' => t('Show full text'),
      'description' => t('This determines if the user will be able to access the "Full Text" of the article if it is available'),
    ),
  );
}

/**
 * Implements hook_user().
 */
function biblio_form_user_profile_form_alter(&$form, &$form_state, $form_id) {
  if ($form['#user_category'] == 'account') {
    $account = $form['#user'];
    include_once drupal_get_path('module', 'biblio') . '/includes/biblio.admin.inc';
    $show_form = variable_get('biblio_show_user_profile_form', '1') || variable_get('biblio_show_crossref_profile_form', '1') || variable_get('biblio_show_openurl_profile_form', '1');
    $admin_show_form = $account->uid == 1 || user_access('administer users') && user_access('administer biblio') ? TRUE : FALSE;
    if ($admin_show_form || $show_form) {
      $form['biblio_fieldset'] = array(
        '#type' => 'fieldset',
        '#title' => t('Biblio settings'),
        '#weight' => 5,
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
      );
      if ($admin_show_form || variable_get('biblio_show_user_profile_form', '1')) {
        $form['biblio_fieldset'] += _biblio_get_user_profile_form($account);
      }
      else {
        $form['biblio_fieldset'] += _biblio_drupal_author_user_map($account);
      }
      if ($admin_show_form || variable_get('biblio_show_openurl_profile_form', '1')) {
        $form['biblio_fieldset'] += _biblio_get_user_openurl_form($account);
      }
      if ($admin_show_form || variable_get('biblio_show_crossref_profile_form', '1')) {
        $form['biblio_fieldset'] += _biblio_get_user_doi_form($account);
      }
    }
  }
}

/**
 *
 */
function biblio_forms() {
  $forms['biblio_admin_author_types_form_new'] = array(
    'callback' => 'biblio_admin_author_types_form',
  );
  $forms['biblio_admin_author_types_form_edit'] = array(
    'callback' => 'biblio_admin_author_types_form',
  );
  return $forms;
}

/**
 * Implements hook_menu().
 *
 * Here we define some built in links for the biblio module, links exposed are:
 */
function biblio_menu() {
  global $user;
  $items = array();
  $base = variable_get('biblio_base', 'biblio');
  $base_title = check_plain(variable_get('biblio_base_title', 'Biblio'));
  $items["{$base}"] = array(
    'title' => $base_title,
    'page callback' => 'biblio_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
  );
  $items["{$base}/authors"] = array(
    'title' => 'Authors',
    'page callback' => 'biblio_author_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'weight' => 1,
  );
  $items["{$base}/keywords"] = array(
    'title' => 'Keywords',
    'page callback' => 'biblio_keyword_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    // 'type' => MENU_LOCAL_TASK,.
    'weight' => 2,
  );
  $items["{$base}/import"] = array(
    'title' => 'Import',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_import_form',
    ),
    'file' => 'includes/biblio.import.export.inc',
    'access callback' => 'user_access',
    'access arguments' => array(
      'import from file',
    ),
    // 'type'              => MENU_LOCAL_TASK,.
    'weight' => 10,
  );
  $items["{$base}/user/%"] = array(
    'title' => 'My publications',
    'page callback' => 'biblio_profile_page',
    'page arguments' => array(
      2,
    ),
    'access callback' => '_biblio_profile_access',
    'access arguments' => array(
      2,
      'menu',
    ),
    'parent' => '',
    'file' => 'includes/biblio.pages.inc',
  );

  /*
    $items["$base/backup"] = array(
    'title' => '',
    'page callback' => 'biblio_backup',
    'access callback' => 'user_access',
    'access arguments' => array('access content'),
    'file' => 'biblio.import.export.inc',
    'type' => MENU_CALLBACK
    );
  */
  $items["{$base}/pot"] = array(
    'title' => '',
    'page callback' => 'biblio_dump_db_data_for_pot',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );
  $wildcard = 2 + (count(explode("/", $base)) - 1);
  $items[$base . '/authors/%'] = array(
    'title' => 'Show author information',
    'page callback' => 'biblio_goto',
    'page arguments' => array(
      $base,
      'f[author]',
      2,
    ),
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/authors/%/edit"] = array(
    'title' => 'Edit author information',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_edit_form',
      $wildcard,
    ),
    'access callback' => 'biblio_access',
    'access arguments' => array(
      'edit_author',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/keywords/%/edit"] = array(
    'title' => '',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_keyword_edit_form',
      $wildcard,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/keyword/%/delete"] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_keyword_delete_confirm',
      $wildcard,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'weight' => 1,
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/view/%"] = array(
    'page callback' => 'biblio_view_node',
    'page arguments' => array(
      $wildcard,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items["user/%user/{$base}"] = array(
    'title' => 'Publications',
    'page callback' => 'biblio_profile_page',
    'page arguments' => array(
      1,
      'profile',
      'no_filters',
    ),
    'access callback' => '_biblio_profile_access',
    'access arguments' => array(
      1,
      'profile',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/config/content/biblio'] = array(
    'title' => 'Biblio settings',
    'description' => 'Configure default behavior of the Biblio module.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_settings',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
  );
  $items['admin/config/content/biblio/basic'] = array(
    'title' => 'Preferences',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/content/biblio/import'] = array(
    'title' => 'Data import',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_import_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.import.export.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/config/content/biblio/export'] = array(
    'title' => 'Export',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_export_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.import.export.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
  );
  $items['admin/config/content/biblio/fields'] = array(
    'title' => 'Fields',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_types_edit_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/config/content/biblio/fields/common'] = array(
    'title' => 'Common',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_types_edit_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/content/biblio/iomap'] = array(
    'title' => 'Import/Export Mapping',
    'page callback' => 'biblio_admin_io_mapper_page',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/config/content/biblio/iomap/formats'] = array(
    'title' => 'Import/Export Mapping',
    'page callback' => 'biblio_admin_io_mapper_page',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -100,
  );
  $formats = module_invoke_all('biblio_mapper_options');
  foreach ($formats as $key => $format) {
    $items['admin/config/content/biblio/iomap/edit/' . $key] = array(
      'title' => $format['title'],
      'page callback' => 'drupal_get_form',
      'page arguments' => array(
        'biblio_admin_io_mapper_form',
        6,
      ),
      'access arguments' => array(
        'administer biblio',
      ),
      'file' => 'includes/biblio.admin.inc',
      'tab_parent' => 'admin/config/content/biblio/iomap',
      'type' => MENU_LOCAL_TASK,
      'weight' => -1,
    );
  }
  $items['admin/config/content/biblio/iomap/%/%/add'] = array(
    'title' => '',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_io_mapper_add_form',
      5,
      6,
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'tab_parent' => 'admin/config/content/biblio/iomap',
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
    'weight' => -1,
  );
  $items['admin/config/content/biblio/pubtype'] = array(
    'title' => 'Publication types',
    'page callback' => 'biblio_admin_types_form',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/config/content/biblio/pubtype/list'] = array(
    'title' => 'List',
    'page callback' => 'biblio_admin_types_form',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/content/biblio/pubtype/delete/%'] = array(
    'title' => '',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_types_delete_form',
      6,
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/pubtype/new'] = array(
    'title' => 'Add New Type',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_types_add_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/config/content/biblio/pubtype/reset'] = array(
    'page callback' => 'biblio_admin_types_reset',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/fields/reset'] = array(
    'title' => 'Reset all types to defaults',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_types_reset_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/config/content/biblio/pubtype/hide'] = array(
    'title' => '',
    'page callback' => 'biblio_admin_types_hide',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/pubtype/show'] = array(
    'title' => '',
    'page callback' => 'biblio_admin_types_show',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/author'] = array(
    'title' => 'Authors',
    'page callback' => 'biblio_author_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -7,
  );
  $items['admin/config/content/biblio/author/list'] = array(
    'title' => 'List',
    'page callback' => 'biblio_author_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -7,
  );
  $items['admin/config/content/biblio/author/%'] = array(
    'title' => 'Show author information',
    'page callback' => 'biblio_goto',
    'page arguments' => array(
      $base,
      'f[author]',
      5,
    ),
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/author/%/edit'] = array(
    'title' => 'Edit author information',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_edit_form',
      5,
    ),
    'access callback' => 'biblio_access',
    'access arguments' => array(
      'edit_author',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
    'weight' => -6,
  );
  $items['admin/config/content/biblio/author/orphans'] = array(
    'title' => 'Orphaned Authors',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_orphans_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'description' => 'Delete orphaned biblio authors.',
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -6,
  );
  $items['admin/config/content/biblio/author/type'] = array(
    'title' => 'Author Types',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_types_form',
      7,
      6,
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -5,
  );
  $items['admin/config/content/biblio/author/type/new'] = array(
    'title' => 'Add New Author Type',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_types_form_new',
      'new',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/config/content/biblio/author/type/%/edit'] = array(
    'title' => 'Edit Author Type',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_types_form_edit',
      'edit',
      6,
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
    'weight' => -9,
  );
  $items['admin/config/content/biblio/author/type/%/delete'] = array(
    'title' => 'Delete',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_author_type_delete_confirm',
      6,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'weight' => 1,
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/content/biblio/keywords'] = array(
    'title' => 'Keywords',
    'page callback' => 'biblio_keyword_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -7,
  );
  $items['admin/config/content/biblio/keywords/list'] = array(
    'title' => 'List',
    'page callback' => 'biblio_keyword_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -7,
  );
  $items['admin/config/content/biblio/keywords/%/edit'] = array(
    'title' => 'Edit keyword information',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_keyword_edit_form',
      5,
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer biblio',
    ),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_CALLBACK,
    'weight' => -6,
  );
  $items['admin/config/content/biblio/keywords/orphans'] = array(
    'title' => 'Orphaned Keywords',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'biblio_admin_keyword_orphans_form',
    ),
    'access arguments' => array(
      'administer biblio',
    ),
    'description' => 'Delete orphaned biblio keywords.',
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => -6,
  );

  /*    $items['admin/config/content/biblio/authors/reset'] = array(
    'title' => t('Reset all Author types to defaults'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('biblio_admin_author_type_reset_form'),
    'access arguments' => array('administer biblio'),
    'file' => 'includes/biblio.admin.inc',
    'type' => MENU_LOCAL_TASK
    );
     */
  $items['biblio/autocomplete'] = array(
    'title' => 'Autocomplete ',
    'page callback' => 'biblio_autocomplete',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );

  /*  $items["$base/list"] = array(
    'title'             => 'List',
    'type'              => MENU_DEFAULT_LOCAL_TASK,
    'weight'            => -10
    );
    $items["$base/filter"] = array(
    'title'             => 'Filter',
    'page callback'     => 'drupal_get_form',
    'page arguments'    => array('biblio_form_filter'),
    'access callback'   => 'user_access',
    'access arguments'  => array('show filter tab'),
    'type'              => MENU_LOCAL_TASK,
    'file'              => 'includes/biblio.pages.inc',
    'weight'            => -9
    );
     */
  $items["{$base}/filter/clear"] = array(
    'title' => '',
    'page callback' => 'biblio_filter_clear',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/help"] = array(
    'title' => 'Help',
    'page callback' => 'biblio_help_page',
    'access callback' => 'user_access',
    'access arguments' => array(
      'access biblio content',
    ),
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/export"] = array(
    'title' => '',
    'page callback' => 'biblio_export',
    'access callback' => 'user_access',
    'access arguments' => array(
      'show export links',
    ),
    'file' => 'includes/biblio.import.export.inc',
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/citekey"] = array(
    'title' => '',
    'page callback' => 'biblio_citekey_view',
    'access arguments' => array(
      'access biblio content',
    ),
    'file' => 'includes/biblio.pages.inc',
    'type' => MENU_CALLBACK,
  );
  $items["{$base}/recent/rss.xml"] = array(
    'title' => 'RSS feed',
    'page callback' => 'biblio_recent_feed',
    'access callback' => 'biblio_access',
    'access arguments' => array(
      'rss',
    ),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Sends the user to the page with URL "$path?$param=$value".
 *
 * @param string $path
 *   The path to send the user to.
 * @param string $param
 *   The query parameter name.
 * @param string $value
 *   The query parameter value.
 */
function biblio_goto($path, $param, $value) {
  drupal_goto($path, array(
    'query' => array(
      $param => $value,
    ),
  ));
}

/**
 *
 */
function biblio_filter_clear() {
  $options = array();
  $_SESSION['biblio_filter'] = array();
  $base = variable_get('biblio_base', 'biblio');
  if (isset($_GET['sort'])) {
    $options['sort'] = $_GET['sort'];
  }
  if (isset($_GET['order'])) {
    $options['order'] = $_GET['order'];
  }
  drupal_goto($base, $options);
}

/**
 *
 */
function biblio_remove_brace($title_string) {

  // $title_string = utf8_encode($title_string);
  $matchpattern = '/\\{\\$(?:(?!\\$\\}).)*\\$\\}|(\\{[^}]*\\})/';
  $output = preg_replace_callback($matchpattern, 'biblio_remove_brace_callback', $title_string);
  return $output;
}

/**
 *
 */
function biblio_remove_brace_callback($match) {
  if (isset($match[1])) {
    $braceless = str_replace('{', '', $match[1]);
    $braceless = str_replace('}', '', $braceless);
    return $braceless;
  }
  return $match[0];
}

/**
 *
 */
function biblio_node_revision_delete($node) {
  if ($node->type == 'biblio') {
    db_delete('biblio')
      ->condition('vid', $node->vid)
      ->execute();
    db_delete('biblio_contributor')
      ->condition(db_and()
      ->condition('nid', $node->nid)
      ->condition('vid', $node->vid))
      ->execute();
    db_delete('biblio_keyword')
      ->condition(db_and()
      ->condition('nid', $node->nid)
      ->condition('vid', $node->vid))
      ->execute();
  }
}

/**
 * Implements hook_node_insert().
 */
function biblio_node_insert($node) {
  _biblio_index_node($node, FALSE);
}

/**
 * Implements hook_node_update().
 */
function biblio_node_update($node) {
  _biblio_index_node($node, TRUE);
}

/**
 * Indexes a single biblio node.
 *
 * @param $node
 *   The node to index.
 * @param bool $update
 *   TRUE if the node is being updated, FALSE if inserted.
 */
function _biblio_index_node($node, $update) {
  if ($node->type === 'biblio' && variable_get('biblio_index') && module_exists('search')) {
    if ($update) {

      // _node_index_node performs() a node_load() without resetting the
      // node_load() cache, so it would index the old version. We reset the cache
      // here. Don't assign node_load to $node because node_load resets e.g. the
      // menus mlid etc.
      $mynode = node_load($node->nid, NULL, TRUE);
      _node_index_node($mynode);
    }
    else {
      _node_index_node($node);
    }
    search_update_totals();
  }
}

/**
 *
 */
function biblio_node_view($node, $view_mode) {
  if ($node->type == 'biblio') {
    switch ($view_mode) {
      case 'full':
        if (variable_get('biblio_hide_bibtex_braces', 0) && !empty($a4)) {
          drupal_set_title(filter_xss($node->title, biblio_get_allowed_tags()));
        }

      // Fall through.
      case 'teaser':
        $show_link = variable_get('biblio_lookup_links', array(
          'google' => TRUE,
        ));
        if (!empty($show_link['google'])) {
          $node->content['links']['biblio_google_scholar'] = array(
            '#links' => array(
              theme('google_scholar_link', array(
                'node' => $node,
              )),
            ),
            '#attributes' => array(
              'class' => array(
                'links',
                'inline',
              ),
            ),
          );
        }
    }
  }
}

/**
 *
 */
function biblio_query_node_access_alter(QueryAlterableInterface $query) {
  global $user;
  if (user_access('access biblio content', $user)) {
    return;
  }
  $tables = $query
    ->getTables();
  foreach ($tables as $alias => $table_info) {
    if (!$table_info instanceof SelectQueryInterface) {
      if ($table_info['table'] == 'node') {
        $query
          ->condition($alias . '.type', 'biblio', '<>');
        break;
      }
    }
  }
}

/**
 *
 */
function biblio_user_presave(&$edit, $account, $catagory) {
  $keys = array_keys($edit);
  foreach ($keys as $key) {
    if (strpos($key, 'biblio_') !== FALSE && isset($edit[$key])) {
      if (isset($account->data['biblio_id_change_count']) && $account->data['biblio_id_change_count'] > 2 && $key == 'biblio_contributor_id' && $edit[$key] != 0) {
        $edit[$key] = 0;
      }
      $edit['data'][$key] = $edit[$key];
      if ($key == 'biblio_contributor_id') {
        if ($edit[$key] != 0 && $edit[$key] != $account->data[$key]) {
          $edit['biblio_id_change_count']++;
        }
        db_update('biblio_contributor_data')
          ->condition('drupal_uid', $account->uid)
          ->fields(array(
          'drupal_uid' => 0,
        ))
          ->execute();
        db_update('biblio_contributor_data')
          ->condition('cid', $edit['biblio_contributor_id'])
          ->fields(array(
          'drupal_uid' => $account->uid,
        ))
          ->execute();
      }
    }
  }
}

/**
 * Implements hook_form().
 *
 * Create the form for collecting the information
 * specific to this node type. This hook requires us to return some HTML
 * that will be later placed inside the form.
 */
function biblio_form($node, &$form_state) {
  global $user;
  $path = drupal_get_path('module', 'biblio');
  if (variable_get('biblio_button_hide', 1) == 1) {
    drupal_add_js($path . '/misc/biblio.nodeformbuttonhide.js', 'file');
  }
  $fields = array();
  $form['biblio_tabs'] = $tabs = array();
  $tid = !empty($form_state['biblio_type']) ? $form_state['biblio_type'] : (isset($node->biblio_type) ? $node->biblio_type : 0);
  $step_two = !empty($tid);

  /* publication type */
  $param['options'] = array(
    "enctype" => "multipart/form-data",
  );
  $result = db_query('SELECT t.* FROM {biblio_types} as t WHERE tid > -2 AND visible = 1');
  foreach ($result as $option) {
    $results[$option->tid] = $option->name;
  }
  asort($results);
  $options[0] = t('Select Type...');
  $options += $results;
  $form['biblio_type'] = array(
    '#type' => 'select',
    '#title' => t('Publication Type'),
    '#default_value' => $tid,
    '#options' => $options,
    '#description' => NULL,
    '#weight' => 2,
    '#attributes' => array(
      'onchange' => 'document.getElementById(\'edit-biblio-next\').click()',
    ),
    '#executes_submit_callback' => TRUE,
    '#limit_validation_errors' => array(),
    '#multiple' => FALSE,
    '#required' => TRUE,
  );
  $form['biblio_next'] = array(
    '#type' => 'submit',
    '#value' => $step_two ? t('Change Publication Type') : t('Next'),
    '#limit_validation_errors' => array(),
    '#weight' => -10,
    '#submit' => array(),
  );
  if (isset($_COOKIE['has_js']) && !$_COOKIE['has_js']) {
    unset($form['biblio_next']['#attributes']);
  }
  if ($step_two) {
    $form['title'] = array(
      '#type' => 'textfield',
      '#title' => t('Title'),
      '#required' => TRUE,
      '#default_value' => trim(isset($form_state['values']['title']) ? $form_state['values']['title'] : $node->title),
      '#maxlength' => 255,
      '#size' => 120,
      '#weight' => 1,
    );

    // Build the field array used to make the form.
    $result = db_query("SELECT * FROM {biblio_fields} b\n              INNER JOIN {biblio_field_type} bt ON b.fid = bt.fid\n              INNER JOIN {biblio_field_type_data} btd ON btd.ftdid=bt.ftdid\n              WHERE bt.tid=:tid ORDER BY bt.weight ASC", array(
      ':tid' => $tid,
    ), array(
      'fetch' => PDO::FETCH_ASSOC,
    ));
    foreach ($result as $row) {
      $fields[$row['name']] = $row;
    }
    _biblio_localize_fields($fields);
    $tabs = array(
      '#type' => 'vertical_tabs',
      '#weight' => 10,
    );
    $tabs += biblio_node_form_vtabs();
    $tabs['biblio_authors'] = array(
      '#type' => 'fieldset',
      '#group' => 'biblio_tabs',
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
      '#title' => 'Authors',
      '#description' => t('Enter a single name per line using a format such as "Smith, John K" or "John K Smith" or "J.K. Smith"'),
    );
    $tabs['biblio_authors'] += biblio_contributor_widget($node, $form_state);
    $form_state['biblio_fields'] = $fields;
    foreach ($fields as $key => $fld) {
      $options = '';
      if ($key == 'biblio_keywords') {
        $sep = check_plain(variable_get('biblio_keyword_sep', ','));

        // Is the kewords are in array form, then implode them into a string.
        if (isset($form_state['values']['biblio_keywords']) && is_array($form_state['values']['biblio_keywords'])) {
          require_once drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc';
          $form_state['values']['biblio_keywords'] = biblio_implode_keywords($form_state['values']['biblio_keywords']);
        }
        if (!empty($node->{$key}) && is_array($node->{$key})) {
          require_once drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc';
          $node->{$key} = biblio_implode_keywords($node->{$key});
        }
        if (empty($fld['hint'])) {
          $fld['hint'] = t('Separate keywords using the " @sep " character', array(
            '@sep' => $sep,
          ));
        }
      }
      $element = array(
        '#default_value' => isset($form_state['values'][$key]) ? $form_state['values'][$key] : (isset($node->{$key}) ? $node->{$key} : ''),
        '#type' => $fld['type'],
        '#title' => check_plain($fld['title']),
        '#size' => $fld['size'],
        '#rows' => 10,
        '#maxlength' => $fld['maxsize'],
        '#weight' => $fld['weight'] / 10,
        '#autocomplete_path' => $fld['autocomplete'] ? 'biblio/autocomplete/' . $fld['name'] : '',
        '#description' => check_plain($fld['hint']),
        '#format' => isset($node->biblio_formats[$key]) ? $node->biblio_formats[$key] : filter_default_format(),
      );

      // The required marker must be added manually. If #required is set, the
      // validation error message will not indicate which tab the element is
      // under. Instead biblio_node_form_validate() sets a custom error message.
      if ($fld['required']) {
        $element['#title'] .= ' ' . theme('form_required_marker');
      }
      if ($key == 'biblio_refereed') {
        $element['#options'] = array(
          '' => t('None'),
          'Refereed' => t('Refereed'),
          'Non-Refereed' => t('Non-Refereed'),
          'Does Not Apply' => t('Does Not Apply'),
          'Unknown' => t('Unknown'),
        );
        $element['#description'] = t('If you are not sure, set this to Unknown or Does Not Apply');
      }
      if ($fld['common'] || $fld['visible']) {
        $tabs[$fld['vtab']][$key] = $element;
      }
    }
  }
  foreach (element_children($tabs) as $key) {
    $tab_children = element_children($tabs[$key]);
    if (empty($tab_children) && $key != 'biblio_full_text') {
      unset($tabs[$key]);
    }
  }

  // $form['format'] = filter_form($node->format, 20);
  // $biblio_form['#tree']  = TRUE;.
  $form['#validate'] = array(
    'biblio_node_form_validate',
  );
  $form['#cache'] = TRUE;
  $form['biblio_tabs'] += $tabs;
  return $form;
}

/**
 *
 */
function biblio_node_form_vtab_info() {
  return array(
    array(
      'tab_id' => 1,
      'weight' => 10,
      'title' => 'Abstract',
      'description' => '',
    ),
    array(
      'tab_id' => 'biblio_full_text',
      'weight' => 11,
      'title' => 'Full text',
      'description' => '',
    ),
    array(
      'tab_id' => 2,
      'weight' => 12,
      'title' => 'Publication',
      'description' => '',
    ),
    array(
      'tab_id' => 3,
      'weight' => 13,
      'title' => 'Publisher',
      'description' => '',
    ),
    array(
      'tab_id' => 4,
      'weight' => 14,
      'title' => 'Identifiers',
      'description' => '',
    ),
    array(
      'tab_id' => 5,
      'weight' => 15,
      'title' => 'Locators',
      'description' => 'URL\'s etc',
    ),
    array(
      'tab_id' => 6,
      'weight' => 16,
      'title' => 'Keywords',
      'description' => '',
    ),
    array(
      'tab_id' => 7,
      'weight' => 17,
      'title' => 'Notes',
      'description' => '',
    ),
    array(
      'tab_id' => 8,
      'weight' => 18,
      'title' => 'Alternate Titles',
      'description' => '',
    ),
    array(
      'tab_id' => 9,
      'weight' => 19,
      'title' => 'Other',
      'description' => '',
    ),
  );
}

/**
 *
 */
function biblio_node_form_vtabs() {
  $vtabs = biblio_node_form_vtab_info();
  foreach ($vtabs as $tab) {
    $form[$tab['tab_id']] = array(
      '#type' => 'fieldset',
      '#group' => 'biblio_tabs',
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
      '#title' => t($tab['title']),
      '#description' => '',
      '#weight' => $tab['weight'],
    );
  }
  return $form;
}

/**
 *
 */
function biblio_contributor_widget($node, &$form_state) {
  $init_count = variable_get('biblio_init_auth_count', 4);
  $contributor_count = 0;
  if (isset($form_state['values']['biblio_contributors'])) {
    $contributors = $form_state['values']['biblio_contributors'];
  }
  elseif (isset($node->biblio_contributors)) {
    $contributors = $node->biblio_contributors;
  }
  else {
    $contributors = array();
  }
  $ctypes = db_query('SELECT * FROM {biblio_contributor_type_data}');
  foreach ($ctypes as $ctype) {
    $options['roles'][$ctype->auth_type] = $ctype->title;
  }
  $options['categories'] = array(
    1 => t('Primary'),
    2 => t('Secondary'),
    3 => t('Tertiary'),
    4 => t('Subsidiary'),
    5 => t('Corporate/Institutional'),
  );

  // Container for just the contributors.
  $wrapper = array();
  $wrapper['biblio_contributors'] = array(
    '#tree' => TRUE,
    '#theme' => 'biblio_contributors',
    '#prefix' => '<div id="biblio-contributors-wrapper">',
    '#suffix' => '</div>',
  );
  foreach ($contributors as $author) {
    $wrapper['biblio_contributors'][] = biblio_contributor_form($author, $options);
    $contributor_count++;
  }
  if (isset($form_state['biblio_contrib_count'])) {
    $form_count = max(max($init_count, $contributor_count), $form_state['biblio_contrib_count']);
  }
  else {
    $form_count = max($init_count, $contributor_count);
    $form_state['biblio_contrib_count'] = $form_count;
  }
  if ($form_count > $contributor_count) {
    $author = array();
    for ($i = 0; $i < $form_count - $contributor_count; $i++) {
      $wrapper['biblio_contributors'][] = biblio_contributor_form($author, $options);
    }
  }
  $wrapper['add_more'] = array(
    '#type' => 'submit',
    '#value' => t('More contributors'),
    '#description' => t("If there aren't enough boxes above, click here to add more."),
    '#weight' => 1,
    // If no javascript action.
    '#submit' => array(
      'biblio_contributors_add_more',
    ),
    '#limit_validation_errors' => array(),
    '#ajax' => array(
      'callback' => 'biblio_contributors_add_more_callback',
      'wrapper' => 'biblio-contributors-wrapper',
    ),
  );
  return $wrapper;
}

/**
 *
 */
function biblio_contributor_form($contributor, $options) {
  $form = array(
    '#tree' => TRUE,
  );
  $form['name'] = array(
    '#type' => 'textfield',
    '#maxlength' => 255,
    '#autocomplete_path' => 'biblio/autocomplete/contributor',
    '#default_value' => isset($contributor['name']) ? $contributor['name'] : '',
  );
  $form['auth_category'] = array(
    '#type' => 'select',
    '#default_value' => isset($contributor['auth_category']) ? $contributor['auth_category'] : '',
    '#options' => $options['categories'],
    '#multiple' => FALSE,
  );
  $form['auth_type'] = array(
    '#type' => 'select',
    '#default_value' => isset($contributor['auth_type']) ? $contributor['auth_type'] : '',
    '#options' => $options['roles'],
    '#multiple' => FALSE,
  );
  $form['cid'] = array(
    '#type' => 'hidden',
    '#default_value' => isset($contributor['cid']) ? $contributor['cid'] : '',
  );
  $form['rank'] = array(
    '#type' => 'textfield',
    '#size' => 6,
    '#default_value' => isset($contributor['rank']) ? $contributor['rank'] : '',
  );
  return $form;
}

/**
 *
 */
function biblio_contributors_add_more_callback($form, &$form_state) {
  return $form['biblio_tabs']['biblio_authors']['biblio_contributors'];
}

/**
 *
 */
function biblio_contributors_add_more($form, &$form_state) {
  $form_state['biblio_contrib_count'] += variable_get('biblio_contrib_fields_delta', 2);
  $form_state['rebuild'] = TRUE;
}

/**
 *
 */
function biblio_form_node_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'biblio_node_form') {
    $form['#pre_render'][] = 'biblio_node_form_pre_render';
    if (!isset($form['biblio_tabs']['biblio_full_text']) && isset($form['body'])) {
      unset($form['body']);
    }
    if (empty($form_state['biblio_type']) && empty($form['vid']['#value'])) {
      foreach (element_children($form) as $form_element) {
        if (strstr($form_element, 'biblio_')) {
          continue;
        }
        if (strstr($form_element, 'form_')) {
          continue;
        }
        if (isset($form[$form_element]['#type']) && $form[$form_element]['#type'] != 'value') {
          $form[$form_element]['#access'] = FALSE;
        }
      }
    }
  }
}

/**
 *
 */
function biblio_node_form_pre_render($form) {
  if (isset($form['biblio_tabs']['biblio_full_text']) && isset($form['body'])) {
    $form['biblio_tabs']['biblio_full_text']['body'] = $form['body'];
    unset($form['body']);
  }
  return $form;
}

/**
 * Implements hook_validate().
 *
 * Errors should be signaled with form_set_error().
 */
function biblio_node_form_validate($form, &$form_state) {
  if ($form_state['triggering_element']['#value'] == t('Next') || $form_state['triggering_element']['#value'] == t('Change Publication Type')) {
    $form_state['rebuild'] = TRUE;
    $form_state['biblio_type'] = $form_state['values']['biblio_type'];
    if ($form_state['values']['biblio_type'] == 0) {
      form_set_error('biblio_type', t('Please select a publication type.'));
    }
    return;
  }
  $format = new stdClass();
  foreach (_biblio_get_formatted_fields() as $field) {
    if (isset($form_state['values'][$field]['format'])) {
      $format->format = $form_state['values'][$field]['format'];
      if (!filter_access($format)) {
        form_set_error($field, t('You do not have access to the !format format', array(
          '!format' => $format->format,
        )));
      }
    }
  }
  if (isset($form_state['values']['biblio_keywords'])) {
    require_once drupal_get_path('module', 'biblio') . '/includes/biblio.keywords.inc';
    if (!is_array($form_state['values']['biblio_keywords'])) {
      $form_state['values']['biblio_keywords'] = biblio_explode_keywords($form_state['values']['biblio_keywords']);
    }
    foreach ($form_state['values']['biblio_keywords'] as $keyword) {
      if (strlen($keyword) > 255) {
        form_set_error('biblio_keywords', t('No single keyword can be greater than 255 characters in length, the word: @kw exceeds this length', array(
          '@kw' => $keyword,
        )));
      }
    }
  }
  if (isset($form_state['biblio_fields'])) {
    $vtabs = biblio_node_form_vtab_info();
    foreach ($vtabs as $tab) {
      $tabs[$tab['tab_id']] = $tab['title'];
    }
    foreach ($form_state['biblio_fields'] as $key => $fld) {
      if ($fld['required'] && isset($form_state['values'][$key]) && empty($form_state['values'][$key])) {
        $tab = $tabs[$fld['vtab']];
        form_set_error($key, t('@fld field is required (on the %tab tab).', array(
          '@fld' => $fld['title'],
          '%tab' => $tab,
        )));
      }
    }
  }
}

/**
 *
 */
function _biblio_numeric_year($year) {
  if (!is_numeric($year)) {
    if (drupal_strtoupper($year) == drupal_strtoupper(t("In Press"))) {
      return 9998;
    }
    if (drupal_strtoupper($year) == drupal_strtoupper(t("Submitted"))) {
      return 9999;
    }
  }
  else {
    return $year;
  }
}

/**
 *
 */
function _biblio_text_year($year) {
  if ($year == 9998) {
    return check_plain(variable_get('biblio_inpress_year_text', t('In Press')));
  }
  if ($year == 9999) {
    return check_plain(variable_get('biblio_no_year_text', t('Submitted')));
  }
  return $year;
}

/**
 *
 */
function _biblio_get_formatted_fields() {
  $fields =& drupal_static(__FUNCTION__);
  if (!isset($fields)) {
    $query = db_select('biblio_fields', 'bf');
    $result = $query
      ->fields('bf', array(
      'name',
    ))
      ->condition('type', 'text_format')
      ->execute();
    foreach ($result as $field) {
      $fields[] = $field->name;
    }
  }
  return (array) $fields;
}

/**
 * Prepare a node for submit to database. Contains code common to insert and update.
 *
 * @param $node
 *
 * @return none
 */
function _biblio_prepare_submit(&$node) {
  $node->biblio_sort_title = biblio_normalize_title($node->title);
  if (!isset($node->biblio_year)) {
    $node->biblio_year = 9999;
  }
  $node->biblio_year = _biblio_numeric_year($node->biblio_year);
  if (variable_get('biblio_auto_citekey', 1) && empty($node->biblio_citekey)) {
    $node->biblio_citekey = biblio_citekey_generate($node);
  }
  foreach (_biblio_get_formatted_fields() as $field) {
    if (isset($node->{$field}) && is_array($node->{$field})) {
      $node->biblio_formats[$field] = $node->{$field}['format'];
      $node->{$field} = $node->{$field}['value'];
    }
    else {
      if (!isset($node->biblio_formats) || !is_array($node->biblio_formats)) {
        $node->biblio_formats = array();
      }
      $node->biblio_formats[$field] = filter_default_format();
    }
  }
}

/**
 * Implements hook_insert().
 *
 * As a new node is being inserted into the database, we need to do our own
 * database inserts.
 */
function biblio_insert($node) {
  module_load_include('inc', 'biblio', 'includes/biblio.util');
  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
  _biblio_prepare_submit($node);
  biblio_insert_contributors($node);
  biblio_insert_keywords($node);
  $node->biblio_coins = biblio_coins($node);
  $duplicate = biblio_hash($node);
  drupal_write_record('biblio', $node);

  // If this is a potential duplcate, write the nids of the pre-existing and new nodes.
  if (isset($duplicate) && $duplicate != $node->nid) {
    $dup_map = array(
      'vid' => $duplicate,
      'did' => $node->nid,
    );
    drupal_write_record('biblio_duplicates', $dup_map);
  }
}

/**
 * Implements hook_update().
 *
 * As an existing node is being updated in the database, we need to do our own
 * database updates.
 */
function biblio_update($node) {
  module_load_include('inc', 'biblio', 'includes/biblio.util');
  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
  _biblio_prepare_submit($node);
  biblio_update_contributors($node);
  biblio_update_keywords($node);
  $node->biblio_coins = biblio_coins($node);

  // Update the node in the database:
  if (!empty($node->revision)) {
    drupal_write_record('biblio', $node);
  }
  else {
    drupal_write_record('biblio', $node, 'vid');
  }
}

/**
 * Implements hook_delete().
 *
 * When a node is deleted, we need to clean up related tables.
 */
function biblio_delete($node) {
  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
  module_load_include('inc', 'biblio', 'includes/biblio.keywords');

  // First remove data from the biblio table.
  db_delete('biblio')
    ->condition('nid', $node->nid)
    ->execute();

  // Now remove the entries from the contributor linking table.
  biblio_delete_contributors($node);
  biblio_delete_keywords($node);
}

/**
 * Implements hook_load().
 *
 * This hook is called
 * every time a node is loaded, and allows us to do some loading of our own.
 */
function biblio_load($nodes) {
  module_load_include('inc', 'biblio', 'includes/biblio.util');
  module_load_include('inc', 'biblio', 'includes/biblio.contributors');
  module_load_include('inc', 'biblio', 'includes/biblio.keywords');
  $vids = array();
  foreach ($nodes as $nid => $node) {
    $vids[] = $node->vid;
  }
  $result = db_query('SELECT b.*, bt.name as biblio_type_name
                      FROM {biblio} b
                      LEFT JOIN {biblio_types} bt on b.biblio_type = bt.tid
                      WHERE b.vid IN (:vids)', array(
    ':vids' => $vids,
  ), array(
    'fetch' => PDO::FETCH_ASSOC,
  ));
  $contributors = biblio_load_contributors_multiple($vids);
  $keywords = biblio_load_keywords_multiple($vids);
  foreach ($result as $record) {
    if ((isset($record['biblio_url']) || isset($record['biblio_accession_number'])) && variable_get('biblio_fix_isi_links', 0)) {
      biblio_fix_isi_links($record);
    }
    foreach ($record as $key => $value) {
      $nodes[$record['nid']]->{$key} = $value;
    }
    $nodes[$record['nid']]->biblio_year = _biblio_text_year($record['biblio_year']);
    $nodes[$record['nid']]->biblio_contributors = isset($contributors[$record['vid']]) ? $contributors[$record['vid']] : array();
    $nodes[$record['nid']]->biblio_keywords = isset($keywords[$record['vid']]) ? $keywords[$record['vid']] : array();
    if (empty($record['biblio_coins'])) {
      $nodes[$record['nid']]->biblio_coins = biblio_coins($nodes[$record['nid']]);
    }
    if ($record['biblio_formats'] != NULL) {
      $nodes[$record['nid']]->biblio_formats = unserialize($record['biblio_formats']);
    }
    else {
      $nodes[$record['nid']]->biblio_formats = array();
    }
  }
}

/**
 *
 */
function biblio_citekey_generate($node) {
  $php = check_plain(variable_get('biblio_citekey_phpcode', ''));
  if (empty($php)) {
    $prefix = variable_get('biblio_citekey_prefix', '');
    $primary_field = variable_get('biblio_citekey_field1', 'nid');
    $secondary_field = variable_get('biblio_citekey_field2', 'nid');
    $citekey = !empty($node->{$primary_field}) ? $node->{$primary_field} : (!empty($node->{$secondary_field}) ? $node->{$secondary_field} : $node->nid);
    return check_plain($prefix . $citekey);
  }
  else {
    ob_start();
    $return = eval($php);
    ob_end_clean();
    return check_plain(strip_tags((string) $return));
  }
}

/**
 * Implements hook_view().
 */
function biblio_view($node, $buildmode = 'full') {
  global $user;
  $links = array();
  $style = biblio_get_style();
  $base = variable_get('biblio_base', 'biblio');
  $base_title = check_plain(variable_get('biblio_base_title', 'Biblio'));
  switch ($buildmode) {
    case 'full':
    case 'print':
      if (variable_get('biblio_hide_bibtex_braces', 0) && !isset($node->view)) {
        $node->title = biblio_remove_brace($node->title);
        drupal_set_title(filter_xss($node->title, biblio_get_allowed_tags()));
      }

    // Fall through.
    case 'search_index':
      switch (variable_get('biblio_node_layout', 'tabular')) {
        case 'orig':
        case 'ft':
          $node->content['body']['#markup'] = theme('biblio_long', array(
            'node' => $node,
            'base' => $base,
            'style_name' => $style,
          ));
          break;
        case 'cite':
          $node->content['body']['#markup'] = theme('biblio_style', array(
            'node' => $node,
            'base' => $base,
            'style_name' => $style,
          ));
          break;
        case 'tabular':
        default:
          $node->content['body']['#markup'] = theme('biblio_tabular', array(
            'node' => $node,
            'base' => $base,
          ));
          break;
      }
      break;
    case 'teaser':
      $node->content['teaser']['#markup'] = theme('biblio_style', array(
        'node' => $node,
        'base' => $base,
        'style_name' => $style,
      ));
      break;
  }
  return $node;
}

/**
 * Implements hook_block().
 *
 * Generates a block containing the latest poll.
 */
function biblio_block_info() {
  $blocks['recent'] = array(
    'info' => t('Recent publications'),
  );
  return $blocks;
}

/**
 *
 */
function biblio_block_configure($delta = '') {
  $form = array();
  $form['block'] = array(
    '#type' => 'fieldset',
    '#collapsible' => FALSE,
    '#collapsed' => FALSE,
    '#title' => t('Options'),
    '#description' => '',
  );
  $form['block']['biblio_rowsperblock'] = array(
    '#type' => 'textfield',
    '#title' => t('Number of results in the "Recent Publications" block'),
    '#default_value' => variable_get('biblio_rowsperblock', 4),
    '#size' => 2,
    '#maxlength' => 2,
    '#description' => t('This sets the number of results that will be displayed in the "New Publications" block.'),
  );
  $form['block']['biblio_block_order'] = array(
    '#type' => 'radios',
    '#title' => t('Order by'),
    '#default_value' => variable_get('biblio_block_order', 'n.created'),
    '#options' => array(
      'n.created' => t('Date Created'),
      'b.biblio_year' => t('Year Published'),
    ),
  );
  return $form;
}

/**
 *
 */
function biblio_block_save($delta = '', $edit = array()) {
  if ($delta == 'recent') {
    variable_set('biblio_rowsperblock', $edit['biblio_rowsperblock']);
    variable_set('biblio_block_order', $edit['biblio_block_order']);
  }
}

/**
 *
 */
function biblio_block_view($delta = '') {
  switch ($delta) {
    case 'recent':
      $num_in_block = variable_get('biblio_rowsperblock', 4);
      $block_order = variable_get('biblio_block_order', 'n.created');
      $query = db_select('node', 'n')
        ->fields('n', array(
        'nid',
        'title',
      ))
        ->condition(db_and()
        ->condition('n.type', 'biblio')
        ->condition('n.status', 1))
        ->orderBy($block_order, 'DESC')
        ->range(0, $num_in_block);
      if ($block_order == 'b.biblio_year') {
        $query
          ->leftJoin('biblio', 'b', 'n.vid=b.vid');
      }
      $result = $query
        ->execute();
      $base = variable_get('biblio_base', 'biblio');
      $block['subject'] = t('Recent Publications');
      $block['content'] = '<div class="item-list"><ul>';
      $options['html'] = TRUE;
      foreach ($result as $pub) {
        $block['content'] .= '<li >' . l(filter_xss($pub->title, biblio_get_allowed_tags()), "node/{$pub->nid}", $options) . '</li>';
      }
      $block['content'] .= '</ul>';
      if (variable_get('biblio_rss', 0)) {
        $block['content'] .= theme('feed_icon', array(
          'url' => url("{$base}/recent/rss.xml", array(
            'absolute' => TRUE,
          )),
          'title' => t('Recent Publications'),
        ));
      }
      $block['content'] .= l(t('More...'), $base);
      $block['content'] .= '</div>';
      return $block;
  }
}

/**
 *
 */
function biblio_recent_feed() {
  $numberInFeed = variable_get('biblio_rss_number_of_entries', 10);
  $query = db_select('node', 'n')
    ->fields('n', array(
    'nid',
    'title',
  ))
    ->condition(db_and()
    ->condition('n.type', 'biblio')
    ->condition('n.status', 1))
    ->orderBy('n.created', 'DESC')
    ->range(0, $numberInFeed);
  $result = $query
    ->execute();
  $siteName = variable_get('site_name', 'Drupal');
  $base = variable_get('biblio_base', 'biblio');
  $channel['title'] = $siteName . ' - ' . t("Recently Added Publications");
  $channel['link'] = url($base, array(
    'absolute' => TRUE,
  ));
  $channel['description'] = t("This feed lists the %num most recently added publications on %site", array(
    '%num' => $numberInFeed,
    '%site' => $siteName,
  ));
  $nids = array();
  foreach ($result as $row) {
    $nids[] = $row->nid;
  }
  node_feed($nids, $channel);
}

/**
 *
 */
function biblio_filter_feed($rss_info, $nids) {
  $base = variable_get('biblio_base', 'biblio');
  $channel['title'] = $rss_info['title'];
  $channel['link'] = url($base . $rss_info['link'], array(
    'absolute' => TRUE,
  ));
  $channel['description'] = $rss_info['description'];
  node_feed($nids, $channel);
}

/**
 *
 */
function biblio_get_db_fields() {
  $fields = array();
  $fields[] = 'nid';
  $fields[] = 'vid';
  $fields[] = 'biblio_type';
  $result = db_query('SELECT name FROM {biblio_fields} ', array(), array(
    'fetch' => PDO::FETCH_ASSOC,
  ));
  foreach ($result as $field) {
    $fields[] = $field['name'];
  }
  return $fields;
}

/**
 * Filter
 * Largely inspired from the footnote module.
 */
function _biblio_citekey_print($citekey) {
  $nid = db_query("SELECT nid FROM {biblio} WHERE biblio_citekey = :key", array(
    ':key' => $citekey,
  ))
    ->fetchField();
  if ($nid) {
    $style = biblio_get_style();
    $base = variable_get('biblio_base', 'biblio');
    $node = node_load($nid);
    return theme('biblio_style', array(
      'node' => $node,
      'base' => $base,
      'style_name' => $style,
    ));
  }
  else {
    return t("Citekey @cite not found", array(
      '@cite' => $citekey,
    ));
  }
}

/**
 *
 */
function biblio_filter_info() {
  $filters['biblio_filter_reference'] = array(
    'title' => t('Biblio module references &lt;bib&gt; <i>or</i> [bib]'),
    'description' => t('Use &lt;bib&gt;citekey&lt;/bib&gt; or [bib]citebkey[/bib]to insert automatically numbered references.'),
    'prepare callback' => '_biblio_filter_reference_prepare',
    'process callback' => '_biblio_filter_reference_process',
    'tips callback' => '_biblio_filter_reference_tips',
  );
  $filters['biblio_filter_inline_reference'] = array(
    'title' => t('Biblio module inline references &lt;ibib&gt; <i>or</i> [ibib]'),
    'description' => t('Use &lt;bib&gt;citekey&lt;/bib&gt; or [bib]citebkey[/bib]to insert automatically numbered references.'),
    'prepare callback' => '_biblio_filter_inline_reference_prepare',
    'process callback' => '_biblio_filter_inline_reference_process',
    'tips callback' => '_biblio_filter_inline_reference_tips',
  );
  return $filters;
}

/**
 *
 */
function _biblio_filter_reference_tips($filter, $format, $long = FALSE) {
  if (!$long) {

    // This string will be shown in the content add/edit form.
    return t('Use &lt;bib&gt;<i>citekey</i>&lt;/bib&gt; <b><i>or</i></b> [bib]<i>citekey</i>[/bib] to insert automatically numbered references.');
  }
  else {
    return t('You can cite references directly into texts with <code>&lt;bib&gt;<i>citekey</i>&lt;/bib&gt; <b><i>or</i></b> [bib]<i>citekey</i>[/bib]</code>. This will be replaced with a running number (the publication reference) and the publication referenced by the citekey within the &lt;bib&gt; tags will be printed at the bottom of the page (the reference).');
  }
}

/**
 *
 */
function _biblio_filter_inline_reference_tips($filter, $format, $long = FALSE) {
  return t('This creates an in line reference to another publication.');
}

/**
 *
 */
function _biblio_filter_reference_prepare($text, $filter, $format, $langcode, $cache, $cache_id) {
  return $text;
}

/**
 *
 */
function _biblio_filter_inline_reference_prepare($text, $filter, $format, $langcode, $cache, $cache_id) {
  return $text;
}

/**
 *
 */
function _biblio_filter_reference_process($text, $filter, $format, $langcode, $cache, $cache_id) {
  $pattern = array(
    '|\\[bib](.*?)\\[/bib]|s',
    '|<bib>(.*?)</bib>|s',
  );

  // This is used with footnote module integration to replace the <bib> tags with <fn> tags.
  if (variable_get('biblio_footnotes_integration', 0) && module_exists('footnotes')) {
    $text = preg_replace_callback($pattern, '_biblio_filter_footnote_callback', $text);
    return $text;
  }
  else {
    $text = preg_replace_callback($pattern, '_biblio_filter_replace_callback', $text);

    // Replace tag <footnotes> with the list of footnotes.
    // If tag is not present, by default add the footnotes at the end.
    // Thanks to acp on drupal.org for this idea. see http://drupal.org/node/87226
    $footer = '';
    $footer = _biblio_filter_replace_callback(NULL, 'output footer');
    if (preg_match('/<bibliography(\\/( )?)?>/', $text) > 0) {
      $text = preg_replace('/<bibliography(\\/( )?)?>/', $footer, $text, 1);
      return $text;
    }
    else {
      return $text . "\n\n" . $footer;
    }
  }
}

/**
 *
 */
function _biblio_filter_inline_reference_process($text, $filter, $format, $langcode, $cache, $cache_id) {
  $pattern = array(
    '|\\[ibib](.*?)\\[/ibib]|s',
    '|<ibib>(.*?)</ibib>|s',
  );
  $text = preg_replace_callback($pattern, '_biblio_inline_filter_replace_callback', $text);
  return $text;
}

/**
 *
 */
function _biblio_inline_filter_replace_callback($matches) {
  $text = _biblio_citekey_print($matches[1]);
  return $text;
}

/**
 *
 */
function _biblio_filter_footnote_callback($matches, $square_brackets = FALSE) {
  if ($square_brackets) {
    $text = '[fn]' . _biblio_citekey_print($matches[1]) . "[/fn]";
  }
  else {
    $text = '<fn>' . _biblio_citekey_print($matches[1]) . "</fn>";
  }
  return $text;
}

/**
 * Helper function called from preg_replace_callback() above.
 *
 * Uses static vars to temporarily store footnotes found.
 * In my understanding, this is not threadsafe?!
 */
function _biblio_filter_replace_callback($matches, $op = '') {
  static $n = 0;
  static $store_matches = array();
  $str = '';
  if ($op == 'output footer') {
    if ($n > 0) {
      $str = '<hr /><h3>' . t('References') . '</h3>';
      $str .= '<div class="references"><ol>';
      for ($m = 1; $m <= $n; $m++) {
        $str .= '<li id="reference' . $m . '"><a name="ref' . $m . '">' . _biblio_citekey_print($store_matches[$m - 1]) . " </a></li>\n\n";
      }
      $str .= '</ol></div>';
    }
    $n = 0;
    $store_matches = array();
    return $str;
  }

  // Default op: act as called by preg_replace_callback()
  $ref = array_search($matches[1], $store_matches);
  if ($ref === FALSE) {
    $n++;

    // $stores_matches[$matches[1]] = $n;.
    array_push($store_matches, $matches[1]);
    $ref = $n;
  }
  else {
    $ref++;
  }
  $allowed_tags = array();
  $title = filter_xss($matches[1], biblio_get_allowed_tags());

  // Html attribute cannot contain quotes.
  $title = str_replace('"', "&quot;", $title);

  // Remove newlines. Browsers don't support them anyway and they'll confuse line break converter in filter.module.
  $title = str_replace("\n", " ", $title);
  $title = str_replace("\r", "", $title);

  // Return '<sup class="see_reference" title="'. $title .'"><a href="#reference'. $n .'">'. $n .'</a></sup>';
  // $text = '<span><a href="#reference'. $n .'">['. $n .']</a> </span>';
  // $text = '<span>['. $n .']</span>';
  // $text .= '<span class="hovertip">'._biblio_citekey_print($title) .'</span>';.
  $text = '<span hovertip="reference' . $ref . '"><a href="#ref' . $ref . '">[' . $ref . ']</a></span>';
  if (module_exists('hovertip')) {
    $text = '<span hovertip="reference' . $ref . '"><a href="#ref' . $ref . '">[' . $ref . ']</a></span>';
    $text .= '<span id="reference' . $ref . '" class="hovertip">' . _biblio_citekey_print($title) . '</span>';
  }
  else {
    $text = '<a href="#ref' . $ref . '" title="Reference ' . $ref . '">[' . $ref . ']</a>';
  }
  return $text;
}

/**
 *
 */
function hook_taxonomy_vocabulary_delete($vocabulary) {
  if ($vocabulary->vid == variable_get('biblio_keyword_vocabulary', FALSE)) {
    variable_del('biblio_keyword_freetagging');
    variable_del('biblio_keyword_vocabulary');
  }
}

/**
 *
 */
function biblio_term_path($term) {
  $base = variable_get('biblio_base', 'biblio');
  if ($term->vid == variable_get('biblio_collection_vocabulary', 0)) {
    return "{$base}/collection/{$term->name}";
  }
  elseif ($term->vid == variable_get('biblio_keyword_vocabulary', 0)) {
    return "{$base}/term_id/{$term->tid}";
  }
  else {
    return;
  }
}

/**
 *
 */
function biblio_hash($node) {
  static $sums = array();
  $duplicate = NULL;
  if (empty($sums)) {
    $res = db_query("SELECT nid, biblio_md5 FROM {biblio} ");
    foreach ($res as $md5) {
      $sums[$md5->biblio_md5] = $md5->nid;
    }
  }
  $hash_string = str_replace(' ', '', drupal_strtolower($node->title));
  if (isset($node->biblio_contributors[0]['lastname'])) {
    $hash_string .= str_replace(' ', '', drupal_strtolower($node->biblio_contributors[0]['lastname']));
  }
  $hash_string .= $node->biblio_year;
  $sum = md5($hash_string);
  if (isset($sums[$sum])) {
    $duplicate = $sums[$sum];
  }
  else {
    $sums[$sum] = $node->nid;
  }
  $node->biblio_md5 = $sum;

  // Return the nid of the potential duplicate.
  return $duplicate;
}

/**
 *
 */
function _biblio_profile_access($user, $type = 'profile') {
  if ($type == 'profile') {
    $key = 'biblio_show_profile';
  }
  elseif ($type == 'menu' && !empty($user) && $user->uid > 0) {
    $key = 'biblio_my_pubs_menu';
  }
  else {
    return FALSE;
  }

  // If user cannot override site settings or user hasn't yet made its selection, we use site default.
  if (!variable_get('biblio_show_user_profile_form', '1') || !isset($user->data[$key])) {

    // Return site default.
    return variable_get($key, '0');
  }
  else {

    // Return user setting.
    return $user->data[$key];
  }
}

/**
 * Helper function to get either the user or system style.
 */
function biblio_get_style() {
  global $user;
  if (isset($user->data['biblio_user_style']) && $user->data['biblio_user_style'] != "system") {
    return $user->data['biblio_user_style'];
  }
  return module_exists('biblio_citeproc') ? variable_get('biblio_citeproc_style', 'ieee.csl') : variable_get('biblio_style', 'cse');
}

/**
 *
 */
function biblio_get_styles() {
  $styles = array();
  if (module_exists('biblio_citeproc')) {
    $result = db_select('biblio_citeproc_styles', 'csl')
      ->fields('csl', array(
      'filename',
      'title',
    ))
      ->orderBy('title', 'ASC')
      ->execute();
    foreach ($result as $style) {
      $styles[$style->filename] = $style->title;
    }
  }
  else {
    $dir = drupal_get_path('module', 'biblio') . '/styles';
    $files = file_scan_directory($dir, '/biblio_style_..*.inc$/');
    foreach ($files as $file) {
      include_once $file->uri;
      $function = $file->name . '_info';
      if (function_exists($function)) {

        // Build and array of the short and long names.
        $styles = array_merge($styles, call_user_func($function));
      }
    }
    ksort($styles);
  }
  return $styles;
}

/**
 * Implements hook_views_api().
 */
function biblio_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'biblio') . '/views',
  );
}

/**
 *
 */
function biblio_fix_isi_links(&$node) {
  $isi = check_plain(variable_get('biblio_isi_url', 'http://apps.isiknowledge.com/InboundService.do?Func=Frame&product=WOS&action=retrieve&SrcApp=EndNote&Init=Yes&SrcAuth=ResearchSoft&mode=FullRecord&UT='));
  if (isset($node['biblio_url']) && preg_match('/Go\\s*to\\s*ISI/', $node['biblio_url'])) {
    $node['biblio_url'] = str_replace('<Go to ISI>://', $isi, $node['biblio_url']);
  }
  if (isset($node['biblio_accession_number']) && preg_match('/^ISI:/', $node['biblio_accession_number'])) {
    $node['biblio_accession_number'] = str_replace("ISI:", $isi, $node['biblio_accession_number']);
  }
}

/**
 *
 */
function biblio_get_allowed_tags() {
  return array(
    'a',
    'b',
    'i',
    'u',
    'sub',
    'sup',
    'span',
  );
}

/**
 *
 */
function biblio_get_title_url_info($node) {
  return array(
    'link' => variable_get('biblio_link_title_url', 0) && !empty($node->biblio_url) ? $node->biblio_url : "node/{$node->nid}",
    'options' => array(
      'attributes' => variable_get('biblio_links_target_new_window', FALSE) ? array(
        'target' => '_blank',
      ) : array(),
      'html' => TRUE,
    ),
  );
}

/**
 * @param string $type
 *   (can be one of "type_names", "type_map" or "field_map")
 * @param string $format
 *   (tagged, ris, endnote_xml8 etc...)
 * @return array $map
 */
function biblio_get_map($type, $format) {
  $result = db_select('biblio_type_maps', 'btm')
    ->fields('btm', array(
    $type,
  ))
    ->condition('format', $format)
    ->execute()
    ->fetchField();
  $map = unserialize($result);
  if ($type == 'export_map' && empty($map)) {
    $schema = drupal_get_schema('biblio');
    $fieldnames = array_keys($schema['fields']);
    asort($fieldnames);
    $map = array_fill_keys($fieldnames, 1);
  }
  drupal_alter('biblio_map', $map, $type, $format);
  return $map;
}

/**
 *
 */
function biblio_save_map($maps) {
  db_insert('biblio_type_maps')
    ->fields($maps)
    ->execute();
}

/**
 * @param string $type
 *   (can be one of "type_names", "type_map" or "field_map")
 * @param string $format
 *   (tagged, ris, endnote_xml8 etc...)
 * @param array $map
 */
function biblio_set_map($type, $format, $map) {
  $map[$type] = serialize($map);
  $map['format'] = $format;
  drupal_write_record('biblio_type_maps', $map, 'format');
}

/**
 *
 */
function biblio_reset_map($type, $format) {
  module_invoke_all($format . '_map_reset', $type);
}

/**
 *
 */
function biblio_field_extra_fields() {
  module_load_include('inc', 'biblio', 'includes/biblio.fields');
  return _biblio_field_extra_fields();
}

/**
 * Fixes node export importing issue #826506.
 */
function biblio_node_export_node_alter($node, $original_node) {
  if ($node->type == 'biblio' && isset($node->biblio_contributors) && is_array($node->biblio_contributors)) {
    foreach ($node->biblio_contributors as $n => $value) {
      unset($node->biblio_contributors[$n]['cid']);
    }
  }
}

/**
 *
 */
function biblio_feeds_processor_targets_alter(&$targets, $entity_type, $bundle_name) {
  module_load_include('inc', 'biblio', 'includes/biblio.feeds');
  return _biblio_feeds_processor_targets_alter($targets, $entity_type, $bundle_name);
}

/**
 *
 */
function biblio_feeds_importer_default() {
  module_load_include('inc', 'biblio', 'includes/biblio.feeds');
  $defaults = array();
  if (module_exists('feeds_oai_pmh')) {
    $defaults += _biblio_feeds_oai_importer_default();
  }
  return $defaults;
}

/**
 *
 */
function biblio_ctools_plugin_api() {
  list($module, $api) = func_get_args();
  if ($module == "feeds" && $api == "feeds_importer_default") {
    return array(
      "version" => 1,
    );
  }
}

Functions

Namesort descending Description
biblio_access
biblio_autocomplete Page callback for autocompletion. Outputs JSON of autocomplete options.
biblio_block_configure
biblio_block_info Implements hook_block().
biblio_block_save
biblio_block_view
biblio_citekey_generate
biblio_contributors_add_more
biblio_contributors_add_more_callback
biblio_contributor_form
biblio_contributor_widget
biblio_cron Implements hook_cron().
biblio_ctools_plugin_api
biblio_delete Implements hook_delete().
biblio_feeds_importer_default
biblio_feeds_processor_targets_alter
biblio_field_extra_fields
biblio_filter_clear
biblio_filter_feed
biblio_filter_info
biblio_fix_isi_links
biblio_form Implements hook_form().
biblio_forms
biblio_form_node_form_alter
biblio_form_user_profile_form_alter Implements hook_user().
biblio_get_allowed_tags
biblio_get_db_fields
biblio_get_map
biblio_get_style Helper function to get either the user or system style.
biblio_get_styles
biblio_get_title_url_info
biblio_goto Sends the user to the page with URL "$path?$param=$value".
biblio_hash
biblio_help Implements hook_help().
biblio_help_page
biblio_init Implements hook_init().
biblio_insert Implements hook_insert().
biblio_load Implements hook_load().
biblio_locale Implements hook_locale().
biblio_locale_refresh_fields Refresh all translatable field strings.
biblio_locale_refresh_types Refresh all publication type strings.
biblio_menu Implements hook_menu().
biblio_node_access
biblio_node_export_node_alter Fixes node export importing issue #826506.
biblio_node_form_pre_render
biblio_node_form_validate Implements hook_validate().
biblio_node_form_vtabs
biblio_node_form_vtab_info
biblio_node_info
biblio_node_insert Implements hook_node_insert().
biblio_node_revision_delete
biblio_node_update Implements hook_node_update().
biblio_node_view
biblio_permission Implements hook_permission().
biblio_query_node_access_alter
biblio_recent_feed
biblio_remove_brace
biblio_remove_brace_callback
biblio_reset_map
biblio_save_map
biblio_set_map
biblio_term_path
biblio_theme Implements hook_theme().
biblio_update Implements hook_update().
biblio_user_presave
biblio_view Implements hook_view().
biblio_views_api Implements hook_views_api().
hook_taxonomy_vocabulary_delete
_biblio_citekey_print Filter Largely inspired from the footnote module.
_biblio_filter_footnote_callback
_biblio_filter_inline_reference_prepare
_biblio_filter_inline_reference_process
_biblio_filter_inline_reference_tips
_biblio_filter_reference_prepare
_biblio_filter_reference_process
_biblio_filter_reference_tips
_biblio_filter_replace_callback Helper function called from preg_replace_callback() above.
_biblio_get_auth_type
_biblio_get_auth_types
_biblio_get_formatted_fields
_biblio_index_node Indexes a single biblio node.
_biblio_inline_filter_replace_callback
_biblio_localize_fields Translate field titles and hints through the interface translation system, if the i18nstrings module is enabled.
_biblio_localize_type Translate a publication type through the interface translation system, if the i18nstrings module is enabled.
_biblio_numeric_year
_biblio_prepare_submit Prepare a node for submit to database. Contains code common to insert and update.
_biblio_profile_access
_biblio_text_year