Add query parameter data loader and data permalink.
authorDavid I. Lehn <dlehn@digitalbazaar.com>
Fri, 15 Jul 2011 16:22:36 -0400
changeset 69 ae967a882caa
parent 67 6f2c639bd25b
child 70 b210c41dddac
Add query parameter data loader and data permalink.

- Can load JSON-LD markup and/or frame data from query parameters.
- JSON-LD markup comes from "json-ld" query parameter.
- Frame comes from "frame" query parameter.
- Parameters can be encoded JSON strings or remote URLs.
- Due to same origin issues, remote URLs must be CORS enabled.
- Provide a permalink for current data that uses query parameters.
playground/index.html
playground/playground.css
playground/playground.js
--- a/playground/index.html	Thu Jul 14 12:09:06 2011 -0700
+++ b/playground/index.html	Fri Jul 15 16:22:36 2011 -0400
@@ -47,23 +47,23 @@
             <ul id="examples">
               <li class="button-list">Simple Examples:</li>
               <li class="button">
-                 <span onmousedown="playground.populate('Person')">Person</span>
-              </li>
-              <li class="button">
-                 <span onmousedown="playground.populate('Event')">Event</span>
+                 <span onmousedown="playground.populateWithExample('Person')">Person</span>
               </li>
               <li class="button">
-                 <span onmousedown="playground.populate('Place')">Place</span>
+                 <span onmousedown="playground.populateWithExample('Event')">Event</span>
               </li>
               <li class="button">
-                 <span onmousedown="playground.populate('Product')">Product</span>
+                 <span onmousedown="playground.populateWithExample('Place')">Place</span>
               </li>
               <li class="button">
-                 <span onmousedown="playground.populate('Recipe')">Recipe</span>
+                 <span onmousedown="playground.populateWithExample('Product')">Product</span>
+              </li>
+              <li class="button">
+                 <span onmousedown="playground.populateWithExample('Recipe')">Recipe</span>
               </li>
               <li class="button-list">Framing Examples:</li>
               <li class="button">
-                 <span onmousedown="playground.populate('Library')">Library</span>
+                 <span onmousedown="playground.populateWithExample('Library')">Library</span>
               </li>
             </ul><br />
 
@@ -76,6 +76,8 @@
                   onkeyup="playground.process()"></textarea>
             </div>
 
+            <div id="permalink"></div>
+
             <div id="markup-errors" class="errors"></div>
 
             <div id="frame-errors" class="errors"></div>
--- a/playground/playground.css	Thu Jul 14 12:09:06 2011 -0700
+++ b/playground/playground.css	Fri Jul 15 16:22:36 2011 -0400
@@ -69,3 +69,6 @@
     padding: 6px 0 4px 18px; /* push text down 1px */
 }
 
+#permalink {
+   text-align: right;
+}
--- a/playground/playground.js	Thu Jul 14 12:09:06 2011 -0700
+++ b/playground/playground.js	Fri Jul 15 16:22:36 2011 -0400
@@ -35,16 +35,110 @@
              ">": "gt"
          }[c] + ";";
       });
-   }
+   };
+
 
    /**
-    * Used to initialize the UI, call once a document load.
+    * Get a query parameter by name.
+    *
+    * Code from:
+    * http://stackoverflow.com/questions/901115/get-query-string-values-in-javascript/5158301#5158301
+    *
+    * @param name a query parameter name.
+    *
+    * @return the value of the parameter or null if it does not exist
+    */
+   function getParameterByName(name) {
+      var match = RegExp('[?&]' + name + '=([^&]*)')
+         .exec(window.location.search);
+      return match && decodeURIComponent(match[1].replace(/\+/g, ' '));
+   };
+
+   /**
+    * Handle URL query parameters.
+    *
+    * Checks "json-ld" and "frame" parameters.  If they look like JSON then
+    * interpret as JSON strings else interpret as URLs of remote resources.
+    * Note: URLs must be CORS enabled to load due to browser same origin policy
+    * issues.
+    */
+   playground.processQueryParameters = function()
+   {
+      // data from the query
+      var queryData = {
+         markup: null,
+         frame: null
+      };
+
+      /**
+       * Read a parameter as JSON or created an jQuery AJAX Deferred call
+       * to read the data.
+       *
+       * @param param a query parameter value.
+       * @param fieldName the field name to populate in queryData object.
+       * @param msgName the param name to use in UI messages.
+       *
+       * @return jQuery Deferred or null
+       */
+      function handleParameter(param, fieldName, msgName)
+      {
+         // the ajax deferred or null
+         var rval = null;
+
+         // check "json-ld" parameter
+         if(param !== null)
+         {
+            hasQueryData = true;
+            if(param.length == 0 || param[0] == "{" || param[0] == "[")
+            {
+               // param looks like JSON
+               queryData[fieldName] = param;
+            }
+            else
+            {
+               // treat param as a URL
+               rval = $.ajax({
+                  url: param,
+                  dataType: 'text',
+                  success: function(data, textStatus, jqXHR) {
+                     queryData[fieldName] = data;
+                  },
+                  error: function(jqXHR, textStatus, errorThrown) {
+                     // FIXME: better error handling
+                     $("#markup-errors")
+                        .text("Error loading " + msgName + " URL: " + param);
+                  }
+               });
+            }
+         };
+
+         return rval;
+      };
+
+      // build deferreds
+      var jsonLdDeferred = handleParameter(
+         getParameterByName("json-ld"), "markup", "JSON-LD");
+      var frameDeferred = handleParameter(
+         getParameterByName("frame"), "frame", "frame");
+
+      // wait for ajax if needed
+      // failures handled in AJAX calls
+      $.when(jsonLdDeferred, frameDeferred)
+         .done(function() {
+            // populate UI with data
+            playground.populateWithJSON(queryData);
+         });
+   };
+
+   /**
+    * Used to initialize the UI, call once on document load.
     */
    playground.init = function()
    {
       $("#tabs").tabs();
       $("#frame").hide();
       $("#tabs").bind("tabsselect", playground.tabSelected);
+      playground.processQueryParameters();
    };
 
    /**
@@ -102,7 +196,7 @@
       try
       {
          $("#frame-errors").text("");
-         var frame = JSON.parse($("#frame").val());
+         frame = JSON.parse($("#frame").val());
       }
       catch(e)
       {
@@ -143,6 +237,28 @@
             var turtle = forge.jsonld.turtle(input);
             $("#turtle").html(playground.htmlEscape(turtle));
          }
+
+         // generate a link for current data
+         var link = "?json-ld=" + encodeURIComponent(JSON.stringify(input));
+         if($("#frame").val().length > 0)
+         {
+            link += "&frame=" + encodeURIComponent(JSON.stringify(frame));
+         }
+         var permalink = '<a href="' + link + '">permalink</a>';
+         // size warning for huge links
+         if((window.location.protocol.length + 2 +
+            window.location.host.length + window.location.pathname.length +
+            link.length) > 2048)
+         {
+            permalink += " (2KB+)"
+         }
+         $("#permalink")
+            .html(permalink)
+            .show();
+      }
+      else
+      {
+         $("#permalink").hide();
       }
       
       // Start the colorization delay
@@ -185,26 +301,29 @@
    };
 
    /**
-    * Callback when an example button is clicked.
+    * Populate the UI with markup and frame JSON. The data parameter should
+    * have a 'markup' field and optional 'frame' field that contain a
+    * serialized JSON string.
     *
-    * @param name the name of the example to pre-populate the input boxes.
+    * @param data object with optional 'markup' and 'frame' fields.
     */
-   playground.populate = function(name)
+   playground.populateWithJSON = function(data)
    {
-      if(name in playground.examples)
+      if('markup' in data && data.markup !== null)
       {
          // fill the markup box with the example
-         $("#markup").val(js_beautify(JSON.stringify(playground.examples[name]),
+         $("#markup").val(js_beautify(
+            data.markup,
             { "indent_size": 3, "brace_style": "expand" }));
          $("#frame").val("{}");
+      }
 
-         if(name in playground.frames)
-         {
-            // fill the frame input box with the example frame
-            $("#frame").val(js_beautify(
-               JSON.stringify(playground.frames[name]),
-               { "indent_size": 3, "brace_style": "expand" }));
-         }
+      if('frame' in data && data.frame !== null)
+      {
+         // fill the frame input box with the example frame
+         $("#frame").val(js_beautify(
+            data.frame,
+            { "indent_size": 3, "brace_style": "expand" }));
       }
 
       // perform processing on the data provided in the input boxes
@@ -214,5 +333,33 @@
       prettyPrint();
    };
 
+   /**
+    * Populate the UI with a named example.
+    *
+    * @param name the name of the example to pre-populate the input boxes.
+    */
+   playground.populateWithExample = function(name)
+   {
+      var data = {
+         markup: null,
+         frame: null
+      };
+
+      if(name in playground.examples)
+      {
+         // fill the markup with the example
+         data.markup = JSON.stringify(playground.examples[name]);
+
+         if(name in playground.frames)
+         {
+            // fill the frame with the example frame
+            data.frame = JSON.stringify(playground.frames[name]);
+         }
+      }
+
+      // populate with the example
+      playground.populateWithJSON(data);
+   };
+
 })(jQuery);