Compare commits

..

3 Commits

  1. 89
      README.md
  2. 6
      bibcite_footnotes.info.yml
  3. 10
      bibcite_footnotes.libraries.yml
  4. 331
      bibcite_footnotes.module
  5. 4
      bibcite_footnotes_article_with_citations/README.md
  6. 13
      bibcite_footnotes_article_with_citations/bibcite_footnotes_article_with_citations.info.yml
  7. 113
      bibcite_footnotes_article_with_citations/config/install/core.entity_form_display.node.bibcite_fn_article_references.default.yml
  8. 57
      bibcite_footnotes_article_with_citations/config/install/core.entity_view_display.node.bibcite_fn_article_references.default.yml
  9. 51
      bibcite_footnotes_article_with_citations/config/install/editor.editor.basic_html_with_references.yml
  10. 21
      bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.body.yml
  11. 98
      bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited.yml
  12. 37
      bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_image.yml
  13. 28
      bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_tags.yml
  14. 87
      bibcite_footnotes_article_with_citations/config/install/filter.format.basic_html_with_references.yml
  15. 17
      bibcite_footnotes_article_with_citations/config/install/node.type.bibcite_fn_article_references.yml
  16. 23
      composer.json
  17. 24
      config/optional/field.storage.node.field_bibcite_fn_works_cited.yml
  18. 93
      css/reference_footnote.css
  19. 73
      js/plugins/reference_footnotes/dialogs/footnotes.js
  20. 24
      js/plugins/reference_footnotes/plugin.js
  21. 28
      js/replace_citations.js
  22. 24
      src/CitationTools.php
  23. 73
      src/Plugin/BibCiteProcessor/CiteprocPhpInline.php
  24. 28
      src/Plugin/CKEditorPlugin/ReferenceFootnotes.php
  25. 336
      src/Plugin/Filter/ReferenceFootnotesFilter.php
  26. 0
      templates/footnote-link.html.twig
  27. 0
      templates/footnote-list.html.twig

89
README.md

@ -6,95 +6,42 @@ Contents
* Introduction * Introduction
* Installation * Installation
* Use * Configuration
* Current Maintainers * Current Maintainers
Introduction Introduction
------------ ------------
A plugin for the Footnotes module (https://www.drupal.org/project/footnotes)
that lets a user insert references created or importeed using the Bibliography
and Citation project (https://www.drupal.org/project/bibcite).
Provides a CKEditor plugin that lets a user select from a list of citations which Provides a CKEditor plugin that lets a user select from a list of citations which
appear in a formatted list at the bottom of the text that contains endnotes appear in a formatted at the bottom of the text area that contains the footnote.
and references.
Installation Installation
------------ ------------
### Works Cited field Install and set up the Footnotes module as per its installation instructions, including
enabling and configuring the Footnotes text filter. If the 'Allowed HTML tags' filter is enabled
1. Go to Administration > Structure > Content Types and edit the type that will include Reference Footnotes you will need to add the following HTML tags for the reference footnotes to display properly.:
2. In the Manage Fields tab, press Add Field.
3. In "Re-use an existing field" select "Entity reference: field_bibcite_fn_works_cited".
4. Enter an appropriate label and press 'Save and continue'.
5. On the next page select all the items in "Reference type" that should be available to choose from as footnotes.
6. Customize the field under "Manage form display" and "Manage display", typically you'll want to
place the Works Cited field directly under the Body field. See below for configuring with
Inline Entity Form.
7. In "Manage display", select "Rendered entity" in the Format drop-down for the Works Cited field.
8. Press the Settings icon and under "View mode" choose "Citation" - a new view mode created
by this module.
#### Inline Enity Form
It's recommended to also install [Inline Entity Form][1] which allowes a user to
create new references directly in the node edit form.
1. In "Entity Form Display", select ''Inline Entity Form - complex".
2. Press the settings button in the rightmost column.
3. Enabling "Allow users to add new reference entities" and
"Allow users to add existing reference entities" is recommended.
[1]: https://www.drupal.org/project/inline_entity_form
### CKEditor filter and toolbar button
1. Enable the module.
2. Go to Administration > Configuration > Content authoring > Text formats and editors.
3. Edit the text format you want to add Reference Footnotes to
4. Enable the Reference Footnotes Filter
5. Drag the Reference Footnotes button into the active buttons toolbar.
6. Configure the options for the Reference Footnotes Filter.
If the 'Allowed HTML tags' filter is enabled add these HTML tags to the allowed list:
```html ```html
<a class href id> <div class id> <span class id> <ol class id type> <a class href id> <div class id> <span class id> <ul class id type>
<sup> <li class id> <ol class id start type> <sup> <li class id>
``` ```
Use Configuration
--- -------------
See the documentation for [Bibliography and Citation - Import][2] module for how to
add citations exported from a citation management system like RefWorks or EndNote.
[2]: https://www.drupal.org/project/bibcite Drag the Reference Footnotes button into the active set of buttons in the text format
you want to use References in and save the settings.
### Adding a Works Cited item You will then need to create or import one or more references using the Bibliography &
Citations project. Those will then appear in a select list when you are editing a text area
If Inline Entity Form is enabled, an author can create new citations or add references to and click on the Reference Footnote button.
previously-imported or created references directly with the 'Add new reference' and
'Add existing reference' buttons.
With Inline Entity Form, newly-added citations are immediately selectable in the
Reference Footnotes dialog.
If not using the inline entity form, you can select previously imported or created references
When you edit the node again, and you click on the Reference Footnote editor toolbar button,
a list of citations will be available to choose from.
### Citation Formatting
The Works Cited field will use the Default style selected in the
Bibliography & Citation administration pages at Administration > Configuration >
Bibliography & Citation > Settings in the Processing tab under Processor.'
Current Maintainers Current Maintainers
------------------- -------------------
* Alexander O'Neill (https://www.drupal.org/u/alxp) * Alexander O'Neill (https://www.drupal.org/u/alxp)
Sponsors
--------
* This work is supported by the [University of Prince Edward Island Robertson Library](https://library.upei.ca).

6
bibcite_footnotes.info.yml

@ -1,11 +1,9 @@
name: 'BibCite Footnotes' name: 'BibCite Footnotes'
type: module type: module
description: 'Inline footnote links for BibCite References' description: 'Inline footnote links for BibCite References'
core_version_requirement: ^8.0 || ^9 || ^10 core: 8.x
package: 'Bibliography & Citation' package: 'Bibliography & Citation'
dependencies: dependencies:
- bibcite:bibcite - bibcite:bibcite
- bibcite:bibcite_entity - bibcite:bibcite_entity
- fakeobjects:fakeobjects - footnotes:footnotes

10
bibcite_footnotes.libraries.yml

@ -3,13 +3,3 @@ reference_footnote:
css: css:
theme: theme:
css/reference_footnote.css: {} css/reference_footnote.css: {}
dependencies:
- core/jquery
- core/drupalSettings
replace_citations:
version: VERSION
js:
js/replace_citations.js: {}
dependencies:
- core/jquery
- core/drupalSettings

331
bibcite_footnotes.module

@ -5,36 +5,10 @@
* Contains bibcite_footnotes.module. * Contains bibcite_footnotes.module.
*/ */
use Drupal\Core\Field\EntityReferenceFieldItemListInterface;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Routing\RouteMatchInterface;
use Drupal\Core\Url; use Drupal\Core\Url;
use Drupal\Core\Link; use Drupal\Core\Link;
use Drupal\bibcite_footnotes\CitationTools;
use Drupal\bibcite_footnotes\Plugin\Filter\ReferenceFootnotesFilter;
use Drupal\field\Entity\FieldConfig;
/**
* Implements hook_theme().
*/
function bibcite_footnotes_theme() {
return [
'bibcite_footnote_link' => [
'render element' => 'fn',
'template' => 'bibcite-footnote-link',
],
'bibcite_footnote_list' => [
'render element' => 'footnotes',
'path' => \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . '/templates',
'template' => 'bibcite-footnote-list',
'variables' => [
'notes' => [],
'note_type' => [],
'config' => [],
],
],
];
}
/** /**
* Implements hook_help(). * Implements hook_help().
@ -53,7 +27,7 @@ function bibcite_footnotes_help($route_name, RouteMatchInterface $route_match) {
} }
/** /**
* Implementation of hook_preprocess_bibcite_footnote_list(). * Implementation of hook_preprocess_footnote_list().
* *
* Gatehrs all notes and prints out Notes and References as separate lists. * Gatehrs all notes and prints out Notes and References as separate lists.
* *
@ -62,25 +36,31 @@ function bibcite_footnotes_help($route_name, RouteMatchInterface $route_match) {
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/ */
function bibcite_footnotes_preprocess_bibcite_footnote_list(&$variables) { function bibcite_footnotes_preprocess_footnote_list(&$variables) {
$config = $variables['config']; $config = \Drupal::config('filter.format.rich_text_references');//filters.filter_reference_footnotes.settings');
$footnotes = $variables['notes']; $footnotes = $variables['footnotes'];
$notes = [ $notes = [
'#theme' => 'item_list', '#theme' => 'item_list',
'#list_type' => 'ul', '#list_type' => 'ul',
'#title' => $variables['note_type'] == $config['notes_section_label'], '#title' => $config->get('filters.filter_reference_footnotes.settings.notes_section_label'),
'#attributes' => ['class' => 'footnotes'], '#attributes' => ['class' => 'footnotes'],
'#wrapper_attributes' => ['class' => 'container'], '#wrapper_attributes' => ['class' => 'container'],
]; ];
$notes['#attached']['library'][] = 'bibcite_footnotes/reference_footnote'; $references= [
$dont_show_backlink_text = $config['reference_dont_show_backlink_text']; '#theme' => 'item_list',
'#list_type' => 'ul',
'#title' => $config->get('filters.filter_reference_footnotes.settings.references_section_label'),
'#attributes' => ['class' => 'footnotes'],
'#wrapper_attributes' => ['class' => 'container'],
];
$references['#attached']['library'][] = 'bibcite_footnotes/reference_footnote';
$dont_show_backlink_text = $config->get('filters.filter_reference_footnotes.settings.reference_dont_show_backlink_text');
$sort_references_by = $config->get('filters.filter_reference_footnotes.settings.reference_sort_by');
$serializer = \Drupal::service('serializer');
$citation_tools = new CitationTools();
if (empty($footnotes)) {
return;
}
foreach ($footnotes as $fn) { foreach ($footnotes as $fn) {
$item = [ $item = [
'#id' => $fn['fn_id'], '#id' => $fn['fn_id'],
@ -89,14 +69,16 @@ function bibcite_footnotes_preprocess_bibcite_footnote_list(&$variables) {
], ],
]; ];
$build = []; $build = [];
$reference_entity_id = $fn['reference']; preg_match('/\[bibcite_reference:(\d*)\]/', $fn['text'], $matches);
$reference_entity_id = $matches[1];
$footnote_link_text = ($dont_show_backlink_text) ? '^' : $fn['value'];
if (!is_array($fn['ref_id'])) { if (!is_array($fn['ref_id'])) {
// Output normal footnote.
$url = Url::fromUserInput('#' . $fn['ref_id'], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]); $url = Url::fromUserInput('#' . $fn['ref_id'], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]);
$link = Link::fromTextAndUrl(($footnote_link_text), $url)->toRenderable(); $link = Link::fromTextAndUrl(($dont_show_backlink_text && $reference_entity_id ? '^' : $fn['value']), $url)->toRenderable();
$build['footnote-link'] = $link; $build[] = $link;
$override_page_in_citation = $fn['page'] ? $fn['page'] : FALSE;
} }
else { else {
// Output footnote that has more than one reference to it in the body. // Output footnote that has more than one reference to it in the body.
@ -106,7 +88,7 @@ function bibcite_footnotes_preprocess_bibcite_footnote_list(&$variables) {
$i = 0; $i = 0;
$url = Url::fromUserInput('#' . $fn['ref_id'][0], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]); $url = Url::fromUserInput('#' . $fn['ref_id'][0], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]);
$build['footnote-link'] = Link::fromTextAndUrl($footnote_link_text, $url)->toRenderable(); $build[] = Link::fromTextAndUrl($fn['value'], $url)->toRenderable();
foreach ($fn['ref_id'] as $ref) { foreach ($fn['ref_id'] as $ref) {
$url = Url::fromUserInput( '#' . $ref, ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-multi']]); $url = Url::fromUserInput( '#' . $ref, ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-multi']]);
@ -114,253 +96,76 @@ function bibcite_footnotes_preprocess_bibcite_footnote_list(&$variables) {
$i++; $i++;
} }
$override_page_in_citation = FALSE;
}
if (isset($fn['ibid']) && $fn['ibid']) {
$build['footnote-text'] = [
'#type' => 'markup',
'#markup' => ' <span class="endnote-text"><span class="ibid">'
. t('Ibid') . '.</span>'
. (!empty($fn['page']) ? ', ' . $fn['page'] : '')
. '</span>',
];
}
else if (!empty($fn['text'])) {
$build['footnote-link'] = Link::fromTextAndUrl($footnote_link_text, $url)->toRenderable();
$build['footnote-text'] = [
'#type' => 'markup',
'#markup' => ' <span class="endnote-text">' . $fn['text'] . '</span>',
];
} }
if (!empty($reference_entity_id)) { if (!empty($reference_entity_id)) {
if (empty($fn['ibid'])) { $reference_storage = \Drupal::entityTypeManager()
$citation_build = $citation_tools->getRenderableReference($reference_entity_id); ->getStorage('bibcite_reference')
if ($override_page_in_citation) { ->load($reference_entity_id);
$citation_build['#data']['page'] = $override_page_in_citation; $data = $serializer->normalize($reference_storage, 'csl');
} $citation_build = ['#theme' => 'bibcite_citation', '#data' => $data];
$build[] = $citation_build;
$build[] = $citation_build; $render = render($build);
} $item['#markup'] = $render;
$item['sort'] = trim(strip_tags(render($citation_build)));
$references['#items'][] = $item;
//$render = render($build);
$citation_build_render = \Drupal::service('renderer')->render($citation_build);
$item['sort'] = trim(strip_tags($citation_build_render));
} }
else {
$build[] = ['#type' => 'markup', '#markup' => ' ' . $fn['text']];
$render = render($build);
$item['#markup'] = $render;
// $item['#markup'] = $render; $notes['#items'][] = $item;
$notes['#items'][] = $build; }
$reference_entity_id = FALSE;
$render = FALSE;
} }
$variables['notes'] = $notes; $variables['notes'] = $notes;
if ($sort_references_by == 'alphabetical') {
usort($references['#items'], '_bibcite_footnotes_reference_array_cmp');
}
$variables['references'] = $references;
} }
/**
* Comparator function for sorting lists of references.
*
* @param $a First item to compare
* @param $b Second item to compare
* @return int Result of the comparison.
*/
function _bibcite_footnotes_reference_array_cmp($a, $b) { function _bibcite_footnotes_reference_array_cmp($a, $b) {
$a1 = (!empty($a['sort']) ? strtolower($a['sort']) : ''); $a1 = (!empty($a['sort']) ? strtolower($a['sort']) : '');
$b1 = (!empty($b['sort']) ? strtolower($b['sort']) : ''); $b1 = (!empty($b['sort']) ? strtolower($b['sort']) : '');
return strcmp($a1, $b1); return strcmp($a1, $b1);
} }
/** function bibcite_footnotes_preprocess_footnote_link(&$variables) {
* Implementation of hook_preprocess_bibcite_footnote_link().
*
* Construct a link inside a block of text so that it points to the reference list.
*
* @param $variables
*/
function bibcite_footnotes_preprocess_bibcite_footnote_link(&$variables) {
// $variables['fn']['fn']['#type'] = 'markeup'; // $variables['fn']['fn']['#type'] = 'markeup';
// $variables['fn']['fn']['#markup'] = '<h2>Hello!</h2>'; // $variables['fn']['fn']['#markup'] = '<h2>Hello!</h2>';
$fn = $variables['fn']['fn']; $fn = $variables['fn']['fn'];
// TODO: Make a more formal way to denote inline citations. $url = Url::fromUserInput('#' . $fn['ref_id'], ['attributes' => ['id' => $fn['fn_id'], 'class' => 'footnote-link']]);
$link = Link::fromTextAndUrl(($dont_show_backlink_text && $reference_entity_id ? '^' : $fn['value']), $url)->toRenderable();
$class = 'see-footnote'; $build[] = $link;
// Generate the hover text
$citation_tools = new CitationTools();
$citation_entity_id = $fn['reference'];
$citation_data = $citation_tools->getRenderableReference($citation_entity_id);
// Citation contains a page reference, so construct parenthetical footnote.
// @TODO: Make it explicit.
if (!empty($fn['page'] && !is_numeric($fn['value']))) {
$fn['value'] = "({$fn['value']}, {$fn['page']})";
$citation_data['#data']['page'] = $fn['page'];
$class .= '-inline';
}
$citation_data_render = \Drupal::service('renderer')->render($citation_data);
$title = trim(strip_tags($citation_data_render));
$url = Url::fromUserInput('#' . $fn['fn_id'], ['attributes' => ['id' => $fn['ref_id'], 'class' => $class, 'title' => $title]]);
$link = Link::fromTextAndUrl($fn['value'], $url)->toRenderable();
unset($variables['fn']['fn']);
$variables['fn']['fn'] = $link;
// $variables['fn']['fn'][] = $link;
} }
/** /**
* Implementation of hook_inline_entity_form_entity_form_alter(). * Implements hook_theme().
*
* Force all entities to be saved once they are created.
*
* @TODO: Add cleanup batch task for orphaned References.
*
* @param $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
function bibcite_footnotes_inline_entity_form_entity_form_alter(&$form, FormStateInterface &$form_state) {
$form['#save_entity'] = TRUE;
}
/**
* Implementation of hook_form_node_form_alter().
*
* This function populates the Reference list drop-down in the CKEditor drop-down.
* It gathers all referenced entities of type bibcite_reference and puts them
* into a JavaScript setting under drupalSettings.bibcite_footnotes.references.
*
* @param $form
* @param \Drupal\Core\Form\FormStateInterface $form_state
*/
function bibcite_footnotes_form_node_form_alter(&$form, FormStateInterface &$form_state) {
$ief = $form_state->get('inline_entity_form');
if ($ief) {
// Inline entity storage uses hashes to separate out the field instances.
$bibcite_references = [];
foreach ($ief as $ief_instance) {
/**
* @var FieldConfig $field_config
*/
if ($field_config = $ief_instance['instance']) {
// Check if this is a bibcite_reference field type.
if ($field_config->getSetting('handler') == 'default:bibcite_reference') {
$field_name = $field_config->get('field_name');
if (!empty($ief_instance['entities'])) {
foreach ($ief_instance['entities'] as $entity_wrapper) {
/**
* @var \Drupal\core\Entity\EntityInterface $entity
*/
$entity = $entity_wrapper['entity'];
if ($entity->getEntityTypeId() == 'bibcite_reference') {
list($citation_text, $citation_key) = bibcite_footnotes_get_ckeditor_select_item($entity);
$bibcite_references[] = [$citation_text, $citation_key];
}
}
}
}
}
}
$triggering_element = $form_state->getTriggeringElement();
if (!$triggering_element) {
$form['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references;
}
else {
$form[$triggering_element['#parents'][0]]['widget']['#attached']['library'][] = 'bibcite_footnotes/replace_citations';
$form[$triggering_element['#parents'][0]]['widget']['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references;
}
}
else {
// Not using Inline Entity Form, get the references if they exist
$entity = $form_state->getFormObject()->getEntity();
$fields = $entity->getFields();
$reference_field = FALSE;
foreach ($fields as $field) {
$type = $field->getFieldDefinition();
if ($type->getType() == 'entity_reference') {
if ($type->getSetting('handler') == 'default:bibcite_reference') {
$referenced_entities = $field->referencedEntities();
$bibcite_references = [];
foreach ($referenced_entities as $referenced_entity) {
list($citation_text, $citation_key) = bibcite_footnotes_get_ckeditor_select_item($referenced_entity);
$bibcite_references[] = [$citation_text, $citation_key];
}
$form['#attached']['drupalSettings']['bibcite_footnotes']['references'] = $bibcite_references;
}
}
}
}
}
/**
* Construct an item to go into the CKEditor Reference drop-down list.
*
* @param $entity
*
* @return array
* The form of the array is ["Citation string", [reference entity id].
*/ */
function bibcite_footnotes_get_ckeditor_select_item($entity): array { function bibcite_footnotes_theme() {
$serializer = \Drupal::service('serializer'); return [
'bibcite_footnotes' => [
$data = $serializer->normalize($entity, 'csl'); 'render element' => 'children',
$build = ['#theme' => 'bibcite_citation', '#data' => $data]; ],
$build_render = \Drupal::service('renderer')->render($build); ];
$citation_text = trim(strip_tags($build_render));
// Attempt to match up pre-saved entities with the eventual saved ones.
$citation_key = $entity->id->first()->getValue()['value'];
return [$citation_text, $citation_key];
} }
/** function bibcite_footnotes_theme_registry_alter(&$theme_registry) {
* Implementation of hook_preprocess_field(). unset($theme_registry['footnote_list']['function']);
* Sort the works cited list by rendered text, which results in author(s) then title. $theme_registry['footnote_list']['path'] = drupal_get_path('module', 'bibcite_footnotes') . '/templates';
* $theme_registry['footnote_list']['template'] = 'footnote-list';
* @param $variables $theme_registry['footnote_list']['variables']['notes'] = [];
* @param $hook $theme_registry['footnote_list']['variables']['references'] = [];
*/ $theme_registry['footnote_list']['variables']['footnotes'] = [];
function bibcite_footnotes_preprocess_field(&$variables, $hook) {
$citation_tools = new CitationTools(); unset($theme_registry['footnote_link']['function']);
if ($variables['field_name'] == 'field_bibcite_fn_works_cited') { $theme_registry['footnote_link']['path'] = drupal_get_path('module', 'bibcite_footnotes') . '/templates';
$theme_registry['footnote_link']['template'] = 'footnote-link';
foreach($variables['element'] as $index => $element) {
if (is_numeric($index)) {
$renderable = $citation_tools->getRenderableReference($element['#bibcite_reference']);
$renderable = \Drupal::service('renderer')->render($renderable);
$items[] = [
'orig_index' => $index,
'orig_element' => $element,
'rendered' => trim(strip_tags($renderable)),
];
}
}
uasort($items, '_bibcite_footnotes_sort_rendered_references');
$i = 0;
foreach ($items as $item) {
$variables['element'][$i] = $item['orig_element'];
$variables['element']['#items'][$i] = $item['orig_element'];
$variables['items'][$i]['content'] = $item['orig_element'];
$i += 1;
}
}
} }
/**
* Comparator function for theme field preprocess.
*
* @param $a
* The first renderable element.
* @param $b
* The second renderable element.
*
* @return int
*/
function _bibcite_footnotes_sort_rendered_references($a, $b) {
if ($a['rendered'] == $b['rendered']) {
return 0;
}
return strtolower($a['rendered']) < strtolower($b['rendered']) ? -1 : 1;
}

4
bibcite_footnotes_article_with_citations/README.md

@ -1,4 +0,0 @@
Description
-----------
Example content type and text format to demonstrate a fully-configured Reference Footnotes setup.

13
bibcite_footnotes_article_with_citations/bibcite_footnotes_article_with_citations.info.yml

@ -1,13 +0,0 @@
name: 'BibCite Footnotes Article with Citations'
type: module
description: 'Example module to show a fully-configured content type and text format with Reference Footnotes.'
core_version_requirement: ^8 || ^9 || ^10
package: 'Bibliography & Citation'
dependencies:
- bibcite_footnotees:bibcite_footnotes
- bibcite:bibcite_import
- bibcite:bibcite_bibtex
- bibcite:bibcite_endnote
- bibcite:bibcite_ris
- bibcite:bibcite_marc
- inline_entity_form:inline_entity_form

113
bibcite_footnotes_article_with_citations/config/install/core.entity_form_display.node.bibcite_fn_article_references.default.yml

@ -1,113 +0,0 @@
langcode: en
status: true
dependencies:
config:
- field.field.node.bibcite_fn_article_references.body
- field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited
- field.field.node.bibcite_fn_article_references.field_image
- field.field.node.bibcite_fn_article_references.field_tags
- image.style.thumbnail
- node.type.bibcite_fn_article_references
module:
- image
- inline_entity_form
- path
- text
id: node.bibcite_fn_article_references.default
targetEntityType: node
bundle: bibcite_fn_article_references
mode: default
content:
body:
type: text_textarea_with_summary
weight: 7
settings:
rows: 9
summary_rows: 3
placeholder: ''
third_party_settings: { }
region: content
created:
type: datetime_timestamp
weight: 2
region: content
settings: { }
third_party_settings: { }
field_bibcite_fn_works_cited:
weight: 8
settings:
form_mode: default
label_singular: ''
label_plural: ''
allow_new: true
allow_existing: true
match_operator: CONTAINS
override_labels: false
collapsible: false
collapsed: false
allow_duplicate: false
third_party_settings: { }
type: inline_entity_form_complex
region: content
field_image:
weight: 10
settings:
progress_indicator: throbber
preview_image_style: thumbnail
third_party_settings: { }
type: image_image
region: content
field_tags:
weight: 9
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
third_party_settings: { }
type: entity_reference_autocomplete
region: content
path:
type: path
weight: 5
region: content
settings: { }
third_party_settings: { }
promote:
type: boolean_checkbox
settings:
display_label: true
weight: 3
region: content
third_party_settings: { }
status:
type: boolean_checkbox
settings:
display_label: true
weight: 6
region: content
third_party_settings: { }
sticky:
type: boolean_checkbox
settings:
display_label: true
weight: 4
region: content
third_party_settings: { }
title:
type: string_textfield
weight: 0
region: content
settings:
size: 60
placeholder: ''
third_party_settings: { }
uid:
type: entity_reference_autocomplete
weight: 1
settings:
match_operator: CONTAINS
size: 60
placeholder: ''
region: content
third_party_settings: { }
hidden: { }

57
bibcite_footnotes_article_with_citations/config/install/core.entity_view_display.node.bibcite_fn_article_references.default.yml

@ -1,57 +0,0 @@
langcode: en
status: true
dependencies:
config:
- field.field.node.bibcite_fn_article_references.body
- field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited
- field.field.node.bibcite_fn_article_references.field_image
- field.field.node.bibcite_fn_article_references.field_tags
- node.type.bibcite_fn_article_references
module:
- image
- text
- user
id: node.bibcite_fn_article_references.default
targetEntityType: node
bundle: bibcite_fn_article_references
mode: default
content:
body:
label: hidden
type: text_default
weight: 1
settings: { }
third_party_settings: { }
region: content
field_bibcite_fn_works_cited:
weight: 2
label: above
settings:
view_mode: citation
link: false
third_party_settings: { }
type: entity_reference_entity_view
region: content
field_image:
weight: 4
label: above
settings:
image_style: ''
image_link: ''
third_party_settings: { }
type: image
region: content
field_tags:
weight: 3
label: above
settings:
link: true
third_party_settings: { }
type: entity_reference_label
region: content
links:
weight: 0
region: content
settings: { }
third_party_settings: { }
hidden: { }

51
bibcite_footnotes_article_with_citations/config/install/editor.editor.basic_html_with_references.yml

@ -1,51 +0,0 @@
langcode: en
status: true
dependencies:
config:
- filter.format.basic_html_with_references
module:
- ckeditor
format: basic_html_with_references
editor: ckeditor
settings:
toolbar:
rows:
-
-
name: Formatting
items:
- Bold
- Italic
-
name: Links
items:
- DrupalLink
- DrupalUnlink
-
name: Lists
items:
- BulletedList
- NumberedList
-
name: Media
items:
- Blockquote
- DrupalImage
-
name: Tools
items:
- Source
- reference_footnotes
plugins:
stylescombo:
styles: ''
language:
language_list: un
image_upload:
status: false
scheme: public
directory: inline-images
max_size: ''
max_dimensions:
width: null
height: null

21
bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.body.yml

@ -1,21 +0,0 @@
langcode: en
status: true
dependencies:
config:
- field.storage.node.body
- node.type.bibcite_fn_article_references
module:
- text
id: node.bibcite_fn_article_references.body
field_name: body
entity_type: node
bundle: bibcite_fn_article_references
label: Body
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
display_summary: true
field_type: text_with_summary

98
bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_bibcite_fn_works_cited.yml

@ -1,98 +0,0 @@
langcode: en
status: true
dependencies:
config:
- bibcite_entity.bibcite_reference_type.artwork
- bibcite_entity.bibcite_reference_type.audiovisual
- bibcite_entity.bibcite_reference_type.bill
- bibcite_entity.bibcite_reference_type.book
- bibcite_entity.bibcite_reference_type.book_chapter
- bibcite_entity.bibcite_reference_type.broadcast
- bibcite_entity.bibcite_reference_type.case
- bibcite_entity.bibcite_reference_type.chart
- bibcite_entity.bibcite_reference_type.classical
- bibcite_entity.bibcite_reference_type.conference_paper
- bibcite_entity.bibcite_reference_type.conference_proceedings
- bibcite_entity.bibcite_reference_type.database
- bibcite_entity.bibcite_reference_type.film
- bibcite_entity.bibcite_reference_type.government_report
- bibcite_entity.bibcite_reference_type.hearing
- bibcite_entity.bibcite_reference_type.journal
- bibcite_entity.bibcite_reference_type.journal_article
- bibcite_entity.bibcite_reference_type.legal_ruling
- bibcite_entity.bibcite_reference_type.magazine_article
- bibcite_entity.bibcite_reference_type.manuscript
- bibcite_entity.bibcite_reference_type.map
- bibcite_entity.bibcite_reference_type.miscellaneous
- bibcite_entity.bibcite_reference_type.miscellaneous_section
- bibcite_entity.bibcite_reference_type.newspaper_article
- bibcite_entity.bibcite_reference_type.patent
- bibcite_entity.bibcite_reference_type.personal
- bibcite_entity.bibcite_reference_type.presentation
- bibcite_entity.bibcite_reference_type.report
- bibcite_entity.bibcite_reference_type.software
- bibcite_entity.bibcite_reference_type.statute
- bibcite_entity.bibcite_reference_type.thesis
- bibcite_entity.bibcite_reference_type.unpublished
- bibcite_entity.bibcite_reference_type.web_article
- bibcite_entity.bibcite_reference_type.web_project_page
- bibcite_entity.bibcite_reference_type.web_service
- bibcite_entity.bibcite_reference_type.website
- field.storage.node.field_bibcite_fn_works_cited
- node.type.bibcite_fn_article_references
id: node.bibcite_fn_article_references.field_bibcite_fn_works_cited
field_name: field_bibcite_fn_works_cited
entity_type: node
bundle: bibcite_fn_article_references
label: 'Works Cited'
description: 'List of works mentioned in this article.'
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
handler: 'default:bibcite_reference'
handler_settings:
target_bundles:
artwork: artwork
audiovisual: audiovisual
bill: bill
book: book
book_chapter: book_chapter
broadcast: broadcast
case: case
chart: chart
classical: classical
conference_paper: conference_paper
conference_proceedings: conference_proceedings
database: database
film: film
government_report: government_report
hearing: hearing
journal: journal
journal_article: journal_article
legal_ruling: legal_ruling
magazine_article: magazine_article
manuscript: manuscript
map: map
miscellaneous: miscellaneous
miscellaneous_section: miscellaneous_section
newspaper_article: newspaper_article
patent: patent
personal: personal
presentation: presentation
report: report
software: software
statute: statute
thesis: thesis
unpublished: unpublished
web_article: web_article
web_project_page: web_project_page
web_service: web_service
website: website
sort:
field: title
direction: ASC
auto_create: false
auto_create_bundle: artwork
field_type: entity_reference

37
bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_image.yml

@ -1,37 +0,0 @@
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_image
- node.type.bibcite_fn_article_references
module:
- image
id: node.bibcite_fn_article_references.field_image
field_name: field_image
entity_type: node
bundle: bibcite_fn_article_references
label: Image
description: ''
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
file_directory: '[date:custom:Y]-[date:custom:m]'
file_extensions: 'png gif jpg jpeg'
max_filesize: ''
max_resolution: ''
min_resolution: ''
alt_field: true
alt_field_required: true
title_field: false
title_field_required: false
default_image:
uuid: ''
alt: ''
title: ''
width: null
height: null
handler: 'default:file'
handler_settings: { }
field_type: image

28
bibcite_footnotes_article_with_citations/config/install/field.field.node.bibcite_fn_article_references.field_tags.yml

@ -1,28 +0,0 @@
langcode: en
status: true
dependencies:
config:
- field.storage.node.field_tags
- node.type.bibcite_fn_article_references
- taxonomy.vocabulary.tags
id: node.bibcite_fn_article_references.field_tags
field_name: field_tags
entity_type: node
bundle: bibcite_fn_article_references
label: Tags
description: 'Enter a comma-separated list. For example: Amsterdam, Mexico City, "Cleveland, Ohio"'
required: false
translatable: true
default_value: { }
default_value_callback: ''
settings:
handler: 'default:taxonomy_term'
handler_settings:
target_bundles:
tags: tags
sort:
field: name
direction: asc
auto_create: true
auto_create_bundle: ''
field_type: entity_reference

87
bibcite_footnotes_article_with_citations/config/install/filter.format.basic_html_with_references.yml

@ -1,87 +0,0 @@
langcode: en
status: true
dependencies:
module:
- bibcite_footnotes
- editor
- footnotes
name: 'Basic HTML with References'
format: basic_html_with_references
weight: 0
filters:
filter_reference_footnotes:
id: filter_reference_footnotes
provider: bibcite_footnotes
status: true
weight: -50
settings:
footnotes_collapse: '1'
footnotes_ibid: '0'
notes_section_label: Notes
reference_dont_show_backlink_text: '0'
works_cited_sort_by: alphabetical
editor_file_reference:
id: editor_file_reference
provider: editor
status: true
weight: -45
settings: { }
filter_html_image_secure:
id: filter_html_image_secure
provider: filter
status: true
weight: -46
settings: { }
filter_url:
id: filter_url
provider: filter
status: false
weight: -41
settings:
filter_url_length: 72
filter_html:
id: filter_html
provider: filter
status: true
weight: -49
settings:
allowed_html: '<a href hreflang id class="" title> <div id class=""> <em> <strong> <cite> <blockquote cite> <code> <ul type class=""> <ol id type class=""> <li id class=""> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id> <span id class=""> <sup> <img src alt data-entity-type data-entity-uuid data-align data-caption> <p> <fn id>'
filter_html_help: true
filter_html_nofollow: false
filter_autop:
id: filter_autop
provider: filter
status: false
weight: -42
settings: { }
filter_align:
id: filter_align
provider: filter
status: true
weight: -48
settings: { }
filter_caption:
id: filter_caption
provider: filter
status: true
weight: -47
settings: { }
filter_htmlcorrector:
id: filter_htmlcorrector
provider: filter
status: false
weight: -40
settings: { }
filter_html_escape:
id: filter_html_escape
provider: filter
status: false
weight: -43
settings: { }
filter_footnotes:
id: filter_footnotes
provider: footnotes
status: false
weight: -44
settings:
footnotes_collapse: '0'

17
bibcite_footnotes_article_with_citations/config/install/node.type.bibcite_fn_article_references.yml

@ -1,17 +0,0 @@
langcode: en
status: true
dependencies:
module:
- menu_ui
third_party_settings:
menu_ui:
available_menus:
- main
parent: 'main:'
name: 'Article with References'
type: bibcite_fn_article_references
description: 'Article that includes a Works Cited field and in-text references.'
help: ''
new_revision: true
preview_mode: 1
display_submitted: true

23
composer.json

@ -1,23 +0,0 @@
{
"name": "roblib/bibcite_footnotes",
"description": "Add citation footnotes with automatic numbering.",
"type": "drupal-module",
"homepage": "https://drupal.org/project/bibcite_footnotes",
"authors": [
{
"name": "Alexander O'Neill (alxp)",
"homepage": "https://www.drupal.org/u/alxp",
"role": "Maintainer"
}
],
"support": {
"issues": "https://drupal.org/project/issues/bibcite_footnotes",
"source": "https://cgit.drupalcode.org/bibcite_footnotes"
},
"license": "GPL-2.0+",
"minimum-stability": "dev",
"require": {
"drupal/core": ">=8.6",
"drupal/fakeobjects": "^1.0"
}
}

24
config/optional/field.storage.node.field_bibcite_fn_works_cited.yml

@ -1,24 +0,0 @@
langcode: en
status: true
dependencies:
module:
- bibcite_entity
- node
third_party_settings:
field_permissions:
permission_type: public
_core:
default_config_hash: pxSiuPskUjLuu_0TFIFVYFyZtkIelIPBysbXt_LyLVk
id: node.field_bibcite_fn_works_cited
field_name: field_bibcite_fn_works_cited
entity_type: node
type: entity_reference
settings:
target_type: bibcite_reference
module: core
locked: false
cardinality: -1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false

93
css/reference_footnote.css

@ -1,95 +1,10 @@
.footnote-list .footnotes .footnote-link, .footnotes .footnote .footnote-link,
.footnote-list .footnotes .footnote-multi { .footnotes .footnote .footnote-multi {
float: left; float: left;
} }
.footnote-list .footnotes .footnote-link::after, .footnotes .footnote .footnote-link::after,
.footnote-list .footnotes .footnote-multi::after { .footnotes .footnote .footnote-multi::after {
content: " "; content: " ";
white-space: pre; white-space: pre;
} }
/*
* CSS specific to Bibcite Footnotes module.
* (Borrowed from Footnotes module.
*
*
* Thanks to binford2k@lug.wsu.edu for this tip and drinkypoo
* for the question leading up to it. http://drupal.org/node/80538
*/
/* Add empty space before footnotes and a black line on top. */
.footnotes {
clear: both;
margin-top: 4em;
margin-bottom: 2em;
border-top: 1px solid #000;
}
/* Make footnotes appear in a smaller font */
.footnotes {
font-size: 0.9em;
}
/*
Make the footnote a supertext^1
*/
.see-footnote {
vertical-align: top;
position: relative;
top: -0.25em;
font-size: 0.9em;
}
/* Hide the bullet of the UL list of footnotes */
ul.footnotes {
list-style-type: none;
margin-left: 0;
padding-left: 0;
}
ul.footnotes li {
margin-left: 2.5em;
list-style-type: none;
background: none; /* Garland theme sets a bullet via background image, this must be unset! See bug 861634 */
}
/* Move the footnote number outside of the margin for footnote text (hanging indent) */
ul.footnotes {
/* This is apparently very needed for the "position: absolute;" below to work correctly */
position: relative;
}
.footnotes .footnote-label {
position: absolute;
left: 0;
z-index: 2;
}
/* Highlight the target footnote (or ref number, if a backlink was used) when user clicks a footnote. */
.see-footnote:target,
.footnotes .footnote:target {
background-color: #eee;
}
.see-footnote:target {
border: solid 1px #aaa;
}
/* Note: This CSS has a minor bug on all versions of IE in that the footnote numbers
are aligned with the absolute bottom of their space, thus being a couple of pixels
lower than their corresponding line of text. IE5.5 has a serious bug in that the numbers
are not shifted left at all, thus being garbled together with the start of their text. */
/*
Make the multiple backlinks a supertext^1
*/
.footnotes .footnote-multi {
vertical-align: top;
position: relative;
top: -0.25em;
font-size: 0.75em;
}
/*
* Textile Footnotes
*/
/* First footnote */
#fn1 {
border-top: 1px solid #000;
margin-top: 3em;
}
.footnote {
font-size: 0.9em;
}

73
js/plugins/reference_footnotes/dialogs/footnotes.js

@ -12,13 +12,13 @@
elements: elements:
[ [
{ {
id: 'reference', id: 'reference_footnote',
type: 'select', type: 'select',
items: [[" - None - ", 0]].concat(typeof(drupalSettings.bibcite_footnotes) !== 'undefined' ? drupalSettings.bibcite_footnotes.references : []), items: editor.config.referenceFootnotes_list,
label: Drupal.t('Reference Footnote item:'), label: Drupal.t('Reference Footnote item:'),
setup: function (element) { setup: function (element) {
if (isEdit) if (isEdit)
this.setValue(element.getAttribute('reference')); this.setValue(element.getText());
} }
}, },
{ {
@ -26,29 +26,8 @@
type: 'textarea', type: 'textarea',
label: Drupal.t('Or add free-form footnote text :'), label: Drupal.t('Or add free-form footnote text :'),
setup: function (element) { setup: function (element) {
if (isEdit) { if (isEdit)
var markup = element.getHtml(); this.setValue(element.getText());
this.setValue(markup);
}
}
},
{
id: 'html-help',
type: 'html',
html: 'HTML tags can be used, e.g., &lt;strong&gt;, &lt;em&gt;, &lt;a href=&quot;...&quot;&gt;',
},
{
id: 'page',
type: 'text',
labelLayout: 'horizontal',
label: Drupal.t('Page(s):'),
style: 'float:left:width:50px',
setup: function (element) {
if (isEdit) {
this.setValue(element.getAttribute('page'));
}
} }
}, },
{ {
@ -61,46 +40,22 @@
if (isEdit) if (isEdit)
this.setValue(element.getAttribute('value')); this.setValue(element.getAttribute('value'));
} }
}
},
{
id: 'value-help',
type: 'html',
html: 'Leave blank for an automatic sequential reference number, or enter a custom footnote value',
}
], ],
} }
], ],
onShow : function() { onShow : function() {
if (isEdit) { if (isEdit) {
this.fakeObj = CKEDITOR.plugins.reference_footnotes.getSelectedFootnote(editor); this.fakeObj = CKEDITOR.plugins.reference_footnotes.getSelectedFootnote( editor );
this.realObj = editor.restoreRealElement(this.fakeObj); this.realObj = editor.restoreRealElement( this.fakeObj );
} }
var select = this.parts.contents.$.getElementsByTagName('select'); this.setupContent( this.realObj );
var selectBox = select.item(0);
// Remove all but the default 'None' item from teh list.
var i;
for (i = selectBox.options.length - 1; i >= 1; i--) {
selectBox.remove(i)
}
// Re-add buttons from the current state of Settings.
if (typeof (drupalSettings.bibcite_footnotes) !== 'undefined') {
drupalSettings.bibcite_footnotes.references.forEach(function (reference) {
var newReference = document.createElement('option');
newReference.text = reference[0];
newReference.setAttribute("value", reference[1]);
selectBox.add(newReference);
});
}
this.setupContent( this.realObj );
}, },
onOk : function() { onOk : function() {
var referenceNote = this.getValueOf('info', 'reference'); var referenceNote = this.getValueOf('info', 'reference_footnote');
var textNote = this.getValueOf('info', 'footnote'); var textNote = this.getValueOf('info', 'footnote');
var page = this.getValueOf('info', 'page'); var value = textNote ? textNote : referenceNote;
CKEDITOR.plugins.reference_footnotes.createFootnote( editor, this.realObj, textNote, this.getValueOf('info', 'value'), referenceNote, page); CKEDITOR.plugins.reference_footnotes.createFootnote( editor, this.realObj, value, this.getValueOf('info', 'value'));
delete this.fakeObj; delete this.fakeObj;
delete this.realObj; delete this.realObj;
} }

24
js/plugins/reference_footnotes/plugin.js

@ -26,22 +26,8 @@
); );
}, },
beforeInit: function( editor )
{
// Adapt some critical editor configuration for better support
// of BBCode environment.
var config = editor.config;
CKEDITOR.tools.extend( config,
{
enterMode : CKEDITOR.ENTER_BR,
basicEntities: false,
entities : false,
fillEmptyBlocks : false
}, true );
},
init: function( editor ) init: function( editor )
{ {
editor.addCommand('createreferencefootnotes', new CKEDITOR.dialogCommand('createreferencefootnotes', { editor.addCommand('createreferencefootnotes', new CKEDITOR.dialogCommand('createreferencefootnotes', {
allowedContent: 'fn[value]' allowedContent: 'fn[value]'
})); }));
@ -108,7 +94,7 @@
})(); })();
CKEDITOR.plugins.reference_footnotes = { CKEDITOR.plugins.reference_footnotes = {
createFootnote: function( editor, origElement, text, value, reference, page) { createFootnote: function( editor, origElement, text, value) {
if (!origElement) { if (!origElement) {
var realElement = CKEDITOR.dom.element.createFromHtml('<fn></fn>'); var realElement = CKEDITOR.dom.element.createFromHtml('<fn></fn>');
} }
@ -117,15 +103,9 @@ CKEDITOR.plugins.reference_footnotes = {
} }
if (text && text.length > 0 ) { if (text && text.length > 0 ) {
realElement.setHtml(text); realElement.setText(text);
} }
realElement.setAttribute('value',value); realElement.setAttribute('value',value);
if (page && page.length > 0) {
realElement.setAttribute('page', page);
}
if (reference && reference.length > 0) {
realElement.setAttribute('reference', reference);
}
var fakeElement = editor.createFakeElement( realElement , 'cke_reference_footnote', 'hiddenfield', false ); var fakeElement = editor.createFakeElement( realElement , 'cke_reference_footnote', 'hiddenfield', false );
editor.insertElement(fakeElement); editor.insertElement(fakeElement);

28
js/replace_citations.js

@ -1,28 +0,0 @@
/**
* @file
* Provides JavaScript additions to entity embed dialog.
*
* This file provides popup windows for previewing embedded entities from the
* embed dialog.
*/
(function ($, Drupal) {
"use strict";
Drupal.behaviors.bibciteFootnotesReplaceCitations = {
attach: function attach(context, settings) {
/*
if (CKEDITOR.instances) {
for (var instance in CKEDITOR.instances) {
var editor = CKEDITOR.instances[instance];
var config = editor.config;
var name = editor.name;
editor.destroy();
CKEDITOR.replace(name, config);
}
}
*/
}
}
})(jQuery, Drupal);

24
src/CitationTools.php

@ -1,24 +0,0 @@
<?php
/**
* Created by PhpStorm.
* User: aoneill
* Date: 2018-10-30
* Time: 2:36 PM
*/
namespace Drupal\bibcite_footnotes;
class CitationTools {
public function getRenderableReference($reference_entity) {
if (is_numeric($reference_entity)) {
$reference_entity = \Drupal::entityTypeManager()
->getStorage('bibcite_reference')
->load($reference_entity);
}
$serializer = \Drupal::service('serializer');
$data = $serializer->normalize($reference_entity, 'csl');
return ['#theme' => 'bibcite_citation', '#data' => $data];
}
}

73
src/Plugin/BibCiteProcessor/CiteprocPhpInline.php

@ -1,73 +0,0 @@
<?php
namespace Drupal\bibcite_footnotes\Plugin\BibCiteProcessor;
use AcademicPuma\CiteProc\CiteProc;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\bibcite\Plugin\BibCiteProcessorBase;
use Drupal\bibcite\Plugin\BibCiteProcessorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines a style provider based on citeproc-php library.
*
* Extended to support inline citation links based on the CSL.
*
* @BibCiteProcessor(
* id = "citeproc-php",
* label = @Translation("Citeproc PHP"),
* )
*/
class CiteprocPhpInline extends BibCiteProcessorBase implements BibCiteProcessorInterface, ContainerFactoryPluginInterface {
/**
* Config factory service.
*
* @var \Drupal\Core\Config\ConfigFactoryInterface
*/
protected $configFactory;
/**
* {@inheritdoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static(
$configuration,
$plugin_id,
$plugin_definition,
$container->get('config.factory')
);
}
/**
* {@inheritdoc}
*/
public function __construct(array $configuration, $plugin_id, $plugin_definition, ConfigFactoryInterface $config_factory) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->configFactory = $config_factory;
}
/**
* {@inheritdoc}
*/
public function getDescription() {
return $this->t('Render citation by citeproc-php library');
}
/**
* {@inheritdoc}
*/
public function render($data, $csl, $lang) {
$cite_proc = new CiteProc($csl, $lang);
$mode = !empty($data['mode']) ? $data['mode'] : NULL;
if (!$data instanceof \stdClass) {
$data = json_decode(json_encode($data));
}
return $cite_proc->render($data, $mode);
}
}

28
src/Plugin/CKEditorPlugin/ReferenceFootnotes.php

@ -33,8 +33,7 @@ class ReferenceFootnotes extends CKEditorPluginBase {
return [ return [
'reference_footnotes' => [ 'reference_footnotes' => [
'label' => t('Reference Footnotes'), 'label' => t('Reference Footnotes'),
'image' => \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . 'image' => drupal_get_path('module', 'bibcite_footnotes') . '/js/plugins/reference_footnotes/images/icon.png',
'/js/plugins/reference_footnotes/images/icon.png',
], ],
]; ];
} }
@ -45,7 +44,7 @@ class ReferenceFootnotes extends CKEditorPluginBase {
public function getFile() { public function getFile() {
// Make sure that the path to the plugin.js matches the file structure of // Make sure that the path to the plugin.js matches the file structure of
// the CKEditor plugin you are implementing. // the CKEditor plugin you are implementing.
return \Drupal::service('extension.list.module')->getPath('bibcite_footnotes') . '/js/plugins/reference_footnotes/plugin.js'; return drupal_get_path('module', 'bibcite_footnotes') . '/js/plugins/reference_footnotes/plugin.js';
} }
/** /**
@ -73,6 +72,27 @@ class ReferenceFootnotes extends CKEditorPluginBase {
* {@inheritdoc} * {@inheritdoc}
*/ */
public function getConfig(Editor $editor) { public function getConfig(Editor $editor) {
return []; $uid = \Drupal::currentUser()->id();
$query = \Drupal::service('entity.query');
$ref_ids = $query
->get('bibcite_reference')
->condition('uid', $uid)
->execute();
$reference_storage = \Drupal::entityTypeManager()->getStorage('bibcite_reference')->loadMultiple($ref_ids);
$view_builder = \Drupal::entityTypeManager()->getViewBuilder('bibcite_reference');
$options = [];
foreach($reference_storage as $ref_id => $ref_item) {
$build = $view_builder->view($ref_item, 'citation');
$render = render($build);
$output = trim(strip_tags($render));
//$options[] = [$output, $ref_id];
$options[] = [$output, "[bibcite_reference:$ref_id]"];
}
return ['referenceFootnotes_list' => $options];
} }
} }

336
src/Plugin/Filter/ReferenceFootnotesFilter.php

@ -2,14 +2,11 @@
namespace Drupal\bibcite_footnotes\Plugin\Filter; namespace Drupal\bibcite_footnotes\Plugin\Filter;
use Drupal\Component\Utility\Xss; use Drupal\footnotes\Plugin\Filter\FootnotesFilter;
use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Form\FormStateInterface;
use Drupal\filter\FilterProcessResult;
use Drupal\filter\Plugin\FilterBase;
/** /**
* Reference Footnotes filter. * Provides a base filter for Reference Footnotes filter.
* *
* @Filter( * @Filter(
* id = "filter_reference_footnotes", * id = "filter_reference_footnotes",
@ -19,14 +16,14 @@ use Drupal\filter\Plugin\FilterBase;
* type = \Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE, * type = \Drupal\filter\Plugin\FilterInterface::TYPE_TRANSFORM_IRREVERSIBLE,
* cache = FALSE, * cache = FALSE,
* settings = { * settings = {
* "footnotes_footnotefootnote_linkcollapse" = FALSE, * "footnotes_collapse" = FALSE,
* "footnotes_ibid" = FALSE,
* "notes_section_label" = "Notes", * "notes_section_label" = "Notes",
* "references_section_label" = "References"
* }, * },
* weight = 0 * weight = 0
* ) * )
*/ */
class ReferenceFootnotesFilter extends FilterBase { class ReferenceFootnotesFilter extends FootnotesFilter {
/** /**
* Object with configuration for reference footnotes. * Object with configuration for reference footnotes.
@ -48,7 +45,6 @@ class ReferenceFootnotesFilter extends FilterBase {
public function __construct(array $configuration, $plugin_id, array $plugin_definition) { public function __construct(array $configuration, $plugin_id, array $plugin_definition) {
parent::__construct($configuration, $plugin_id, $plugin_definition); parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->renderer = \Drupal::service('renderer');
$this->config = \Drupal::config('reference_footnotes.settings'); $this->config = \Drupal::config('reference_footnotes.settings');
$this->configEditable = \Drupal::configFactory() $this->configEditable = \Drupal::configFactory()
->getEditable('reference_footnotes.settings'); ->getEditable('reference_footnotes.settings');
@ -69,333 +65,37 @@ class ReferenceFootnotesFilter extends FilterBase {
public function settingsForm(array $form, FormStateInterface $form_state) { public function settingsForm(array $form, FormStateInterface $form_state) {
$settings['footnotes_collapse'] = [ $settings['footnotes_collapse'] = [
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $this->t('Collapse reference footnotes with identical content'), '#title' => t('Collapse reference footnotes with identical content'),
'#default_value' => $this->settings['footnotes_collapse'], '#default_value' => $this->settings['footnotes_collapse'],
'#description' => t('If two reference footnotes have the exact same content, they will be collapsed into one as if using the same value="" attribute.'), '#description' => t('If two reference footnotes have the exact same content, they will be collapsed into one as if using the same value="" attribute.'),
]; ];
$settings['footnotes_ibid'] = [
'#type' => 'checkbox',
'#title' => $this->t('Display subsequent instances of multiple references with \'Ibid.\''),
'#default_value' => $this->settings['footnotes_ibid'],
];
$settings['notes_section_label'] = [ $settings['notes_section_label'] = [
'#type' => 'textfield', '#type' => 'textfield',
'#title' => t('Notes section heading label'), '#title' => t('Notes section label'),
'#default_value' => $this->settings['notes_section_label'], '#default_value' => $this->settings['notes_section_label'],
]; ];
$settings['references_section_label'] = [
'#type' => 'textfield',
'#title' => $this->t('References section label'),
'#description' => $this->t('E.g., "Works Cited" for MLA style.'),
'#default_value' => $this->settings['references_section_label'],
];
$settings['reference_dont_show_backlink_text'] = [ $settings['reference_dont_show_backlink_text'] = [
'#type' => 'checkbox', '#type' => 'checkbox',
'#title' => $this->t("Don't show note 'value' text in reference list."), '#title' => $this->t("Don't show note 'value' text in reference list."),
'#description' => $this->t("Suitable for MLA-style citations, like (Smith, 33-22)"), '#description' => $this->t("Suitable for MLA-style citations, like (Smith, 33-22)"),
'#default_value' => $this->settings['reference_dont_show_backlink_text'], '#default_value' => $this->settings['reference_dont_show_backlink_text'],
]; ];
$settings['works_cited_sort_by'] = [ $settings['reference_sort_by'] = [
'#type' => 'select', '#type' => 'select',
'#title' => $this->t("Sort Workd Cited list by"), '#title' => $this->t("Sort references list by"),
'#options' => [ '#options' => [
'weight' => $this->t("Manually"), 'order' => $this->t("Order in text"),
'alphabetical' => $this->t("Alphabetically"), 'alphabetical' => $this->t("Alphabetical"),
], ],
'#default_value' => $this->settings['works_cited_sort_by'], '#default_value' => $this->settings['reference_sort_by'],
]; ];
return $settings; return $settings;
} }
/**
* Helper function called from preg_replace_callback() above.
*
* Uses static vars to temporarily store footnotes found.
* This is not threadsafe, but PHP isn't.
*
* @param array $matches
* Elements from array:
* - 0: complete matched string.
* - 1: tag name.
* - 2: tag attributes.
* - 3: tag content.
* @param string $op
* Operation.
*
* @return string
* Return the string processed by geshi library.
*/
protected function replaceCallback($matches, $op = '') {
static $opt_collapse = 0;
static $n = 0;
static $store_matches = [];
static $used_values = [];
$str = '';
if ($op == 'prepare') {
// In the 'prepare' case, the first argument contains the options to use.
// The name 'matches' is incorrect, we just use the variable anyway.
$opt_collapse = isset($matches['footnotes_collapse']) && $matches['footnotes_collapse'];
return 0;
}
if ($op == 'output footer') {
if (count($store_matches) > 0) {
// Separate out endontes and reference notes.
if ($this->settings['footnotes_ibid']) {
$this->ibidemify($references);
}
// Only if there are stored fn matches, pass the array of fns to be
// themed as a list
$markup = [
'#theme' => 'bibcite_footnote_list',
'#notes' => $store_matches,
'#config' => $this->settings,
];
$str = \Drupal::service('renderer')->render($markup, FALSE);
}
// Reset the static variables so they can be used again next time.
$n = 0;
$store_matches = [];
$used_values = [];
return $str;
}
// Default op: act as called by preg_replace_callback()
// Random string used to ensure footnote id's are unique, even
// when contents of multiple nodes reside on same page.
// (fixes http://drupal.org/node/194558).
$randstr = $this->randstr();
$value = $this->extractAttribute($matches, 'value');
$page = $this->extractAttribute($matches, 'page');
$reference = $this->extractAttribute($matches, 'reference');
if ($value) {
// A value label was found. If it is numeric, record it in $n so further
// notes can increment from there.
// After adding support for multiple references to same footnote in the
// body (http://drupal.org/node/636808) also must check that $n is
// monotonously increasing.
if (is_numeric($value) && $n < $value) {
$n = $value;
}
}
elseif ($opt_collapse and $value_existing = $this->findFootnote($matches[2], $reference, $store_matches)) {
// An identical footnote already exists. Set value to the previously
// existing value.
$value = $value_existing;
}
else {
// No value label, either a plain <fn> or unparsable attributes. Increment
// the footnote counter, set label equal to it.
$n++;
$value = $n;
}
// Remove illegal characters from $value so it can be used as an HTML id
// attribute.
$value_id = preg_replace('|[^\w\-]|', '', $value);
// Create a sanitized version of $text that is suitable for using as HTML
// attribute value. (In particular, as the title attribute to the footnote
// link).
$allowed_tags = [];
$text_clean = Xss::filter($matches['2'], $allowed_tags);
// HTML attribute cannot contain quotes.
$text_clean = str_replace('"', "&quot;", $text_clean);
// Remove newlines. Browsers don't support them anyway and they'll confuse
// line break converter in filter.module.
$text_clean = str_replace("\n", " ", $text_clean);
$text_clean = str_replace("\r", "", $text_clean);
// Create a footnote item as an array.
$fn = [
'value' => $value,
'text' => $matches[2],
'text_clean' => $text_clean,
'page' => $page,
'reference' => $reference,
'fn_id' => 'footnote' . $value_id . '_' . $randstr,
'ref_id' => 'footnoteref' . $value_id . '_' . $randstr,
];
// We now allow to repeat the footnote value label, in which case the link
// to the previously existing footnote is returned. Content of the current
// footnote is ignored. See http://drupal.org/node/636808 .
if (!in_array($value, $used_values)) {
// This is the normal case, add the footnote to $store_matches.
// Store the footnote item.
array_push($store_matches, $fn);
array_push($used_values, $value);
}
else {
// A footnote with the same label already exists.
// Use the text and id from the first footnote with this value.
// Any text in this footnote is discarded.
$i = array_search($value, $used_values);
$fn['text'] = $store_matches[$i]['text'];
$fn['text_clean'] = $store_matches[$i]['text_clean'];
$fn['fn_id'] = $store_matches[$i]['fn_id'];
// Push the new ref_id into the first occurrence of this footnote label
// The stored footnote thus holds a list of ref_id's rather than just one
// id.
$ref_array = is_array($store_matches[$i]['ref_id']) ? $store_matches[$i]['ref_id'] : [$store_matches[$i]['ref_id']];
array_push($ref_array, $fn['ref_id']);
$store_matches[$i]['ref_id'] = $ref_array;
}
// Return the item themed into a footnote link.
// Drupal 7 requires we use "render element" which just introduces a wrapper
// around the old array.
$fn = [
'#theme' => 'bibcite_footnote_link',
'fn' => $fn,
];
$result = \Drupal::service('renderer')->render($fn, FALSE);
return $result;
}
/**
* @inheritdoc
*/
private function findFootnote($text, $reference, &$store_matches) {
if (!empty($store_matches)) {
foreach ($store_matches as &$fn) {
if ($fn['text'] == $text && $fn['reference'] == $reference) {
return $fn['value'];
}
}
}
return FALSE;
}
/**
* @param $matches
* @param $value_match
*
* @return string
*/
protected function extractAttribute($matches, $attribute): string {
$value = '';
// Did the pattern match anything in the <fn> tag?
if ($matches[1]) {
// See if value attribute can parsed, either well-formed in quotes eg
// <fn value="3">.
if (preg_match('|' . $attribute . '=["\'](.*?)["\']|', $matches[1], $value_match)) {
$value = $value_match[1];
// Or without quotes eg <fn value=8>.
}
elseif (preg_match('|' . $attribute . '=(\S*)|', $matches[1], $value_match)) {
$value = $value_match[1];
}
}
return $value;
}
/**
* Determine references that are the same as one above it
* to be replaced with the string 'Ibid'.
*
* @param array $footnotes
*/
protected function ibidemify(&$footnotes) {
$prev_reference_id = FALSE;
foreach ($footnotes as $index => $fn) {
if ($prev_reference_id) {
if ($fn['reference'] == $prev_reference_id) {
$footnotes[$index]['ibid'] = TRUE;
continue;
}
}
$prev_reference_id = $fn['reference'];
}
}
/**
* {@inheritdoc}
*/
public function process($text, $langcode) {
// Supporting both [fn] and <fn> now. Thanks to fletchgqc
// http://drupal.org/node/268026.
// Convert all square brackets to angle brackets. This way all further code
// just manipulates angle brackets. (Angle brackets are preferred here for
// the simple reason that square brackets are more tedious to use in
// regexps).
if (is_array($text)) {
implode($text);
}
$text = preg_replace('|\[fn([^\]]*)\]|', '<fn$1>', $text);
$text = preg_replace('|\[/fn\]|', '</fn>', $text);
$text = preg_replace('|\[footnotes([^\]]*)\]|', '<footnotes$1>', $text);
// Check that there are an even number of open and closing tags.
// If there is one closing tag missing, append this to the end.
// If there is more disparity, throw a warning and continue.
// A closing tag may sometimes be missing when we are processing a teaser
// and it has been cut in the middle of the footnote.
// See http://drupal.org/node/253326
$foo = [];
$open_tags = preg_match_all("|<fn([^>]*)>|", $text, $foo);
$close_tags = preg_match_all("|</fn>|", $text, $foo);
if ($open_tags == $close_tags + 1) {
$text = $text . '</fn>';
}
elseif ($open_tags > $close_tags + 1) {
trigger_error($this->t("You have unclosed fn tags. This is invalid and will
produce unpredictable results."));
}
// Before doing the replacement, the callback function needs to know which
// options to use.
$this->replaceCallback($this->settings, 'prepare');
$pattern = '|<fn([^>]*)>(.*?)</fn>|s';
$text = preg_replace_callback($pattern, [
$this,
'replaceCallback',
], $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 = $this->replaceCallback(NULL, 'output footer');
$pattern = '|(<footnotes([^\]]*)>)|';
if (preg_match($pattern, $text) > 0) {
$text = preg_replace($pattern, $footer, $text, 1);
}
elseif (!empty($footer)) {
$text .= "\n\n" . $footer;
}
$result = new FilterProcessResult($text);
$result->setAttachments([
'library' => [
'footnotes/footnotes',
],
]);
return $result;
}
/**
* Helper function to return a random text string.
*
* @return string
* Random (lowercase) alphanumeric string.
*/
public function randstr() {
$chars = "abcdefghijklmnopqrstuwxyz1234567890";
$str = "";
// Seeding with srand() not necessary in modern PHP versions.
for ($i = 0; $i < 7; $i++) {
$n = rand(0, strlen($chars) - 1);
$str .= substr($chars, $n, 1);
}
return $str;
}
} }

0
templates/bibcite-footnote-link.html.twig → templates/footnote-link.html.twig

0
templates/bibcite-footnote-list.html.twig → templates/footnote-list.html.twig

Loading…
Cancel
Save