diff --git a/config/install/disqus.settings.yml b/config/install/disqus.settings.yml index e298599..ebd01e8 100644 --- a/config/install/disqus.settings.yml +++ b/config/install/disqus.settings.yml @@ -14,3 +14,7 @@ advanced: disqus_sso: false disqus_use_site_logo: false disqus_logo: '' + lazy_loading: + status: 0 + method: 'scroll' + class: disqus-lazy-load diff --git a/disqus.module b/disqus.module index b025827..e9671a1 100644 --- a/disqus.module +++ b/disqus.module @@ -241,7 +241,31 @@ function disqus_field_views_data(FieldStorageConfigInterface $field_storage) { * Implements hook_theme(). */ function disqus_theme() { + // Grab domain to append to noscript. $domain = \Drupal::config('disqus.settings')->get('disqus_domain'); + + // Grab current node so we can get disqus field. + $node = \Drupal::routeMatch()->getParameter('node'); + // Make sure we loaded a node. + // @TODO: Check for other entity types - not just Node. + $data_disqus_identifier = ''; + if ($node instanceof NodeInterface) { + $data_disqus_identifier = 'node/' . $node->id(); + $node_fields = $node->getFields(); + + // Loop through and see if we have a Disqus field override. + foreach ($node_fields as $key => $value) { + /** @var \Drupal\Core\Field\FieldItemList $value */ + $field_definition = $value->getFieldDefinition()->getType(); + if ($field_definition === 'disqus_comment') { + if (!$value->isEmpty()) { + $data_disqus_identifier = $value->getValue(); + break; + } + } + } + } + return [ 'disqus_noscript' => [ 'variables' => [ @@ -249,6 +273,12 @@ function disqus_theme() { 'url' => "http://$domain.disqus.com/", ], ], + 'disqus_lazy_load' => [ + 'variables' => [ + 'data_disqus_identifier' => $data_disqus_identifier, + 'children' => NULL, + ], + ], ]; } @@ -271,3 +301,38 @@ function disqus_api() { } return $disqus; } + +/** + * {@inheritdoc} + */ +function disqus_preprocess_html(&$variables) { + $load_count_js = Drupal::config('disqus.settings')->get('advanced.lazy_loading.comment_count.load_comment_count_js'); + if ($load_count_js) { + $variables['page']['#attached']['library'][] = 'disqus/comment_count'; + } +} + +/** + * {@inheritdoc} + */ +function disqus_library_info_build() { + $domain = Drupal::config('disqus.settings')->get('disqus_domain'); + $libraries = []; + $libraries['comment_count'] = [ + 'version' => '1.0', + 'js' => [ + 'https://' . $domain . '.disqus.com/count.js' => [ + 'type' => 'external', + 'attributes' => [ + 'async' => TRUE, + 'id' => 'dsq-count-scr', + ] + ], + ], + 'dependencies' => [ + 'disqus/disqus', + ], + ]; + + return $libraries; +} diff --git a/js/disqus.js b/js/disqus.js index 551a92e..0d7dd0a 100644 --- a/js/disqus.js +++ b/js/disqus.js @@ -16,7 +16,27 @@ var disqus_config; "use strict"; -Drupal.disqus = {}; +/** + * JS load helper functions. + */ +Drupal.disqus = { + loadCommentScript: function (shortname) { + // Make the AJAX call to get the Disqus comments. + this.loadScript(shortname, 'embed.js') + }, + loadCountScript: function (shortname) { + // Make the AJAX call to get the number of comments. + this.loadScript(shortname, 'count.js'); + }, + loadScript: function (shortname, scriptName) { + $.ajax({ + type: 'GET', + url: '//' + shortname + '.disqus.com/' + scriptName, + dataType: 'script', + cache: false + }); + } +}; /** * Drupal Disqus behavior. @@ -68,12 +88,29 @@ Drupal.behaviors.disqus = { }; // Make the AJAX call to get the Disqus comments. - jQuery.ajax({ - type: 'GET', - url: '//' + disqus_shortname + '.disqus.com/embed.js', - dataType: 'script', - cache: false - }); + if (settings.disqus.lazyLoadMethod || '') { + switch (settings.disqus.lazyLoadMethod) { + case 'click': + $('.' + (settings.disqus.lazyLoadClass || '')) + .css('cursor', 'pointer') + .bind('click', function (event) { + $(event.currentTarget).remove(); + Drupal.disqus.loadCommentScript(disqus_shortname); + }); + break; + case 'scroll': + $(window).scroll(function scrollHandler(event) { + if ($(window).scrollTop() + $(window).height() > $('#disqus_thread').offset().top) { + Drupal.disqus.loadCommentScript(disqus_shortname); + $(window).unbind('scroll', scrollHandler); + } + }); + break; + } + } + else { + Drupal.disqus.loadCommentScript(disqus_shortname); + } }); } @@ -81,14 +118,7 @@ Drupal.behaviors.disqus = { if (settings.disqusComments || false) { // Ensure that comment numbers JavaScript is only loaded once. $('body').once('disqusComments').each(function () { - disqus_shortname = settings.disqusComments; - // Make the AJAX call to get the number of comments. - jQuery.ajax({ - type: 'GET', - url: '//' + disqus_shortname + '.disqus.com/count.js', - dataType: 'script', - cache: false - }); + Drupal.disqus.loadCountScript(settings.disqusComments); }); } } diff --git a/src/DisqusCommentManager.php b/src/DisqusCommentManager.php index 28d9582..f95f30b 100644 --- a/src/DisqusCommentManager.php +++ b/src/DisqusCommentManager.php @@ -2,6 +2,7 @@ namespace Drupal\disqus; +use Drupal\Component\Utility\Html; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Config\ConfigFactory; use Drupal\Core\Entity\EntityFieldManagerInterface; @@ -15,6 +16,16 @@ use Drupal\Core\Url; */ class DisqusCommentManager implements DisqusCommentManagerInterface { + /** + * Lazy load the Disqus script when the Disqus comment block becomes visible. + */ + const DISQUS_LAZY_LOAD_ON_SCROLL = 'scroll'; + + /** + * Lazy load the Disqus script when an element is clicked. + */ + const DISQUS_LAZY_LOAD_ON_CLICK = 'click'; + /** * The current user. * @@ -197,4 +208,25 @@ class DisqusCommentManager implements DisqusCommentManagerInterface { return $data; } + /** + * Assembles data about lazy loading. + * + * @return array + */ + public function lazy_load_settings() { + $data = array(); + + switch (\Drupal::config('disqus.settings')->get('advanced.lazy_loading.method')) { + case DisqusCommentManager::DISQUS_LAZY_LOAD_ON_SCROLL: + $data['lazyLoadMethod'] = 'scroll'; + break; + case DisqusCommentManager::DISQUS_LAZY_LOAD_ON_CLICK: + $data['lazyLoadClass'] = HTML::escape(\Drupal::config('disqus.settings')->get('advanced.lazy_loading.class')); + $data['lazyLoadMethod'] = 'click'; + break; + } + + return $data; + } + } diff --git a/src/Element/Disqus.php b/src/Element/Disqus.php index 7a302b5..4decff7 100644 --- a/src/Element/Disqus.php +++ b/src/Element/Disqus.php @@ -63,7 +63,7 @@ class Disqus extends RenderElement { /** @var \Drupal\Core\Render\RendererInterface $renderer */ $renderer = \Drupal::service('renderer'); $element = [ - '#theme_wrappers' => ['disqus_noscript', 'container'], + '#theme_wrappers' => ['disqus_noscript', 'disqus_lazy_load', 'container'], '#attributes' => ['id' => 'disqus_thread'], ]; $renderer->addCacheableDependency($element, $disqus_settings); @@ -113,6 +113,10 @@ class Disqus extends RenderElement { if (!empty($callbacks)) { $disqus['callbacks'] = $callbacks; } + // Lazy loading configuration. + if (\Drupal::config('disqus.settings')->get('advanced.lazy_loading.status')) { + $disqus += \Drupal::service('disqus.manager')->lazy_load_settings(); + } // Check if we want to track new comments in Google Analytics. if ($disqus_settings->get('behavior.disqus_track_newcomment_ga')) { // Add a callback when a new comment is posted. diff --git a/src/Form/DisqusSettingsForm.php b/src/Form/DisqusSettingsForm.php index acdc35f..8f0a5bf 100644 --- a/src/Form/DisqusSettingsForm.php +++ b/src/Form/DisqusSettingsForm.php @@ -258,6 +258,64 @@ class DisqusSettingsForm extends ConfigFormBase { ], ]; + $form['advanced']['lazy_loading'] = [ + '#weight' => 6, + '#type' => 'fieldset', + '#title' => t('Lazy Loading'), + '#collapsible' => FALSE, + '#collapsed' => FALSE, + ]; + + $form['advanced']['lazy_loading']['disqus_lazy_load'] = [ + '#type' => 'checkbox', + '#title' => t('Use Lazy Loading'), + '#description' => t('Prevent the Disqus script from loading until triggered by user activity.'), + '#default_value' => $disqus_config->get('advanced.lazy_loading.status'), + ]; + + $form['advanced']['lazy_loading']['disqus_lazy_load_method'] = [ + '#type' => 'select', + '#title' => t('Lazy Loading Trigger'), + '#description' => t('The type of user activity used to determine when the Disqus script is loaded.'), + '#default_value' => $disqus_config->get('advanced.lazy_loading.method'), + '#options' => [ + DisqusCommentManager::DISQUS_LAZY_LOAD_ON_SCROLL => t('When the Disqus block scrolls into view'), + DisqusCommentManager::DISQUS_LAZY_LOAD_ON_CLICK => t('When the user clicks on an HTML element'), + ], + '#states' => [ + 'visible' => [ + 'input[name="disqus_lazy_load"]' => ['checked' => TRUE], + ], + ], + ]; + + $form['advanced']['lazy_loading']['disqus_lazy_load_class'] = [ + '#type' => 'textfield', + '#title' => t('Triggering Class'), + '#description' => t('The HTML class of the elements that trigger the lazy loading.'), + '#default_value' => $disqus_config->get('advanced.lazy_loading.class'), + '#states' => [ + 'visible' => [ + 'select[name="disqus_lazy_load_method"]' => ['value' => DisqusCommentManager::DISQUS_LAZY_LOAD_ON_CLICK], + ], + ], + ]; + + $form['advanced']['lazy_loading']['comment_count'] = [ + '#weight' => 6, + '#type' => 'fieldset', + '#title' => t('Load Comment Count JS'), + '#collapsible' => FALSE, + '#collapsed' => FALSE, + ]; + + $form['advanced']['lazy_loading']['comment_count']['disqus_count_js'] = [ + '#type' => 'checkbox', + '#title' => t('Load comment count javascript.'), + '#description' => t('This will load up the comment count javascript from Disqus.'), + '#default_value' => $disqus_config->get('advanced.lazy_loading.comment_count.load_comment_count_js'), + ]; + return parent::buildForm($form, $form_state); } @@ -276,6 +334,10 @@ class DisqusSettingsForm extends ConfigFormBase { ->set('advanced.disqus_secretkey', $form_state->getValue('disqus_secretkey')) ->set('advanced.sso.disqus_sso', $form_state->getValue('disqus_sso')) ->set('advanced.sso.disqus_use_site_logo', $form_state->getValue('disqus_use_site_logo')) + ->set('advanced.lazy_loading.status', $form_state->getValue('disqus_lazy_load')) + ->set('advanced.lazy_loading.method', $form_state->getValue('disqus_lazy_load_method')) + ->set('advanced.lazy_loading.class', $form_state->getValue('disqus_lazy_load_class')) + ->set('advanced.lazy_loading.comment_count.load_comment_count_js', $form_state->getValue('disqus_count_js')) ->save(); if ($form_state->hasValue('disqus_api_update')) {