diff --git a/geofield.module b/geofield.module index b12e1f5..b6139d5 100644 --- a/geofield.module +++ b/geofield.module @@ -325,6 +325,93 @@ function geofield_views_api() { ); } +/** + * Implements hook_menu(). + */ +function geofield_menu() { + $items = array(); + $items['admin/structure/geofield_filter_ajax/%geofield_views_ui_cache/%'] = array( + 'access callback' => 'user_access', + 'access arguments' => array('administer views'), + // We need function views_ui_config_item_form() from views_ui. + 'file' => 'views_ui.admin.inc', + 'file path' => 'core/modules/views_ui', + 'page callback' => '_geofield_views_ui_change_proximity_widget_js', + 'page arguments' => array(3, 4), + 'delivery callback' => 'ajax_deliver', + 'type' => MENU_CALLBACK, + ); + return $items; +} + +/** + * Wrapper for views_ui loader callback. + * + * To avoid dependency on views_ui, which might not be enabled. + */ +function geofield_views_ui_cache_load($name) { + if (module_exists('views_ui')) { + return views_ui_cache_load($name); + } + // Page not found. + return FALSE; +} + +/** + * Callback for AJAX to return a form part for replacement. + * + * @param view $view + * The views object. + * @param string $display_id + * Name of the current display, for example 'page'. + */ +function _geofield_views_ui_change_proximity_widget_js(view $view, $display_id) { + if (isset($_POST['plugin'])) { + $plugin_name = $_POST['plugin']; + } + else { + backdrop_not_found(); + backdrop_exit(); + } + + $form_state = form_state_defaults(); + // Form builder expects those at least: + $form_state['view'] = $view; + $form_state['display_id'] = $display_id; + $form_state['type'] = 'filter'; + $form_state['id'] = 'field_geofield_distance'; + + // Initially (before submitting), this $item is only stub. + $item = $view->get_item($display_id, 'filter', 'field_geofield_distance'); + $item['source'] = $plugin_name; + + if (isset($_POST['operator'])) { + $item['operator'] = $_POST['operator']; + } + // Hardcode for now. + if ($plugin_name = 'manual') { + $item['value']['origin'] = array('lat' => '', 'lon' => ''); + } + else { + $item['value']['origin'] = ''; + } + $form_state['view']->set_item($form_state['display_id'], $form_state['type'], $form_state['id'], $item); + + $form = backdrop_build_form('views_ui_config_item_form', $form_state); + if (isset($form['options']['value'])) { + // Put it into cache so we don't lose default value settings. + views_ui_cache_set($form_state['view']); + // @see js/viewsProximityValue.js + return $form['options']['value']; + } + elseif (isset($form['options']['group_info'])) { + views_ui_cache_set($form_state['view']); + return $form['options']['group_info']['group_items']; + } + + return ''; +} + /** * Geofield Compute Values * diff --git a/js/viewsProximityValue.js b/js/viewsProximityValue.js index 5fe2d74..ad3a2d8 100644 --- a/js/viewsProximityValue.js +++ b/js/viewsProximityValue.js @@ -1,13 +1,89 @@ -;(function ($) { +/** + * @file + * Dynamically update Views admin UI form items fetched via POST request. + */ +(function ($) { + + "use strict"; + Backdrop.behaviors.viewsProximityValue = { + /** + * @param array data + */ + updateFormItem: function (data) { + let formItemsWrapped = data[1].data; + let formItems = $(formItemsWrapped).find('.geofield-proximity-field-wrapper'); + if (formItems.length) { + $('.geofield-proximity-field-wrapper').replaceWith(formItems); + } + }, + updateMultipleFormItems: function (data) { + let fullHTML = data[1].data; + let nodes = $.parseHTML(fullHTML); + let index = 1; + for (const node of nodes) { + if ($(node).hasClass('geofield-proximity-field-wrapper')) { + $('tr#views-row-' + index + ' .geofield-proximity-field-wrapper').replaceWith(node); + index++; + } + } + }, + /** + * @return bool + */ + formHasRange: function () { + let checkedValue = $('#edit-options-operator').find(':checked').val(); + if (checkedValue === 'between' || checkedValue === 'not between') { + return true; + } + return false; + }, + /** + * + */ attach: function (context, settings) { - if (!$('body').hasClass('page-admin-structure-views-nojs')) { - $('#edit-options-source-change').hide(); + const widget = this; + let isGrouped = false; + if ($('#edit-options-group-button-radios :checked').val() === '1') { + isGrouped = true; } - $('#edit-options-source').change(function() { - $('#edit-options-source-change').mousedown(); - $('#edit-options-source-change').submit(); + let hasRange = widget.formHasRange(); + $.ajaxSetup({ + type: 'POST', + url: $('#edit-options-source').data('path'), + dataType: 'json' + }); + + $('#edit-options-source').on('change', function() { + let postData = { + plugin: this.value + }; + $.ajax( { data: postData } ) + .done( function (data) { + if (isGrouped === false) { + widget.updateFormItem(data); + } + else { + widget.updateMultipleFormItems(data); + } + }); + }); + + $('#edit-options-operator').on('change', function() { + // Only post if necessary. + if (hasRange === widget.formHasRange()) { + return; + } + let postData = { + plugin: $('#edit-options-source').val(), + operator: $(this).find(':checked').val() + }; + $.ajax( { data: postData } ) + .done( function (data) { + widget.updateFormItem(data); + hasRange = widget.formHasRange(); + }); }); } }; -})(jQuery); \ No newline at end of file +})(jQuery); diff --git a/views/handlers/geofield_handler_filter.inc b/views/handlers/geofield_handler_filter.inc index 3fe0d70..29b0daa 100644 --- a/views/handlers/geofield_handler_filter.inc +++ b/views/handlers/geofield_handler_filter.inc @@ -130,11 +130,16 @@ class geofield_handler_filter extends views_handler_filter_numeric { '#default_value' => $this->options['source'], ); + global $base_path; + $form['source']['#attributes']['data-path'] = $base_path . 'admin/structure/geofield_filter_ajax/' . $this->view->name . '/' . $this->view->current_display; + + // This only works with Javascript disabled. $form['source_change'] = array( '#type' => 'submit', '#value' => 'Change Source Widget', '#submit' => array('geofield_views_ui_change_proximity_widget'), ); + $form['source_change']['#attributes']['class'][] = 'js-hide'; $proximityHandlers = module_invoke_all('proximity_views_handlers'); foreach ($proximityHandlers as $key => $handler) {