packages feed

vega-view 0.2.0.2 → 0.3.0.0

raw patch · 4 files changed

+230/−56 lines, 4 files

Files

ChangeLog.md view
@@ -1,5 +1,12 @@ # Changelog for vega-view +## 0.3.0.0++Add drag-and-drop support to the main page. You can now drag in a file+(or multiple files) and have their contents be displayed. There is a mode+for selecting how new visualizations are added to the page: at the top+(default), at the bottom, or clear-out any previous plots.+ ## 0.2.0.2  Bump base minimum version to supporg ghc 8 or later, to save
README.md view
@@ -13,9 +13,12 @@ specifications - i.e. the JSON representing a visualization - as a visualization. It relies on [Vega Embed](https://github.com/vega/vega-embed) to do all-the hard work, and just provides a basic web server that will list the-files in a given directory and, when selected, create the-call to Vega Embed.+the hard work, and just provides a basic web server that:++ - you can drag-and-drop files onto to view them;+ + - and will list the files in a given directory and, when selected,+   view them inline or on a separate page.  ## License 
app/Main.hs view
@@ -132,21 +132,219 @@     Left _ -> pure Nothing     Right s -> pure (Just (createView s (takeBaseName infile))) ++addTextJS, addTitleJS, addDescriptionJS :: [H.Html]++addTextJS = [ "function addText(parent, text) { "+            , "parent.appendChild(document.createTextNode(text)); "+            , "} "+            ]++-- TODO: should parent node be emoved from DOM on close? depends on+--       what page it is being used in+addTitleJS = [ "function addTitle(div, infile) { "+             , "const el = document.createElement('p'); "+             , "el.setAttribute('class', 'location'); "+             , "addText(el, 'File: ' + infile); "+             , "div.appendChild(el); "+             , "const close = document.createElement('span'); "+             , "close.setAttribute('class', 'close'); "+             , "el.appendChild(close); "+             , "close.addEventListener('click', (ev) => { "+             , "div.style.display = 'none'; "+             , "while (div.firstChild) { "+             , "div.removeChild(div.firstChild); "+             , "} "+             , "}); "+             , "} "+             ]++addDescriptionJS =+  [ "function addDescription(div, spec) { "+  , "if (!spec.description || spec.description === '') { return; } "+  , "const el = document.createElement('p'); "+  , "el.setAttribute('class', 'description'); "+  , "addText(el, spec.description); "+  , "div.appendChild(el); "+  , "} "+  ]+++dragJS :: H.Html+dragJS =+  let cts = [ "function preventDefault(event) { event.preventDefault(); } "+            , "window.addEventListener('dragenter', preventDefault, false); "+            , "window.addEventListener('dragover', preventDefault); "+            , "window.addEventListener('drop', handleDrop); "+            , "function handleDrop(ev) { "+            , "ev.preventDefault(); "+            , "if (ev.dataTransfer.items) { "+            , "for (var i = 0; i < ev.dataTransfer.items.length; i++) { "+            , "if (ev.dataTransfer.items[i].kind === 'file') { "+            , "readFromDrop(ev.dataTransfer.items[i].getAsFile()); "+            , "} } } else { "+            , "for (var i = 0; i < ev.dataTransfer.files.length; i++) { "+            , "readFromDrop(ev.dataTransfer.files[i]); "+            , "} } "+            , "} "+            , "function readFromDrop(file) { "+            , "if (file.type !== 'application/json') { return; } "+            , "const reader = new FileReader(); "+            , "reader.onload = (event) => { embedSpec(file.name, event.target.result); } "+            , "reader.onerror = (event) => { alert('Unable to read from ' + file.name); } "+            , "reader.readAsText(file); "+            , "}"+            , "function embedSpec(filename, filects) { "+            , "let spec;"+            , "try { "+            , "spec = JSON.parse(filects); "+            , "} catch (error) { "+            , "reportParseError(filename); "+            , "return; "+            , "} "+            , "const parent = document.getElementById('vizlist'); "+            , "if (addMode === 'single') { "+            , "while (parent.firstChild) { "+            , "parent.removeChild(parent.firstChild);"+            , "} }"+            , "const div = document.createElement('div'); "+            , "div.setAttribute('class', 'vizview'); "+            , "if (addMode === 'top') { "+            , "parent.insertBefore(div, parent.firstChild); "+            , "} else { parent.appendChild(div); } "+            , "addTitle(div, filename); "+            , "addDescription(div, spec); "+            , "const vdiv = document.createElement('div'); "+            , "div.appendChild(vdiv); "+            , "vegaEmbed(vdiv, spec); "+            , "div.style.display = 'block';"+            , "} "+            , "var addMode = 'top'; " -- should read from HTML or set HTML+            , "document.getElementById('mode-select')."+            , "addEventListener('change', (ev) => { "+            , "const sel = ev.target; "+            , "for (var i = 0; i < sel.length; i++) { "+            , "if (sel[i].selected) { addMode = sel[i].value; break; } "+            , "} "+            , "}); "+            -- do we want to report the details of the error?+            -- be lazy and use an alert for now+            , "function reportParseError(filename) { "+            , "alert('Unable to parse ' + filename + ' as JSON'); "+            , "} "+            ] ++ addTextJS ++ addTitleJS ++ addDescriptionJS++      +      -- add newlines for debugging, although I've done something+      -- stupid to require this -- TODO track down+      ncts = concatMap (\n -> [n, "\n"]) cts+      jsCts = mconcat ncts+      +      -- jsCts = mconcat cts++  in (H.script ! A.type_ "text/javascript") jsCts+++closeCSS, descriptionCSS, locationCSS :: [H.Html]+closeCSS = [ ".close { "+           , "background: red; "+           , "border-radius: 50%; "+           , "cursor: pointer; "+           , "float: left; "+           , "height: 1em; "+           , "margin-right: 0.5em; "+           , "width: 1em; "+           , "}"+           ]++descriptionCSS = [ "p.decription { "+                 , "}"+                 ]++locationCSS = [ "p.location { "+              , "background: rgba(0, 0, 0, 0.2);"+              , "font-weight: bold; "+              , "margin: -1em; "+              , "margin-bottom: 1em; "+              , "padding: 0.5em; "+              , "} "+              ]+++dragCSS :: H.Html+dragCSS =+  let cts = [ "body { margin: 0; } "+            , ".vizview { "+            , "background: white; "+            , "border: 2px solid rgba(0, 0, 0, 0.6); "+            , "margin: 0.5em; "+            , "float: left; "+            , "padding: 1em; "+            , "} "+            , "#infobar { "+            , "background: rgb(120, 120, 200); "+            , "color: white; "+            , "font-family: sans-serif; "+            , "padding: 0.5em; "+            , "} "+            , "#infobar #title { "+            , "font-size: 150%; "+            , "font-variant-caps: small-caps; "+            , "margin-right: 2em; "+            , "} "+            , "#infobar label { "+            , "margin-right: 0.5em; "+            , "}"+            , "#mainbar { "+            , "padding: 1em; "+            , "} "+            ] ++ closeCSS ++ descriptionCSS ++ locationCSS++  in (H.style ! A.type_ "text/css") (mconcat cts)+    indexPage :: H.Html indexPage =   H.docTypeHtml ! A.lang "en-US" $ do-    H.head (H.title "View a Vega or Vega-Lite specification")+    H.head $ do+      H.title "View a Vega or Vega-Lite specification"+      vegaEmbed+      dragCSS      H.body $ do-      H.h1 "View a Vega or Vega-Lite specification."+      (H.div ! A.id "infobar") $ do+        (H.span ! A.id "title") "View a Vega or Vega-Lite specification"+        (H.label ! A.for "mode-select") "Drop mode:"+        (H.select ! A.id "mode-select") $ do+          (H.option ! A.value "single") "Single"+          -- TODO: can get selected="" with this, but not selected as a+          --       stand-alone attribute+          (H.option ! A.value "top" ! A.selected "") "Add at start"+          (H.option ! A.value "bottom") "Add to end" -      H.p (mconcat [ "This is version "-                   , H.toHtml (showVersion version)-                   , " of vega-view. Go to "-                   , (H.a ! A.href "/display/") "/display/"-                   , " to see the available visualizations."-                   ])+      let elink url = H.a ! A.href url ! A.target "_blank"++      (H.div ! A.id "mainbar") $ do+        H.p (mconcat [ "This is version "+                     , H.toHtml (showVersion version)+                     , " of "+                     , elink "https://github.com/DougBurke/vega-view#readme"+                       "vega-view"+                     , ". Go to "+                     , (H.a ! A.href "/display/") "/display/"+                     , " to see the available visualizations, or "+                     , "drag files containing "+                     , elink "https://vega.github.io/vega-lite/" "Vega"+                     , " or "+                     , elink "https://vega.github.io/vega-lite/" "Vega-Lite"+                     , " visualizations onto this page to view them."+                     ])++        (H.div ! A.id "vizlist") ""++      -- since too lazy to set up an onload handler, stick all the JS+      -- here+      dragJS         -- Return the directories in ths directory, and the JSON files we@@ -228,8 +426,8 @@ -- -- TODO: allow the user to drag the window around ---inlineJS :: H.Html-inlineJS =+embedJS :: H.Html+embedJS =   let cts = [ "function embed(path) { "             , "var req = new XMLHttpRequest(); "             , "req.addEventListener('load', embedSpec); "@@ -254,38 +452,13 @@             , "} "             , "div.style.display = 'block';"             , "} "-            , "function addText(parent, text) { "-            , "parent.appendChild(document.createTextNode(text)); "-            , "} "-            , "function addTitle(div, infile) { "-            , "const el = document.createElement('p'); "-            , "el.setAttribute('class', 'location'); "-            , "addText(el, 'File: ' + infile); "-            , "div.appendChild(el); "-            , "const close = document.createElement('span'); "-            , "close.setAttribute('class', 'close'); "-            , "addText(close, '[X]'); "-            , "el.appendChild(close); "-            , "close.addEventListener('click', (ev) => { "-            , "div.style.display = 'none'; "-            , "while (div.firstChild) { "-            , "div.removeChild(div.firstChild);"-            , "} "-            , "});"-            , "}"-            , "function addDescription(div, spec) { "-            , "if (!spec.description || spec.description === '') { return; } "-            , "const el = document.createElement('p'); "-            , "el.setAttribute('class', 'description'); "-            , "addText(el, spec.description); "-            , "div.appendChild(el); "-            , "}"-            ]+            ] ++ addTextJS ++ addTitleJS ++ addDescriptionJS+   in (H.script ! A.type_ "text/javascript") (mconcat cts)  -inlineCSS :: H.Html-inlineCSS =+embedCSS :: H.Html+embedCSS =   let cts = [ "#vizview { "             , "background: white; "             , "border: 2px solid rgba(0, 0, 0, 0.6); "@@ -296,17 +469,8 @@             , "position: fixed; "             , "top: 2em; "             , "} "-            , "p.location { "-            , "background: rgba(0, 0, 0, 0.2);"-            , "font-weight: bold; "-            , "margin: -1em; "-            , "margin-bottom: 1em; "-            , "padding: 0.5em; "-            , "} "-            , ".close { "-            , "float: right; "-            , "}"-            ]+            ] ++ closeCSS ++ descriptionCSS ++ locationCSS+   in (H.style ! A.type_ "text/css") (mconcat cts)  @@ -321,8 +485,8 @@         H.head $ do           H.title (H.toHtml ("Files to view: " ++ indir))           vegaEmbed-          inlineJS-          inlineCSS+          embedJS+          embedCSS          H.body $ do           H.h1 "Vega and Vega-Lite viewer"
vega-view.cabal view
@@ -1,5 +1,5 @@ name:           vega-view-version:        0.2.0.2+version:        0.3.0.0 synopsis:       Easily view Vega or Vega-Lite visualizations. description:    A web server that is used to view all the Vega and Vega-Lite                 specifications in a directory, or sub-directory. It is similar