From fdde2b0cd2e9c8eda2a454523dd1d1d878fe96c3 Mon Sep 17 00:00:00 2001 From: Alexander O'Neill Date: Fri, 30 Nov 2018 06:42:04 -0400 Subject: [PATCH] Add Entity Reference and Inline Entity Form support. --- README.md | 32 +++++- bibcite_footnotes.info.yml | 1 + bibcite_footnotes.libraries.yml | 10 ++ bibcite_footnotes.module | 106 ++++++++++++++++++ .../reference_footnotes/dialogs/footnotes.js | 18 ++- js/replace_citations.js | 28 +++++ .../CKEditorPlugin/ReferenceFootnotes.php | 23 +--- .../Filter/ReferenceFootnotesFilter.php | 10 +- 8 files changed, 195 insertions(+), 33 deletions(-) create mode 100644 js/replace_citations.js diff --git a/README.md b/README.md index c195b82..ed513be 100644 --- a/README.md +++ b/README.md @@ -12,12 +12,9 @@ Contents 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 -appear in a formatted at the bottom of the text area that contains the footnote. +appear in a formatted list at the bottom of the text area that contains endnotes +and references. Installation ------------ @@ -34,6 +31,13 @@ you will need to add the following HTML tags for the reference footnotes to disp Configuration ------------- +Add a field to a node type that is an Entity Reference field pointing to +Bibcite Reference entities. + +Go to Admin -> Configuration -> Content Authoring -> Text Formats and Editors. + +Edit a Rich text format that will include reference footnotes. + 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. @@ -41,7 +45,25 @@ You will then need to create or import one or more references using the Bibliogr Citations project. Those will then appear in a select list when you are editing a text area and click on the Reference Footnote button. +Optionally you can install Inline Entity Form which allowes a user to +create new references directly in the node edit form. + +Adding References to Content +---------------------------- + +If not using the inline entity form, select the references that appear in the +list of referenced Bibcite reference types that should be available to the editor, +ten save the node. + +When you edit the node again, and you click on the Reference Footnote button, +a list of citaitons will be available to choose from. + Current Maintainers ------------------- * Alexander O'Neill (https://www.drupal.org/u/alxp) + +Sponsors +-------- + + * This work is supported by the [University of Prince Edward Island Robertson Librrary](https://library.upei.ca). diff --git a/bibcite_footnotes.info.yml b/bibcite_footnotes.info.yml index a8880af..e8e089a 100644 --- a/bibcite_footnotes.info.yml +++ b/bibcite_footnotes.info.yml @@ -6,4 +6,5 @@ package: 'Bibliography & Citation' dependencies: - bibcite:bibcite - bibcite:bibcite_entity + - core:entity_reference - footnotes:footnotes diff --git a/bibcite_footnotes.libraries.yml b/bibcite_footnotes.libraries.yml index 66a8c36..a14bf7c 100644 --- a/bibcite_footnotes.libraries.yml +++ b/bibcite_footnotes.libraries.yml @@ -3,3 +3,13 @@ reference_footnote: css: theme: css/reference_footnote.css: {} + dependencies: + - core/jquery + - core/drupalSettings +replace_citations: + version: VERSION + js: + js/replace_citations.js: {} + dependencies: + - core/jquery + - core/drupalSettings \ No newline at end of file diff --git a/bibcite_footnotes.module b/bibcite_footnotes.module index 180dc63..07d76b0 100644 --- a/bibcite_footnotes.module +++ b/bibcite_footnotes.module @@ -5,12 +5,14 @@ * Contains bibcite_footnotes.module. */ +use Drupal\Core\Field\EntityReferenceFieldItemListInterface; use Drupal\Core\Form\FormStateInterface; use Drupal\Core\Routing\RouteMatchInterface; use Drupal\Core\Url; use Drupal\Core\Link; use Drupal\bibcite_footnotes\CitationTools; use Drupal\bibcite_footnotes\Plugin\Filter\ReferenceFootnotesFilter; +use Drupal\field\Entity\FieldConfig; /** * Implements hook_theme(). @@ -207,3 +209,107 @@ function bibcite_footnotes_preprocess_bibcite_footnote_link(&$variables) { $variables['fn']['fn'] = $link; // $variables['fn']['fn'][] = $link; } + +/** + * Implementation of hook_inline_entity_form_entity_form_alter(). + * + * 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 + */ + $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 { + $serializer = \Drupal::service('serializer'); + + $data = $serializer->normalize($entity, 'csl'); + $build = ['#theme' => 'bibcite_citation', '#data' => $data]; + $citation_text = trim(strip_tags(render($build))); + // Attempt to match up pre-saved entities with the eventual saved ones. + $citation_key = $entity->id->first()->getValue()['value']; + return [$citation_text, $citation_key]; +} diff --git a/js/plugins/reference_footnotes/dialogs/footnotes.js b/js/plugins/reference_footnotes/dialogs/footnotes.js index 4723972..dd91a43 100644 --- a/js/plugins/reference_footnotes/dialogs/footnotes.js +++ b/js/plugins/reference_footnotes/dialogs/footnotes.js @@ -14,7 +14,7 @@ { id: 'reference', type: 'select', - items: editor.config.referenceFootnotes_list, + items: [[" - None - ", 0]].concat(drupalSettings.bibcite_footnotes.references), label: Drupal.t('Reference Footnote item:'), setup: function (element) { if (isEdit) @@ -65,6 +65,22 @@ this.fakeObj = CKEDITOR.plugins.reference_footnotes.getSelectedFootnote( editor ); this.realObj = editor.restoreRealElement( this.fakeObj ); } + var select = this.parts.contents.$.getElementsByTagName('select'); + 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. + 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() { diff --git a/js/replace_citations.js b/js/replace_citations.js new file mode 100644 index 0000000..a519f0e --- /dev/null +++ b/js/replace_citations.js @@ -0,0 +1,28 @@ +/** + * @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); diff --git a/src/Plugin/CKEditorPlugin/ReferenceFootnotes.php b/src/Plugin/CKEditorPlugin/ReferenceFootnotes.php index 2b94cc5..069bc9d 100644 --- a/src/Plugin/CKEditorPlugin/ReferenceFootnotes.php +++ b/src/Plugin/CKEditorPlugin/ReferenceFootnotes.php @@ -72,27 +72,6 @@ class ReferenceFootnotes extends CKEditorPluginBase { * {@inheritdoc} */ public function getConfig(Editor $editor) { - $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, $ref_id]; - } - - return ['referenceFootnotes_list' => $options]; + return []; } - } diff --git a/src/Plugin/Filter/ReferenceFootnotesFilter.php b/src/Plugin/Filter/ReferenceFootnotesFilter.php index 032d386..47f1890 100644 --- a/src/Plugin/Filter/ReferenceFootnotesFilter.php +++ b/src/Plugin/Filter/ReferenceFootnotesFilter.php @@ -184,6 +184,8 @@ class ReferenceFootnotesFilter extends FootnotesFilter { $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 @@ -195,7 +197,7 @@ class ReferenceFootnotesFilter extends FootnotesFilter { $n = $value; } } - elseif ($opt_collapse and $value_existing = $this->findFootnote($matches[2], $store_matches)) { + 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; @@ -211,8 +213,6 @@ class ReferenceFootnotesFilter extends FootnotesFilter { // attribute. $value_id = preg_replace('|[^\w\-]|', '', $value); - $page = $this->extractAttribute($matches, 'page'); - $reference = $this->extractAttribute($matches, 'reference'); // Create a sanitized version of $text that is suitable for using as HTML // attribute value. (In particular, as the title attribute to the footnote @@ -279,10 +279,10 @@ class ReferenceFootnotesFilter extends FootnotesFilter { /** * @inheritdoc */ - private function findFootnote($text, &$store_matches) { + private function findFootnote($text, $reference, &$store_matches) { if (!empty($store_matches)) { foreach ($store_matches as &$fn) { - if ($fn['text'] == $text) { + if ($fn['text'] == $text && $fn['reference'] == $reference) { return $fn['value']; } }