diff --git a/css/style.css b/css/style.css index fa7d054139efd358096530c501d6c7446d5a8164..a13e66492d6ed0380fe2df3079392e99f618a796 100644 --- a/css/style.css +++ b/css/style.css @@ -243,3 +243,13 @@ e.g. multipage*/ border: 0 none; margin: 0; } + +/* Views AJAX pagination support */ +.pagination ul > li > a.progress-disabled { + float: left; +} +.pagination ul > li a .throbber { + margin: 0 -0.25em 0 0.5em; + position: relative; + top: 1px; +} diff --git a/includes/pager.inc b/includes/pager.inc index cab241f8ad3751ba4a32e1961e33713566cf387f..f9c0d79bdb7956f06630ac2af7e075c023d7a04e 100644 --- a/includes/pager.inc +++ b/includes/pager.inc @@ -80,7 +80,7 @@ function bootstrap_pager($variables) { if ($i > 1) { $items[] = array( 'class' => array('pager-ellipsis', 'disabled'), - 'data' => '', + 'data' => '', ); } // Now generate the actual pager piece. @@ -107,7 +107,7 @@ function bootstrap_pager($variables) { if ($i < $pager_max) { $items[] = array( 'class' => array('pager-ellipsis', 'disabled'), - 'data' => '', + 'data' => '', ); } } diff --git a/includes/theme.inc b/includes/theme.inc index f5c511ffb9e84991ef9a82bb4edeb00866a99ec3..f44e4b9bbf6c7e607df227bb711a2b1bda6dfe9d 100644 --- a/includes/theme.inc +++ b/includes/theme.inc @@ -298,13 +298,28 @@ function bootstrap_js_alter(&$js) { libraries_load('bootstrap', 'minified'); } + $theme_path = drupal_get_path('theme', 'bootstrap'); + // Replace core progress bar JS with the Bootstrap equivilent. if (isset($js['misc/progress.js']) && !empty($js['misc/progress.js'])) { unset($js['misc/progress.js']); - $progress = drupal_get_path('theme', 'bootstrap') . '/js/progress.js'; + $progress = $theme_path . '/js/progress.js'; $js[$progress] = drupal_js_defaults($progress); } + // Fix broken Views AJAX pagers. + if (module_exists('views') && !empty($js[drupal_get_path('module', 'views') . '/js/ajax_view.js'])) { + // Override core ajax prototype function to append throbber inside links, + // instead of after it (floating issues). + $ajax = $theme_path . '/js/bootstrap_ajax.js'; + $js[$ajax] = drupal_js_defaults($ajax); + $js[$ajax]['group'] = JS_THEME; + // Override views prototype function to bind to Bootstrap pagination. + $ajax_view = $theme_path . '/js/bootstrap_ajax_view.js'; + $js[$ajax_view] = drupal_js_defaults($ajax_view); + $js[$ajax_view]['group'] = JS_THEME; + } + $js = array_diff_key($js, $excludes); if (theme_get_setting('cdn_bootstrap')) { $files[] = '//netdna.bootstrapcdn.com/twitter-bootstrap/'. theme_get_setting('cdn_bootstrap_version') .'/js/bootstrap.min.js'; diff --git a/js/bootstrap_ajax.js b/js/bootstrap_ajax.js new file mode 100644 index 0000000000000000000000000000000000000000..141c15235b2784b671b284f8d88c7a34598ad170 --- /dev/null +++ b/js/bootstrap_ajax.js @@ -0,0 +1,74 @@ +(function ($) { + +/** + * Override Drupal's AJAX prototype beforeSend function so it can append the + * throbber inside the pager links. + */ +Drupal.ajax.prototype.beforeSend = function (xmlhttprequest, options) { + // For forms without file inputs, the jQuery Form plugin serializes the form + // values, and then calls jQuery's $.ajax() function, which invokes this + // handler. In this circumstance, options.extraData is never used. For forms + // with file inputs, the jQuery Form plugin uses the browser's normal form + // submission mechanism, but captures the response in a hidden IFRAME. In this + // circumstance, it calls this handler first, and then appends hidden fields + // to the form to submit the values in options.extraData. There is no simple + // way to know which submission mechanism will be used, so we add to extraData + // regardless, and allow it to be ignored in the former case. + if (this.form) { + options.extraData = options.extraData || {}; + + // Let the server know when the IFRAME submission mechanism is used. The + // server can use this information to wrap the JSON response in a TEXTAREA, + // as per http://jquery.malsup.com/form/#file-upload. + options.extraData.ajax_iframe_upload = '1'; + + // The triggering element is about to be disabled (see below), but if it + // contains a value (e.g., a checkbox, textfield, select, etc.), ensure that + // value is included in the submission. As per above, submissions that use + // $.ajax() are already serialized prior to the element being disabled, so + // this is only needed for IFRAME submissions. + var v = $.fieldValue(this.element); + if (v !== null) { + options.extraData[this.element.name] = v; + } + } + + // Disable the element that received the change to prevent user interface + // interaction while the Ajax request is in progress. ajax.ajaxing prevents + // the element from triggering a new request, but does not prevent the user + // from changing its value. + $(this.element).addClass('progress-disabled').attr('disabled', true); + + // Insert progressbar or throbber. + if (this.progress.type == 'bar') { + var progressBar = new Drupal.progressBar('ajax-progress-' + this.element.id, eval(this.progress.update_callback), this.progress.method, eval(this.progress.error_callback)); + if (this.progress.message) { + progressBar.setProgress(-1, this.progress.message); + } + if (this.progress.url) { + progressBar.startMonitoring(this.progress.url, this.progress.interval || 1500); + } + this.progress.element = $(progressBar.element).addClass('ajax-progress ajax-progress-bar'); + this.progress.object = progressBar; + $(this.element).after(this.progress.element); + } + else if (this.progress.type == 'throbber') { + this.progress.element = $('
 
'); + // If progress type has the Bootstrap pagination parent, then append the + // throbber instead of attaching it after the link. + if ($(this.element).parents('.pagination')) { + if (this.progress.message) { + $('.throbber', this.progress.element).append('
' + this.progress.message + '
'); + } + $(this.element).append(this.progress.element); + } + else { + if (this.progress.message) { + $('.throbber', this.progress.element).after('
' + this.progress.message + '
'); + } + $(this.element).after(this.progress.element); + } + } +}; + +})(jQuery); diff --git a/js/bootstrap_ajax_view.js b/js/bootstrap_ajax_view.js new file mode 100644 index 0000000000000000000000000000000000000000..ec6b55d5cee2ca2b05ca28dd579c189382dd7490 --- /dev/null +++ b/js/bootstrap_ajax_view.js @@ -0,0 +1,12 @@ +(function ($) { + +/** + * Override Views prototype function so it can recognize Bootstrap AJAX pagers. + * Attach the ajax behavior to each link. + */ +Drupal.views.ajaxView.prototype.attachPagerAjax = function() { + this.$view.find('ul.pager > li > a, th.views-field a, .attachment .views-summary a, .pagination ul li a') + .each(jQuery.proxy(this.attachPagerLinkAjax, this)); +}; + +})(jQuery);