clean up, codemirror
authorNicholas Bollweg <nicholas.bollweg@gtri.gatech.edu>
Thu, 06 Feb 2014 14:49:50 -0500
changeset 2090 4a4b4dacb673
parent 2089 6e906fde7dec
child 2091 1408d0d54131
clean up, codemirror
playground/playground.js
--- a/playground/playground.js	Thu Feb 06 14:49:05 2014 -0500
+++ b/playground/playground.js	Thu Feb 06 14:49:50 2014 -0500
@@ -11,11 +11,13 @@
   var playground = window.playground;
   
   // the codemirror editors
-  playground.editors = {
-    markup: null,
-    frame: null,
-    context: null
-  };
+  playground.editors = {};
+  
+  // ... and outputs
+  playground.outputs = {};
+  
+  // default theme
+  playground.theme = "neat";
   
   // the last parsed version of same
   playground.lastParsed = {
@@ -26,14 +28,7 @@
 
   // set the active tab to the compacted view
   playground.activeTab = 'tab-compacted';
-
-  // the counter is used to throttle colorization requests in milliseconds
-  playground.colorizeDelay = 500;
-
-  // the colorize timeout is used to keep track of the timeout object of the
-  // colorize delay
-  playground.colorizeTimeout = null;
-
+  
   // map of original to modifed contexts
   playground.contextMap = {
     // FIXME: remove schema.org support once they serve a JSON-LD context
@@ -45,18 +40,6 @@
   playground.activeContextMap = {};
 
   /**
-   * Escapes text that will affect HTML markup.
-   *
-   * @param text the string to re-encode as HTML.
-   */
-  playground.htmlEscape = function(text) {
-    // replace each special HTML character in the string
-    return text.replace(/([&<>])/g, function (c) {
-      return '&' + {'&': 'amp', '<': 'lt', '>': 'gt'}[c] + ';';
-    });
-  };
-
-  /**
    * Get a query parameter by name.
    *
    * Code from:
@@ -71,6 +54,20 @@
       .exec(window.location.search);
     return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
   };
+  
+  /**
+   * Consistent human-readable JSON formatting
+   *
+   * @param the object or string to humanize
+   *
+   * @return a string containing the humanized string
+   */
+  playground.humanize = function(value) {
+    return js_beautify(
+      $.type(value) === "string" ? value : JSON.stringify(value),
+      {'indent_size': 2, 'brace_style': 'expand'}
+    );
+  };
 
   /**
    * Handle URL query parameters.
@@ -147,7 +144,7 @@
     var startTab = getParameterByName('startTab');
     if(startTab) {
       // strip 'tab-' to get the tab's panel's ID
-      $('#tabs').tabs('select', '#' + startTab.substr(4));
+      //$('#tabs').tabs('select', '#' + startTab.substr(4));
     }
 
     // wait for ajax if needed
@@ -168,19 +165,19 @@
    * Used to initialize the UI, call once on document load.
    */
   playground.init = function() {
-    $('#tabs').tabs();
-    $('#tabs').bind('tabsselect', playground.tabSelected);
-    if(window.location.search) {
-      playground.processQueryParameters();
-    }
+    // enable bootstrap tabs
+    $('#tabs a').click(function (e) {
+      e.preventDefault();
+      $(this).tab('show');
+    }).on("show", playground.tabSelected);
     
+    // show keybaord shortcuts
     $('.popover-info').popover({
-      placement: "bottom",
+      placement: "left",
       html: true,
       content: $(".popover-info-content").html()
     });
     
-    var processTimer;
     
     CodeMirror.commands.autocomplete = function(cm) {
       CodeMirror.showHint(cm, CodeMirror.hint.jsonld, {
@@ -188,74 +185,89 @@
       });
     };
     
-    CodeMirror.commands.at_autocomplete = function(cm){
+    CodeMirror.commands.at_autocomplete = function(cm) {
       CodeMirror.showHint(cm, CodeMirror.hint.jsonld, {
         isAt: true,
         lastParsed: playground.lastParsed[cm.options._playground_key]
       });
     };
     
-    // these are the keys that move the cursor
-    var noHint = [
-      8, // backspace
-      9, // hey! where's my tab?
-      33, 34, 35, 46, // pg/home/end
-      37, 38, 39, 40, // arrows
-      12, // enter
-      27 //escape
-    ];
+    $(".codemirror-input").each(playground.init.editor);
+    $(".codemirror-output").each(playground.init.output);
     
-    $.each(playground.editors, function(key){
-      var editor = playground.editors[key] = CodeMirror.fromTextArea(
-        $("#" + key)[0], {
-          lineNumbers: true,
-          matchBrackets: true,
-          autoCloseBrackets: true,
-          lineWrapping: true,
-          mode: "application/ld+json",
-          gutters: ["CodeMirror-lint-markers"],
-          theme: "elegant",
-          lint: true,
-          extraKeys: {
-            "Ctrl-Space": "autocomplete"
-          },
-          _playground_key: key
-        });
+    if(window.location.search) {
+      playground.processQueryParameters();
+    }
+  };
+  
+  playground.init.editor = function(){
+    var key = this.id,
+      editor = playground.editors[key] = CodeMirror.fromTextArea(this, {
+        matchBrackets: true,
+        autoCloseBrackets: true,
+        lineWrapping: true,
+        mode: "application/ld+json",
+        gutters: ["CodeMirror-lint-markers"],
+        theme: playground.theme,
+        lint: true,
+        extraKeys: {
+          "Ctrl-Space": "autocomplete"
+        },
+        _playground_key: key
+      });
+    
+    // set up 'process' areas to process JSON-LD after typing
+    editor.on("change", playground.process);
+    
+    // check on every keyup for `@`: doesn't get caught by (extra|custom)Keys
+    editor.on("keyup", function(editor, evt) {
+      // these are the keys that move the cursor
+      var noHint = [
+        8, // backspace
+        9, // hey! where's my tab?
+        33, 34, 35, 46, // pg/home/end
+        37, 38, 39, 40, // arrows
+        12, // enter
+        27 //escape
+      ];
       
-      // set up 'process' areas to process JSON-LD after typing
-      editor.on("change", function() {
-        clearTimeout(processTimer);
-        processTimer = setTimeout(playground.process, 500);
-      });
+      if(noHint.indexOf(evt.keyCode) >= 0) { return; }
       
-      // check on every keyup for `@`: doesn't get caught by (extra|custom)Keys
-      editor.on("keyup", function(editor, evt){
-        if(noHint.indexOf(evt.keyCode) >= 0){ return; }
-        var cursor = editor.getCursor(),
-          token = editor.getTokenAt(cursor),
-          chr = token.string[cursor.ch - token.start - 1];
-        if(chr === "@"){
-          CodeMirror.commands.at_autocomplete(editor, evt);
-        }
+      var cursor = editor.getCursor(),
+        token = editor.getTokenAt(cursor),
+        chr = token.string[cursor.ch - token.start - 1];
+      if(chr === "@") {
+        CodeMirror.commands.at_autocomplete(editor, evt);
+      }
+    });
+  };
+  
+  playground.init.output = function() {      
+    var key = this.id,
+      output = playground.outputs[key] = CodeMirror.fromTextArea(this, {
+        readOnly: true,
+        lineWrapping: true,
+        mode: ["normalized", "nquads"].indexOf(key) > -1
+          ? "text/n-triples"
+          : "application/ld+json",
+        theme: playground.theme
       });
-    }); // each
   };
 
   /**
    * Callback for when tabs are selected in the UI.
    *
    * @param event the event that fired when the tab was selected.
-   * @param ui the ui tab object that was selected
    */
-  playground.tabSelected = function(event, ui) {
-    playground.activeTab = ui.tab.id;
-    if(ui.tab.id === 'tab-compacted' || ui.tab.id === 'tab-flattened' ||
-      ui.tab.id === 'tab-framed') {
+  playground.tabSelected = function(evt) {
+    
+    var id = playground.activeTab = evt.target.id;
+    
+    if(['tab-compacted', 'tab-flattened', 'tab-framed'].indexOf(id) > -1) {
       // these options require more UI inputs, so compress UI space
-     $('#markup-div').removeClass('span12');
-     $('#markup-div').addClass('span6');
+     $('#markup-div').removeClass('span12').addClass('span6');
 
-      if(ui.tab.id === 'tab-compacted' || ui.tab.id === 'tab-flattened') {
+      if(id !== 'tab-framed') {
         $('#param-type').html('JSON-LD Context');
         $('#context-div').show();
         $('#frame-div').hide();
@@ -268,18 +280,13 @@
     }
     else {
       // else no input textarea required
-      $('#context-div').hide();
-      $('#frame-div').hide();
-      $('#markup-div').removeClass('span6');
-      $('#markup-div').addClass('span12');
+      $('#context-div, #frame-div').hide();
+      $('#markup-div').removeClass('span6').addClass('span12');
       $('#param-type').html('');
     }
 
     // perform processing on the data provided in the input boxes
     playground.process();
-
-    // apply the syntax colorization
-    prettyPrint();
   };
 
   /**
@@ -295,53 +302,58 @@
 
       // set base IRI
       var options = {base: document.baseURI};
-
+      
       if(playground.activeTab === 'tab-compacted') {
         processor.compact(input, param, options).then(function(compacted) {
-          $('#compacted').html(js_beautify(
-            playground.htmlEscape(JSON.stringify(compacted)),
-            {'indent_size': 2}).replace(/\n/g, '<br>'));
+          
+          playground.outputs["compacted"]
+            .setValue(playground.humanize(compacted));
+            
           resolver.resolve();
         }, resolver.reject);
       }
       else if(playground.activeTab === 'tab-expanded') {
         processor.expand(input, options).then(function(expanded) {
-          $('#expanded').html(js_beautify(
-            playground.htmlEscape(JSON.stringify(expanded)),
-            {'indent_size': 2}).replace(/\n/g, '<br>'));
+          
+          playground.outputs["expanded"]
+            .setValue(playground.humanize(expanded));
+            
           resolver.resolve();
         }, resolver.reject);
       }
       else if(playground.activeTab === 'tab-flattened') {
         processor.flatten(input, param, options).then(function(flattened) {
-          $('#flattened').html(js_beautify(
-            playground.htmlEscape(JSON.stringify(flattened)),
-            {'indent_size': 2}).replace(/\n/g, '<br>'));
+          
+          playground.outputs["flattened"]
+            .setValue(playground.humanize(flattened));
+            
           resolver.resolve();
         }, resolver.reject);
       }
       else if(playground.activeTab === 'tab-framed') {
         processor.frame(input, param, options).then(function(framed) {
-          $('#framed').html(js_beautify(
-            playground.htmlEscape(JSON.stringify(framed)),
-            {'indent_size': 2}).replace(/\n/g, '<br>'));
+          
+          playground.outputs["framed"]
+            .setValue(playground.humanize(framed));
+            
           resolver.resolve();
         }, resolver.reject);
       }
       else if(playground.activeTab === 'tab-nquads') {
         options.format = 'application/nquads';
         processor.toRDF(input, options).then(function(nquads) {
-          $('#nquads').html(
-            playground.htmlEscape(nquads).replace(/\n/g, '<br>'));
+          
+          playground.outputs["nquads"].setValue(nquads);
+          
           resolver.resolve();
         }, resolver.reject);
       }
       else if(playground.activeTab === 'tab-normalized') {
         options.format = 'application/nquads';
         processor.normalize(input, options).then(function(normalized) {
-          $('#normalized').html(
-            playground.htmlEscape(normalized).replace(/\n/g, '<br>'));
-          resolver.resolve();
+          
+          playground.outputs["normalized"].setValue(normalized);
+            
         }, resolver.reject);
       }
     });
@@ -408,9 +420,6 @@
     // errors detected
     if(errors) {
       $('#permalink').hide();
-
-      // start the colorization delay
-      playground.checkColorizeDelay(true);
       return;
     }
 
@@ -438,9 +447,6 @@
       $('#permalink')
         .html(permalink)
         .show();
-
-      // start the colorization delay
-      playground.checkColorizeDelay(true);
     }, function(err) {
       // FIXME: add better error handling output
       $('#processing-errors').text(JSON.stringify(err));
@@ -448,35 +454,6 @@
   };
 
   /**
-   * Performs a check on the colorize delay. If the delay hits 0, the
-   * markup is colorized.
-   *
-   * @param reset true if the colorization timeout should be reset
-   */
-  playground.checkColorizeDelay = function(reset) {
-    // if the counter reset flag is set, reset the counter
-    if(reset) {
-      playground.colorizeDelay = 500;
-    }
-    else {
-      playground.colorizeDelay -= 250;
-    }
-
-    if(playground.colorizeDelay <= 0) {
-      // if the delay has expired, perform colorization
-      prettyPrint();
-    }
-    else {
-      // if the delay has not expired, continue counting down
-      if(playground.colorizeTimeout) {
-        clearTimeout(playground.colorizeTimeout);
-      }
-      playground.colorizeTimeout =
-        setTimeout(playground.checkColorizeDelay, 250);
-    }
-  };
-
-  /**
    * Populate the UI with markup, frame, and context JSON. The data parameter
    * should have a 'markup' field and optional 'frame' and 'context' fields
    * that contain a serialized JSON string.
@@ -489,15 +466,13 @@
     if('markup' in data && data.markup !== null) {
       hasData = true;
       // fill the markup box with the example
-      playground.editors.markup.setValue(js_beautify(
-        data.markup, {'indent_size': 2, 'brace_style': 'expand'}));
+      playground.editors.markup.setValue(playground.humanize(data.markup));
     }
 
     if('frame' in data && data.frame !== null) {
       hasData = true;
       // fill the frame input box with the given frame
-      playground.editors.frame.setValue(js_beautify(
-        data.frame, {'indent_size': 2, 'brace_style': 'expand'}));
+      playground.editors.frame.setValue(playground.humanize(data.frame));
     }
     else {
       playground.editors.frame.setValue('{}');
@@ -506,8 +481,7 @@
     if('context' in data && data.context !== null) {
       hasData = true;
       // fill the context input box with the given context
-      playground.editors.context.setValue(js_beautify(
-        data.context, {'indent_size': 2, 'brace_style': 'expand'}));
+      playground.editors.context.setValue(playground.humanize(data.context));
     }
     else {
       playground.editors.context.setValue('{}');
@@ -516,9 +490,6 @@
     if(hasData) {
       // perform processing on the data provided in the input boxes
       playground.process();
-
-      // apply the syntax colorization
-      prettyPrint();
     }
   };
 
@@ -558,6 +529,7 @@
     playground.populateWithJSON(data);
   };
 
+
   // event handlers
   $(document).ready(function() {
     // Add custom document loader that uses a context URL map.
@@ -594,9 +566,10 @@
       playground.process();
     });
     
-    $('#theme-select a').click(function(evt){
+    $('#theme-select a').click(function(evt) {
       var theme = evt.currentTarget.text,
-        file = evt.currentTarget.title ? evt.currentTarget.title : theme;
+        file = evt.currentTarget.title ? evt.currentTarget.title : theme,
+        key;
       
       $("#theme-name").text(theme);
       
@@ -605,10 +578,13 @@
         file + ".css" 
       );
       
-      for(var key in playground.editors){
+      for(key in playground.editors) {
         playground.editors[key].setOption("theme", theme);
       }
+      
+      for(key in playground.outputs) {
+        playground.outputs[key].setOption("theme", theme);
+      }
     });
   });
-
 })(jQuery);