package io.trygvis.cj
import scala.collection.JavaConversions._
import scala.xml.{Group, NodeSeq, Elem}
import java.net.{MalformedURLException, URL, URI, URLEncoder}
import net.hamnaberg.json.collection.{Property, Link, Json4sHelpers, JsonCollection}
import net.hamnaberg.json.collection.Render.IMAGE
import org.json4s.native.JsonMethods
import java.io.{PrintWriter, StringWriter, Writer}
class Views(baseUrl: String) {
val notSet = Not set
def tryLink(s: String) = try {
val url = new URL(s)
{s}
} catch {
case _: MalformedURLException => {s}
}
def render(uri: URI) = {
val s = uri.toURL.toExternalForm
baseUrl + "render?url=" + URLEncoder.encode(s, "utf-8")
}
def delete(uri: URI) = {
val s = uri.toURL.toExternalForm
baseUrl + "render?url=" + URLEncoder.encode(s, "utf-8") + "&action=delete"
}
def examples: Array[Elem] = Array("minimal", "collection", "item", "queries", "template", "error") map { name =>
val cj = baseUrl + "examples/from-spec/" + name + ".collection+json"
{name}
}
def getStackTrace(aThrowable: Throwable) = {
val result: Writer = new StringWriter()
val printWriter: PrintWriter = new PrintWriter(result)
aThrowable.printStackTrace(printWriter)
result.toString
}
/*
mixin get_name(link, prefix, i)
- var name = typeof link.name == 'string' ? link.name : undefined
- var prompt = typeof link.prompt == 'string' ? link.prompt : undefined
- var prefix = typeof prefix == 'string' ? prefix + ': ' : ''
|#{prefix + (name || prompt || '#' + i)}
*/
def getName(link: Link, prefix: String, i: Int) = {
// var name = link.name
val name = Json4sHelpers.getAsString(link.underlying, "name")
prefix + name.orElse(link.prompt).getOrElse("#" + i)
}
def index = {
def innerContent =
❤ Collection+JSON ❤
About
This is an interactive explorer for the Collection+JSON hypermedia. Give it an URL and it will render is as good as it can.
The purpose is twofold: it is a useful tool to inspect
collections while developing or debugging an application. At
the same time it's useful to show the power of
hypermedia
by showing how much a generic user agent can do by using
only the generic Collection+JSON specification and not
knowing anything about your application.
See also
There's a growing C+J community that's discussing on the Google Group.
Reading the (quite light) formal specification is
useful. It also has a tutorial and some examples.
Using
Feel to use this service! However, note that it's running on a free
Heroku
instance so it might fail, be slow or otherwise useless.
If you want to run it against your own local servers you can either run it yourself, or use apps like
localtunnel.com to make your application publicly available.
{cj.links match {
case Nil =>
NodeSeq.Empty
case _ =>
Collection Links
{cj.links.zipWithIndex.map { case (l, i) =>
val name = Json4sHelpers.getAsString(l.underlying, "name")
val title = l.prompt.orElse(name) match {
case Some(t) => ": " + t
case _ => ""
}
Group(Seq(
{"Collection link #" + (i + 1) + title}
, link(l)))
}}
}}
// TODO: If the collection has prev/next links, add buttons to automaticaly navigate those.
// TODO: Add ability to show the raw part of the collection.
def items(cj: JsonCollection) = {
def itemLinks(cj: JsonCollection) = {
val first = cj.findLinkByRel("first")
val prev = cj.findLinkByRel("prev")
val next = cj.findLinkByRel("next")
val last = cj.findLinkByRel("last")
if(first.isDefined || prev.isDefined || next.isDefined || last.isDefined) {
{links.zipWithIndex.map { case (l, i2) =>
Group(Seq(
Item Link #{i2 + 1}
, link(l)))
}}
}}
Data
{item.data map { d =>
{d.name}
{d.value}
}}
Data
}
}
{itemLinks(cj)}
}
def queries(implicit cj: JsonCollection) = {
{cj.queries.zipWithIndex map { case (query, i) =>
val prompt = Json4sHelpers.getAsString(query.underlying, "prompt")
val name = Json4sHelpers.getAsString(query.underlying, "name")
val title = prompt.orElse(name).getOrElse("Unnamed query #" + (i + 1))
{title}
}}
}
def template(implicit cj: JsonCollection) =
The data will be submitted to {href(cj.href)}
/*
block error
div(class='row-fluid')
dl
dt title
dd
if collection.error.title
| #{collection.error.title}
else
i Not set
dt code
dd
if collection.error.code
| #{collection.error.code}
else
i Not set
dt message
dd
if collection.error.message
- var lines = collection.error.message.split('\n')
if lines.length > 1
for line in lines
| #{line.replace(/ /g, ' ')}
br
else
| #{collection.error.message}
else
i Not set
*/
def error(implicit cj: JsonCollection) = {
val e = cj.error.get
val message = e.message map { m =>
val lines = m.split('\n')
lines.map(s => scala.xml.Text(s): NodeSeq).reduce(_ ++ ++ _)
}