View source
<?php
function biblio_citeproc_style_manager_form($form) {
$form = array();
$options = array();
$tree = array();
$cache = cache_get('biblio_citeproc_styles');
if (!$cache || $cache->expire < time()) {
if (!($style_zip_file = variable_get('biblio_citeproc_styles_zip_file', FALSE))) {
$style_zip_file = _get_zip_from_github();
}
if ($style_zip_file) {
$options = _get_csl_list_from_zip($style_zip_file);
}
if (!empty($options)) {
$expire = time() + 2592000;
cache_set('biblio_citeproc_styles', $options, 'cache', $expire);
}
}
else {
$options = $cache->data;
}
$form['remote_names'] = array(
'#type' => 'value',
'#value' => $options,
);
asort($options);
$form['available_styles'] = array(
'#type' => 'select',
'#title' => t('Available styles'),
'#size' => 15,
'#multiple' => TRUE,
'#description' => t('Choose the styles you would like to download and install.'),
);
$form['install'] = array(
'#type' => 'submit',
'#value' => '<--',
'#description' => t('Install the selected styles from GitHub'),
);
$form['remove'] = array(
'#type' => 'submit',
'#value' => '-->',
'#description' => t('Un-install the selected styles'),
);
$form['default'] = array(
'#type' => 'submit',
'#value' => t('Set as site default'),
);
$form['edit'] = array(
'#type' => 'submit',
'#value' => t('Edit selected'),
);
$form['install_all'] = array(
'#type' => 'submit',
'#value' => t('Install all'),
);
$form['#attributes']['enctype'] = 'multipart/form-data';
$form['import_csl_file'] = array(
'#type' => 'file',
'#title' => t('Import Local CSL file'),
'#default_value' => '',
'#size' => 60,
);
$form['import'] = array(
'#type' => 'submit',
'#value' => t('Import'),
'#submit' => array(
'biblio_citeproc_csl_file_import_submit',
),
);
$query = "SELECT filename,id,sha1,title FROM {biblio_citeproc_styles} ORDER BY filename ASC";
$result = db_query($query);
$titles = array();
$installed = array();
while ($style = db_fetch_object($result)) {
$installed[$style->id] = $style->filename;
$titles[$style->filename] = $style->title;
}
$options = array_diff($options, $titles);
$form['available_styles']['#options'] = $options;
$form['installed_styles'] = array(
'#type' => 'select',
'#title' => t('Installed styles'),
'#size' => 15,
'#options' => biblio_get_styles(),
'#multiple' => TRUE,
'#description' => t('Currently installed styles.'),
);
$form['current_default'] = array(
'#value' => $titles[variable_get('biblio_citeproc_style', 'cse.csl')],
);
return $form;
}
function theme_biblio_citeproc_style_manager_form($form) {
$rows = array();
$header = array();
$rows[] = array(
array(
'data' => t('Current default style'),
),
array(
'data' => '<b>' . drupal_render($form['current_default']) . '</b>',
),
);
$rows[] = array(
array(
'data' => t('Example citation:'),
),
array(
'data' => biblio_citeproc_example_citation(),
),
);
$output = theme('table', $header, $rows);
$rows = array();
$rows[] = array(
array(
'data' => drupal_render($form['installed_styles']) . '<br>' . drupal_render($form['default']) . drupal_render($form['edit']),
),
array(
'data' => drupal_render($form['install']) . '<br>' . drupal_render($form['remove']),
),
array(
'data' => drupal_render($form['available_styles']) . '<br>' . drupal_render($form['install_all']),
),
);
$rows[] = array(
array(
'data' => drupal_render($form['import_csl_file']) . drupal_render($form['import']),
'colspan' => 3,
),
);
$output .= theme('table', $header, $rows);
$output .= drupal_render($form);
return $output;
}
function biblio_citeproc_style_manager_form_validate($form, &$form_state) {
if ($form_state['clicked_button']['#value'] == '<--' && count($form_state['values']['available_styles'])) {
if (count($form_state['values']['available_styles']) > 60) {
$message = t('You may not select more than 60 styles for installation at one time');
form_error($form['available_styles'], $message);
}
}
if ($form_state['clicked_button']['#value'] == t('Set as site default') && !count($form_state['values']['installed_styles'])) {
form_error($form['installed_styles'], t('You must select an installed style to set as the default.'));
}
}
function biblio_citeproc_style_manager_form_submit($form, &$form_state) {
if ($form_state['clicked_button']['#value'] == '<--' && count($form_state['values']['available_styles'])) {
if (!($style_zip_file = variable_get('biblio_citeproc_styles_zip_file', FALSE))) {
$style_zip_file = _get_zip_from_github();
}
if (!$style_zip_file) {
form_set_error('<--', t('Could not get the style files from GitHub'));
}
$selected = $form_state['values']['available_styles'];
_install_selected_from_zip($style_zip_file, $selected);
}
if ($form_state['clicked_button']['#value'] == '-->' && count($form_state['values']['installed_styles'])) {
foreach ($form_state['values']['installed_styles'] as $id) {
db_query("DELETE FROM {biblio_citeproc_styles} WHERE filename = '%s'", $id);
}
}
if ($form_state['clicked_button']['#value'] == t('Set as site default') && count($form_state['values']['installed_styles'])) {
$def = array_shift($form_state['values']['installed_styles']);
variable_set('biblio_citeproc_style', $def);
}
if ($form_state['clicked_button']['#value'] == t('Edit selected') && count($form_state['values']['installed_styles'])) {
$style = array_shift($form_state['values']['installed_styles']);
$dest = drupal_get_destination();
drupal_goto('admin/settings/biblio/citeproc/styles/' . $style . '/edit');
}
if ($form_state['clicked_button']['#value'] == t('Install all')) {
$batch_op = array(
'title' => t('Importing all styles from GitHub repository'),
'operations' => array(
array(
'_get_zip_from_github',
array(),
),
array(
'_install_from_zip',
array(),
),
),
'progressive' => TRUE,
'finished' => '_csl_import_batch_finished',
'init_message' => t('Downloading file...'),
'progress_message' => t('Saving styles...'),
'file' => './' . drupal_get_path('module', 'biblio_citeproc') . '/biblio_citeproc.admin.inc',
);
batch_set($batch_op);
batch_process('admin/settings/biblio/styles');
}
}
function biblio_citeproc_csl_file_import_submit($form, &$form_state) {
$validators = array(
'file_validate_extensions' => array(
'csl xml',
),
'biblio_citeproc_validate_csl_file' => array(),
);
if ($import_file = file_save_upload('import_csl_file', $validators)) {
$csl = file_get_contents($import_file->uri);
_install_csl($import_file->filename, $csl);
}
}
function _get_github_repo_tree($url = '') {
$options = array();
$tree = array();
$treeURL = 'https://api.github.com/repos/citation-style-language/styles/contents';
if (!empty($url)) {
$treeURL = $url;
}
$result = drupal_http_request($treeURL);
if ($result->code == 200) {
$tree = json_decode($result->data);
}
else {
$message = t('Attempt to get list of styles from GitHub resulted in an HTTP error: !code. ', array(
'!code' => $result->code,
));
$cache = cache_get('biblio_citeproc_styles');
if ($cache) {
$message .= t('I will use cached data instead.');
$mess_type = 'warning';
$options = $cache->data;
}
else {
$message .= t('I have no cached data, so you will not be able to install new styles at this time.');
$mess_type = 'error';
}
drupal_set_message($message, $mess_type);
}
foreach ($tree as $file) {
if ($file->type == 'file' && strstr($file->name, '.csl')) {
$options[$file->path] = basename($file->name);
}
elseif ($file->type == 'dir') {
$options = array_merge($options, _get_github_repo_tree($file->url));
}
}
return $options;
}
function _install_csl($name, $csl, $sha = NULL, $all = FALSE) {
static $installed = array();
if (empty($installed)) {
$query = "SELECT filename,id,sha1,title FROM {biblio_citeproc_styles} ORDER BY filename ASC";
$result = db_query($query);
$installed = array();
while ($style = db_fetch_object($result)) {
$installed[$style->id] = $style;
}
}
$xml = simplexml_load_string($csl);
if ($xml) {
$parent = '';
foreach ($xml->info->link as $link) {
$attrs = $link
->attributes();
if (isset($attrs['rel']) && $attrs['rel'] == 'independent-parent') {
$parent = (string) $attrs['href'];
}
}
if (!$all && !empty($parent)) {
$csl_file_contents = db_result(db_query("SELECT csl FROM {biblio_citeproc_styles} WHERE id = '%s'", $parent));
if (!$csl_file_contents) {
drupal_set_message(t('You do not have the parent style file: !parent_id installed. You must install !parent_id before you can use !csl_id', array(
'!parent_id' => basename($parent),
'!csl_id' => $name,
)), 'error');
}
}
$sha1 = isset($sha) ? $sha : sha1($csl);
$record = array(
'filename' => $name,
'parent' => $parent,
'title' => trim((string) $xml->info->title),
'summary' => (string) $xml->info->summary,
'csl' => $csl,
'sha1' => $sha1,
'id' => (string) $xml->info->id,
);
if (!array_key_exists($record['id'], $installed)) {
db_query("INSERT INTO {biblio_citeproc_styles} (filename, parent, title, summary, csl, sha1, id) VALUES ('%s', '%s', '%s', '%s', '%s', %b, '%s')", $record);
$installed[$record['id']] = TRUE;
}
elseif ($record['sha1'] != $installed[$record['id']]->sha1) {
db_query("UPDATE {biblio_citeproc_styles} SET filename = '%s', parent = '%s', title = '%s', summary = '%s', csl = %b, sha1 = '%s' WHERE id = '%s'", $record);
}
elseif ($record['sha1'] == $installed[$record['id']]->sha1) {
$message = t('The CSL file you supplied: !name, is already installed', array(
'!name' => $name,
));
drupal_set_message($message, 'warning');
}
}
else {
drupal_set_message(t('I could not parse the CSL provided as valid XML', 'error'));
}
}
function _get_zip_from_github(&$context = NULL) {
$zip_url = 'https://github.com/citation-style-language/styles/zipball/master';
$dest_dir = file_directory_path();
$parsed_url = parse_url($zip_url);
$destination = realpath($dest_dir) . '/' . 'Biblio-CiteProc-Styles.zip';
$zip_file = drupal_http_request($zip_url);
if ($zip_file->code != 200 && $zip_file->code != 302) {
drupal_set_message(t('HTTP error @errorcode occurred when trying to fetch @remote.', array(
'@errorcode' => $zip_file->code,
'@remote' => $zip_url,
)), 'error');
return FALSE;
}
$filename = file_save_data($zip_file->data, $destination);
if (!empty($filename)) {
variable_set('biblio_citeproc_styles_zip_file', $destination);
cache_clear_all('biblio_citeproc_styles');
}
return $destination;
}
function _install_csl_from_github($path) {
$csl = '';
$github_URL = 'https://api.github.com/repos/citation-style-language/styles/contents/';
$URL = $github_URL . $path;
$result = drupal_http_request($URL);
if ($result->code == 200) {
$file = json_decode($result->data);
switch ($file->encoding) {
case 'base64':
$csl = base64_decode($file->content);
break;
}
_install_csl($file->name, $csl, $file->sha);
}
else {
$message = t('Attempt to get style: %name from GitHub resulted in an HTTP error: !code. ', array(
'%name' => $path,
'!code' => $result->code,
));
$mess_type = 'error';
drupal_set_message($message, $mess_type);
}
return;
}
function _get_csl_list_from_zip($filename) {
$options = array();
$za = new ZipArchive();
if ($za
->open($filename) !== TRUE) {
$message = t('Could not open zip file containing styles: @file', array(
'@file' => realpath($filename),
));
$message = check_plain($message);
drupal_set_message($message, 'error');
return $options;
}
$num_files = $za->numFiles;
for ($i = 0; $i < $num_files; $i++) {
$name = $za
->getNameIndex($i);
$name = basename($name);
if (strstr($name, '.csl')) {
$csl = $za
->getFromIndex($i);
$xml = simplexml_load_string($csl);
if ($xml) {
$options[$i] = trim((string) $xml->info->title);
}
}
}
$za
->close();
asort($options);
return $options;
}
function _install_from_zip(&$context = NULL) {
$destination = variable_get('biblio_citeproc_styles_zip_file', '');
if (!empty($destination)) {
$zip = zip_open($destination);
$za = new ZipArchive();
if ($za
->open($destination) !== TRUE) {
$message = t('Could not open zip file containing styles: !file', array(
'!file' => realpath($destination),
));
$message = check_plain($message);
drupal_set_message($message, 'error');
return;
}
if (empty($context['sandbox'])) {
$context['sandbox']['progress'] = 0;
$context['results']['install_count'] = 0;
}
$num_files = $za->numFiles;
$start = $context['sandbox']['progress'];
$end = min($start + 50, $num_files);
for ($i = $start; $i < $end; $i++) {
$name = $za
->getNameIndex($i);
$name = basename($name);
if (strstr($name, '.csl')) {
$csl = $za
->getFromIndex($i);
_install_csl($name, $csl, NULL, TRUE);
$context['results']['install_count']++;
}
$context['sandbox']['progress']++;
}
$za
->close();
if ($context['sandbox']['progress'] != $num_files) {
$context['finished'] = $context['sandbox']['progress'] / $num_files;
}
}
}
function _install_selected_from_zip($filename = '', $ids = array()) {
$za = new ZipArchive();
if ($za
->open($filename) == TRUE) {
foreach ($ids as $id) {
$name = $za
->getNameIndex($id);
$name = basename($name);
if (strstr($name, '.csl')) {
$csl = $za
->getFromIndex($id);
_install_csl($name, $csl);
}
}
$za
->close();
}
}
function _csl_import_batch_finished($success, $results, $operations) {
$destination = variable_get('biblio_citeproc_styles_zip_file', '');
file_delete($destination);
variable_del('biblio_citeproc_styles_zip_file');
}
function biblio_citeproc_example_citation() {
global $language;
$contributors = array(
0 => array(
'lastname' => 'Oneauth',
'firstname' => 'Joe',
'initials' => 'A',
'auth_category' => 1,
'cid' => -1,
),
1 => array(
'lastname' => 'Twoauth',
'firstname' => 'John',
'initials' => 'B',
'auth_category' => 1,
'cid' => -2,
),
);
$node = new stdClass();
$node->nid = -1;
$node->title = 'This is a fantastic title.';
$node->biblio_contributors[1] = $contributors;
$node->biblio_type = 102;
$node->biblio_year = 2010;
$node->biblio_volume = 1;
$node->biblio_issue = 2;
$node->biblio_secondary_title = 'Journal of Fantastic Articles';
$node->biblio_pages = ' 424-31';
$node->biblio_coins = '';
return theme_biblio_citeproc_style($node);
}
function biblio_citeproc_csl_editor($form_state, $style) {
$csl = db_fetch_object(db_query("SELECT id,parent,csl FROM {biblio_citeproc_styles} WHERE filename = '%s'", array(
':id' => $style,
)));
if (!isset($csl->csl)) {
drupal_set_message(t('Biblio-CiteProc could not fetch the style file: !csl_id from the database. Check your CiteProc settings.', array(
'!csl_id' => $style,
)), 'error');
return;
}
if (!empty($csl->parent)) {
$csl = db_fetch_object(db_query("SELECT id,csl FROM {biblio_citeproc_styles} WHERE id = '%s'", array(
':id' => $csl->parent,
)));
}
if (isset($csl->csl)) {
$csl_file_contents = $csl->csl;
}
$form['editor'] = array(
'#title' => t('Editing %style', array(
'%style' => $style,
)),
'#type' => 'textarea',
'#rows' => 40,
'#format' => 'csl',
'#default_value' => $csl_file_contents,
);
$form['save'] = array(
'#value' => t('Save'),
'#type' => 'submit',
);
$form['cancel'] = array(
'#value' => t('Cancel'),
'#type' => 'submit',
);
$form['style'] = array(
'#value' => $style,
'#type' => 'hidden',
);
$form['id'] = array(
'#value' => $csl->id,
'#type' => 'hidden',
);
return $form;
}
function biblio_citeproc_csl_editor_validate($form, &$form_state) {
if ($form_state['clicked_button']['#value'] == t('Save')) {
$csl = $form_state['values']['editor'];
$valid = biblio_citeproc_validate_csl($csl);
if (!empty($valid)) {
form_set_error('editor', $valid[0]);
}
else {
$form_state['values']['editor'] = $csl;
}
}
}
function biblio_citeproc_csl_editor_submit($form, &$form_state) {
$form_state['redirect'] = 'admin/settings/biblio/citeproc/styles';
if ($form_state['clicked_button']['#value'] == t('Save')) {
$record = array(
'id' => $form_state['values']['id'],
'csl' => $form_state['values']['editor'],
);
drupal_write_record('biblio_citeproc_styles', $record, 'id');
}
}
function biblio_citeproc_validate_csl_file($file) {
if ($file->source == 'import_csl_file') {
$csl = file_get_contents($file->uri);
return biblio_citeproc_validate_csl($csl);
}
}
function biblio_citeproc_validate_csl($csl) {
$rng_schema = drupal_get_path('module', 'biblio_citeproc') . '/schema/csl.rng';
$doc = new DOMDocument();
$doc
->loadXML($csl);
$updated = $doc
->getElementsByTagName('updated')
->item(0);
$updated->nodeValue = date(DATE_ATOM, time());
$valid = $doc
->relaxNGValidate($rng_schema);
$csl = $doc
->saveXML();
return $valid ? array() : array(
t('The supplied CSL file did not pass CSL 1.0 validation'),
);
}