Xikui Wang has uploaded a new change for review.

  https://asterix-gerrit.ics.uci.edu/1574

Change subject: Pretty JSON output
......................................................................

Pretty JSON output

1. Added Pretty JSON output query option.
2. Tweaked front end JS to rerender the JSON result. (Take the HTML
    element and rerender it with json-viewer plugin).
3. Added jquery.json-viewer library (MIT License) to front end, with
several customization: a) Several compatibility bug fix (semi-colon,
  comment); b) expand logo change.

Change-Id: Ieec8489c0a055b01e754bba5f9827a7c1f175567
---
M 
asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
M asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
A 
asterixdb/asterix-app/src/main/resources/webui/static/css/jquery.json-viewer.css
A asterixdb/asterix-app/src/main/resources/webui/static/js/jquery.json-viewer.js
4 files changed, 209 insertions(+), 2 deletions(-)


  git pull ssh://asterix-gerrit.ics.uci.edu:29418/asterixdb 
refs/changes/74/1574/1

diff --git 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
index f401576..088d153 100644
--- 
a/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
+++ 
b/asterixdb/asterix-app/src/main/java/org/apache/asterix/app/result/ResultPrinter.java
@@ -87,7 +87,7 @@
         // output by displayCSVHeader(), so skip it here
         if (conf.is(SessionConfig.FORMAT_HTML)) {
             conf.out().println("<h4>Results:</h4>");
-            conf.out().println("<pre>");
+            conf.out().println("<pre class=\"result-content\">");
         }
 
         try {
diff --git a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html 
b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
index 878b1cf..a83c636 100644
--- a/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
+++ b/asterixdb/asterix-app/src/main/resources/webui/querytemplate.html
@@ -35,8 +35,10 @@
 
 <link href="/webui/static/css/style.css" rel="stylesheet"
        type="text/css" />
+<script src="/webui/static/js/jquery.json-viewer.js"></script>
+<link href="/webui/static/css/jquery.json-viewer.css" type="text/css" 
rel="stylesheet" />
 
-<script type="text/javascript">
+  <script type="text/javascript">
 $(document).ready(function() {
 
     var optionButtonSize = $('#checkboxes-on').width();
@@ -155,6 +157,28 @@
                 }
             }
 
+            /* Handling Pretty JSON */
+            var resultFormat = $('#output-format option:checked').val();
+            var prettyJson = $('[name="pretty-json"]').is(':checked');
+            if ( prettyJson && (resultFormat == 'LOSSLESS_JSON' || 
resultFormat == 'CLEAN_JSON')) {
+              $('.result-content').each(
+                  function(idx) {
+                    var results = $(this).text().split('\n');
+                    $(this).css('padding-left', '20px');
+                    $(this).text('');
+                    for (var iter1 = 0; iter1 < results.length - 1; iter1++) {
+                      if (results[iter1].length < 1) {
+                        continue;
+                      }
+                      var resultJSON = $.parseJSON(results[iter1]);
+                            $(this).append($('<div/>').attr("id", 
"json-record"+idx+"-"+iter1));
+                            
$('#json-record'+idx+"-"+iter1).jsonViewer(resultJSON);
+                    }
+                  }
+                );
+            }
+
+
             var contentString = data.toString();
             if (contentString.indexOf(durPattern) != -1) {
                 $('<div/>')
@@ -235,6 +259,7 @@
                   <option value="LOSSLESS_JSON">JSON (lossless)</option>
                 </select>
               </label>
+              <label class="optlabel"><input type="checkbox" 
name="pretty-json" value="true" /> Pretty JSON</label>
               <label class="optlabel"><input type="checkbox" 
name="wrapper-array" value="true" /> Wrap results in outer array</label>
               <label class="checkbox optlabel"><input type="checkbox" 
name="print-expr-tree" value="true" /> Print parsed expressions</label>
               <label class="checkbox optlabel"><input type="checkbox" 
name="print-rewritten-expr-tree" value="true" /> Print rewritten 
expressions</label>
diff --git 
a/asterixdb/asterix-app/src/main/resources/webui/static/css/jquery.json-viewer.css
 
b/asterixdb/asterix-app/src/main/resources/webui/static/css/jquery.json-viewer.css
new file mode 100644
index 0000000..d6143f9
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/main/resources/webui/static/css/jquery.json-viewer.css
@@ -0,0 +1,45 @@
+/* Syntax highlighting for JSON objects */
+ul.json-dict, ol.json-array {
+  list-style-type: none;
+  margin: 0 0 0 1px;
+  border-left: 1px dotted #ccc;
+  padding-left: 2em;
+}
+.json-string {
+  color: #0B7500;
+}
+.json-literal {
+  color: #1A01CC;
+  font-weight: bold;
+}
+
+/* Toggle button */
+a.json-toggle {
+  position: relative;
+  color: inherit;
+  text-decoration: none;
+}
+a.json-toggle:focus {
+  outline: none;
+}
+a.json-toggle:before {
+  color: #aaa;
+  content: "\25BC"; /* down arrow */
+  position: absolute;
+  display: inline-block;
+  width: 1em;
+  left: -1em;
+}
+a.json-toggle.collapsed:before {
+  content: "\25B6"; /* left arrow */
+}
+
+/* Collapsable placeholder links */
+a.json-placeholder {
+  color: #aaa;
+  padding: 0 1em;
+  text-decoration: none;
+}
+a.json-placeholder:hover {
+  text-decoration: underline;
+}
diff --git 
a/asterixdb/asterix-app/src/main/resources/webui/static/js/jquery.json-viewer.js
 
b/asterixdb/asterix-app/src/main/resources/webui/static/js/jquery.json-viewer.js
new file mode 100644
index 0000000..6ef9bdd
--- /dev/null
+++ 
b/asterixdb/asterix-app/src/main/resources/webui/static/js/jquery.json-viewer.js
@@ -0,0 +1,137 @@
+/**
+ * jQuery json-viewer
+ * @author: Alexandre Bodelot <alexandre.bode...@gmail.com>
+ */
+(function($){
+
+  /**
+   * Check if arg is either an array with at least 1 element, or a dict with 
at least 1 key
+   * @return boolean
+   */
+  function isCollapsable(arg) {
+    return arg instanceof Object && Object.keys(arg).length > 0;
+  }
+
+  /**
+   * Check if a string represents a valid url
+   * @return boolean
+   */
+  function isUrl(string) {
+     var regexp = 
/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/;
+     return regexp.test(string);
+  }
+
+  /**
+   * Transform a json object into html representation
+   * @return string
+   */
+  function json2html(json, options) {
+    var html = '';
+    if (typeof json === 'string') {
+      json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, 
'&gt;');
+      if (isUrl(json))
+        html += '<a href="' + json + '" class="json-string">' + json + '</a>';
+      else
+        html += '<span class="json-string">"' + json + '"</span>';
+    }
+    else if (typeof json === 'number') {
+      html += '<span class="json-literal">' + json + '</span>';
+    }
+    else if (typeof json === 'boolean') {
+      html += '<span class="json-literal">' + json + '</span>';
+    }
+    else if (json === null) {
+      html += '<span class="json-literal">null</span>';
+    }
+    else if (json instanceof Array) {
+      if (json.length > 0) {
+        html += '[<ol class="json-array">';
+        for (var i = 0; i < json.length; ++i) {
+          html += '<li>';
+          if (isCollapsable(json[i])) {
+            html += '<a href class="json-toggle"></a>';
+          }
+          html += json2html(json[i], options);
+          if (i < json.length - 1) {
+            html += ',';
+          }
+          html += '</li>';
+        }
+        html += '</ol>]';
+      }
+      else {
+        html += '[]';
+      }
+    }
+    else if (typeof json === 'object') {
+      var key_count = Object.keys(json).length;
+      if (key_count > 0) {
+        html += '{<ul class="json-dict">';
+        for (var key in json) {
+          if (json.hasOwnProperty(key)) {
+            html += '<li>';
+            var keyRepr = options.withQuotes ?
+              '<span class="json-string">"' + key + '"</span>' : key;
+            if (isCollapsable(json[key])) {
+              html += '<a href class="json-toggle">' + keyRepr + '</a>';
+            }
+            else {
+              html += keyRepr;
+            }
+            html += ': ' + json2html(json[key], options);
+            if (--key_count > 0)
+              html += ',';
+            html += '</li>';
+          }
+        }
+        html += '</ul>}';
+      }
+      else {
+        html += '{}';
+      }
+    }
+    return html;
+  }
+
+  /**
+   * jQuery plugin method
+   * @param json: a javascript object
+   * @param options: an optional options hash
+   */
+  $.fn.jsonViewer = function(json, options) {
+    options = options || {};
+
+    return this.each(function() {
+
+      var html = json2html(json, options);
+      if (isCollapsable(json))
+        html = '<a href class="json-toggle"></a>' + html;
+
+      $(this).html(html);
+
+      $(this).off('click');
+      $(this).on('click', 'a.json-toggle', function() {
+        var target = $(this).toggleClass('collapsed').siblings('ul.json-dict, 
ol.json-array');
+        target.toggle();
+        if (target.is(':visible')) {
+          target.siblings('.json-placeholder').remove();
+        }
+        else {
+          var count = target.children('li').length;
+          var placeholder = count + (count > 1 ? ' items' : ' item');
+          target.after('<a href class="json-placeholder">' + placeholder + 
'</a>');
+        }
+        return false;
+      });
+
+      $(this).on('click', 'a.json-placeholder', function() {
+        $(this).siblings('a.json-toggle').click();
+        return false;
+      });
+
+      if (options.collapsed == true) {
+        $(this).find('a.json-toggle').click();
+      }
+    });
+  };
+})(jQuery);

-- 
To view, visit https://asterix-gerrit.ics.uci.edu/1574
To unsubscribe, visit https://asterix-gerrit.ics.uci.edu/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ieec8489c0a055b01e754bba5f9827a7c1f175567
Gerrit-PatchSet: 1
Gerrit-Project: asterixdb
Gerrit-Branch: master
Gerrit-Owner: Xikui Wang <xkk...@gmail.com>

Reply via email to