From a810cd1de0a177fb90d9ea853859aaeab5e35b2a Mon Sep 17 00:00:00 2001
From: Nathan Haug <nate@quicksketch.org>
Date: Thu, 25 Jul 2013 22:57:09 -0700
Subject: [PATCH] Issue #2050871: Make the Views preview work.

---
 charts.module                                 | 22 +++++++++++-
 modules/charts_google/charts_google.inc       | 23 +++----------
 modules/charts_google/charts_google.js        | 18 ++++++----
 modules/charts_google/charts_google.module    | 13 +------
 .../charts_highcharts/charts_highcharts.inc   | 19 ++---------
 .../charts_highcharts/charts_highcharts.js    | 10 +++---
 .../charts_highcharts.module                  | 11 ------
 views/charts_plugin_style_chart.inc           | 34 ++++++++++++++-----
 8 files changed, 72 insertions(+), 78 deletions(-)

diff --git a/charts.module b/charts.module
index add1d3e..3d3392d 100644
--- a/charts.module
+++ b/charts.module
@@ -174,6 +174,9 @@ function charts_theme() {
     'charts_settings_fields' => array(
       'render element' => 'element',
     ),
+    'charts_chart' => array(
+      'render element' => 'element',
+    ),
   );
 }
 
@@ -226,6 +229,9 @@ function charts_pre_render_element($element) {
   // Convert integer properties to save library modules the hassle.
   charts_cast_element_integer_values($element);
 
+  // Generic theme function assuming it will be suitable for most chart types.
+  $element['#theme'] = 'charts_chart';
+
   // Include the library specific file and render via their callback.
   if (isset($chart_library_info['file'])) {
     $module_path = drupal_get_path('module', $chart_library_info['module']);
@@ -378,7 +384,21 @@ function charts_cast_element_integer_values(&$element) {
       charts_cast_element_integer_values($element[$property_name]);
     }
     elseif ($property_name && in_array($property_name, $integer_options)) {
-      $element[$property_name] = is_null($element[$property_name]) ? NULL : (int) $element[$property_name];
+      $element[$property_name] = (is_null($element[$property_name]) || strlen($element[$property_name]) === 0) ? NULL : (int) $element[$property_name];
     }
   }
 }
+
+
+/**
+ * Output the chart renderable as a string.
+ */
+function theme_charts_chart($variables) {
+  $element = $variables['element'];
+
+  $attributes = $element['#attributes'];
+  $attributes['id'] = $element['#id'];
+  $attributes['class'][] = 'chart';
+
+  return '<div ' . drupal_attributes($attributes) . '>' . (isset($element['#chart']) ? $element['#chart'] : '') . '</div>';
+}
diff --git a/modules/charts_google/charts_google.inc b/modules/charts_google/charts_google.inc
index 559dcb2..22d6a15 100644
--- a/modules/charts_google/charts_google.inc
+++ b/modules/charts_google/charts_google.inc
@@ -30,9 +30,9 @@ function _charts_google_render($chart) {
   // Trim out empty options.
   charts_trim_array($chart_definition['options']);
 
-  $chart['#theme'] = 'charts_google_chart';
   $chart['#attached']['library'][] = array('charts_google', 'charts_google');
-  $chart['#attached']['js'][] = array('data' => array('chartsGoogle' => array($chart['#id'] => $chart_definition)), 'type' => 'setting');
+  $chart['#attributes']['class'][] = 'charts-google';
+  $chart['#attributes']['data-chart'] = drupal_json_encode($chart_definition);
 
   return $chart;
 }
@@ -105,7 +105,7 @@ function _charts_google_populate_chart_axes($chart, $chart_definition) {
 
       // Populate the chart data.
       $axis = array();
-      $axis['title'] = $chart[$key]['#title'];
+      $axis['title'] = $chart[$key]['#title'] ? $chart[$key]['#title'] : '';
       $axis['titleTextStyle']['color'] = $chart[$key]['#title_color'];
       $axis['titleTextStyle']['bold'] = $chart[$key]['#title_font_weight'] === 'bold' ? TRUE : FALSE;
       $axis['titleTextStyle']['italic'] = $chart[$key]['#title_font_style'] === 'italic' ? TRUE : FALSE;
@@ -126,8 +126,8 @@ function _charts_google_populate_chart_axes($chart, $chart_definition) {
       $axis['baselineColor'] = $chart[$key]['#base_line_color'];
       $axis['minorGridlines']['color'] = $chart[$key]['#minor_grid_line_color'];
       $axis['viewWindowMode'] = isset($chart[$key]['#max']) ? 'explicit' : NULL;
-      $axis['viewWindow']['max'] = isset($chart[$key]['#max']) ? $chart[$key]['#max'] : NULL;
-      $axis['viewWindow']['min'] = isset($chart[$key]['#max']) ? (int) $chart[$key]['#min'] : NULL;
+      $axis['viewWindow']['max'] = strlen($chart[$key]['#max']) ? (int) $chart[$key]['#max'] : NULL;
+      $axis['viewWindow']['min'] = strlen($chart[$key]['#min']) ? (int) $chart[$key]['#min'] : NULL;
 
       // Multi-axis support only applies to the major axis in Google charts.
       $chart_type_info = chart_get_type($chart['#chart_type']);
@@ -292,16 +292,3 @@ function _charts_google_populate_chart_data(&$chart, $chart_definition) {
 
   return $chart_definition;
 }
-
-/**
- * Output the chart renderable as a string.
- */
-function theme_charts_google_chart($variables) {
-  $element = $variables['element'];
-
-  $attributes = $element['#attributes'];
-  $attributes['id'] = $element['#id'];
-  $attributes['class'][] = 'chart-render';
-
-  return '<div ' . drupal_attributes($attributes) . '></div>';
-}
diff --git a/modules/charts_google/charts_google.js b/modules/charts_google/charts_google.js
index 50f2a7d..feeba5e 100644
--- a/modules/charts_google/charts_google.js
+++ b/modules/charts_google/charts_google.js
@@ -6,16 +6,20 @@
 
 Drupal.behaviors.chartsGoogle = {};
 Drupal.behaviors.chartsGoogle.attach = function(context, settings) {
-  google.setOnLoadCallback(renderCharts);
+  // First time loading in Views preview may not work because the Google JS
+  // API may not yet be loaded.
+  if (typeof google !== 'undefined') {
+    google.load('visualization', '1', { callback: renderCharts });
+  }
+
   function renderCharts() {
-    for (var elementId in settings['chartsGoogle']) {
-      if (settings['chartsGoogle'].hasOwnProperty(elementId)) {
-        var config = settings['chartsGoogle'][elementId];
+    $('.charts-google').once('charts-google-processed', function() {
+      if ($(this).attr('data-chart')) {
+        var config = $.parseJSON($(this).attr('data-chart'));
         var wrap = new google.visualization.ChartWrapper();
         wrap.setChartType(config.visualization);
         wrap.setDataTable(config.data);
         wrap.setOptions(config.options);
-        wrap.setContainerId(elementId);
 
         // Apply data formatters. This only affects tooltips. The same format is
         // already applied via the hAxis/vAxis.format option.
@@ -79,9 +83,9 @@ Drupal.behaviors.chartsGoogle.attach = function(context, settings) {
           }
         }
 
-        wrap.draw();
+        wrap.draw(this);
       }
-    }
+    });
   }
 };
 
diff --git a/modules/charts_google/charts_google.module b/modules/charts_google/charts_google.module
index f2d8472..1bfd99d 100644
--- a/modules/charts_google/charts_google.module
+++ b/modules/charts_google/charts_google.module
@@ -13,17 +13,6 @@ function charts_google_charts_info() {
   return $info;
 }
 
-/**
- * Implements hook_theme().
- */
-function charts_google_theme() {
-  $info['charts_google_chart'] = array(
-    'render element' => 'element',
-    'file' => 'charts_google.inc',
-  );
-  return $info;
-}
-
 /**
  * Implements hook_library().
  */
@@ -33,7 +22,7 @@ function charts_google_library() {
     'website' => 'https://google-developers.appspot.com/chart/',
     'version' => '1.0',
     'js' => array(
-      array('data' => 'https://www.google.com/jsapi?autoload=' . urlencode('{"modules":[{"name":"visualization","version":"1","packages":["corechart","table"]}]}'), 'type' => 'external'),
+      array('data' => 'https://www.google.com/jsapi', 'type' => 'external'),
     ),
   );
   $library['charts_google'] = array(
diff --git a/modules/charts_highcharts/charts_highcharts.inc b/modules/charts_highcharts/charts_highcharts.inc
index 5b0b8d9..4caaa8b 100644
--- a/modules/charts_highcharts/charts_highcharts.inc
+++ b/modules/charts_highcharts/charts_highcharts.inc
@@ -38,9 +38,9 @@ function _charts_highcharts_render($chart) {
     $chart['#id'] = drupal_html_id('highchart-render');
   }
 
-  $chart['#theme'] = 'charts_highcharts_chart';
   $chart['#attached']['library'][] = array('charts_highcharts', 'charts_highcharts');
-  $chart['#attached']['js'][] = array('data' => array('chartsHighcharts' => array($chart['#id'] => $chart_definition)), 'type' => 'setting');
+  $chart['#attributes']['class'][] = 'charts-highchart';
+  $chart['#attributes']['data-chart'] = drupal_json_encode($chart_definition);
 
   return $chart;
 }
@@ -66,7 +66,7 @@ function _charts_highcharts_type($renderable_type) {
  */
 function _charts_highcharts_populate_chart_options($chart, $chart_definition) {
   $chart_definition['chart']['type'] = $chart['#chart_type'];
-  $chart_definition['title']['text'] = $chart['#title'];
+  $chart_definition['title']['text'] = $chart['#title'] ? $chart['#title'] : '';
   $chart_definition['title']['style']['color'] = $chart['#title_color'];
   $chart_definition['title']['style']['fontWeight'] = $chart['#title_font_weight'];
   $chart_definition['title']['style']['fontStyle'] = $chart['#title_font_style'];
@@ -295,16 +295,3 @@ function _charts_highcharts_populate_chart_data(&$chart, $chart_definition) {
 
   return $chart_definition;
 }
-
-/**
- * Output the chart renderable as a string.
- */
-function theme_charts_highcharts_chart($variables) {
-  $element = $variables['element'];
-
-  $attributes = $element['#attributes'];
-  $attributes['id'] = $element['#id'];
-  $attributes['class'][] = 'chart-render';
-
-  return '<div ' . drupal_attributes($attributes) . '></div>';
-}
diff --git a/modules/charts_highcharts/charts_highcharts.js b/modules/charts_highcharts/charts_highcharts.js
index 5418eea..5519c01 100644
--- a/modules/charts_highcharts/charts_highcharts.js
+++ b/modules/charts_highcharts/charts_highcharts.js
@@ -6,12 +6,12 @@
 
 Drupal.behaviors.chartsHighcharts = {};
 Drupal.behaviors.chartsHighcharts.attach = function(context, settings) {
-  for (var elementId in settings['chartsHighcharts']) {
-    if (settings['chartsHighcharts'].hasOwnProperty(elementId)) {
-      var config = settings['chartsHighcharts'][elementId];
-      $('#' + elementId).highcharts(config);
+  $('.charts-highchart').once('charts-highchart-processed', function() {
+    if ($(this).attr('data-chart')) {
+      var config = $.parseJSON($(this).attr('data-chart'));
+      $(this).highcharts(config);
     }
-  }
+  });
 };
 
 })(jQuery);
diff --git a/modules/charts_highcharts/charts_highcharts.module b/modules/charts_highcharts/charts_highcharts.module
index 92af1c6..bd761ec 100644
--- a/modules/charts_highcharts/charts_highcharts.module
+++ b/modules/charts_highcharts/charts_highcharts.module
@@ -17,17 +17,6 @@ function charts_highcharts_charts_info() {
   return $info;
 }
 
-/**
- * Implements hook_theme().
- */
-function charts_highcharts_theme() {
-  $info['charts_highcharts_chart'] = array(
-    'render element' => 'element',
-    'file' => 'charts_highcharts.inc',
-  );
-  return $info;
-}
-
 /**
  * Implements hook_library().
  */
diff --git a/views/charts_plugin_style_chart.inc b/views/charts_plugin_style_chart.inc
index aa7cba8..1dae418 100644
--- a/views/charts_plugin_style_chart.inc
+++ b/views/charts_plugin_style_chart.inc
@@ -58,13 +58,35 @@ class charts_plugin_style_chart extends views_plugin_style {
   }
 
   /**
-   * Define and display a chart from the grouped values.
+   * Make sure the display and all associated handlers are valid.
+   *
+   * @return
+   *   Empty array if the display is valid; an array of error strings if it is not.
    */
-  function render() {
-    if (!empty($this->view->preview)) {
-      return t('Preview is not supported with the chart display type.');
+  function validate() {
+    $errors = array();
+    $field_handlers = $this->display->handler->get_handlers('field');
+
+    if (count($field_handlers)) {
+      $data_field_key = !empty($this->options['data_fields']) ? current($this->options['data_fields']) : NULL;
+      if (empty($data_field_key)) {
+        $errors[] = t('At least one data field must be selected in the chart configuration before this chart may be shown');
+      }
+      else {
+        $data_field = isset($field_handlers[$data_field_key]) ? $field_handlers[$data_field_key] : NULL;
+        if (!isset($data_field)) {
+          $errors[] = t('A field you have specified as a data field in your chart settings no longer exists. Edit the chart settings and select at least one data field.');
+        }
+      }
     }
 
+    return $errors;
+  }
+
+  /**
+   * Define and display a chart from the grouped values.
+   */
+  function render() {
     // Calculate the labels field alias.
     $field_handlers = $this->display->handler->get_handlers('field');
     $label_field = FALSE;
@@ -91,10 +113,6 @@ class charts_plugin_style_chart extends views_plugin_style {
       $data_field_key = current($this->options['data_fields']);
       $data_field = isset($field_handlers[$data_field_key]) ? $field_handlers[$data_field_key] : NULL;
 
-      if (!isset($data_field)) {
-        return t('At least one field must be set as a data source in the chart format configuration.');
-      }
-
       $data = array();
       foreach ($this->view->result as $row) {
         $data_row = array();
-- 
GitLab