Commit 13e0fc74 authored by jrb's avatar jrb Committed by Sam152

Issue #1121530 by jrb, Sam152: Make the ajax loading more lightweight with menu callback

parent dca76871
div#views_infinite_scroll-ajax-loader {
text-align: center;
}
<?php
/**
* @file
* drush integration for views_infinite_scroll.
*/
/**
* Implements hook_drush_command().
*
* In this hook, you specify which commands your
* drush module makes available, what it does and
* description.
*
* Notice how this structure closely resembles how
* you define menu hooks.
*
* @See drush_parse_command() for a list of recognized keys.
*
* @return
* An associative array describing your command(s).
*/
function views_infinite_scroll_drush_command() {
$items = array();
$items['dl-autopager'] = array(
'callback' => 'views_infinite_scroll_drush_autopager_download',
'description' => dt('Downloads the required autopager jquery plugin.'),
);
return $items;
}
/**
* Implements hook_drush_help().
*
* This function is called whenever a drush user calls
* 'drush help <name-of-your-command>'
*
* @param
* A string with the help section (prepend with 'drush:')
*
* @return
* A string with the help text for your command.
*/
function views_infinite_scroll_drush_help($section) {
switch ($section) {
case 'drush:dl-autopager':
return dt("Downloads the required autopager jquery plugin.");
}
}
/**
* Example drush command callback.
*
* This is where the action takes place.
*
* In this function, all of Drupals API is (usually) available, including
* any functions you have added in your own modules/themes.
*
* To print something to the terminal window, use drush_print().
*
*/
function views_infinite_scroll_drush_autopager_download() {
if (module_exists('libraries')) {
$path = 'sites/all/libraries/autopager';
// Create the path if it does not exist.
if (!is_dir($path)) {
drush_op('mkdir', $path);
drush_log(dt('Directory @path was created', array('@path' => $path)), 'notice');
}
}
else {
$path = drupal_get_path('module', 'views_infinite_scroll') . '/js';
}
drush_op('chdir', $path);
// Download the plugin.
if (drush_shell_exec('wget http://jquery-autopager.googlecode.com/files/jquery.autopager-1.0.0.js')) {
drush_log(dt('jquery.autopager-1.0.0.js has been downloaded to @path', array('@path' => $path)), 'success');
}
else {
drush_log(dt('Drush was unable to download jquery.autopager-1.0.0.js to @path', array('@path' => $path)), 'error');
}
}
(function ($) {
/**
* Attach infinite scroll to the relevant views.
*/
Drupal.behaviors.views_infinite_scroll = {
attach: function (context, settings) {
// Make sure that autopager plugin is loaded.
if (!$.autopager) {
alert(Drupal.t('Autopager jQuery plugin is not loaded.'));
return;
}
var settings = settings.views_infinite_scroll[0];
// Ensure we are refreshing the view component.
var view_selector = 'div.view-id-' + settings.view_name + '.view-display-id-' + settings.display;
var $view = $(context).is(view_selector) ? $(context) : $(context).find(view_selector);
if ($view.length == 0) {
return;
}
// Destroy an existing instance of autopager.
$.autopager('destroy');
var content_selector = view_selector + ' > ' + settings.content_selector;
var $items = $view.find(settings.items_selector);
var $pager = $view.find('> div.item-list ' + settings.pager_selector);
var next_selector = view_selector + ' ' + settings.next_selector;
var $next = $(next_selector);
var $img_location = $view.find('div.view-content');
var img_path = settings.img_path;
var img = '<div id="views_infinite_scroll-ajax-loader"><img src="' + img_path + '" alt="loading..."/></div>';
$($pager).hide();
$.autopager({
appendTo: content_selector,
content: content_selector + ' ' + settings.items_selector,
link: next_selector,
page: 0,
autoLoad: !settings.manual_load,
start: function () {
$img_location.after(img);
},
load: function (current, next) {
$('div#views_infinite_scroll-ajax-loader').remove();
Drupal.attachBehaviors(this);
// Use >= because of views page numbers begin at 0.
if (settings.manual_load && next.page >= settings.pager_max) {
$next.hide();
}
}
});
if (settings.manual_load) {
// The pager is hidden. Pop "next" link out so it will be visible.
$next.text(settings.text);
$next.click(function (e) {
e.preventDefault();
// do load
$.autopager('load');
});
$($pager).before($next);
// Wrap the button to allow for easier styling in the theme
$next.wrap('<div id="views_infinite_scroll_button" />');
}
else {
$($pager).hide();
// Trigger autoload if content height is less than doc height already
var prev_content_height = $(content_selector).height();
do {
var last = $($items).filter(':last');
if (last.offset().top + last.height() < $(document).scrollTop() + $(window).height()) {
last = $($items).filter(':last');
$.autopager('load');
}
else {
break;
}
}
while ($(content_selector).height() > prev_content_height);
}
}
};
})(jQuery);
<?php
/**
* @file
* Theme infinite scroll page
*/
function theme_views_infinite_scroll_pager($variables) {
$tags = $variables['tags'];
$limit = isset($variables['limit']) ? $variables['limit'] : 10;
$view_name = $variables['view_name'];
$element = isset($variables['element']) ? $variables['element'] : 0;
$current_display = $variables['current_display'];
$content_selector = isset($variables['content_selector']) ? $variables['content_selector'] : 'div.view-content';
$items_selector = isset($variables['items_selector']) ? $variables['items_selector'] : 'div.view-content .views-row';
$img_path = $variables['img_path'];
$manual_load = isset($variables['manual_load']) ? $variables['manual_load'] : FALSE;
$text = isset($variables['text']) ? $variables['text'] : array('default' => 'Show More', 'translatable' => TRUE);
$parameters = $variables['parameters'];
$quantity = $variables['quantity'];
$PAGER_CLASS = 'pager';
global $pager_page_array, $pager_total;
// Calculate various markers within this pager piece:
// Middle is used to "center" pages around the current page.
$pager_middle = ceil($quantity / 2);
// current is the page we are currently paged to
$pager_current = $pager_page_array[$element] + 1;
// max is the maximum page number
$pager_max = $pager_total[$element];
// End of marker calculations.
$li_previous = theme('pager_previous',
array(
'text' => (isset($tags[1]) ? $tags[1] : t('‹‹')),
'limit' => $limit,
'element' => $element,
'interval' => 1,
'parameters' => $parameters,
)
);
if (empty($li_previous)) {
$li_previous = "&nbsp;";
}
$li_next = theme('pager_next',
array(
'text' => (isset($tags[3]) ? $tags[3] : t('››')),
'limit' => $limit,
'element' => $element,
'interval' => 1,
'parameters' => $parameters,
)
);
if (empty($li_next)) {
$li_next = "&nbsp;";
}
if ($pager_total[$element] > 1) {
$items[] = array(
'class' => array('pager-previous'),
'data' => $li_previous,
);
$items[] = array(
'class' => array('pager-current'),
'data' => t('@current of @max', array('@current' => $pager_current, '@max' => $pager_max)),
);
$items[] = array(
'class' => array('pager-next'),
'data' => $li_next,
);
$settings = array(
'views_infinite_scroll' => array(
array(
'view_name' => $view_name,
'display' => $current_display,
'pager_selector' => 'ul.' . $PAGER_CLASS,
'next_selector' => 'li.pager-next a:first',
'content_selector' => $content_selector,
'items_selector' => $items_selector,
'img_path' => $img_path,
'manual_load' => $manual_load,
'text' => t($text),
'pager_max' => $pager_max,
),
),
);
drupal_add_css(drupal_get_path('module', 'views_infinite_scroll') . '/css/views_infinite_scroll.css');
drupal_add_js($settings, array('type' => 'setting', 'scope' => JS_DEFAULT));
// Add Autopager jQuery plugin
// If libraries module is installed, check for the plugin in libraries dir.
if (module_exists('libraries') && file_exists(libraries_get_path('autopager') .'/jquery.autopager-1.0.0.js')) {
drupal_add_js(libraries_get_path('autopager') .'/jquery.autopager-1.0.0.js');
}
// else, load it from views_infinite_scroll/js dir.
else {
$autopager_module_path = drupal_get_path('module', 'views_infinite_scroll') . '/js/jquery.autopager-1.0.0.js';
drupal_add_js($autopager_module_path);
}
drupal_add_js(drupal_get_path('module', 'views_infinite_scroll') . '/js/views_infinite_scroll.js');
return theme('item_list', array('items' => $items, 'title' => NULL, 'type' => 'ul', 'attributes' => array('class' => array($PAGER_CLASS))));
}
}
<?php
/**
* @file
* Views infinite scroll pager template.
*/
?>
<ul class="pager pager--infinite-scroll <?php print $automatic_scroll_class ?>">
<li class="pager__item">
<?php print render($button); ?>
</li>
</ul>
(function ($) {
"use strict";
var $window = $(window);
// The threshold for how far to the bottom you should reach before reloading.
var scroll_threshold = 200;
var vis_index = 0;
/**
* Insert a views infinite scroll view into the document after AJAX.
*
* @param {object} $new_view The new view coming from the server.
*/
$.fn.infiniteScrollInsertView = function ($new_view) {
var $existing_view = this;
var $existing_content = $existing_view.find('.view-content').children();
$new_view.find('.view-content').prepend($existing_content);
$existing_view.replaceWith($new_view);
$(document).trigger('infiniteScrollComplete', [$new_view, $existing_content]);
};
/**
* Handle the automatic paging based on the scroll amount.
*/
Drupal.behaviors.views_infinite_scroll_automatic = {
attach : function(context, settings) {
var settings = settings.views_infinite_scroll;
var loadingImg = '<div class="views_infinite_scroll-ajax-loader"><img src="' + settings.img_path + '" alt="loading..."/></div>';
$('.pager--infinite-scroll.pager--infinite-scroll-auto', context).once().each(function() {
var $pager = $(this);
$pager.find('.pager__item').hide();
if ($pager.find('.pager__item a').length) {
$pager.append(loadingImg);
}
$window.bind('scroll.views_infinite_scroll_' + vis_index, function() {
if (window.innerHeight + window.pageYOffset > $pager.offset().top - scroll_threshold) {
$pager.find('.pager__item a').click();
$window.unbind('scroll.views_infinite_scroll_' + vis_index);
}
});
vis_index++;
});
}
};
})(jQuery);
; $Id:
name = Views Infinite Scroll
description = Provides an Infinite Scrolling pager for Views
package = Views
core = 7.x
dependencies[] = views
files[] = views_infinite_scroll.module
files[] = views_infinite_scroll.views.inc
files[] = views_plugin_pager_infinite_scroll.inc
files[] = drush/views_infinite_scroll.drush.inc
files[] = theme/views_infinite_scroll_theme.inc
<?php
// $Id:
/**
* @file
* Create a pager plugin to allow infinite scroll on views.
*/
/**
* Implements hook_views_api().
*/
function views_infinite_scroll_views_api() {
return array('api' => '3.0-alpha1');
return array('api' => 3);
}
/**
* Implements hook_views_plugin().
*/
function views_infinite_scroll_views_plugins() {
return array(
'module' => 'views_infinite_scroll',
'pager' => array(
'infinite_scroll' => array(
'title' => t('Infinite Scroll'),
'handler' => 'views_plugin_pager_infinite_scroll',
'uses options' => TRUE,
'parent' => 'full',
),
),
);
}
/**
* Implements hook_theme().
*/
function views_infinite_scroll_theme() {
$path = drupal_get_path('module', 'views_infinite_scroll');
// Some quasi clever array merging here.
$base = array(
'file' => 'views_infinite_scroll_theme.inc',
'path' => "$path/theme",
return array(
'views_infinite_scroll_pager' => array(
'variables' => array(
'element' => NULL,
),
'template' => 'views-infinite-scroll-pager',
),
);
}
// Our extra version of pager from pager.inc
$hooks['views_infinite_scroll_pager'] = $base + array(
'variables' => array(
'tags' => array(),
'limit' => 10,
'element' => 0,
'parameters' => array(),
),
'pattern' => 'views_infinite_scroll_pager__',
/**
* Implements hook_views_ajax_data_alter().
*/
function views_infinite_scroll_views_ajax_data_alter(&$commands, view $view) {
if (!isset($view->query->pager->plugin_name) || $view->query->pager->plugin_name !== 'infinite_scroll' || !isset($_GET['page'])) {
return;
}
foreach ($commands as $delta => &$command) {
if (!empty($command['method']) && $command['method'] === 'replaceWith') {
// Change the standard replace command to a custom one which will provide
// the infinite scroll effect.
$command['method'] = 'infiniteScrollInsertView';
}
// Remove the behaviour of scrolling to the top of the page.
if ($command['command'] === 'viewsScrollTop') {
unset($commands[$delta]);
}
}
}
/**
* Implements hook_preprocess_views_infinite_scroll_pager().
*/
function views_infinite_scroll_preprocess_views_infinite_scroll_pager(&$vars) {
$vars['button'] = array(
'#theme' => 'pager_next',
'#text' => $vars['text'],
);
return $hooks;
$vars['automatic_scroll_class'] = (empty($vars['manual_load'])) ? 'pager--infinite-scroll-auto' : '';
}
<?php
/**
* @file
* Provides the views plugin information.
*/
/**
* Implements hook_views_plugin().
*/
function views_infinite_scroll_views_plugins() {
return array(
'module' => 'views_infinite_scroll',
'pager' => array(
'infinite_scroll' => array(
'title' => t('Infinite Scroll'),
'help' => t('views_infinite_scroll'),
'handler' => 'views_plugin_pager_infinite_scroll',
'uses options' => TRUE,
'parent' => 'full',
),
),
);
}
<?php
/**
* The plugin to handle full pager.
* @file
* Contains \views_plugin_pager_infinite_scroll.
*/
/**
* The plugin to handle the infinite scroll pager.
*
* @ingroup views_pager_plugins
*/
class views_plugin_pager_infinite_scroll extends views_plugin_pager_full {
function init(&$view, &$display, $options = array()) {
parent::init($view, $display, $options);
}
/**
* {@inheritdoc}
*/
function option_definition() {
$options = parent::option_definition();
$options['manual_load'] = array('default' => 0);
$options['text'] = array('default' => 'Show More', 'translatable' => TRUE);
$options['items_per_page'] = array('default' => 10);
$options['offset'] = array('default' => 0);
return $options;
}
/**
* Provide the default form for setting options.
* {@inheritdoc}
*/
function options_form(&$form, &$form_state) {
parent::options_form($form, $form_state);
$form['items_per_page'] = array(
'#title' => t('Items to display'),
'#type' => 'textfield',
'#description' => t('The number of items to display. Enter 0 for no limit.'),
'#default_value' => $this->options['items_per_page'],
);
$form['offset'] = array(
'#type' => 'textfield',
'#title' => t('Offset'),
'#description' => t('The number of items to skip. For example, if this field is 3, the first 3 items will be skipped and not displayed.'),
'#default_value' => $this->options['offset'],
);
$form['manual_load'] = array(
'#type' => 'checkbox',
'#title' => t('Load subsequent pages manually instead of automatically'),
'#description' => t('When checked, use a link to trigger loading of subsequent pages instead of window scroll.'),
'#default_value' => $this->options['manual_load'],
'#weight' => -10,
);
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Manual load label'),
......@@ -40,64 +55,35 @@ class views_plugin_pager_infinite_scroll extends views_plugin_pager_full {
'#dependency' => array(
'edit-pager-options-manual-load' => array(1),
),
'#weight' => -10,
);
}
/**
* {@inheritdoc}
*/
function options_validate(&$form, &$form_state) {
}
/**
* {@inheritdoc}
*/
function summary_title() {
return "Infinite Scroll";
if (!empty($this->options['offset'])) {
return format_plural($this->options['items_per_page'], 'Infinite scroll pager, @count item, skip @skip', 'Infinite scroll pager, @count items, skip @skip', array(
'@count' => $this->options['items_per_page'],
'@skip' => $this->options['offset']
));
}
return format_plural($this->options['items_per_page'], 'Infinite scroll pager, @count item', 'Infinite scroll pager, @count items', array('@count' => $this->options['items_per_page']));
return t('Infinite Scroll: @parent', ['@parent' => parent::summary_title()]);
}
/**
* {@inheritdoc}
*/
function render($input) {
global $base_url;
$content_selector = '';
$style_options = $this->view->style_options;
$items_selector = '';
$img_path = $base_url . '/' . drupal_get_path('module', 'views_infinite_scroll') . '/images/ajax-loader.gif';
switch ($this->view->plugin_name) {
case 'default':
$content_selector = 'div.view-content';
$items_selector = '.views-row';
break;
case 'grid':
$content_selector = 'div.view-content > table > tbody';
$items_selector = 'tr';
break;
case 'list':
if (array_key_exists('wrapper_class', $style_options) && !empty($style_options['wrapper_class'])) {
$wrapper_class = '.' . $style_options['wrapper_class'];
}
else {
$wrapper_class = '.item-list';
}
$content_selector = 'div.view-content>' . $wrapper_class . ' > *';
$items_selector = '.views-row';
break;
case 'table':
$content_selector = 'div.view-content > table > tbody';
$items_selector = 'tr';
break;
}
$this->view->set_use_ajax(TRUE);
$pager_theme = views_theme_functions('views_infinite_scroll_pager', $this->view, $this->display);
return theme($pager_theme, array(
'tags' => $input,
'quantity' => $this->options['items_per_page'],
'view_name' => $this->view->name,
'current_display' => $this->view->current_display,
'content_selector' => $content_selector,
'items_selector' => $items_selector,
'img_path' => $img_path,
'element' => $this->options['id'],
'manual_load' => $this->options['manual_load'],
'text' => $this->options['text'],
)
$settings = array(
'views_infinite_scroll' => array(
'img_path' => url(drupal_get_path('module', 'views_infinite_scroll') . '/images/ajax-loader.gif'),
),
);
drupal_add_js($settings, array('type' => 'setting', 'scope' => JS_DEFAULT));
drupal_add_js(drupal_get_path('module', 'views_infinite_scroll') . '/views-infinite-scroll.js', array('scope' => 'footer'));
return theme($pager_theme, array('text' => $this->options['text'], 'manual_load' => $this->options['manual_load']));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment