├── project ├── build.properties ├── build.sbt └── Build.scala ├── samples └── play2 │ └── todolist │ ├── public │ ├── stylesheets │ │ └── main.css │ ├── images │ │ └── favicon.png │ └── swagger-ui │ │ ├── javascripts │ │ ├── jquery.slideto.min.js │ │ ├── jquery.wiggle.min.js │ │ ├── swagger-service-sample.js │ │ ├── jquery.ba-bbq.min.js │ │ ├── doc.js │ │ ├── underscore-min.js │ │ ├── swagger-ui.js │ │ ├── spine.js │ │ ├── swagger-service.js │ │ ├── jquery.tmpl.js │ │ └── chosen.jquery.js │ │ ├── index.html │ │ └── stylesheets │ │ └── screen.css │ ├── project │ ├── build.properties │ ├── plugins.sbt │ └── Build.scala │ ├── .gitignore │ ├── app │ ├── api │ │ └── sorting │ │ │ └── OrderDirection.scala │ ├── db │ │ └── TodoSchema.scala │ ├── util │ │ └── binding │ │ │ ├── binders.scala │ │ │ └── EnumerationBindable.scala │ ├── models │ │ ├── formats.scala │ │ └── Todo.scala │ ├── Global.scala │ └── controllers │ │ ├── Swagger.scala │ │ └── Todos.scala │ └── conf │ ├── routes │ └── application.conf ├── .gitignore ├── core └── src │ ├── main │ └── scala │ │ └── net │ │ └── eamelink │ │ └── swaggerkit │ │ ├── SchemaBuilder.scala │ │ └── domain.scala │ └── test │ └── scala │ └── net │ └── eamelink │ └── swaggerkit │ └── ModelSpec.scala ├── README.textile └── play2 └── src ├── test └── scala │ └── net │ └── eamelink │ └── swaggerkit │ └── play2 │ └── WritersSpec.scala └── main └── scala └── net └── eamelink └── swaggerkit └── play2 └── Writers.scala /project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.5 2 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/stylesheets/main.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project/build.sbt: -------------------------------------------------------------------------------- 1 | scalacOptions ++= Seq("-feature", "-deprecation") 2 | -------------------------------------------------------------------------------- /samples/play2/todolist/project/build.properties: -------------------------------------------------------------------------------- 1 | sbt.version=0.13.5 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | .project 3 | .classpath 4 | .settings 5 | .cache 6 | -------------------------------------------------------------------------------- /samples/play2/todolist/.gitignore: -------------------------------------------------------------------------------- 1 | logs 2 | project/project 3 | project/target 4 | target 5 | tmp 6 | .history 7 | dist -------------------------------------------------------------------------------- /samples/play2/todolist/public/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/eamelink/swaggerkit/HEAD/samples/play2/todolist/public/images/favicon.png -------------------------------------------------------------------------------- /samples/play2/todolist/app/api/sorting/OrderDirection.scala: -------------------------------------------------------------------------------- 1 | package api.sorting 2 | 3 | object OrderDirection extends Enumeration { 4 | val asc = Value("asc") 5 | val desc = Value("desc") 6 | } 7 | -------------------------------------------------------------------------------- /core/src/main/scala/net/eamelink/swaggerkit/SchemaBuilder.scala: -------------------------------------------------------------------------------- 1 | package net.eamelink.swaggerkit 2 | 3 | /** 4 | * Trait with methods for building Schemas 5 | */ 6 | trait SchemaBuilder { 7 | implicit def typeToProperty(st: Type): Property = Property(st) 8 | } -------------------------------------------------------------------------------- /samples/play2/todolist/app/db/TodoSchema.scala: -------------------------------------------------------------------------------- 1 | package db 2 | 3 | import org.squeryl.PrimitiveTypeMode._ 4 | import org.squeryl.Schema 5 | import models.Todo 6 | 7 | object TodoSchema extends Schema { 8 | val todosTable = table[Todo] 9 | 10 | on(todosTable) (t => declare( 11 | t.id is(primaryKey, autoIncremented) 12 | )) 13 | } -------------------------------------------------------------------------------- /samples/play2/todolist/project/plugins.sbt: -------------------------------------------------------------------------------- 1 | // Comment to get more information during initialization 2 | logLevel := Level.Warn 3 | 4 | // The Typesafe repository 5 | resolvers += "Typesafe repository" at "http://repo.typesafe.com/typesafe/releases/" 6 | 7 | // Use the Play sbt plugin for Play projects 8 | addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.3.6") 9 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/util/binding/binders.scala: -------------------------------------------------------------------------------- 1 | package util.binding 2 | 3 | import models.Todo 4 | import api.sorting.OrderDirection 5 | 6 | object binders { 7 | implicit object OrderDirectionBindable extends EnumerationBindable[OrderDirection.Value](OrderDirection) 8 | implicit object TodoOrderBindable extends EnumerationBindable[Todo.Order.Value](Todo.Order) 9 | } -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/jquery.slideto.min.js: -------------------------------------------------------------------------------- 1 | (function(b){b.fn.slideto=function(a){a=b.extend({slide_duration:"slow",highlight_duration:3E3,highlight:true,highlight_color:"#FFFF99"},a);return this.each(function(){obj=b(this);b("body").animate({scrollTop:obj.offset().top},a.slide_duration,function(){a.highlight&&b.ui.version&&obj.effect("highlight",{color:a.highlight_color},a.highlight_duration)})})}})(jQuery); 2 | -------------------------------------------------------------------------------- /samples/play2/todolist/project/Build.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import Keys._ 3 | import PlayProject._ 4 | 5 | object ApplicationBuild extends Build { 6 | 7 | val appName = "todolist" 8 | val appVersion = "1.1" 9 | 10 | val appDependencies = Seq( 11 | "org.squeryl" %% "squeryl" % "0.9.5-7" 12 | ) 13 | 14 | val main = PlayProject(appName, appVersion, appDependencies, mainLang = SCALA).settings( 15 | routesImport ++= Seq("models._", "util.binding.binders._", "api.sorting._")) dependsOn (swaggerkitPlay2) 16 | 17 | lazy val swaggerkitPlay2 = ProjectRef(file("../../.."), "swaggerkit-play2") 18 | } 19 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/util/binding/EnumerationBindable.scala: -------------------------------------------------------------------------------- 1 | package util.binding 2 | 3 | import play.api.mvc.QueryStringBindable 4 | 5 | class EnumerationBindable[A](enum: Enumeration) extends QueryStringBindable[A] { 6 | override def bind(key: String, params: Map[String, Seq[String]]): Option[Either[String, A]] = { 7 | params.get(key).map { 8 | passedValueSeq => enum.values.find { value => 9 | value.toString == passedValueSeq.mkString 10 | }.map { 11 | value => Right(value.asInstanceOf[A]) 12 | }.getOrElse { 13 | Left("Invalid " + key + ", allowed are one of " + enum.values.mkString(", ")) 14 | } 15 | } 16 | } 17 | 18 | override def unbind(key: String, value: A): String = key + "=" + value 19 | } 20 | 21 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/models/formats.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import play.api.libs.json._ 4 | import net.eamelink.swaggerkit._ 5 | import net.eamelink.swaggerkit.SimpleTypes._ 6 | import org.joda.time.format.ISODateTimeFormat 7 | 8 | object formats { 9 | val dateTimeFormatter = ISODateTimeFormat.dateTime 10 | 11 | implicit object DefaultTodo extends Writes[Todo] with SchemaBuilder { 12 | def writes(todo: Todo): JsValue = JsObject(List( 13 | "id" -> JsNumber(todo.id), 14 | "text" -> JsString(todo.text), 15 | "due" -> JsString(dateTimeFormatter.print(todo.due)), 16 | "done" -> JsBoolean(todo.done))) 17 | 18 | lazy val schema = Schema("Todo") has ( 19 | "id" -> Integer, 20 | "text" -> String, 21 | "due" -> String, 22 | "done" -> Boolean) 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/jquery.wiggle.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | jQuery Wiggle 3 | Author: WonderGroup, Jordan Thomas 4 | URL: http://labs.wondergroup.com/demos/mini-ui/index.html 5 | License: MIT (http://en.wikipedia.org/wiki/MIT_License) 6 | */ 7 | 8 | jQuery.fn.wiggle=function(o){var d={speed:50,wiggles:3,travel:5,callback:null};var o=jQuery.extend(d,o);return this.each(function(){var cache=this;var wrap=jQuery(this).wrap('
').css("position","relative");var calls=0;for(i=1;i<=o.wiggles;i++){jQuery(this).animate({left:"-="+o.travel},o.speed).animate({left:"+="+o.travel*2},o.speed*2).animate({left:"-="+o.travel},o.speed,function(){calls++;if(jQuery(cache).parent().hasClass('wiggle-wrap')){jQuery(cache).parent().replaceWith(cache);} 9 | if(calls==o.wiggles&&jQuery.isFunction(o.callback)){o.callback();}});}});}; 10 | -------------------------------------------------------------------------------- /samples/play2/todolist/conf/routes: -------------------------------------------------------------------------------- 1 | # Routes 2 | # This file defines all application routes (Higher priority routes first) 3 | # ~~~~ 4 | 5 | # Home page 6 | GET / controllers.Swagger.ui 7 | 8 | GET /api/todos controllers.Todos.list(search: Option[String], withDone: Option[Boolean], orderBy: Option[Todo.Order.Value], direction: Option[OrderDirection.Value]) 9 | POST /api/todos controllers.Todos.create 10 | GET /api/todos/:todoId controllers.Todos.show(todoId: Long) 11 | PUT /api/tools/:todoId controllers.Todos.update(todoId: Long) 12 | 13 | # Swagger routes 14 | GET /api/resources.json controllers.Swagger.discover() 15 | GET /api/:id.json controllers.Swagger.resource(id) 16 | 17 | # Map static resources from the /public folder to the /assets URL path 18 | GET /assets/*file controllers.Assets.at(path="/public", file) 19 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/swagger-service-sample.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | // create and initialize SwaggerService 3 | var swaggerService = new SwaggerService("http://swagr.api.wordnik.com/v4/list.json"); 4 | swaggerService.init(); 5 | 6 | // Create convenience references to Spine models 7 | var ApiResource = swaggerService.ApiResource(); 8 | 9 | // Register a callback for when apis are loaded 10 | ApiResource.bind("refresh", apisLoaded); 11 | 12 | function apisLoaded() { 13 | for(var i = 0; i < ApiResource.all().length; i++) { 14 | var apiResource = ApiResource.all()[i]; 15 | log("---------------------------------------------"); 16 | log("------------- apiResource : " + apiResource.name); 17 | apiResource.apiList.logAll(); 18 | apiResource.modelList.logAll(); 19 | } 20 | 21 | if (window.console) console.log("apis loaded"); 22 | } 23 | 24 | }); 25 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/Global.scala: -------------------------------------------------------------------------------- 1 | import db.TodoSchema 2 | import play.api.GlobalSettings 3 | import org.squeryl.SessionFactory 4 | import org.squeryl.Session 5 | import org.squeryl.adapters.H2Adapter 6 | import org.squeryl.PrimitiveTypeMode._ 7 | import play.api.db.DB 8 | import play.api.Application 9 | import models.Todo 10 | import org.joda.time.DateTime 11 | 12 | object Global extends GlobalSettings { 13 | override def onStart(app: Application) { 14 | SessionFactory.concreteFactory = Some(() => 15 | Session.create(DB.getConnection()(app), new H2Adapter)) 16 | 17 | inTransaction { 18 | TodoSchema.create 19 | } 20 | 21 | // Load sample Todo's 22 | inTransaction { 23 | Todo.insert(Todo("Create sample app for swaggerkit-play2", new DateTime(2012, 5, 5, 14, 9), true)) 24 | Todo.insert(Todo("Write more documentation", (new DateTime()).plusHours(4), false)) 25 | Todo.insert(Todo("Fix bugs in swaggerkit-play", (new DateTime()).plusDays(1), false)) 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /samples/play2/todolist/conf/application.conf: -------------------------------------------------------------------------------- 1 | # This is the main configuration file for the application. 2 | # ~~~~~ 3 | 4 | # Secret key 5 | # ~~~~~ 6 | # The secret key is used to secure cryptographics functions. 7 | # If you deploy your application to several instances be sure to use the same key! 8 | application.secret="F@O^L@`NaM8:_BUylP>qY=?UXp@ models.formats.DefaultTodo.schema)))) 27 | 28 | def ui() = Action { 29 | Redirect("/assets/swagger-ui/index.html") 30 | } 31 | 32 | def discover() = Action { request => 33 | Ok(Json.toJson(apiDocumentation(request.host))) 34 | } 35 | 36 | def resource(id: String) = Action { request => 37 | val path = "/%s.{format}" format id 38 | apiDocumentation(request.host).apis.filter(_.path == path).headOption.map { doc => 39 | Ok(Json.toJson(doc)) 40 | }.getOrElse(NotFound) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /project/Build.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | import Keys._ 3 | 4 | object Settings { 5 | val name = "swaggerkit" 6 | 7 | val buildSettings = Defaults.coreDefaultSettings ++ Seq( 8 | version := "0.4-SNAPSHOT", 9 | crossScalaVersions := Seq("2.10.4", "2.11.4"), 10 | organization := "net.eamelink" 11 | ) 12 | } 13 | 14 | object Resolvers { 15 | val typesafeRepo = "Typesafe Repository" at "http://repo.typesafe.com/typesafe/releases/" 16 | } 17 | 18 | object Dependencies { 19 | lazy val play = "com.typesafe.play" %% "play" % "2.3.6" 20 | lazy val specs = "org.specs2" %% "specs2" % "2.4.11" % "test" 21 | } 22 | 23 | object ApplicationBuild extends Build { 24 | import Settings._ 25 | import Resolvers._ 26 | import Dependencies._ 27 | 28 | lazy val root = Project(name, file("."), settings = buildSettings ++ Seq( 29 | publish := {}) 30 | ) aggregate (core, play2) 31 | 32 | lazy val core = Project(name + "-core", file("core"), settings = buildSettings ++ Seq( 33 | publishTo <<= version { (v: String) => 34 | val path = if(v.trim.endsWith("SNAPSHOT")) "snapshots-public" else "releases-public" 35 | Some(Resolver.url("Lunatech Artifactory", new URL("http://artifactory.lunatech.com/artifactory/%s/" format path))) 36 | }, 37 | resolvers := Seq(typesafeRepo), 38 | libraryDependencies ++= Seq(specs))) 39 | 40 | lazy val play2 = Project(name + "-play2", file("play2"), settings = buildSettings ++ Seq( 41 | publishTo <<= version { (v: String) => 42 | val path = if(v.trim.endsWith("SNAPSHOT")) "snapshots-public" else "releases-public" 43 | Some(Resolver.url("Lunatech Artifactory", new URL("http://artifactory.lunatech.com/artifactory/%s/" format path))) 44 | }, 45 | resolvers := Seq(typesafeRepo), 46 | libraryDependencies ++= Seq(play, specs))) dependsOn (core) 47 | 48 | } 49 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/models/Todo.scala: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import org.squeryl.PrimitiveTypeMode._ 4 | import db.TodoSchema 5 | import api.sorting.OrderDirection 6 | import org.squeryl.dsl.ast.ExpressionNode 7 | import org.squeryl.KeyedEntity 8 | import org.joda.time.DateTime 9 | 10 | case class Todo private ( 11 | id: Long, 12 | text: String, 13 | due: DateTime, 14 | done: Boolean) extends KeyedEntity[Long] 15 | 16 | object Todo { 17 | import TodoSchema._ 18 | 19 | object Order extends Enumeration { 20 | val id = Value("id") 21 | val text = Value("text") 22 | val done = Value("done") 23 | 24 | def buildOrder(todo: Todo, order: Order.Value, od: OrderDirection.Value): ExpressionNode = order match { 25 | // We use backticks to avoid declaring a new variable 26 | case `id` => if (od == OrderDirection.asc) todo.id else todo.id desc 27 | case `text` => if (od == OrderDirection.asc) todo.text else todo.text desc 28 | case `done` => if (od == OrderDirection.asc) todo.id else todo.done desc 29 | } 30 | } 31 | 32 | def apply(text: String, due: DateTime, done: Boolean) = { 33 | new Todo(0, text, due, done) 34 | } 35 | def findById(id: Long): Option[Todo] = inTransaction { 36 | from(todosTable)(t => where(t.id === id) select (t)).headOption 37 | } 38 | 39 | def find(search: Option[String], withDone: Boolean, order: Order.Value, direction: OrderDirection.Value): Seq[Todo] = inTransaction { 40 | val doneFilter = if(withDone) None else Some(false) 41 | from(todosTable)((todo) => 42 | where( 43 | todo.text like search.? and 44 | todo.done === doneFilter.? 45 | ) 46 | select (todo) 47 | orderBy Order.buildOrder(todo, order, direction)).toList 48 | } 49 | 50 | def insert(todo: Todo): Todo = inTransaction { 51 | todosTable.insert(todo.copy()) 52 | } 53 | 54 | def delete(id: Long) = inTransaction { 55 | todosTable.delete(id) 56 | } 57 | } -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. Swaggerkit 2 | 3 | Swaggerkit is a Scala toolkit that helps you generate the Swagger JSON for your REST API, that allows Swagger-aware tools to automatically discover and use your API, and the Swagger-UI tool to show documentation and a sandbox for your API. 4 | 5 | The Swagger project itself consists of the Swagger Specification and some implementations for servers and clients. There is a Scala implementation, but it relies on JaxRS, which is often not the technology of choice in your Scala REST API. 6 | 7 | Swaggerkit is an alternative implementation that has no dependencies on JaxRS, or any other technology for that matter (except for Scala...). It is basically an set of case classes that form the data structures as described in the Swagger Specification. 8 | 9 | From these case classes, the JSON must be generated. This project currently contains an implementation that uses the Play 2.0 JSON library for that. 10 | 11 | h2. Versions 12 | 13 | Version 0.3 is the latest for Play 2.3.x, built for both Scala 2.10 and 2.11 14 | 15 | 16 | h2. Design considerations 17 | 18 | * There is no magic. There are case classes and a small DSL to help you construct the entire documentation structure, but nothing is inferred or automatically generated. 19 | 20 | h2. Current Limitations 21 | 22 | * JSON only, there is no XML output supported. This limitation can be lifted in the future. 23 | * JSON generation currently depends on Play 2 library, because that's where I use it for. This limitation can be lifted in the future. 24 | * Swagger specification version not very stable. This is mainly build around a Swagger-1.1-SNAPSHOT version of the spec. 25 | * It has been built for Swagger-UI commit b659da04, which is from February. 26 | 27 | h2. Getting started 28 | 29 | There is no Maven repo yet, so you'll have to build this yourself with SBT. Then, there is no real documentation or examples yet, so you're on your own. For now, you can take a look at the sample Play 2 application in samples/play2/todolist and in the SampleApiDocumentation trait in the source (src/test/scala/net/eamelink/swaggerkit/play2/WritersSpec.scala). 30 | 31 | h2. License 32 | 33 | This software is licensed under the Apache 2 license, quoted below. 34 | 35 | Copyright 2012 Erik Bakker (http://eamelink.net). 36 | 37 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use this project except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0. 38 | 39 | Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 40 | -------------------------------------------------------------------------------- /play2/src/test/scala/net/eamelink/swaggerkit/play2/WritersSpec.scala: -------------------------------------------------------------------------------- 1 | package net.eamelink.swaggerkit.play2 2 | 3 | import net.eamelink.swaggerkit._ 4 | import net.eamelink.swaggerkit.SimpleTypes._ 5 | import org.specs2.mutable.Specification 6 | import org.specs2.specification.Scope 7 | import play.api.libs.json._ 8 | 9 | class WritersSpec extends Specification with SampleApiDocumentation { 10 | "The JSON output for a resource discovery page" should { 11 | 12 | val json = Writers.ApiDocumentationWriter.writes(apiDoc) 13 | 14 | "contain the base path" in { 15 | (json \ "basePath").as[String] must_== apiDoc.basePath 16 | } 17 | 18 | "contain the swagger version" in { 19 | (json \ "swaggerVersion").as[String] must_== apiDoc.swaggerVersion 20 | } 21 | 22 | "contain the api version" in { 23 | (json \ "apiVersion").as[String] must_== apiDoc.apiVersion 24 | } 25 | 26 | "list the proper number of apis" in { 27 | (json \ "apis").as[List[JsValue]] must have size (1) 28 | } 29 | 30 | "list the resource declaration path for a resource" in { 31 | ((json \ "apis")(0) \ "path").as[String] must_== apiDoc.apis(0).path 32 | } 33 | 34 | "list the description for a resource" in { 35 | ((json \ "apis")(0) \ "description").as[String] must_== apiDoc.apis(0).description 36 | } 37 | } 38 | } 39 | 40 | trait SampleApiDocumentation extends Scope with SchemaBuilder { 41 | lazy val apiDoc = ApiDocumentation( 42 | basePath = "http://api.example.com/", 43 | swaggerVersion = "1.1-SNAPSHOT", 44 | apiVersion = "1", 45 | apis = List(ResourceDeclaration( 46 | path = "/albums.{format}", 47 | description = "Operations on Albums", 48 | resourcePath = "/albums", 49 | basePath = "http://api.example.com/", 50 | swaggerVersion = "1.1-SNAPSHOT", 51 | apiVersion = "1", 52 | apis = List( 53 | albumsApi, albumApi), 54 | models = Map("Album" -> albumSchema)))) 55 | 56 | lazy val albumsApi = Api("/albums") describedBy "An albums API" withOperations (listAlbums, createAlbum) 57 | lazy val albumApi = Api("/album/{albumId}") describedBy "An album API" withOperations (showAlbum, updateAlbum, deleteAlbum) 58 | 59 | lazy val listAlbums = Operation("listAlbums", GET, "List albums") takes ( 60 | QueryParam("query", String) is "Filter by name", 61 | QueryParam("orderBy", String) is "The sort field. Defaults to 'id'" withValues ("id", "title")) // TODO: Maybe add sample data where this is populated by an Enumeration? 62 | 63 | lazy val createAlbum = Operation("createAlbum", POST, "Create a new album") takes ( 64 | BodyParam(albumSchema)) 65 | 66 | lazy val showAlbum = Operation("showAlbum", GET, "Show an album") takes ( 67 | PathParam("albumId", String) is "The album id") note 68 | "This is just a sample note" 69 | 70 | lazy val updateAlbum = Operation("updateAlbum", PUT, "Update an album") takes () // TODO 71 | 72 | lazy val deleteAlbum = Operation("deleteAlbum", DELETE, "Delete an album") takes () // TODO 73 | 74 | lazy val albumSchema = Schema("Album") has ( 75 | "id" -> Integer, 76 | "title" -> String, 77 | "photos" -> Array(photoSchema)) 78 | 79 | lazy val photoSchema = Schema("Photo") has ( 80 | "id" -> Integer, 81 | "title" -> String) 82 | } -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/jquery.ba-bbq.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery BBQ: Back Button & Query Library - v1.2.1 - 2/17/2010 3 | * http://benalman.com/projects/jquery-bbq-plugin/ 4 | * 5 | * Copyright (c) 2010 "Cowboy" Ben Alman 6 | * Dual licensed under the MIT and GPL licenses. 7 | * http://benalman.com/about/license/ 8 | */ 9 | 10 | (function($,p){var i,m=Array.prototype.slice,r=decodeURIComponent,a=$.param,c,l,v,b=$.bbq=$.bbq||{},q,u,j,e=$.event.special,d="hashchange",A="querystring",D="fragment",y="elemUrlAttr",g="location",k="href",t="src",x=/^.*\?|#.*$/g,w=/^.*\#/,h,C={};function E(F){return typeof F==="string"}function B(G){var F=m.call(arguments,1);return function(){return G.apply(this,F.concat(m.call(arguments)))}}function n(F){return F.replace(/^[^#]*#?(.*)$/,"$1")}function o(F){return F.replace(/(?:^[^?#]*\?([^#]*).*$)?.*/,"$1")}function f(H,M,F,I,G){var O,L,K,N,J;if(I!==i){K=F.match(H?/^([^#]*)\#?(.*)$/:/^([^#?]*)\??([^#]*)(#?.*)/);J=K[3]||"";if(G===2&&E(I)){L=I.replace(H?w:x,"")}else{N=l(K[2]);I=E(I)?l[H?D:A](I):I;L=G===2?I:G===1?$.extend({},I,N):$.extend({},N,I);L=a(L);if(H){L=L.replace(h,r)}}O=K[1]+(H?"#":L||!K[1]?"?":"")+L+J}else{O=M(F!==i?F:p[g][k])}return O}a[A]=B(f,0,o);a[D]=c=B(f,1,n);c.noEscape=function(G){G=G||"";var F=$.map(G.split(""),encodeURIComponent);h=new RegExp(F.join("|"),"g")};c.noEscape(",/");$.deparam=l=function(I,F){var H={},G={"true":!0,"false":!1,"null":null};$.each(I.replace(/\+/g," ").split("&"),function(L,Q){var K=Q.split("="),P=r(K[0]),J,O=H,M=0,R=P.split("]["),N=R.length-1;if(/\[/.test(R[0])&&/\]$/.test(R[N])){R[N]=R[N].replace(/\]$/,"");R=R.shift().split("[").concat(R);N=R.length-1}else{N=0}if(K.length===2){J=r(K[1]);if(F){J=J&&!isNaN(J)?+J:J==="undefined"?i:G[J]!==i?G[J]:J}if(N){for(;M<=N;M++){P=R[M]===""?O.length:R[M];O=O[P]=M').hide().insertAfter("body")[0].contentWindow;q=function(){return a(n.document[c][l])};o=function(u,s){if(u!==s){var t=n.document;t.open().close();t[c].hash="#"+u}};o(a())}}m.start=function(){if(r){return}var t=a();o||p();(function s(){var v=a(),u=q(t);if(v!==t){o(t=v,u);$(i).trigger(d)}else{if(u!==t){i[c][l]=i[c][l].replace(/#.*/,"")+"#"+u}}r=setTimeout(s,$[d+"Delay"])})()};m.stop=function(){if(!n){r&&clearTimeout(r);r=0}};return m})()})(jQuery,this); 20 | -------------------------------------------------------------------------------- /core/src/test/scala/net/eamelink/swaggerkit/ModelSpec.scala: -------------------------------------------------------------------------------- 1 | package net.eamelink.swaggerkit 2 | 3 | import SimpleTypes._ 4 | import org.specs2.mutable.Specification 5 | import org.specs2.specification.Scope 6 | 7 | class ModelSpec extends Specification { 8 | 9 | "The SchemaBuilder trait" should { 10 | "provide an implicit conversion from Type to Property" in { 11 | object t extends SchemaBuilder { 12 | val p: Property = Number 13 | } 14 | success 15 | } 16 | } 17 | 18 | "A Type" should { 19 | "have a name" in { 20 | val t: Type = Number 21 | t.name 22 | success 23 | } 24 | } 25 | 26 | "SimpleTypes" should { 27 | "contain all primitives from draft-zyp-json-schema-03" in { 28 | val primitives: Seq[Type] = Seq(String, Number, Integer, Boolean, Object, Any) 29 | success 30 | } 31 | 32 | "have an Array Type constructor that takes a Type as parameter" in { 33 | val primitive: Type = Array(String) 34 | success 35 | } 36 | } 37 | 38 | "A Property" should { 39 | "take a description with 'is'" in { 40 | val p = Property(String) is "Real name" 41 | p.description must_== Some("Real name") 42 | } 43 | 44 | "take allowed values with 'allows'" in { 45 | val p = Property(String) allows ("Mr", "Dr", "Mrs", "Prof") 46 | p.allowableValues must beSome 47 | } 48 | } 49 | 50 | "The HttpMethod trait" should { 51 | "be extended by GET, POST, PUT and DELETE" in { 52 | val methods: Seq[HttpMethod] = List(GET, POST, PUT, DELETE) 53 | success 54 | } 55 | } 56 | 57 | "A Parameter" should { 58 | "have a factory QueryParam" in { 59 | QueryParam("foo", Number).paramType must_== "query" 60 | } 61 | 62 | "have a factory PathParam" in { 63 | PathParam("foo", Number).paramType must_== "path" 64 | } 65 | 66 | "have a factory BodyParam" in { 67 | BodyParam(Number).paramType must_== "body" 68 | } 69 | 70 | "take a description with 'is'" in new SampleParam { 71 | (param is "bar").description must beSome.which(_ == "bar") 72 | } 73 | 74 | "have a switch 'isRequired'" in new SampleParam { 75 | (param isRequired).required must_== true 76 | } 77 | 78 | "have a switch 'isOptional'" in new SampleParam { 79 | (param isOptional).required must_== false 80 | } 81 | 82 | "have a switch 'allowsMultiple'" in new SampleParam { 83 | (param allowsMultiple).allowMultiple must_== true 84 | } 85 | 86 | "have a switch 'noMultiple'" in new SampleParam { 87 | (param noMultiple).allowMultiple must_== false 88 | } 89 | 90 | "take a vararg values in 'withValues'" in new SampleParam { 91 | (param withValues ("a", "b", "c")).allowableValues must beSome 92 | } 93 | 94 | "take an enum with values in 'withValues'" in new SampleParam { 95 | object WeekDay extends Enumeration { 96 | type WeekDay = Value 97 | val Mon, Tue, Wed, Thu, Fri, Sat, Sun = Value 98 | } 99 | (param withValues (WeekDay)).allowableValues must beSome 100 | } 101 | 102 | } 103 | 104 | "An Operation" should { 105 | "take a vararg parameters with 'takes'" in new SampleOperation with SampleParam { 106 | (operation takes param).parameters must contain(param) 107 | } 108 | 109 | "take a note with 'note'" in new SampleOperation { 110 | (operation note "foobar").notes must beSome.which(_ == "foobar") 111 | } 112 | } 113 | 114 | "An Api" should { 115 | "take a description with 'describedBy'" in new SampleApi { 116 | (api describedBy "foobar").description must beSome.which(_ == "foobar") 117 | } 118 | 119 | "take a vararg operations in 'withOperations'" in new SampleApi with SampleOperation { 120 | (api withOperations operation).operations must contain(operation) 121 | } 122 | } 123 | } 124 | 125 | trait SampleParam extends Scope { 126 | val param = QueryParam("foo", Number) 127 | } 128 | 129 | trait SampleOperation extends Scope { 130 | val operation = Operation("foo", GET, "bar") 131 | } 132 | 133 | trait SampleApi extends Scope { 134 | val api = Api("foo") 135 | } -------------------------------------------------------------------------------- /play2/src/main/scala/net/eamelink/swaggerkit/play2/Writers.scala: -------------------------------------------------------------------------------- 1 | package net.eamelink.swaggerkit.play2 2 | 3 | import net.eamelink.swaggerkit._ 4 | import play.api.libs.json._ 5 | import scala.collection.mutable.ListBuffer 6 | 7 | object Writers { 8 | 9 | implicit object ApiDocumentationWriter extends Writes[ApiDocumentation] { 10 | def writes(rl: ApiDocumentation): JsValue = JsObject(List( 11 | "basePath" -> JsString(rl.basePath), 12 | "swaggerVersion" -> JsString(rl.swaggerVersion), 13 | "apiVersion" -> JsString(rl.apiVersion), 14 | "apis" -> JsArray(rl.apis.map(resourceDeclaration => JsObject(List( 15 | "path" -> JsString(resourceDeclaration.path), 16 | "description" -> JsString(resourceDeclaration.description)))).toList))) 17 | } 18 | 19 | implicit object ResourceDeclarationWriter extends Writes[ResourceDeclaration] { 20 | def writes(ad: ResourceDeclaration): JsValue = JsObject(List( 21 | "resourcePath" -> JsString(ad.resourcePath), 22 | "basePath" -> JsString(ad.basePath), 23 | "apiVersion" -> JsString(ad.apiVersion), 24 | "swaggerVersion" -> JsString(ad.swaggerVersion), 25 | "apis" -> JsArray(ad.apis.map(api => ApiWriter.writes(api))), 26 | "models" -> JsObject(ad.models.map(pair => pair._1 -> SchemaWriter.writes(pair._2)).toList))) 27 | } 28 | 29 | object ParameterWriter extends Writes[Parameter] { 30 | 31 | def writes(param: Parameter): JsValue = { 32 | var properties = new ListBuffer[(String, JsValue)] 33 | 34 | param.name.map(n => properties += "name" -> JsString(n)) 35 | param.description.map(d => properties += "description" -> JsString(d)) 36 | 37 | // A boolean is represented by type string, and a list of allowable values 38 | param.dataType.name match { 39 | case "boolean" => { 40 | properties += "dataType" -> JsString("string") 41 | properties += booleanValues 42 | } 43 | case _ => { 44 | properties += "dataType" -> JsString(param.dataType.name) 45 | } 46 | } 47 | 48 | properties += "required" -> JsBoolean(param.required) 49 | properties += "allowMultiple" -> JsBoolean(param.allowMultiple) 50 | properties += "paramType" -> JsString(param.paramType) 51 | if (param.allowableValues.isDefined) { 52 | properties += "allowableValues" -> JsObject(List( 53 | "values" -> JsArray(param.allowableValues.get.map(JsString(_)).toList), 54 | "valueType" -> JsString("LIST"))) 55 | } 56 | param.valueTypeInternal.map(vti => properties += "valueTypeInternal" -> JsString(vti)) 57 | 58 | JsObject(properties) 59 | } 60 | 61 | private val booleanValues = "allowableValues" -> JsObject(List( 62 | "values" -> JsArray(List(JsString("0"), JsString("1"))), 63 | "valueType" -> JsString("LIST"))) 64 | } 65 | 66 | object OperationWriter extends Writes[Operation] { 67 | def writes(op: Operation): JsValue = JsObject(List( 68 | "parameters" -> JsArray(op.parameters.map(param => ParameterWriter.writes(param))), 69 | "httpMethod" -> JsString(op.httpMethod.toString), 70 | "notes" -> JsString(op.notes.getOrElse("")), 71 | "responseTypeInternal" -> JsString(op.responseTypeInternal.getOrElse("")), 72 | "nickname" -> JsString(op.nickName), 73 | "responseClass" -> JsString(op.responseClass.getOrElse("")), 74 | "summary" -> JsString(op.summary))) 75 | } 76 | 77 | object ApiWriter extends Writes[Api] { 78 | def writes(api: Api): JsValue = JsObject(List( 79 | "path" -> JsString(api.path), 80 | "description" -> JsString(api.description.getOrElse("")), 81 | "operations" -> JsArray(api.operations.map(op => OperationWriter.writes(op))))) 82 | } 83 | 84 | object PropertyWriter extends Writes[Property] { 85 | def writes(p: Property): JsValue = JsObject(List( 86 | "type" -> JsString(p.typ.name))) 87 | } 88 | 89 | object SchemaWriter extends Writes[Schema] { 90 | def writes(s: Schema): JsValue = JsObject(List( 91 | "properties" -> { 92 | s.properties match { 93 | case None => JsNull 94 | case Some(properties) => JsObject(properties.map(p => p._1 -> PropertyWriter.writes(p._2)).toList) 95 | } 96 | })) 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /samples/play2/todolist/app/controllers/Todos.scala: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import play.api.mvc._ 4 | import play.api.libs.json._ 5 | import play.api.data.Form 6 | import play.api.data.Form._ 7 | import play.api.data.Forms._ 8 | import net.eamelink.swaggerkit._ 9 | import net.eamelink.swaggerkit.SimpleTypes._ 10 | import models.Todo 11 | import models.formats.DefaultTodo 12 | import api.sorting.OrderDirection 13 | import org.joda.time.DateTime 14 | 15 | object Todos extends Controller { 16 | val dateFormat = "yyyy-MM-dd hh:mm"; 17 | 18 | lazy val todosApi = Api("/todos") describedBy "A todos API" withOperations (listOperation, createOperation) 19 | lazy val todoApi = Api("/todos/{todoId}") describedBy "A todo API" withOperations (showOperation, updateOperation, deleteOperation) 20 | 21 | lazy val listOperation = Operation("listTodos", GET, "Get a list of todos") takes ( 22 | QueryParam("search", String) is "A search query. Searches in the todo text.", 23 | QueryParam("withDone", Boolean) is "Show completed todos as well. Defaults to '0'", 24 | QueryParam("orderBy", String) is "The sort field. Defaults to 'due'" withValues Todo.Order, 25 | QueryParam("direction", String) is "The order direction. Defaults to 'asc'" withValues OrderDirection) note 26 | "This is just a sample note." 27 | 28 | def list(search: Option[String], withDone: Option[Boolean], orderBy: Option[Todo.Order.Value], direction: Option[OrderDirection.Value]) = Action { 29 | Ok(Json.toJson(Todo.find(search.map("%" + _ + "%"), withDone.getOrElse(false), orderBy.getOrElse(Todo.Order.id), direction.getOrElse(OrderDirection.asc)))) 30 | } 31 | 32 | val showOperation = Operation("showTodo", GET, "Get a todo") takes ( 33 | PathParam("todoId", String) is "The todo id") note 34 | "And this is another sample note." 35 | 36 | def show(todoId: Long) = Action { implicit request => 37 | Todo.findById(todoId).map { todo => 38 | Ok(Json.toJson(todo)) 39 | }.getOrElse[Result](NotFound) 40 | } 41 | 42 | val createOperation = Operation("createTodo", POST, "Create a todo") takes ( 43 | BodyParam(DefaultTodo.schema) is "The Todo item you want to create") note 44 | "This method returns the created todo item, and a Location header pointing to its url." 45 | 46 | def create() = Action { implicit request => 47 | val createForm = Form( 48 | tuple( 49 | "text" -> text, 50 | "due" -> date(dateFormat), 51 | "done" -> boolean)) 52 | createForm.bindFromRequest.fold( 53 | formWithErrors => Forbidden(formWithErrors.errorsAsJson), 54 | value => { 55 | val createdTodo = Todo.insert( 56 | Todo(value._1, new DateTime(value._2.getTime), value._3)) 57 | Created(Json.toJson(createdTodo)).withHeaders( 58 | LOCATION -> routes.Todos.show(createdTodo.id).toString()) 59 | }) 60 | } 61 | 62 | val updateOperation = Operation("updateTodo", PUT, "Update a todo") takes ( 63 | PathParam("todoId", String) is "The id of the todo to update", 64 | BodyParam(DefaultTodo.schema)) note 65 | "This operation returns the updated todo item, and a Location header pointing to its url." 66 | 67 | def update(todoId: Long) = Action { implicit request => 68 | 69 | Todo.findById(todoId).map { existingTodo => 70 | val updateForm = Form( 71 | tuple( 72 | "text" -> text, 73 | "done" -> boolean, 74 | "due" -> date(dateFormat))) 75 | 76 | val json = request.body.asJson.get.asInstanceOf[JsObject] 77 | 78 | updateForm.bindFromRequest.fold( 79 | formWithErrors => Forbidden(formWithErrors.errorsAsJson), 80 | value => { 81 | val updatedTodo = existingTodo.copy( 82 | text = value._1) 83 | Ok(Json.toJson(updatedTodo)).withHeaders( 84 | LOCATION -> routes.Todos.show(updatedTodo.id).toString()) 85 | }) 86 | }.getOrElse(NotFound) 87 | } 88 | 89 | lazy val deleteOperation = Operation("deleteTodo", DELETE, "Delete a todo item") takes ( 90 | PathParam("todoId", String) is "The id of the todo to delete") note 91 | "This method returns a 204 when successful, a 404 when the todo item was not found." 92 | 93 | def delete(todoId: Long) = Action { 94 | Todo.findById(todoId).map{ todo => 95 | Todo.delete(todo.id) 96 | NoContent 97 | }.getOrElse(NotFound) 98 | } 99 | } -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/doc.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // Helper function for vertically aligning DOM elements 4 | // http://www.seodenver.com/simple-vertical-align-plugin-for-jquery/ 5 | $.fn.vAlign = function() { 6 | return this.each(function(i){ 7 | var ah = $(this).height(); 8 | var ph = $(this).parent().height(); 9 | var mh = (ph - ah) / 2; 10 | $(this).css('margin-top', mh); 11 | }); 12 | }; 13 | 14 | $.fn.stretchFormtasticInputWidthToParent = function() { 15 | return this.each(function(i){ 16 | var p_width = $(this).closest("form").innerWidth(); 17 | var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest("form").css('padding-right'), 10); 18 | var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10); 19 | $(this).css('width', p_width - p_padding - this_padding); 20 | }); 21 | }; 22 | 23 | $('form.formtastic li.string input, form.formtastic textarea').stretchFormtasticInputWidthToParent(); 24 | 25 | // Vertically center these paragraphs 26 | // Parent may need a min-height for this to work.. 27 | $('ul.downplayed li div.content p').vAlign(); 28 | 29 | // When a sandbox form is submitted.. 30 | $("form.sandbox").submit(function(){ 31 | 32 | var error_free = true; 33 | 34 | // Cycle through the forms required inputs 35 | $(this).find("input.required").each(function() { 36 | 37 | // Remove any existing error styles from the input 38 | $(this).removeClass('error'); 39 | 40 | // Tack the error style on if the input is empty.. 41 | if ($(this).val() == '') { 42 | $(this).addClass('error'); 43 | $(this).wiggle(); 44 | error_free = false; 45 | } 46 | 47 | }); 48 | 49 | return error_free; 50 | }); 51 | 52 | }); 53 | 54 | function clippyCopiedCallback(a) { 55 | $('#api_key_copied').fadeIn().delay(1000).fadeOut(); 56 | 57 | // var b = $("#clippy_tooltip_" + a); 58 | // b.length != 0 && (b.attr("title", "copied!").trigger("tipsy.reload"), setTimeout(function() { 59 | // b.attr("title", "copy to clipboard") 60 | // }, 61 | // 500)) 62 | } 63 | 64 | // Logging function that accounts for browsers that don't have window.console 65 | function log() { 66 | if (window.console) console.log.apply(console,arguments); 67 | } 68 | 69 | var Docs = { 70 | 71 | shebang: function() { 72 | 73 | // If shebang has an operation nickname in it.. 74 | // e.g. /docs/#!/words/get_search 75 | var fragments = $.param.fragment().split('/'); 76 | fragments.shift(); // get rid of the bang 77 | 78 | switch (fragments.length) { 79 | case 1: 80 | // Expand all operations for the resource and scroll to it 81 | log('shebang resource:' + fragments[0]); 82 | var dom_id = 'resource_' + fragments[0]; 83 | 84 | Docs.expandEndpointListForResource(fragments[0]); 85 | $("#"+dom_id).slideto({highlight: false}); 86 | break; 87 | case 2: 88 | // Refer to the endpoint DOM element, e.g. #words_get_search 89 | log('shebang endpoint: ' + fragments.join('_')); 90 | 91 | // Expand Resource 92 | Docs.expandEndpointListForResource(fragments[0]); 93 | $("#"+dom_id).slideto({highlight: false}); 94 | 95 | // Expand operation 96 | var li_dom_id = fragments.join('_'); 97 | var li_content_dom_id = li_dom_id + "_content"; 98 | 99 | log("li_dom_id " + li_dom_id); 100 | log("li_content_dom_id " + li_content_dom_id); 101 | 102 | Docs.expandOperation($('#'+li_content_dom_id)); 103 | $('#'+li_dom_id).slideto({highlight: false}); 104 | break; 105 | } 106 | 107 | }, 108 | 109 | toggleEndpointListForResource: function(resource) { 110 | var elem = $('li#resource_' + resource + ' ul.endpoints'); 111 | if (elem.is(':visible')) { 112 | Docs.collapseEndpointListForResource(resource); 113 | } else { 114 | Docs.expandEndpointListForResource(resource); 115 | } 116 | }, 117 | 118 | // Expand resource 119 | expandEndpointListForResource: function(resource) { 120 | $('#resource_' + resource).addClass('active'); 121 | 122 | var elem = $('li#resource_' + resource + ' ul.endpoints'); 123 | elem.slideDown(); 124 | }, 125 | 126 | // Collapse resource and mark as explicitly closed 127 | collapseEndpointListForResource: function(resource) { 128 | $('#resource_' + resource).removeClass('active'); 129 | 130 | var elem = $('li#resource_' + resource + ' ul.endpoints'); 131 | elem.slideUp(); 132 | }, 133 | 134 | expandOperationsForResource: function(resource) { 135 | // Make sure the resource container is open.. 136 | Docs.expandEndpointListForResource(resource); 137 | $('li#resource_' + resource + ' li.operation div.content').each(function() { 138 | Docs.expandOperation($(this)); 139 | }); 140 | }, 141 | 142 | collapseOperationsForResource: function(resource) { 143 | // Make sure the resource container is open.. 144 | Docs.expandEndpointListForResource(resource); 145 | $('li#resource_' + resource + ' li.operation div.content').each(function() { 146 | Docs.collapseOperation($(this)); 147 | }); 148 | }, 149 | 150 | expandOperation: function(elem) { 151 | elem.slideDown(); 152 | }, 153 | 154 | collapseOperation: function(elem) { 155 | elem.slideUp(); 156 | }, 157 | 158 | toggleOperationContent: function(dom_id) { 159 | var elem = $('#' + dom_id); 160 | (elem.is(':visible')) ? Docs.collapseOperation(elem) : Docs.expandOperation(elem); 161 | } 162 | 163 | }; 164 | -------------------------------------------------------------------------------- /core/src/main/scala/net/eamelink/swaggerkit/domain.scala: -------------------------------------------------------------------------------- 1 | package net.eamelink.swaggerkit 2 | 3 | /** 4 | * Container for the entire API documentation. 5 | * 6 | * This is a model for the resource discovery page. 7 | */ 8 | case class ApiDocumentation( 9 | basePath: String, 10 | swaggerVersion: String, 11 | apiVersion: String, 12 | apis: List[ResourceDeclaration]) 13 | 14 | /** 15 | * Resource declaration, lists api's and model's for a given resource. 16 | */ 17 | case class ResourceDeclaration( 18 | // Properties shown on the resource discovery page. 19 | path: String, 20 | description: String, 21 | 22 | // Properties shown on the page for the given resource. 23 | resourcePath: String, 24 | basePath: String, 25 | swaggerVersion: String, 26 | apiVersion: String, 27 | apis: List[Api], 28 | models: Map[String, Schema]) 29 | 30 | object ResourceDeclaration { 31 | /** 32 | * Resource declaration constructor that finds all models in operations. 33 | */ 34 | def apply(path: String, description: String, resourcePath: String, basePath: String, swaggerVersion: String, apiVersion: String, apis: List[Api]): ResourceDeclaration = 35 | ResourceDeclaration(path, description, resourcePath, basePath, swaggerVersion, apiVersion, apis, findModels(apis)) 36 | 37 | /** 38 | * Find models that are references by the list of Api. 39 | * 40 | * Currently only looks for parameters, not operation return types. 41 | */ 42 | private def findModels(apis: List[Api]): Map[String, Schema] = { 43 | apis.flatMap { api => 44 | api.operations.flatMap { operation => 45 | operation.parameters.map(_.dataType).collect { 46 | case schema: Schema => (schema.name -> schema) 47 | } 48 | } 49 | }.toMap 50 | } 51 | } 52 | 53 | /** 54 | * API, collection of operations on the same URL 55 | */ 56 | case class Api( 57 | path: String, 58 | description: Option[String] = None, 59 | operations: List[Operation] = Nil) { 60 | 61 | def describedBy(description: String) = copy(description = Some(description)) 62 | def withOperations(ops: Operation*) = copy(operations = ops.toList) 63 | } 64 | 65 | /** 66 | * Http operation on a given url 67 | */ 68 | case class Operation( 69 | nickName: String, 70 | httpMethod: HttpMethod, 71 | summary: String, 72 | parameters: List[Parameter] = Nil, 73 | notes: Option[String] = None, 74 | responseTypeInternal: Option[String] = None, 75 | responseClass: Option[String] = None) { 76 | 77 | def takes(params: Parameter*) = copy(parameters = params.toList) 78 | def note(note: String) = copy(notes = Some(note)) 79 | } 80 | 81 | /** 82 | * Http request parameter 83 | */ 84 | case class Parameter( 85 | name: Option[String], 86 | description: Option[String] = None, 87 | dataType: Type, 88 | required: Boolean = false, 89 | valueTypeInternal: Option[String] = None, 90 | allowMultiple: Boolean = false, 91 | allowableValues: Option[Seq[String]] = None, 92 | paramType: String) { 93 | 94 | def is(description: String) = copy(description = Some(description)) 95 | def isRequired() = copy(required = true) 96 | def isOptional() = copy(required = false) 97 | def allowsMultiple() = copy(allowMultiple = true) 98 | def noMultiple() = copy(allowMultiple = false) 99 | def withValues(values: String*) = copy(allowableValues = Some(values)) 100 | def withValues(enum: Enumeration) = copy(allowableValues = Some(enum.values.map(_.toString).toList)) 101 | } 102 | 103 | /** 104 | * Factory for 'query' request parameters 105 | */ 106 | object QueryParam { 107 | def apply(name: String, dataType: Type) = Parameter(name = Some(name), dataType = dataType, paramType = "query", allowableValues = None) 108 | } 109 | 110 | /** 111 | * Factory for 'path' request parameters 112 | */ 113 | object PathParam { 114 | def apply(name: String, dataType: Type) = Parameter(name = Some(name), dataType = dataType, paramType = "path", required = true, allowableValues = None) 115 | } 116 | 117 | /** 118 | * Factory for 'body' request parameters 119 | */ 120 | object BodyParam { 121 | def apply(dataType: Type) = Parameter(None, dataType = dataType, paramType = "body", required = true) 122 | } 123 | 124 | /** 125 | * Http methods: GET, POST etc. 126 | */ 127 | sealed trait HttpMethod 128 | case object GET extends HttpMethod 129 | case object POST extends HttpMethod 130 | case object PUT extends HttpMethod 131 | case object DELETE extends HttpMethod 132 | 133 | /** 134 | * A description of a complex type. 135 | */ 136 | case class Schema(name: String, properties: Option[Map[String, Property]] = None) extends Type { 137 | def has(props: (String, Property)*) = copy(properties = Some(props.toMap)) 138 | } 139 | 140 | /** 141 | * A property of a Schema. 142 | */ 143 | case class Property( 144 | typ: Type, 145 | description: Option[String] = None, 146 | allowableValues: Option[Seq[String]] = None) { 147 | 148 | def is(description: String) = copy(description = Some(description)) 149 | def allows(vals: String*) = copy(allowableValues = Some(vals.toSeq)) 150 | } 151 | 152 | /** 153 | * A property type from a 'model' in the Swagger output. 154 | * 155 | * This can be a Simple type, or a Schema. In Swagger, for a Schema just the name is outputted. 156 | */ 157 | trait Type { 158 | def name: String 159 | } 160 | 161 | /** 162 | * Predefined primitives, or "Simple Types" as the spec calls them 163 | * 164 | * @see http://tools.ietf.org/html/draft-zyp-json-schema-03 section 5.1 165 | */ 166 | object SimpleTypes { 167 | object String extends Type { val name = "string" } 168 | object Number extends Type { val name = "number" } 169 | object Integer extends Type { val name = "integer" } 170 | object Boolean extends Type { val name = "boolean" } 171 | object Object extends Type { val name = "object" } 172 | object Any extends Type { val name = "any" } 173 | case class Array(innerType: Type) extends Type { def name = "Array[" + innerType.name + "]" } 174 | } -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Swagger API Explorer 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 24 |
25 |
    26 |
    27 | 54 | 58 | 111 | 119 | 138 | 148 | 154 | 160 |
    161 | Enter the base URL of the API that you wish to explore, or try 162 | localhost:9000/api 163 |
    164 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/underscore-min.js: -------------------------------------------------------------------------------- 1 | // Underscore.js 1.1.7 2 | // (c) 2011 Jeremy Ashkenas, DocumentCloud Inc. 3 | // Underscore is freely distributable under the MIT license. 4 | // Portions of Underscore are inspired or borrowed from Prototype, 5 | // Oliver Steele's Functional, and John Resig's Micro-Templating. 6 | // For all details and documentation: 7 | // http://documentcloud.github.com/underscore 8 | (function(){var p=this,C=p._,m={},i=Array.prototype,n=Object.prototype,f=i.slice,D=i.unshift,E=n.toString,l=n.hasOwnProperty,s=i.forEach,t=i.map,u=i.reduce,v=i.reduceRight,w=i.filter,x=i.every,y=i.some,o=i.indexOf,z=i.lastIndexOf;n=Array.isArray;var F=Object.keys,q=Function.prototype.bind,b=function(a){return new j(a)};typeof module!=="undefined"&&module.exports?(module.exports=b,b._=b):p._=b;b.VERSION="1.1.7";var h=b.each=b.forEach=function(a,c,b){if(a!=null)if(s&&a.forEach===s)a.forEach(c,b);else if(a.length=== 9 | +a.length)for(var e=0,k=a.length;e=e.computed&&(e={value:a,computed:b})});return e.value};b.min=function(a, 13 | c,d){if(!c&&b.isArray(a))return Math.min.apply(Math,a);var e={computed:Infinity};h(a,function(a,b,f){b=c?c.call(d,a,b,f):a;bd?1:0}),"value")};b.groupBy=function(a,b){var d={};h(a,function(a,f){var g=b(a,f);(d[g]||(d[g]=[])).push(a)});return d};b.sortedIndex=function(a,c,d){d|| 14 | (d=b.identity);for(var e=0,f=a.length;e>1;d(a[g])=0})})};b.difference=function(a,c){return b.filter(a,function(a){return!b.include(c,a)})};b.zip=function(){for(var a=f.call(arguments),c=b.max(b.pluck(a,"length")),d=Array(c),e=0;e=0;d--)b=[a[d].apply(this,b)];return b[0]}};b.after= 20 | function(a,b){return function(){if(--a<1)return b.apply(this,arguments)}};b.keys=F||function(a){if(a!==Object(a))throw new TypeError("Invalid object");var b=[],d;for(d in a)l.call(a,d)&&(b[b.length]=d);return b};b.values=function(a){return b.map(a,b.identity)};b.functions=b.methods=function(a){var c=[],d;for(d in a)b.isFunction(a[d])&&c.push(d);return c.sort()};b.extend=function(a){h(f.call(arguments,1),function(b){for(var d in b)b[d]!==void 0&&(a[d]=b[d])});return a};b.defaults=function(a){h(f.call(arguments, 21 | 1),function(b){for(var d in b)a[d]==null&&(a[d]=b[d])});return a};b.clone=function(a){return b.isArray(a)?a.slice():b.extend({},a)};b.tap=function(a,b){b(a);return a};b.isEqual=function(a,c){if(a===c)return!0;var d=typeof a;if(d!=typeof c)return!1;if(a==c)return!0;if(!a&&c||a&&!c)return!1;if(a._chain)a=a._wrapped;if(c._chain)c=c._wrapped;if(a.isEqual)return a.isEqual(c);if(c.isEqual)return c.isEqual(a);if(b.isDate(a)&&b.isDate(c))return a.getTime()===c.getTime();if(b.isNaN(a)&&b.isNaN(c))return!1; 22 | if(b.isRegExp(a)&&b.isRegExp(c))return a.source===c.source&&a.global===c.global&&a.ignoreCase===c.ignoreCase&&a.multiline===c.multiline;if(d!=="object")return!1;if(a.length&&a.length!==c.length)return!1;d=b.keys(a);var e=b.keys(c);if(d.length!=e.length)return!1;for(var f in a)if(!(f in c)||!b.isEqual(a[f],c[f]))return!1;return!0};b.isEmpty=function(a){if(b.isArray(a)||b.isString(a))return a.length===0;for(var c in a)if(l.call(a,c))return!1;return!0};b.isElement=function(a){return!!(a&&a.nodeType== 23 | 1)};b.isArray=n||function(a){return E.call(a)==="[object Array]"};b.isObject=function(a){return a===Object(a)};b.isArguments=function(a){return!(!a||!l.call(a,"callee"))};b.isFunction=function(a){return!(!a||!a.constructor||!a.call||!a.apply)};b.isString=function(a){return!!(a===""||a&&a.charCodeAt&&a.substr)};b.isNumber=function(a){return!!(a===0||a&&a.toExponential&&a.toFixed)};b.isNaN=function(a){return a!==a};b.isBoolean=function(a){return a===!0||a===!1};b.isDate=function(a){return!(!a||!a.getTimezoneOffset|| 24 | !a.setUTCFullYear)};b.isRegExp=function(a){return!(!a||!a.test||!a.exec||!(a.ignoreCase||a.ignoreCase===!1))};b.isNull=function(a){return a===null};b.isUndefined=function(a){return a===void 0};b.noConflict=function(){p._=C;return this};b.identity=function(a){return a};b.times=function(a,b,d){for(var e=0;e/g,interpolate:/<%=([\s\S]+?)%>/g}; 25 | b.template=function(a,c){var d=b.templateSettings;d="var __p=[],print=function(){__p.push.apply(__p,arguments);};with(obj||{}){__p.push('"+a.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(d.interpolate,function(a,b){return"',"+b.replace(/\\'/g,"'")+",'"}).replace(d.evaluate||null,function(a,b){return"');"+b.replace(/\\'/g,"'").replace(/[\r\n\t]/g," ")+"__p.push('"}).replace(/\r/g,"\\r").replace(/\n/g,"\\n").replace(/\t/g,"\\t")+"');}return __p.join('');";d=new Function("obj",d);return c?d(c):d}; 26 | var j=function(a){this._wrapped=a};b.prototype=j.prototype;var r=function(a,c){return c?b(a).chain():a},H=function(a,c){j.prototype[a]=function(){var a=f.call(arguments);D.call(a,this._wrapped);return r(c.apply(b,a),this._chain)}};b.mixin(b);h(["pop","push","reverse","shift","sort","splice","unshift"],function(a){var b=i[a];j.prototype[a]=function(){b.apply(this._wrapped,arguments);return r(this._wrapped,this._chain)}});h(["concat","join","slice"],function(a){var b=i[a];j.prototype[a]=function(){return r(b.apply(this._wrapped, 27 | arguments),this._chain)}});j.prototype.chain=function(){this._chain=!0;return this};j.prototype.value=function(){return this._wrapped}})(); 28 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/swagger-ui.js: -------------------------------------------------------------------------------- 1 | jQuery(function($) { 2 | 3 | // this.baseUrl = "http://petstore.swagger.wordnik.com/api/resources.json"; 4 | // this.apiKey = "special-key"; 5 | 6 | var ApiSelectionController = Spine.Controller.create({ 7 | proxied: ["showApi"], 8 | 9 | baseUrlList: new Array(), 10 | 11 | init: function() { 12 | if (this.supportsLocalStorage()) { 13 | var baseUrl = localStorage.getItem("com.wordnik.swagger.ui.baseUrl"); 14 | var apiKey = localStorage.getItem("com.wordnik.swagger.ui.apiKey"); 15 | 16 | if (baseUrl && baseUrl.length > 0) 17 | $("#input_baseUrl").val(baseUrl); 18 | 19 | if (apiKey && apiKey.length > 0) 20 | $("#input_apiKey").val(apiKey); 21 | 22 | } else { 23 | log("localStorage not supported, user will need to specifiy the api url"); 24 | } 25 | 26 | $("a#explore").click(this.showApi); 27 | 28 | this.adaptToScale(); 29 | $(window).resize(function() { 30 | apiSelectionController.adaptToScale(); 31 | }); 32 | 33 | this.handleEnter(); 34 | }, 35 | 36 | handleEnter: function(){ 37 | var self = this; 38 | var submit = function() { 39 | self.showApi(); 40 | }; 41 | $('#input_baseUrl').keydown(function(e) { 42 | if(e.which != 13) return; 43 | submit(); 44 | }); 45 | $('#input_apiKey').keydown(function(e) { 46 | if(e.which != 13) return; 47 | submit(); 48 | }); 49 | }, 50 | 51 | adaptToScale: function() { 52 | // var form_width = $('form#api_selector').width(); 53 | // var inputs_width = 0; 54 | // $('form#api_selector div.input').each( function(){ inputs_width += $(this).outerWidth(); }); 55 | // 56 | // // Update with of baseUrl input 57 | // var free_width = form_width - inputs_width; 58 | // $('#input_baseUrl').width($('#input_baseUrl').width() + free_width - 50); 59 | }, 60 | 61 | 62 | slapOn: function() { 63 | // messageController.showMessage("Please enter the base URL of the API that you wish to explore."); 64 | $("#content_message").show(); 65 | $("#resources_container").hide(); 66 | this.showApi(); 67 | }, 68 | 69 | supportsLocalStorage: function() { 70 | try { 71 | return 'localStorage' in window && window['localStorage'] !== null; 72 | } catch(e) { 73 | return false; 74 | } 75 | }, 76 | 77 | showApi: function() { 78 | var baseUrl = jQuery.trim($("#input_baseUrl").val()); 79 | var apiKey = jQuery.trim($("#input_apiKey").val()); 80 | if (baseUrl.length == 0) { 81 | $("#input_baseUrl").wiggle(); 82 | } else { 83 | if (this.supportsLocalStorage()) { 84 | localStorage.setItem("com.wordnik.swagger.ui.apiKey", apiKey); 85 | localStorage.setItem("com.wordnik.swagger.ui.baseUrl", baseUrl); 86 | } 87 | var resourceListController = ResourceListController.init({ 88 | baseUrl: baseUrl, 89 | apiKey: apiKey 90 | }); 91 | } 92 | } 93 | }); 94 | 95 | var MessageController = Spine.Controller.create({ 96 | showMessage: function(msg) { 97 | if (msg) { 98 | $("#content_message").html(msg); 99 | $("#content_message").show(); 100 | } else { 101 | $("#content_message").html(""); 102 | $("#content_message").hide(); 103 | } 104 | 105 | }, 106 | 107 | clearMessage: function() { 108 | this.showMessage(); 109 | } 110 | }); 111 | var messageController = MessageController.init(); 112 | 113 | // The following heirarchy is followed by these view controllers 114 | // ResourceListController 115 | // >>> ResourceController 116 | // >>> ApiController 117 | // >>> OperationController 118 | var ResourceListController = Spine.Controller.create({ 119 | proxied: ["addAll", "addOne"], 120 | 121 | ApiResource: null, 122 | 123 | init: function() { 124 | if (this.baseUrl == null) { 125 | throw new Error("A baseUrl must be passed to ResourceListController"); 126 | } 127 | 128 | $("#content_message").hide(); 129 | $("#resources_container").hide(); 130 | $("#resources").html(""); 131 | 132 | // create and initialize SwaggerService 133 | var swaggerService = new SwaggerService(this.baseUrl, this.apiKey, 134 | function(msg) { 135 | if (msg) 136 | messageController.showMessage(msg); 137 | else 138 | messageController.showMessage("Fetching remote JSON..."); 139 | }); 140 | 141 | // $("#api_host_url").html(swaggerService.apiHost()); 142 | 143 | swaggerService.init(); 144 | 145 | // Create convenience references to Spine models 146 | this.ApiResource = swaggerService.ApiResource(); 147 | 148 | this.ApiResource.bind("refresh", this.addAll); 149 | }, 150 | 151 | addAll: function() { 152 | this.ApiResource.each(this.addOne); 153 | messageController.clearMessage(); 154 | $("#resources_container").slideDown(function() { 155 | setTimeout(function() { 156 | Docs.shebang(); 157 | }, 158 | 400); 159 | }); 160 | }, 161 | 162 | addOne: function(apiResource) { 163 | ResourceController.init({ 164 | item: apiResource, 165 | container: "#resources" 166 | }); 167 | } 168 | }); 169 | 170 | var ResourceController = Spine.Controller.create({ 171 | proxied: ["renderApi", "renderOperation"], 172 | 173 | templateName: "#resourceTemplate", 174 | apiResource: null, 175 | apiList: null, 176 | modelList: null, 177 | 178 | init: function() { 179 | this.render(); 180 | this.apiResource = this.item; 181 | this.apiList = this.apiResource.apiList; 182 | this.modelList = this.apiResource.modelList; 183 | this.apiList.each(this.renderApi); 184 | }, 185 | 186 | render: function() { 187 | $(this.templateName).tmpl(this.item).appendTo(this.container); 188 | $('#colophon').fadeIn(); 189 | }, 190 | 191 | renderApi: function(api) { 192 | var resourceApisContainer = "#" + this.apiResource.name + "_endpoint_list"; 193 | ApiController.init({ 194 | item: api, 195 | container: resourceApisContainer 196 | }); 197 | 198 | } 199 | 200 | }); 201 | 202 | 203 | var ApiController = Spine.Controller.create({ 204 | proxied: ["renderOperation"], 205 | 206 | api: null, 207 | templateName: "#apiTemplate", 208 | 209 | init: function() { 210 | this.render(); 211 | 212 | this.api = this.item; 213 | 214 | this.api.operations.each(this.renderOperation); 215 | }, 216 | 217 | render: function() { 218 | $(this.templateName).tmpl(this.item).appendTo(this.container); 219 | }, 220 | 221 | renderOperation: function(operation) { 222 | var operationsContainer = "#" + this.api.name + "_endpoint_operations"; 223 | OperationController.init({ 224 | item: operation, 225 | container: operationsContainer 226 | }); 227 | } 228 | }); 229 | 230 | 231 | // Param Model 232 | // ---------------------------------------------------------------------------------------------- 233 | var Param = Spine.Model.setup( 234 | "Param", 235 | ["name", "defaultValue", 'description', 'required', 'dataType', 'allowableValues', 'paramType', 'allowMultiple', "readOnly"] 236 | ); 237 | 238 | Param.include({ 239 | 240 | cleanup: function() { 241 | this.defaultValue = this.defaultValue || ''; 242 | }, 243 | 244 | templateName: function(){ 245 | var n = "#paramTemplate"; 246 | 247 | if (this.allowableValues && this.allowableValues.valueType == "LIST") { 248 | n += "Select"; 249 | } else { 250 | if (this.required) n += "Required"; 251 | if (this.readOnly) n += "ReadOnly"; 252 | } 253 | 254 | return(n); 255 | } 256 | 257 | }); 258 | 259 | 260 | var OperationController = Spine.Controller.create({ 261 | proxied: ["submitOperation", "showResponse", "showErrorStatus", "showCompleteStatus"], 262 | 263 | operation: null, 264 | templateName: "#operationTemplate", 265 | elementScope: "#operationTemplate", 266 | 267 | init: function() { 268 | this.render(); 269 | 270 | this.operation = this.item; 271 | this.isGetOperation = (this.operation.httpMethodLowercase == "get"); 272 | this.elementScope = "#" + this.operation.apiName + "_" + this.operation.nickname + "_" + this.operation.httpMethod; 273 | 274 | this.renderParams(); 275 | }, 276 | 277 | render: function() { 278 | $(this.templateName).tmpl(this.item).appendTo(this.container); 279 | }, 280 | 281 | renderParams: function() { 282 | if (this.operation.parameters && this.operation.parameters.count() > 0) { 283 | var operationParamsContainer = this.elementScope + "_params"; 284 | 285 | for (var p = 0; p < this.operation.parameters.count(); p++) { 286 | var param = Param.init(this.operation.parameters.all()[p]); 287 | // Only GET operations display forms.. 288 | param.readOnly = !this.isGetOperation; 289 | param.cleanup(); 290 | 291 | $(param.templateName()).tmpl(param).appendTo(operationParamsContainer); 292 | } 293 | } 294 | 295 | var submitButtonId = this.elementScope + "_content_sandbox_response_button"; 296 | if (this.isGetOperation) { 297 | $(submitButtonId).click(this.submitOperation); 298 | } else { 299 | $(submitButtonId).hide(); 300 | 301 | var valueHeader = this.elementScope + "_value_header"; 302 | $(valueHeader).html("Default Value"); 303 | } 304 | 305 | }, 306 | 307 | submitOperation: function() { 308 | var form = $(this.elementScope + "_form"); 309 | var error_free = true; 310 | var missing_input = null; 311 | 312 | // Cycle through the form's required inputs 313 | form.find("input.required").each(function() { 314 | 315 | // Remove any existing error styles from the input 316 | $(this).removeClass('error'); 317 | 318 | // Tack the error style on if the input is empty.. 319 | if ($(this).val() == '') { 320 | if (missing_input == null) 321 | missing_input = $(this); 322 | $(this).addClass('error'); 323 | $(this).wiggle(); 324 | error_free = false; 325 | } 326 | 327 | }); 328 | 329 | if (error_free) { 330 | var invocationUrl = this.operation.invocationUrl(form.serializeArray()); 331 | $(".request_url", this.elementScope + "_content_sandbox_response").html("
    " + invocationUrl + "
    "); 332 | $.getJSON(invocationUrl, this.showResponse).complete(this.showCompleteStatus).error(this.showErrorStatus); 333 | } 334 | 335 | }, 336 | 337 | showResponse: function(response) { 338 | // log(response); 339 | var prettyJson = JSON.stringify(response, null, "\t").replace(/\n/g, "
    "); 340 | // log(prettyJson); 341 | $(".response_body", this.elementScope + "_content_sandbox_response").html(prettyJson); 342 | 343 | $(this.elementScope + "_content_sandbox_response").slideDown(); 344 | }, 345 | 346 | showErrorStatus: function(data) { 347 | // log("error " + data.status); 348 | this.showStatus(data); 349 | $(this.elementScope + "_content_sandbox_response").slideDown(); 350 | }, 351 | 352 | showCompleteStatus: function(data) { 353 | // log("complete " + data.status); 354 | this.showStatus(data); 355 | }, 356 | 357 | showStatus: function(data) { 358 | // log(data); 359 | // log(data.getAllResponseHeaders()); 360 | var response_body = "
    " + JSON.stringify(JSON.parse(data.responseText), null, 2).replace(/\n/g, "
    ") + "
    "; 361 | $(".response_code", this.elementScope + "_content_sandbox_response").html("
    " + data.status + "
    "); 362 | $(".response_body", this.elementScope + "_content_sandbox_response").html(response_body); 363 | $(".response_headers", this.elementScope + "_content_sandbox_response").html("
    " + data.getAllResponseHeaders() + "
    "); 364 | } 365 | 366 | }); 367 | 368 | // Attach controller to window* 369 | window.apiSelectionController = ApiSelectionController.init(); 370 | 371 | if (this.baseUrl) { 372 | window.resourceListController = ResourceListController.init({ 373 | baseUrl: this.baseUrl, 374 | apiKey: this.apiKey 375 | }); 376 | } else { 377 | apiSelectionController.slapOn(); 378 | } 379 | 380 | }); 381 | 382 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/spine.js: -------------------------------------------------------------------------------- 1 | (function(){ 2 | 3 | var Spine; 4 | if (typeof exports !== "undefined") { 5 | Spine = exports; 6 | } else { 7 | Spine = this.Spine = {}; 8 | } 9 | 10 | Spine.version = "0.0.4"; 11 | 12 | var $ = Spine.$ = this.jQuery || this.Zepto || function(){ return arguments[0]; }; 13 | 14 | var makeArray = Spine.makeArray = function(args){ 15 | return Array.prototype.slice.call(args, 0); 16 | }; 17 | 18 | var isArray = Spine.isArray = function(value){ 19 | return Object.prototype.toString.call(value) == "[object Array]"; 20 | }; 21 | 22 | // Shim Array, as these functions aren't in IE 23 | if (typeof Array.prototype.indexOf === "undefined") 24 | Array.prototype.indexOf = function(value){ 25 | for ( var i = 0; i < this.length; i++ ) 26 | if ( this[ i ] === value ) 27 | return i; 28 | return -1; 29 | }; 30 | 31 | var Events = Spine.Events = { 32 | bind: function(ev, callback) { 33 | var evs = ev.split(" "); 34 | var calls = this._callbacks || (this._callbacks = {}); 35 | 36 | for (var i=0; i < evs.length; i++) 37 | (this._callbacks[evs[i]] || (this._callbacks[evs[i]] = [])).push(callback); 38 | 39 | return this; 40 | }, 41 | 42 | trigger: function() { 43 | var args = makeArray(arguments); 44 | var ev = args.shift(); 45 | 46 | var list, calls, i, l; 47 | if (!(calls = this._callbacks)) return false; 48 | if (!(list = this._callbacks[ev])) return false; 49 | 50 | for (i = 0, l = list.length; i < l; i++) 51 | if (list[i].apply(this, args) === false) 52 | break; 53 | 54 | return true; 55 | }, 56 | 57 | unbind: function(ev, callback){ 58 | if ( !ev ) { 59 | this._callbacks = {}; 60 | return this; 61 | } 62 | 63 | var list, calls, i, l; 64 | if (!(calls = this._callbacks)) return this; 65 | if (!(list = this._callbacks[ev])) return this; 66 | 67 | if ( !callback ) { 68 | delete this._callbacks[ev]; 69 | return this; 70 | } 71 | 72 | for (i = 0, l = list.length; i < l; i++) 73 | if (callback === list[i]) { 74 | list.splice(i, 1); 75 | break; 76 | } 77 | 78 | return this; 79 | } 80 | }; 81 | 82 | var Log = Spine.Log = { 83 | trace: true, 84 | 85 | logPrefix: "(App)", 86 | 87 | log: function(){ 88 | if ( !this.trace ) return; 89 | if (typeof console == "undefined") return; 90 | var args = makeArray(arguments); 91 | if (this.logPrefix) args.unshift(this.logPrefix); 92 | console.log.apply(console, args); 93 | return this; 94 | } 95 | }; 96 | 97 | // Classes (or prototypial inheritors) 98 | 99 | if (typeof Object.create !== "function") 100 | Object.create = function(o) { 101 | function F() {} 102 | F.prototype = o; 103 | return new F(); 104 | }; 105 | 106 | var moduleKeywords = ["included", "extended"]; 107 | 108 | var Class = Spine.Class = { 109 | inherited: function(){}, 110 | created: function(){}, 111 | 112 | prototype: { 113 | initialize: function(){}, 114 | init: function(){} 115 | }, 116 | 117 | create: function(include, extend){ 118 | var object = Object.create(this); 119 | object.parent = this; 120 | object.prototype = object.fn = Object.create(this.prototype); 121 | 122 | if (include) object.include(include); 123 | if (extend) object.extend(extend); 124 | 125 | object.created(); 126 | this.inherited(object); 127 | return object; 128 | }, 129 | 130 | init: function(){ 131 | var instance = Object.create(this.prototype); 132 | instance.parent = this; 133 | 134 | instance.initialize.apply(instance, arguments); 135 | instance.init.apply(instance, arguments); 136 | return instance; 137 | }, 138 | 139 | proxy: function(func){ 140 | var thisObject = this; 141 | return(function(){ 142 | return func.apply(thisObject, arguments); 143 | }); 144 | }, 145 | 146 | proxyAll: function(){ 147 | var functions = makeArray(arguments); 148 | for (var i=0; i < functions.length; i++) 149 | this[functions[i]] = this.proxy(this[functions[i]]); 150 | }, 151 | 152 | include: function(obj){ 153 | for(var key in obj) 154 | if (moduleKeywords.indexOf(key) == -1) 155 | this.fn[key] = obj[key]; 156 | 157 | var included = obj.included; 158 | if (included) included.apply(this); 159 | return this; 160 | }, 161 | 162 | extend: function(obj){ 163 | for(var key in obj) 164 | if (moduleKeywords.indexOf(key) == -1) 165 | this[key] = obj[key]; 166 | 167 | var extended = obj.extended; 168 | if (extended) extended.apply(this); 169 | return this; 170 | } 171 | }; 172 | 173 | Class.prototype.proxy = Class.proxy; 174 | Class.prototype.proxyAll = Class.proxyAll; 175 | Class.instancet = Class.init; 176 | Class.sub = Class.create; 177 | 178 | // Models 179 | 180 | Spine.guid = function(){ 181 | return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { 182 | var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8); 183 | return v.toString(16); 184 | }).toUpperCase(); 185 | }; 186 | 187 | var Model = Spine.Model = Class.create(); 188 | 189 | Model.extend(Events); 190 | 191 | Model.extend({ 192 | setup: function(name, atts){ 193 | var model = Model.sub(); 194 | if (name) model.name = name; 195 | if (atts) model.attributes = atts; 196 | return model; 197 | }, 198 | 199 | created: function(sub){ 200 | this.records = {}; 201 | this.attributes = this.attributes ? 202 | makeArray(this.attributes) : []; 203 | }, 204 | 205 | find: function(id){ 206 | var record = this.records[id]; 207 | if ( !record ) throw("Unknown record"); 208 | return record.clone(); 209 | }, 210 | 211 | exists: function(id){ 212 | try { 213 | return this.find(id); 214 | } catch (e) { 215 | return false; 216 | } 217 | }, 218 | 219 | refresh: function(values){ 220 | values = this.fromJSON(values); 221 | this.records = {}; 222 | 223 | for (var i=0, il = values.length; i < il; i++) { 224 | var record = values[i]; 225 | record.newRecord = false; 226 | record.id = record.id || Spine.guid(); 227 | this.records[record.id] = record; 228 | } 229 | 230 | this.trigger("refresh"); 231 | return this; 232 | }, 233 | 234 | // adeed by ayush 235 | createAll: function(values){ 236 | values = this.fromJSON(values); 237 | for (var i=0, il = values.length; i < il; i++) { 238 | var record = values[i]; 239 | record.newRecord = false; 240 | record.id = record.id || Spine.guid(); 241 | this.records[record.id] = record; 242 | } 243 | 244 | return this; 245 | }, 246 | 247 | select: function(callback){ 248 | var result = []; 249 | 250 | for (var key in this.records) 251 | if (callback(this.records[key])) 252 | result.push(this.records[key]); 253 | 254 | return this.cloneArray(result); 255 | }, 256 | 257 | findByAttribute: function(name, value){ 258 | for (var key in this.records) 259 | if (this.records[key][name] == value) 260 | return this.records[key].clone(); 261 | }, 262 | 263 | findAllByAttribute: function(name, value){ 264 | return(this.select(function(item){ 265 | return(item[name] == value); 266 | })); 267 | }, 268 | 269 | each: function(callback){ 270 | for (var key in this.records) 271 | callback(this.records[key]); 272 | }, 273 | 274 | all: function(){ 275 | return this.cloneArray(this.recordsValues()); 276 | }, 277 | 278 | first: function(){ 279 | var record = this.recordsValues()[0]; 280 | return(record && record.clone()); 281 | }, 282 | 283 | last: function(){ 284 | var values = this.recordsValues(); 285 | var record = values[values.length - 1]; 286 | return(record && record.clone()); 287 | }, 288 | 289 | count: function(){ 290 | return this.recordsValues().length; 291 | }, 292 | 293 | deleteAll: function(){ 294 | for (var key in this.records) 295 | delete this.records[key]; 296 | }, 297 | 298 | destroyAll: function(){ 299 | for (var key in this.records) 300 | this.records[key].destroy(); 301 | }, 302 | 303 | update: function(id, atts){ 304 | this.find(id).updateAttributes(atts); 305 | }, 306 | 307 | create: function(atts){ 308 | var record = this.init(atts); 309 | return record.save(); 310 | }, 311 | 312 | destroy: function(id){ 313 | this.find(id).destroy(); 314 | }, 315 | 316 | sync: function(callback){ 317 | this.bind("change", callback); 318 | }, 319 | 320 | fetch: function(callbackOrParams){ 321 | typeof(callbackOrParams) == "function" ? 322 | this.bind("fetch", callbackOrParams) : 323 | this.trigger("fetch", callbackOrParams); 324 | }, 325 | 326 | toJSON: function(){ 327 | return this.recordsValues(); 328 | }, 329 | 330 | fromJSON: function(objects){ 331 | if ( !objects ) return; 332 | if ( typeof objects == "string" ) 333 | objects = JSON.parse(objects); 334 | if ( isArray(objects) ) { 335 | var results = []; 336 | for (var i=0; i < objects.length; i++) 337 | results.push(this.init(objects[i])); 338 | return results; 339 | } else { 340 | return this.init(objects); 341 | } 342 | }, 343 | 344 | // Private 345 | 346 | recordsValues: function(){ 347 | var result = []; 348 | for (var key in this.records) 349 | result.push(this.records[key]); 350 | return result; 351 | }, 352 | 353 | cloneArray: function(array){ 354 | var result = []; 355 | for (var i=0; i < array.length; i++) 356 | result.push(array[i].clone()); 357 | return result; 358 | }, 359 | 360 | // added by ayush 361 | logAll: function() { 362 | for(var i = 0; i < this.all().length; i++) { 363 | var e = this.all()[i]; 364 | if(window.console) console.log(e.toString()); 365 | } 366 | } 367 | 368 | }); 369 | 370 | Model.include({ 371 | model: true, 372 | newRecord: true, 373 | 374 | init: function(atts){ 375 | if (atts) this.load(atts); 376 | this.trigger("init", this); 377 | }, 378 | 379 | isNew: function(){ 380 | return this.newRecord; 381 | }, 382 | 383 | isValid: function(){ 384 | return(!this.validate()); 385 | }, 386 | 387 | validate: function(){ }, 388 | 389 | load: function(atts){ 390 | for(var name in atts) 391 | this[name] = atts[name]; 392 | }, 393 | 394 | attributes: function(){ 395 | var result = {}; 396 | for (var i=0; i < this.parent.attributes.length; i++) { 397 | var attr = this.parent.attributes[i]; 398 | result[attr] = this[attr]; 399 | } 400 | result.id = this.id; 401 | return result; 402 | }, 403 | 404 | eql: function(rec){ 405 | return(rec && rec.id === this.id && 406 | rec.parent === this.parent); 407 | }, 408 | 409 | save: function(){ 410 | var error = this.validate(); 411 | if ( error ) { 412 | this.trigger("error", this, error); 413 | return false; 414 | } 415 | 416 | this.trigger("beforeSave", this); 417 | this.newRecord ? this.create() : this.update(); 418 | this.trigger("save", this); 419 | return this; 420 | }, 421 | 422 | updateAttribute: function(name, value){ 423 | this[name] = value; 424 | return this.save(); 425 | }, 426 | 427 | updateAttributes: function(atts){ 428 | this.load(atts); 429 | return this.save(); 430 | }, 431 | 432 | destroy: function(){ 433 | this.trigger("beforeDestroy", this); 434 | delete this.parent.records[this.id]; 435 | this.destroyed = true; 436 | this.trigger("destroy", this); 437 | this.trigger("change", this, "destroy"); 438 | }, 439 | 440 | dup: function(){ 441 | var result = this.parent.init(this.attributes()); 442 | result.newRecord = this.newRecord; 443 | return result; 444 | }, 445 | 446 | clone: function(){ 447 | return Object.create(this); 448 | }, 449 | 450 | reload: function(){ 451 | if ( this.newRecord ) return this; 452 | var original = this.parent.find(this.id); 453 | this.load(original.attributes()); 454 | return original; 455 | }, 456 | 457 | toJSON: function(){ 458 | return(this.attributes()); 459 | }, 460 | 461 | exists: function(){ 462 | return(this.id && this.id in this.parent.records); 463 | }, 464 | 465 | // Private 466 | 467 | update: function(){ 468 | this.trigger("beforeUpdate", this); 469 | var records = this.parent.records; 470 | records[this.id].load(this.attributes()); 471 | var clone = records[this.id].clone(); 472 | this.trigger("update", clone); 473 | this.trigger("change", clone, "update"); 474 | }, 475 | 476 | create: function(){ 477 | this.trigger("beforeCreate", this); 478 | if ( !this.id ) this.id = Spine.guid(); 479 | this.newRecord = false; 480 | var records = this.parent.records; 481 | records[this.id] = this.dup(); 482 | var clone = records[this.id].clone(); 483 | this.trigger("create", clone); 484 | this.trigger("change", clone, "create"); 485 | }, 486 | 487 | bind: function(events, callback){ 488 | return this.parent.bind(events, this.proxy(function(record){ 489 | if ( record && this.eql(record) ) 490 | callback.apply(this, arguments); 491 | })); 492 | }, 493 | 494 | trigger: function(){ 495 | return this.parent.trigger.apply(this.parent, arguments); 496 | } 497 | }); 498 | 499 | // Controllers 500 | 501 | var eventSplitter = /^(\w+)\s*(.*)$/; 502 | 503 | var Controller = Spine.Controller = Class.create({ 504 | tag: "div", 505 | 506 | initialize: function(options){ 507 | this.options = options; 508 | 509 | for (var key in this.options) 510 | this[key] = this.options[key]; 511 | 512 | if (!this.el) this.el = document.createElement(this.tag); 513 | this.el = $(this.el); 514 | 515 | if ( !this.events ) this.events = this.parent.events; 516 | if ( !this.elements ) this.elements = this.parent.elements; 517 | 518 | if (this.events) this.delegateEvents(); 519 | if (this.elements) this.refreshElements(); 520 | if (this.proxied) this.proxyAll.apply(this, this.proxied); 521 | }, 522 | 523 | $: function(selector){ 524 | return $(selector, this.el); 525 | }, 526 | 527 | delegateEvents: function(){ 528 | for (var key in this.events) { 529 | var methodName = this.events[key]; 530 | var method = this.proxy(this[methodName]); 531 | 532 | var match = key.match(eventSplitter); 533 | var eventName = match[1], selector = match[2]; 534 | 535 | if (selector === '') { 536 | this.el.bind(eventName, method); 537 | } else { 538 | this.el.delegate(selector, eventName, method); 539 | } 540 | } 541 | }, 542 | 543 | refreshElements: function(){ 544 | for (var key in this.elements) { 545 | this[this.elements[key]] = this.$(key); 546 | } 547 | }, 548 | 549 | delay: function(func, timeout){ 550 | setTimeout(this.proxy(func), timeout || 0); 551 | } 552 | }); 553 | 554 | Controller.include(Events); 555 | Controller.include(Log); 556 | 557 | Spine.App = Class.create(); 558 | Spine.App.extend(Events); 559 | Controller.fn.App = Spine.App; 560 | })(); 561 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/swagger-service.js: -------------------------------------------------------------------------------- 1 | function SwaggerService(discoveryUrl, _apiKey, statusCallback) { 2 | if (!discoveryUrl) 3 | throw new Error("discoveryUrl must be passed while creating SwaggerService"); 4 | 5 | // constants 6 | discoveryUrl = jQuery.trim(discoveryUrl); 7 | if (discoveryUrl.length == 0) 8 | throw new Error("discoveryUrl must be passed while creating SwaggerService"); 9 | 10 | if (! (discoveryUrl.toLowerCase().indexOf("http:") == 0 || discoveryUrl.toLowerCase().indexOf("https:") == 0)) { 11 | discoveryUrl = ("http://" + discoveryUrl); 12 | } 13 | 14 | var globalBasePath = null; 15 | var formatString = ".{format}"; 16 | var statusListener = statusCallback; 17 | var apiKey = _apiKey; 18 | 19 | var apiKeySuffix = ""; 20 | if (apiKey) { 21 | apiKey = jQuery.trim(apiKey); 22 | if (apiKey.length > 0) 23 | apiKeySuffix = "?api_key=" + apiKey; 24 | } 25 | 26 | function log() { 27 | if (window.console) console.log.apply(console,arguments); 28 | } 29 | 30 | function error(m) { 31 | log("ERROR: " + m); 32 | } 33 | 34 | function updateStatus(status) { 35 | statusListener(status); 36 | } 37 | 38 | function endsWith(str, suffix) { 39 | return str.indexOf(suffix, str.length - suffix.length) !== -1; 40 | } 41 | 42 | // make some models public 43 | this.ApiResource = function() { 44 | return ApiResource; 45 | }; 46 | 47 | this.apiHost = function() { 48 | return globalBasePath; 49 | }; 50 | 51 | this.formatString = function() { 52 | return formatString; 53 | }; 54 | 55 | // Model: ApiResource 56 | var ApiResource = Spine.Model.setup("ApiResource", ["name", "baseUrl", "path", "path_json", "path_xml", "description", "apiLists", "modelList"]); 57 | ApiResource.include({ 58 | path_json: null, 59 | path_xml: null, 60 | 61 | init: function(atts) { 62 | if (atts) this.load(atts); 63 | this.path_json = this.path.replace("{format}", "json"); 64 | this.path_xml = this.path.replace("{format}", "xml"); 65 | this.baseUrl = globalBasePath; 66 | //execluded 9 letters to remove .{format} from name 67 | this.name = this.path.split("/"); 68 | this.name = this.name[this.name.length - 1]; 69 | this.name = this.name.replace(".{format}",'').replace(/\//g, "_"); 70 | // this.name = this.path.substr(1, this.path.length - formatString.length - 1).replace(/\//g, "_"); 71 | this.apiList = Api.sub(); 72 | this.modelList = ApiModel.sub(); 73 | }, 74 | 75 | addApis: function(apiObjects, basePath) { 76 | // log("apiObjects: %o", apiObjects); 77 | this.apiList.createAll(apiObjects); 78 | this.apiList.each(function(api) { 79 | api.setBaseUrl(basePath); 80 | }); 81 | }, 82 | 83 | addModel: function(modelObject) { 84 | this.modelList.create(modelObject); 85 | }, 86 | 87 | toString: function() { 88 | return this.path_json + ": " + this.description; 89 | } 90 | }); 91 | 92 | // Model: Api 93 | var Api = Spine.Model.setup("Api", ["baseUrl", "path", "path_json", "path_xml", "name", "description", "operations", "path_json", "path_xml"]); 94 | Api.include({ 95 | init: function(atts) { 96 | if (atts) this.load(atts); 97 | 98 | var secondPathSeperatorIndex = this.path.indexOf("/", 1); 99 | if (secondPathSeperatorIndex > 0) { 100 | var prefix = this.path.substr(0, secondPathSeperatorIndex); 101 | var suffix = this.path.substr(secondPathSeperatorIndex, this.path.length); 102 | // log(this.path + ":: " + prefix + "..." + suffix); 103 | this.path_json = prefix.replace("{format}", "json") + suffix; 104 | this.path_xml = prefix.replace("{format}", "xml") + suffix;; 105 | 106 | if (this.path.indexOf("/") == 0) { 107 | this.name = this.path.substr(1, secondPathSeperatorIndex - formatString.length - 1); 108 | } else { 109 | this.name = this.path.substr(0, secondPathSeperatorIndex - formatString.length - 1); 110 | } 111 | } else { 112 | this.path_json = this.path.replace("{format}", "json"); 113 | this.path_xml = this.path.replace("{format}", "xml"); 114 | 115 | if (this.path.indexOf("/") == 0) { 116 | this.name = this.path.substr(1, this.path.length - formatString.length - 1); 117 | } else { 118 | this.name = this.path.substr(0, this.path.length - formatString.length - 1); 119 | } 120 | } 121 | 122 | var value = this.operations; 123 | 124 | this.operations = ApiOperation.sub(); 125 | if (value) { 126 | for (var i = 0; i < value.length; i++) { 127 | var obj = value[i]; 128 | obj.apiName = this.name; 129 | obj.path = this.path; 130 | obj.path_json = this.path_json; 131 | obj.path_xml = this.path_xml; 132 | 133 | } 134 | 135 | this.operations.refresh(value); 136 | } 137 | 138 | updateStatus("Loading " + this.path + "..."); 139 | 140 | }, 141 | 142 | setBaseUrl: function(u) { 143 | this.baseUrl = u; 144 | this.operations.each(function(o) { 145 | o.baseUrl = u; 146 | }); 147 | }, 148 | 149 | toString: function() { 150 | var opsString = ""; 151 | for (var i = 0; i < this.operations.all().length; i++) { 152 | var e = this.operations.all()[i]; 153 | 154 | if (opsString.length > 0) 155 | opsString += ", "; 156 | 157 | opsString += e.toString(); 158 | } 159 | return this.path_json + "- " + this.operations.all().length + " operations: " + opsString; 160 | } 161 | 162 | }); 163 | 164 | // Model: ApiOperation 165 | var ApiOperation = Spine.Model.setup("ApiOperation", ["baseUrl", "path", "path_json", "path_xml", "summary", "notes", "deprecated", "open", "httpMethod", "httpMethodLowercase", "nickname", "responseClass", "parameters", "apiName"]); 166 | ApiOperation.include({ 167 | init: function(atts) { 168 | if (atts) this.load(atts); 169 | 170 | this.httpMethodLowercase = this.httpMethod.toLowerCase(); 171 | 172 | var value = this.parameters; 173 | this.parameters = ApiParameter.sub(); 174 | if (value) this.parameters.refresh(value); 175 | }, 176 | 177 | toString: function() { 178 | var paramsString = "("; 179 | for (var i = 0; i < this.parameters.all().length; i++) { 180 | var e = this.parameters.all()[i]; 181 | 182 | if (paramsString.length > 1) 183 | paramsString += ", "; 184 | 185 | paramsString += e.toString(); 186 | } 187 | paramsString += ")"; 188 | 189 | return "{" + this.path_json + "| " + this.nickname + paramsString + ": " + this.summary + "}"; 190 | }, 191 | 192 | invocationUrl: function(formValues) { 193 | var formValuesMap = new Object(); 194 | for (var i = 0; i < formValues.length; i++) { 195 | var formValue = formValues[i]; 196 | if (formValue.value && jQuery.trim(formValue.value).length > 0) 197 | formValuesMap[formValue.name] = formValue.value; 198 | } 199 | 200 | var urlTemplateText = this.path_json.split("{").join("${"); 201 | // log("url template = " + urlTemplateText); 202 | var urlTemplate = $.template(null, urlTemplateText); 203 | var url = $.tmpl(urlTemplate, formValuesMap)[0].data; 204 | // log("url with path params = " + url); 205 | 206 | var queryParams = apiKeySuffix; 207 | this.parameters.each(function(param) { 208 | var paramValue = jQuery.trim(formValuesMap[param.name]); 209 | if (param.paramType == "query" && paramValue.length > 0) { 210 | queryParams += queryParams.length > 0 ? "&": "?"; 211 | queryParams += param.name; 212 | queryParams += "="; 213 | queryParams += formValuesMap[param.name]; 214 | } 215 | }); 216 | 217 | url = this.baseUrl + url + queryParams; 218 | // log("final url with query params and base url = " + url); 219 | 220 | return url; 221 | } 222 | 223 | }); 224 | 225 | // Model: ApiParameter 226 | var ApiParameter = Spine.Model.setup("ApiParameter", ["name", "description", "required", "dataType", "allowableValues", "paramType", "allowMultiple"]); 227 | ApiParameter.include({ 228 | init: function(atts) { 229 | if (atts) this.load(atts); 230 | 231 | this.name = this.name || this.dataType; 232 | 233 | if(this.allowableValues){ 234 | var value = this.allowableValues; 235 | if(value.valueType == "LIST"){ 236 | this.allowableValues = AllowableListValues.sub(); 237 | } else if (value.valueType == "RANGE"){ 238 | this.allowableValues = AllowableRangeValues.sub(); 239 | } 240 | if (value) this.allowableValues = this.allowableValues.create(value); 241 | } 242 | }, 243 | 244 | toString: function() { 245 | if (this.allowableValues) 246 | return this.name + ": " + this.dataType + " " + this.allowableValues; 247 | else 248 | return this.name + ": " + this.dataType; 249 | } 250 | 251 | }); 252 | 253 | var AllowableListValues = Spine.Model.setup("AllowableListValues", ["valueType", "values"]); 254 | AllowableListValues.include({ 255 | init: function(atts) { 256 | if (atts) this.load(atts); 257 | this.name = "allowableValues"; 258 | }, 259 | toString: function() { 260 | if (this.values) 261 | return "["+this.values+"]"; 262 | else 263 | return ""; 264 | } 265 | }); 266 | 267 | var AllowableRangeValues = Spine.Model.setup("AllowableRangeValues", ["valueType", "inclusive", "min", "max"]); 268 | AllowableRangeValues.include({ 269 | init: function(atts) { 270 | if (atts) this.load(atts); 271 | this.name = "allowableValues"; 272 | }, 273 | 274 | toString: function() { 275 | if (this.min && this.max) 276 | return "[" + min + "," + max + "]"; 277 | else 278 | return ""; 279 | } 280 | }); 281 | 282 | 283 | // Model: ApiModel 284 | var ApiModel = Spine.Model.setup("ApiModel", ["id", "fields"]); 285 | ApiModel.include({ 286 | init: function(atts) { 287 | if (atts) this.load(atts); 288 | 289 | if (!this.fields) { 290 | var propertiesListObject = this.properties; 291 | this.fields = ApiModelProperty.sub(); 292 | 293 | for (var propName in propertiesListObject) { 294 | if (propName != "parent") { 295 | var p = propertiesListObject[propName]; 296 | p.name = propName; 297 | p.id = Spine.guid(); 298 | // log(p); 299 | this.fields.create(p); 300 | } 301 | } 302 | //log("got " + this.fields.count() + " fields for " + this.id); 303 | } 304 | }, 305 | 306 | toString: function() { 307 | var propsString = ""; 308 | 309 | propsString += "("; 310 | for (var i = 0; i < this.fields.all().length; i++) { 311 | var e = this.fields.all()[i]; 312 | 313 | if (propsString.length > 1) 314 | propsString += ", "; 315 | 316 | propsString += e.toString(); 317 | } 318 | propsString += ")"; 319 | 320 | if (this.required) 321 | return this.id + " (required): " + propsString; 322 | else 323 | return this.id + ": " + propsString; 324 | } 325 | 326 | }); 327 | 328 | 329 | // Model: ApiModelProperty 330 | var ApiModelProperty = Spine.Model.setup("ApiModelProperty", ["name", "required", "dataType"]); 331 | ApiModelProperty.include({ 332 | init: function(atts) { 333 | if (atts) this.load(atts); 334 | 335 | if (!this.dataType) { 336 | if (atts.type == "any") 337 | this.dataType = "object"; 338 | else if (atts.type == "array") { 339 | if (atts.items) { 340 | if (atts.items.$ref) { 341 | this.dataType = "array[" + atts.items.$ref + "]"; 342 | } else { 343 | this.dataType = "array[" + atts.items.type + "]"; 344 | } 345 | } else { 346 | this.dataType = "array"; 347 | } 348 | } else 349 | this.dataType = atts.type; 350 | 351 | } 352 | }, 353 | 354 | toString: function() { 355 | if (this.required) 356 | return this.name + ": " + this.dataType + " (required)"; 357 | else 358 | return this.name + ": " + this.dataType; 359 | } 360 | 361 | }); 362 | 363 | // Controller 364 | var ModelController = Spine.Controller.create({ 365 | countLoaded: 0, 366 | proxied: ["fetchResources", "loadResources", "apisLoaded", "modelsLoaded"], 367 | discoveryUrlList: [], 368 | discoveryUrlListCursor: 0, 369 | 370 | init: function() { 371 | // log("ModelController.init"); 372 | 373 | this.fetchEndpoints(); 374 | }, 375 | 376 | fetchEndpoints: function() { 377 | updateStatus("Fetching API List..."); 378 | var baseDiscoveryUrl = endsWith(discoveryUrl, "/") ? discoveryUrl.substr(0, discoveryUrl.length - 1) : discoveryUrl; 379 | if(endsWith(baseDiscoveryUrl, "/resources.json")) 380 | baseDiscoveryUrl = baseDiscoveryUrl.substr(0, baseDiscoveryUrl.length - "/resources.json".length); 381 | else if(endsWith(baseDiscoveryUrl, "/resources")) 382 | baseDiscoveryUrl = baseDiscoveryUrl.substr(0, baseDiscoveryUrl.length - "/resources".length); 383 | 384 | this.discoveryUrlList.push(discoveryUrl); 385 | this.discoveryUrlList.push(baseDiscoveryUrl); 386 | this.discoveryUrlList.push(baseDiscoveryUrl + "/resources.json"); 387 | this.discoveryUrlList.push(baseDiscoveryUrl + "/resources"); 388 | 389 | log("Will try the following urls to discover api endpoints:") 390 | for(var i = 0; i < this.discoveryUrlList.length; i++) 391 | log(" > " + this.discoveryUrlList[i]); 392 | 393 | this.fetchEndpointsSeq(); 394 | }, 395 | 396 | fetchEndpointsSeq: function() { 397 | var controller = this; 398 | 399 | if(this.discoveryUrlListCursor < this.discoveryUrlList.length) { 400 | var url = this.discoveryUrlList[this.discoveryUrlListCursor++] 401 | updateStatus("Fetching API List from " + url); 402 | log("Trying url " + url); 403 | $.getJSON(url + apiKeySuffix, function(response) { 404 | }) 405 | .success(function(response) { 406 | log("Setting globalBasePath to " + response.basePath); 407 | globalBasePath = response.basePath; 408 | ApiResource.createAll(response.apis); 409 | controller.fetchResources(response.basePath); 410 | }) 411 | .error(function(response) { 412 | controller.fetchEndpointsSeq(); 413 | }); 414 | } else { 415 | log ('Error with resource discovery. Exhaused all possible endpoint urls'); 416 | 417 | var urlsTried = ""; 418 | for(var i = 0; i < this.discoveryUrlList.length; i++) { 419 | urlsTried = urlsTried + "
    " + this.discoveryUrlList[i]; 420 | } 421 | 422 | updateStatus("Unable to fetch API Listing. Tried the following urls:" + urlsTried); 423 | } 424 | }, 425 | 426 | fetchResources: function(basePath) { 427 | log("fetchResources: basePath = " + basePath); 428 | //ApiResource.logAll(); 429 | for (var i = 0; i < ApiResource.all().length; i++) { 430 | var apiResource = ApiResource.all()[i]; 431 | this.fetchResource(apiResource); 432 | } 433 | }, 434 | 435 | fetchResource: function(apiResource) { 436 | var controller = this; 437 | updateStatus("Fetching " + apiResource.name + "..."); 438 | var resourceUrl = globalBasePath + apiResource.path_json + apiKeySuffix; 439 | log("resourceUrl: %o", resourceUrl); 440 | $.getJSON(resourceUrl, 441 | function(response) { 442 | controller.loadResources(response, apiResource); 443 | }); 444 | }, 445 | 446 | loadResources: function(response, apiResource) { 447 | try { 448 | this.countLoaded++; 449 | // log(response); 450 | if (response.apis) { 451 | apiResource.addApis(response.apis, response.basePath); 452 | } 453 | // updateStatus("Parsed Apis"); 454 | //log(response.models); 455 | if (response.models) { 456 | // log("response.models.length = " + response.models.length); 457 | for (var modeName in response.models) { 458 | var m = response.models[modeName]; 459 | // log("creating " + m.id); 460 | apiResource.addModel(m); 461 | // apiResource.modelList.create(m); 462 | } 463 | } 464 | 465 | updateStatus(); 466 | } finally { 467 | if (this.countLoaded == ApiResource.count()) { 468 | // log("all models/api loaded"); 469 | ApiResource.trigger("refresh"); 470 | } 471 | } 472 | } 473 | 474 | }); 475 | 476 | this.init = function() { 477 | this.modelController = ModelController.init(); 478 | }; 479 | }; 480 | 481 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/jquery.tmpl.js: -------------------------------------------------------------------------------- 1 | /* 2 | * jQuery Templating Plugin 3 | * Copyright 2010, John Resig 4 | * Dual licensed under the MIT or GPL Version 2 licenses. 5 | */ 6 | 7 | (function(jQuery, undefined) { 8 | var oldManip = jQuery.fn.domManip, tmplItmAtt = "_tmplitem", htmlExpr = /^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /, 9 | newTmplItems = {}, wrappedItems = {}, appendToTmplItems, topTmplItem = { key: 0, data: {} }, itemKey = 0, cloneIndex = 0, stack = []; 10 | 11 | function newTmplItem(options, parentItem, fn, data) { 12 | // Returns a template item data structure for a new rendered instance of a template (a 'template item'). 13 | // The content field is a hierarchical array of strings and nested items (to be 14 | // removed and replaced by nodes field of dom elements, once inserted in DOM). 15 | var newItem = { 16 | data: data || (parentItem ? parentItem.data : {}), 17 | _wrap: parentItem ? parentItem._wrap : null, 18 | tmpl: null, 19 | parent: parentItem || null, 20 | nodes: [], 21 | calls: tiCalls, 22 | nest: tiNest, 23 | wrap: tiWrap, 24 | html: tiHtml, 25 | update: tiUpdate 26 | }; 27 | if (options) { 28 | jQuery.extend(newItem, options, { nodes: [], parent: parentItem }); 29 | } 30 | if (fn) { 31 | // Build the hierarchical content to be used during insertion into DOM 32 | newItem.tmpl = fn; 33 | newItem._ctnt = newItem._ctnt || newItem.tmpl(jQuery, newItem); 34 | newItem.key = ++itemKey; 35 | // Keep track of new template item, until it is stored as jQuery Data on DOM element 36 | (stack.length ? wrappedItems : newTmplItems)[itemKey] = newItem; 37 | } 38 | return newItem; 39 | } 40 | 41 | // Override appendTo etc., in order to provide support for targeting multiple elements. (This code would disappear if integrated in jquery core). 42 | jQuery.each({ 43 | appendTo: "append", 44 | prependTo: "prepend", 45 | insertBefore: "before", 46 | insertAfter: "after", 47 | replaceAll: "replaceWith" 48 | }, function(name, original) { 49 | jQuery.fn[ name ] = function(selector) { 50 | var ret = [], insert = jQuery(selector), elems, i, l, tmplItems, 51 | parent = this.length === 1 && this[0].parentNode; 52 | 53 | appendToTmplItems = newTmplItems || {}; 54 | if (parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1) { 55 | insert[ original ](this[0]); 56 | ret = this; 57 | } else { 58 | for (i = 0,l = insert.length; i < l; i++) { 59 | cloneIndex = i; 60 | elems = (i > 0 ? this.clone(true) : this).get(); 61 | jQuery.fn[ original ].apply(jQuery(insert[i]), elems); 62 | ret = ret.concat(elems); 63 | } 64 | cloneIndex = 0; 65 | ret = this.pushStack(ret, name, insert.selector); 66 | } 67 | tmplItems = appendToTmplItems; 68 | appendToTmplItems = null; 69 | jQuery.tmpl.complete(tmplItems); 70 | return ret; 71 | }; 72 | }); 73 | 74 | jQuery.fn.extend({ 75 | // Use first wrapped element as template markup. 76 | // Return wrapped set of template items, obtained by rendering template against data. 77 | tmpl: function(data, options, parentItem) { 78 | return jQuery.tmpl(this[0], data, options, parentItem); 79 | }, 80 | 81 | // Find which rendered template item the first wrapped DOM element belongs to 82 | tmplItem: function() { 83 | return jQuery.tmplItem(this[0]); 84 | }, 85 | 86 | // Consider the first wrapped element as a template declaration, and get the compiled template or store it as a named template. 87 | template: function(name) { 88 | return jQuery.template(name, this[0]); 89 | }, 90 | 91 | domManip: function(args, table, callback, options) { 92 | // This appears to be a bug in the appendTo, etc. implementation 93 | // it should be doing .call() instead of .apply(). See #6227 94 | if (args[0] && args[0].nodeType) { 95 | var dmArgs = jQuery.makeArray(arguments), argsLength = args.length, i = 0, tmplItem; 96 | while (i < argsLength && !(tmplItem = jQuery.data(args[i++], "tmplItem"))) { 97 | } 98 | if (argsLength > 1) { 99 | dmArgs[0] = [jQuery.makeArray(args)]; 100 | } 101 | if (tmplItem && cloneIndex) { 102 | dmArgs[2] = function(fragClone) { 103 | // Handler called by oldManip when rendered template has been inserted into DOM. 104 | jQuery.tmpl.afterManip(this, fragClone, callback); 105 | }; 106 | } 107 | oldManip.apply(this, dmArgs); 108 | } else { 109 | oldManip.apply(this, arguments); 110 | } 111 | cloneIndex = 0; 112 | if (!appendToTmplItems) { 113 | jQuery.tmpl.complete(newTmplItems); 114 | } 115 | return this; 116 | } 117 | }); 118 | 119 | jQuery.extend({ 120 | // Return wrapped set of template items, obtained by rendering template against data. 121 | tmpl: function(tmpl, data, options, parentItem) { 122 | var ret, topLevel = !parentItem; 123 | if (topLevel) { 124 | // This is a top-level tmpl call (not from a nested template using {{tmpl}}) 125 | parentItem = topTmplItem; 126 | tmpl = jQuery.template[tmpl] || jQuery.template(null, tmpl); 127 | wrappedItems = {}; // Any wrapped items will be rebuilt, since this is top level 128 | } else if (!tmpl) { 129 | // The template item is already associated with DOM - this is a refresh. 130 | // Re-evaluate rendered template for the parentItem 131 | tmpl = parentItem.tmpl; 132 | newTmplItems[parentItem.key] = parentItem; 133 | parentItem.nodes = []; 134 | if (parentItem.wrapped) { 135 | updateWrapped(parentItem, parentItem.wrapped); 136 | } 137 | // Rebuild, without creating a new template item 138 | return jQuery(build(parentItem, null, parentItem.tmpl(jQuery, parentItem))); 139 | } 140 | if (!tmpl) { 141 | return []; // Could throw... 142 | } 143 | if (typeof data === "function") { 144 | data = data.call(parentItem || {}); 145 | } 146 | if (options && options.wrapped) { 147 | updateWrapped(options, options.wrapped); 148 | } 149 | ret = jQuery.isArray(data) ? 150 | jQuery.map(data, function(dataItem) { 151 | return dataItem ? newTmplItem(options, parentItem, tmpl, dataItem) : null; 152 | }) : 153 | [ newTmplItem(options, parentItem, tmpl, data) ]; 154 | return topLevel ? jQuery(build(parentItem, null, ret)) : ret; 155 | }, 156 | 157 | // Return rendered template item for an element. 158 | tmplItem: function(elem) { 159 | var tmplItem; 160 | if (elem instanceof jQuery) { 161 | elem = elem[0]; 162 | } 163 | while (elem && elem.nodeType === 1 && !(tmplItem = jQuery.data(elem, "tmplItem")) && (elem = elem.parentNode)) { 164 | } 165 | return tmplItem || topTmplItem; 166 | }, 167 | 168 | // Set: 169 | // Use $.template( name, tmpl ) to cache a named template, 170 | // where tmpl is a template string, a script element or a jQuery instance wrapping a script element, etc. 171 | // Use $( "selector" ).template( name ) to provide access by name to a script block template declaration. 172 | 173 | // Get: 174 | // Use $.template( name ) to access a cached template. 175 | // Also $( selectorToScriptBlock ).template(), or $.template( null, templateString ) 176 | // will return the compiled template, without adding a name reference. 177 | // If templateString includes at least one HTML tag, $.template( templateString ) is equivalent 178 | // to $.template( null, templateString ) 179 | template: function(name, tmpl) { 180 | if (tmpl) { 181 | // Compile template and associate with name 182 | if (typeof tmpl === "string") { 183 | // This is an HTML string being passed directly in. 184 | tmpl = buildTmplFn(tmpl) 185 | } else if (tmpl instanceof jQuery) { 186 | tmpl = tmpl[0] || {}; 187 | } 188 | if (tmpl.nodeType) { 189 | // If this is a template block, use cached copy, or generate tmpl function and cache. 190 | tmpl = jQuery.data(tmpl, "tmpl") || jQuery.data(tmpl, "tmpl", buildTmplFn(tmpl.innerHTML)); 191 | } 192 | return typeof name === "string" ? (jQuery.template[name] = tmpl) : tmpl; 193 | } 194 | // Return named compiled template 195 | return name ? (typeof name !== "string" ? jQuery.template(null, name) : 196 | (jQuery.template[name] || 197 | // If not in map, treat as a selector. (If integrated with core, use quickExpr.exec) 198 | jQuery.template(null, htmlExpr.test(name) ? name : jQuery(name)))) : null; 199 | }, 200 | 201 | encode: function(text) { 202 | // Do HTML encoding replacing < > & and ' and " by corresponding entities. 203 | return ("" + text).split("<").join("<").split(">").join(">").split('"').join(""").split("'").join("'"); 204 | } 205 | }); 206 | 207 | jQuery.extend(jQuery.tmpl, { 208 | tag: { 209 | "tmpl": { 210 | _default: { $2: "null" }, 211 | open: "if($notnull_1){_=_.concat($item.nest($1,$2));}" 212 | // tmpl target parameter can be of type function, so use $1, not $1a (so not auto detection of functions) 213 | // This means that {{tmpl foo}} treats foo as a template (which IS a function). 214 | // Explicit parens can be used if foo is a function that returns a template: {{tmpl foo()}}. 215 | }, 216 | "wrap": { 217 | _default: { $2: "null" }, 218 | open: "$item.calls(_,$1,$2);_=[];", 219 | close: "call=$item.calls();_=call._.concat($item.wrap(call,_));" 220 | }, 221 | "each": { 222 | _default: { $2: "$index, $value" }, 223 | open: "if($notnull_1){$.each($1a,function($2){with(this){", 224 | close: "}});}" 225 | }, 226 | "if": { 227 | open: "if(($notnull_1) && $1a){", 228 | close: "}" 229 | }, 230 | "else": { 231 | _default: { $1: "true" }, 232 | open: "}else if(($notnull_1) && $1a){" 233 | }, 234 | "html": { 235 | // Unecoded expression evaluation. 236 | open: "if($notnull_1){_.push($1a);}" 237 | }, 238 | "=": { 239 | // Encoded expression evaluation. Abbreviated form is ${}. 240 | _default: { $1: "$data" }, 241 | open: "if($notnull_1){_.push($.encode($1a));}" 242 | }, 243 | "!": { 244 | // Comment tag. Skipped by parser 245 | open: "" 246 | } 247 | }, 248 | 249 | // This stub can be overridden, e.g. in jquery.tmplPlus for providing rendered events 250 | complete: function(items) { 251 | newTmplItems = {}; 252 | }, 253 | 254 | // Call this from code which overrides domManip, or equivalent 255 | // Manage cloning/storing template items etc. 256 | afterManip: function afterManip(elem, fragClone, callback) { 257 | // Provides cloned fragment ready for fixup prior to and after insertion into DOM 258 | var content = fragClone.nodeType === 11 ? 259 | jQuery.makeArray(fragClone.childNodes) : 260 | fragClone.nodeType === 1 ? [fragClone] : []; 261 | 262 | // Return fragment to original caller (e.g. append) for DOM insertion 263 | callback.call(elem, fragClone); 264 | 265 | // Fragment has been inserted:- Add inserted nodes to tmplItem data structure. Replace inserted element annotations by jQuery.data. 266 | storeTmplItems(content); 267 | cloneIndex++; 268 | } 269 | }); 270 | 271 | //========================== Private helper functions, used by code above ========================== 272 | 273 | function build(tmplItem, nested, content) { 274 | // Convert hierarchical content into flat string array 275 | // and finally return array of fragments ready for DOM insertion 276 | var frag, ret = content ? jQuery.map(content, function(item) { 277 | return (typeof item === "string") ? 278 | // Insert template item annotations, to be converted to jQuery.data( "tmplItem" ) when elems are inserted into DOM. 279 | (tmplItem.key ? item.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g, "$1 " + tmplItmAtt + "=\"" + tmplItem.key + "\" $2") : item) : 280 | // This is a child template item. Build nested template. 281 | build(item, tmplItem, item._ctnt); 282 | }) : 283 | // If content is not defined, insert tmplItem directly. Not a template item. May be a string, or a string array, e.g. from {{html $item.html()}}. 284 | tmplItem; 285 | if (nested) { 286 | return ret; 287 | } 288 | 289 | // top-level template 290 | ret = ret.join(""); 291 | 292 | // Support templates which have initial or final text nodes, or consist only of text 293 | // Also support HTML entities within the HTML markup. 294 | ret.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/, function(all, before, middle, after) { 295 | frag = jQuery(middle).get(); 296 | 297 | storeTmplItems(frag); 298 | if (before) { 299 | frag = unencode(before).concat(frag); 300 | } 301 | if (after) { 302 | frag = frag.concat(unencode(after)); 303 | } 304 | }); 305 | return frag ? frag : unencode(ret); 306 | } 307 | 308 | function unencode(text) { 309 | // Use createElement, since createTextNode will not render HTML entities correctly 310 | var el = document.createElement("div"); 311 | el.innerHTML = text; 312 | return jQuery.makeArray(el.childNodes); 313 | } 314 | 315 | // Generate a reusable function that will serve to render a template against data 316 | function buildTmplFn(markup) { 317 | return new Function("jQuery", "$item", 318 | "var $=jQuery,call,_=[],$data=$item.data;" + 319 | 320 | // Introduce the data as local variables using with(){} 321 | "with($data){_.push('" + 322 | 323 | // Convert the template into pure JavaScript 324 | jQuery.trim(markup) 325 | .replace(/([\\'])/g, "\\$1") 326 | .replace(/[\r\t\n]/g, " ") 327 | .replace(/\$\{([^\}]*)\}/g, "{{= $1}}") 328 | .replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g, 329 | function(all, slash, type, fnargs, target, parens, args) { 330 | var tag = jQuery.tmpl.tag[ type ], def, expr, exprAutoFnDetect; 331 | if (!tag) { 332 | throw "Template command not found: " + type; 333 | } 334 | def = tag._default || []; 335 | if (parens && !/\w$/.test(target)) { 336 | target += parens; 337 | parens = ""; 338 | } 339 | if (target) { 340 | target = unescape(target); 341 | args = args ? ("," + unescape(args) + ")") : (parens ? ")" : ""); 342 | // Support for target being things like a.toLowerCase(); 343 | // In that case don't call with template item as 'this' pointer. Just evaluate... 344 | expr = parens ? (target.indexOf(".") > -1 ? target + parens : ("(" + target + ").call($item" + args)) : target; 345 | exprAutoFnDetect = parens ? expr : "(typeof(" + target + ")==='function'?(" + target + ").call($item):(" + target + "))"; 346 | } else { 347 | exprAutoFnDetect = expr = def.$1 || "null"; 348 | } 349 | fnargs = unescape(fnargs); 350 | return "');" + 351 | tag[ slash ? "close" : "open" ] 352 | .split("$notnull_1").join(target ? "typeof(" + target + ")!=='undefined' && (" + target + ")!=null" : "true") 353 | .split("$1a").join(exprAutoFnDetect) 354 | .split("$1").join(expr) 355 | .split("$2").join(fnargs ? 356 | fnargs.replace(/\s*([^\(]+)\s*(\((.*?)\))?/g, function(all, name, parens, params) { 357 | params = params ? ("," + params + ")") : (parens ? ")" : ""); 358 | return params ? ("(" + name + ").call($item" + params) : all; 359 | }) 360 | : (def.$2 || "") 361 | ) + 362 | "_.push('"; 363 | }) + 364 | "');}return _;" 365 | ); 366 | } 367 | 368 | function updateWrapped(options, wrapped) { 369 | // Build the wrapped content. 370 | options._wrap = build(options, true, 371 | // Suport imperative scenario in which options.wrapped can be set to a selector or an HTML string. 372 | jQuery.isArray(wrapped) ? wrapped : [htmlExpr.test(wrapped) ? wrapped : jQuery(wrapped).html()] 373 | ).join(""); 374 | } 375 | 376 | function unescape(args) { 377 | return args ? args.replace(/\\'/g, "'").replace(/\\\\/g, "\\") : null; 378 | } 379 | 380 | function outerHtml(elem) { 381 | var div = document.createElement("div"); 382 | div.appendChild(elem.cloneNode(true)); 383 | return div.innerHTML; 384 | } 385 | 386 | // Store template items in jQuery.data(), ensuring a unique tmplItem data data structure for each rendered template instance. 387 | function storeTmplItems(content) { 388 | var keySuffix = "_" + cloneIndex, elem, elems, newClonedItems = {}, i, l, m; 389 | for (i = 0,l = content.length; i < l; i++) { 390 | if ((elem = content[i]).nodeType !== 1) { 391 | continue; 392 | } 393 | elems = elem.getElementsByTagName("*"); 394 | for (m = elems.length - 1; m >= 0; m--) { 395 | processItemKey(elems[m]); 396 | } 397 | processItemKey(elem); 398 | } 399 | function processItemKey(el) { 400 | var pntKey, pntNode = el, pntItem, tmplItem, key; 401 | // Ensure that each rendered template inserted into the DOM has its own template item, 402 | if ((key = el.getAttribute(tmplItmAtt))) { 403 | while (pntNode.parentNode && (pntNode = pntNode.parentNode).nodeType === 1 && !(pntKey = pntNode.getAttribute(tmplItmAtt))) { 404 | } 405 | if (pntKey !== key) { 406 | // The next ancestor with a _tmplitem expando is on a different key than this one. 407 | // So this is a top-level element within this template item 408 | // Set pntNode to the key of the parentNode, or to 0 if pntNode.parentNode is null, or pntNode is a fragment. 409 | pntNode = pntNode.parentNode ? (pntNode.nodeType === 11 ? 0 : (pntNode.getAttribute(tmplItmAtt) || 0)) : 0; 410 | if (!(tmplItem = newTmplItems[key])) { 411 | // The item is for wrapped content, and was copied from the temporary parent wrappedItem. 412 | tmplItem = wrappedItems[key]; 413 | tmplItem = newTmplItem(tmplItem, newTmplItems[pntNode] || wrappedItems[pntNode], null, true); 414 | tmplItem.key = ++itemKey; 415 | newTmplItems[itemKey] = tmplItem; 416 | } 417 | if (cloneIndex) { 418 | cloneTmplItem(key); 419 | } 420 | } 421 | el.removeAttribute(tmplItmAtt); 422 | } else if (cloneIndex && (tmplItem = jQuery.data(el, "tmplItem"))) { 423 | // This was a rendered element, cloned during append or appendTo etc. 424 | // TmplItem stored in jQuery data has already been cloned in cloneCopyEvent. We must replace it with a fresh cloned tmplItem. 425 | cloneTmplItem(tmplItem.key); 426 | newTmplItems[tmplItem.key] = tmplItem; 427 | pntNode = jQuery.data(el.parentNode, "tmplItem"); 428 | pntNode = pntNode ? pntNode.key : 0; 429 | } 430 | if (tmplItem) { 431 | pntItem = tmplItem; 432 | // Find the template item of the parent element. 433 | // (Using !=, not !==, since pntItem.key is number, and pntNode may be a string) 434 | while (pntItem && pntItem.key != pntNode) { 435 | // Add this element as a top-level node for this rendered template item, as well as for any 436 | // ancestor items between this item and the item of its parent element 437 | pntItem.nodes.push(el); 438 | pntItem = pntItem.parent; 439 | } 440 | // Delete content built during rendering - reduce API surface area and memory use, and avoid exposing of stale data after rendering... 441 | delete tmplItem._ctnt; 442 | delete tmplItem._wrap; 443 | // Store template item as jQuery data on the element 444 | jQuery.data(el, "tmplItem", tmplItem); 445 | } 446 | function cloneTmplItem(key) { 447 | key = key + keySuffix; 448 | tmplItem = newClonedItems[key] = 449 | (newClonedItems[key] || newTmplItem(tmplItem, newTmplItems[tmplItem.parent.key + keySuffix] || tmplItem.parent, null, true)); 450 | } 451 | } 452 | } 453 | 454 | //---- Helper functions for template item ---- 455 | 456 | function tiCalls(content, tmpl, data, options) { 457 | if (!content) { 458 | return stack.pop(); 459 | } 460 | stack.push({ _: content, tmpl: tmpl, item:this, data: data, options: options }); 461 | } 462 | 463 | function tiNest(tmpl, data, options) { 464 | // nested template, using {{tmpl}} tag 465 | return jQuery.tmpl(jQuery.template(tmpl), data, options, this); 466 | } 467 | 468 | function tiWrap(call, wrapped) { 469 | // nested template, using {{wrap}} tag 470 | var options = call.options || {}; 471 | options.wrapped = wrapped; 472 | // Apply the template, which may incorporate wrapped content, 473 | return jQuery.tmpl(jQuery.template(call.tmpl), call.data, options, call.item); 474 | } 475 | 476 | function tiHtml(filter, textOnly) { 477 | var wrapped = this._wrap; 478 | return jQuery.map( 479 | jQuery(jQuery.isArray(wrapped) ? wrapped.join("") : wrapped).filter(filter || "*"), 480 | function(e) { 481 | return textOnly ? 482 | e.innerText || e.textContent : 483 | e.outerHTML || outerHtml(e); 484 | }); 485 | } 486 | 487 | function tiUpdate() { 488 | var coll = this.nodes; 489 | jQuery.tmpl(null, null, null, this).insertBefore(coll[0]); 490 | jQuery(coll).remove(); 491 | } 492 | })(jQuery); 493 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/javascripts/chosen.jquery.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | /* 3 | Chosen, a Select Box Enhancer for jQuery and Protoype 4 | by Patrick Filler for Harvest, http://getharvest.com 5 | 6 | Available for use under the MIT License, http://en.wikipedia.org/wiki/MIT_License 7 | 8 | Copyright (c) 2011 by Harvest 9 | */ var $, Chosen, SelectParser, get_side_border_padding, root; 10 | var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; 11 | root = typeof exports !== "undefined" && exports !== null ? exports : this; 12 | $ = jQuery; 13 | $.fn.extend({ 14 | chosen: function(data, options) { 15 | return $(this).each(function(input_field) { 16 | if (!($(this)).hasClass("chzn-done")) { 17 | return new Chosen(this, data, options); 18 | } 19 | }); 20 | } 21 | }); 22 | Chosen = (function() { 23 | function Chosen(elmn) { 24 | this.set_default_values(); 25 | this.form_field = elmn; 26 | this.form_field_jq = $(this.form_field); 27 | this.is_multiple = this.form_field.multiple; 28 | this.default_text_default = this.form_field.multiple ? "Select Some Options" : "Select an Option"; 29 | this.set_up_html(); 30 | this.register_observers(); 31 | this.form_field_jq.addClass("chzn-done"); 32 | } 33 | Chosen.prototype.set_default_values = function() { 34 | this.click_test_action = __bind(function(evt) { 35 | return this.test_active_click(evt); 36 | }, this); 37 | this.active_field = false; 38 | this.mouse_on_container = false; 39 | this.results_showing = false; 40 | this.result_highlighted = null; 41 | this.result_single_selected = null; 42 | return this.choices = 0; 43 | }; 44 | Chosen.prototype.set_up_html = function() { 45 | var container_div, dd_top, dd_width, sf_width; 46 | this.container_id = this.form_field.id.length ? this.form_field.id.replace('.', '_') : this.generate_field_id(); 47 | this.container_id += "_chzn"; 48 | this.f_width = this.form_field_jq.width(); 49 | this.default_text = this.form_field_jq.attr('title') ? this.form_field_jq.attr('title') : this.default_text_default; 50 | container_div = $("
    ", { 51 | id: this.container_id, 52 | "class": 'chzn-container', 53 | style: 'width: ' + this.f_width + 'px;' 54 | }); 55 | if (this.is_multiple) { 56 | container_div.html('
      '); 57 | } else { 58 | container_div.html('' + this.default_text + '
        '); 59 | } 60 | this.form_field_jq.hide().after(container_div); 61 | this.container = $('#' + this.container_id); 62 | this.container.addClass("chzn-container-" + (this.is_multiple ? "multi" : "single")); 63 | this.dropdown = this.container.find('div.chzn-drop').first(); 64 | dd_top = this.container.height(); 65 | dd_width = this.f_width - get_side_border_padding(this.dropdown); 66 | this.dropdown.css({ 67 | "width": dd_width + "px", 68 | "top": dd_top + "px" 69 | }); 70 | this.search_field = this.container.find('input').first(); 71 | this.search_results = this.container.find('ul.chzn-results').first(); 72 | this.search_field_scale(); 73 | this.search_no_results = this.container.find('li.no-results').first(); 74 | if (this.is_multiple) { 75 | this.search_choices = this.container.find('ul.chzn-choices').first(); 76 | this.search_container = this.container.find('li.search-field').first(); 77 | } else { 78 | this.search_container = this.container.find('div.chzn-search').first(); 79 | this.selected_item = this.container.find('.chzn-single').first(); 80 | sf_width = dd_width - get_side_border_padding(this.search_container) - get_side_border_padding(this.search_field); 81 | this.search_field.css({ 82 | "width": sf_width + "px" 83 | }); 84 | } 85 | this.results_build(); 86 | return this.set_tab_index(); 87 | }; 88 | Chosen.prototype.register_observers = function() { 89 | this.container.click(__bind(function(evt) { 90 | return this.container_click(evt); 91 | }, this)); 92 | this.container.mouseenter(__bind(function(evt) { 93 | return this.mouse_enter(evt); 94 | }, this)); 95 | this.container.mouseleave(__bind(function(evt) { 96 | return this.mouse_leave(evt); 97 | }, this)); 98 | this.search_results.click(__bind(function(evt) { 99 | return this.search_results_click(evt); 100 | }, this)); 101 | this.search_results.mouseover(__bind(function(evt) { 102 | return this.search_results_mouseover(evt); 103 | }, this)); 104 | this.search_results.mouseout(__bind(function(evt) { 105 | return this.search_results_mouseout(evt); 106 | }, this)); 107 | this.form_field_jq.bind("liszt:updated", __bind(function(evt) { 108 | return this.results_update_field(evt); 109 | }, this)); 110 | this.search_field.blur(__bind(function(evt) { 111 | return this.input_blur(evt); 112 | }, this)); 113 | this.search_field.keyup(__bind(function(evt) { 114 | return this.keyup_checker(evt); 115 | }, this)); 116 | this.search_field.keydown(__bind(function(evt) { 117 | return this.keydown_checker(evt); 118 | }, this)); 119 | if (this.is_multiple) { 120 | this.search_choices.click(__bind(function(evt) { 121 | return this.choices_click(evt); 122 | }, this)); 123 | return this.search_field.focus(__bind(function(evt) { 124 | return this.input_focus(evt); 125 | }, this)); 126 | } else { 127 | return this.selected_item.focus(__bind(function(evt) { 128 | return this.activate_field(evt); 129 | }, this)); 130 | } 131 | }; 132 | Chosen.prototype.container_click = function(evt) { 133 | if (evt && evt.type === "click") { 134 | evt.stopPropagation(); 135 | } 136 | if (!this.pending_destroy_click) { 137 | if (!this.active_field) { 138 | if (this.is_multiple) { 139 | this.search_field.val(""); 140 | } 141 | $(document).click(this.click_test_action); 142 | this.results_show(); 143 | } else if (!this.is_multiple && evt && ($(evt.target) === this.selected_item || $(evt.target).parents("a.chzn-single").length)) { 144 | evt.preventDefault(); 145 | this.results_toggle(); 146 | } 147 | return this.activate_field(); 148 | } else { 149 | return this.pending_destroy_click = false; 150 | } 151 | }; 152 | Chosen.prototype.mouse_enter = function() { 153 | return this.mouse_on_container = true; 154 | }; 155 | Chosen.prototype.mouse_leave = function() { 156 | return this.mouse_on_container = false; 157 | }; 158 | Chosen.prototype.input_focus = function(evt) { 159 | if (!this.active_field) { 160 | return setTimeout((__bind(function() { 161 | return this.container_click(); 162 | }, this)), 50); 163 | } 164 | }; 165 | Chosen.prototype.input_blur = function(evt) { 166 | if (!this.mouse_on_container) { 167 | this.active_field = false; 168 | return setTimeout((__bind(function() { 169 | return this.blur_test(); 170 | }, this)), 100); 171 | } 172 | }; 173 | Chosen.prototype.blur_test = function(evt) { 174 | if (!this.active_field && this.container.hasClass("chzn-container-active")) { 175 | return this.close_field(); 176 | } 177 | }; 178 | Chosen.prototype.close_field = function() { 179 | $(document).unbind("click", this.click_test_action); 180 | if (!this.is_multiple) { 181 | this.selected_item.attr("tabindex", this.search_field.attr("tabindex")); 182 | this.search_field.attr("tabindex", -1); 183 | } 184 | this.active_field = false; 185 | this.results_hide(); 186 | this.container.removeClass("chzn-container-active"); 187 | this.winnow_results_clear(); 188 | this.clear_backstroke(); 189 | this.show_search_field_default(); 190 | return this.search_field_scale(); 191 | }; 192 | Chosen.prototype.activate_field = function() { 193 | if (!this.is_multiple && !this.active_field) { 194 | this.search_field.attr("tabindex", this.selected_item.attr("tabindex")); 195 | this.selected_item.attr("tabindex", -1); 196 | } 197 | this.container.addClass("chzn-container-active"); 198 | this.active_field = true; 199 | this.search_field.val(this.search_field.val()); 200 | return this.search_field.focus(); 201 | }; 202 | Chosen.prototype.test_active_click = function(evt) { 203 | if ($(evt.target).parents('#' + this.container_id).length) { 204 | return this.active_field = true; 205 | } else { 206 | return this.close_field(); 207 | } 208 | }; 209 | Chosen.prototype.results_build = function() { 210 | var content, data, startTime, _i, _len, _ref; 211 | startTime = new Date(); 212 | this.parsing = true; 213 | this.results_data = SelectParser.select_to_array(this.form_field); 214 | if (this.is_multiple && this.choices > 0) { 215 | this.search_choices.find("li.search-choice").remove(); 216 | this.choices = 0; 217 | } else if (!this.is_multiple) { 218 | this.selected_item.find("span").text(this.default_text); 219 | } 220 | content = ''; 221 | _ref = this.results_data; 222 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 223 | data = _ref[_i]; 224 | if (data.group) { 225 | content += this.result_add_group(data); 226 | } else if (!data.empty) { 227 | content += this.result_add_option(data); 228 | if (data.selected && this.is_multiple) { 229 | this.choice_build(data); 230 | } else if (data.selected && !this.is_multiple) { 231 | this.selected_item.find("span").text(data.text); 232 | } 233 | } 234 | } 235 | this.show_search_field_default(); 236 | this.search_field_scale(); 237 | this.search_results.html(content); 238 | return this.parsing = false; 239 | }; 240 | Chosen.prototype.result_add_group = function(group) { 241 | if (!group.disabled) { 242 | group.dom_id = this.container_id + "_g_" + group.array_index; 243 | return '
      • ' + $("
        ").text(group.label).html() + '
      • '; 244 | } else { 245 | return ""; 246 | } 247 | }; 248 | Chosen.prototype.result_add_option = function(option) { 249 | var classes; 250 | if (!option.disabled) { 251 | option.dom_id = this.container_id + "_o_" + option.array_index; 252 | classes = option.selected && this.is_multiple ? [] : ["active-result"]; 253 | if (option.selected) { 254 | classes.push("result-selected"); 255 | } 256 | if (option.group_array_index != null) { 257 | classes.push("group-option"); 258 | } 259 | return '
      • ' + $("
        ").text(option.text).html() + '
      • '; 260 | } else { 261 | return ""; 262 | } 263 | }; 264 | Chosen.prototype.results_update_field = function() { 265 | this.result_clear_highlight(); 266 | this.result_single_selected = null; 267 | return this.results_build(); 268 | }; 269 | Chosen.prototype.result_do_highlight = function(el) { 270 | var high_bottom, high_top, maxHeight, visible_bottom, visible_top; 271 | if (el.length) { 272 | this.result_clear_highlight(); 273 | this.result_highlight = el; 274 | this.result_highlight.addClass("highlighted"); 275 | maxHeight = parseInt(this.search_results.css("maxHeight"), 10); 276 | visible_top = this.search_results.scrollTop(); 277 | visible_bottom = maxHeight + visible_top; 278 | high_top = this.result_highlight.position().top + this.search_results.scrollTop(); 279 | high_bottom = high_top + this.result_highlight.outerHeight(); 280 | if (high_bottom >= visible_bottom) { 281 | return this.search_results.scrollTop((high_bottom - maxHeight) > 0 ? high_bottom - maxHeight : 0); 282 | } else if (high_top < visible_top) { 283 | return this.search_results.scrollTop(high_top); 284 | } 285 | } 286 | }; 287 | Chosen.prototype.result_clear_highlight = function() { 288 | if (this.result_highlight) { 289 | this.result_highlight.removeClass("highlighted"); 290 | } 291 | return this.result_highlight = null; 292 | }; 293 | Chosen.prototype.results_toggle = function() { 294 | if (this.results_showing) { 295 | return this.results_hide(); 296 | } else { 297 | return this.results_show(); 298 | } 299 | }; 300 | Chosen.prototype.results_show = function() { 301 | var dd_top; 302 | if (!this.is_multiple) { 303 | this.selected_item.addClass("chzn-single-with-drop"); 304 | if (this.result_single_selected) { 305 | this.result_do_highlight(this.result_single_selected); 306 | } 307 | } 308 | dd_top = this.is_multiple ? this.container.height() : this.container.height() - 1; 309 | this.dropdown.css({ 310 | "top": dd_top + "px", 311 | "left": 0 312 | }); 313 | this.results_showing = true; 314 | this.search_field.focus(); 315 | this.search_field.val(this.search_field.val()); 316 | return this.winnow_results(); 317 | }; 318 | Chosen.prototype.results_hide = function() { 319 | if (!this.is_multiple) { 320 | this.selected_item.removeClass("chzn-single-with-drop"); 321 | } 322 | this.result_clear_highlight(); 323 | this.dropdown.css({ 324 | "left": "-9000px" 325 | }); 326 | return this.results_showing = false; 327 | }; 328 | Chosen.prototype.set_tab_index = function(el) { 329 | var ti; 330 | if (this.form_field_jq.attr("tabindex")) { 331 | ti = this.form_field_jq.attr("tabindex"); 332 | this.form_field_jq.attr("tabindex", -1); 333 | if (this.is_multiple) { 334 | return this.search_field.attr("tabindex", ti); 335 | } else { 336 | this.selected_item.attr("tabindex", ti); 337 | return this.search_field.attr("tabindex", -1); 338 | } 339 | } 340 | }; 341 | Chosen.prototype.show_search_field_default = function() { 342 | if (this.is_multiple && this.choices < 1 && !this.active_field) { 343 | this.search_field.val(this.default_text); 344 | return this.search_field.addClass("default"); 345 | } else { 346 | this.search_field.val(""); 347 | return this.search_field.removeClass("default"); 348 | } 349 | }; 350 | Chosen.prototype.search_results_click = function(evt) { 351 | var target; 352 | target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 353 | if (target.length) { 354 | this.result_highlight = target; 355 | return this.result_select(); 356 | } 357 | }; 358 | Chosen.prototype.search_results_mouseover = function(evt) { 359 | var target; 360 | target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); 361 | if (target) { 362 | return this.result_do_highlight(target); 363 | } 364 | }; 365 | Chosen.prototype.search_results_mouseout = function(evt) { 366 | if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { 367 | return this.result_clear_highlight(); 368 | } 369 | }; 370 | Chosen.prototype.choices_click = function(evt) { 371 | evt.preventDefault(); 372 | if (this.active_field && !($(evt.target).hasClass("search-choice" || $(evt.target).parents('.search-choice').first)) && !this.results_showing) { 373 | return this.results_show(); 374 | } 375 | }; 376 | Chosen.prototype.choice_build = function(item) { 377 | var choice_id, link; 378 | choice_id = this.container_id + "_c_" + item.array_index; 379 | this.choices += 1; 380 | this.search_container.before('
      • ' + item.text + '
      • '); 381 | link = $('#' + choice_id).find("a").first(); 382 | return link.click(__bind(function(evt) { 383 | return this.choice_destroy_link_click(evt); 384 | }, this)); 385 | }; 386 | Chosen.prototype.choice_destroy_link_click = function(evt) { 387 | evt.preventDefault(); 388 | this.pending_destroy_click = true; 389 | return this.choice_destroy($(evt.target)); 390 | }; 391 | Chosen.prototype.choice_destroy = function(link) { 392 | this.choices -= 1; 393 | this.show_search_field_default(); 394 | if (this.is_multiple && this.choices > 0 && this.search_field.val().length < 1) { 395 | this.results_hide(); 396 | } 397 | this.result_deselect(link.attr("rel")); 398 | return link.parents('li').first().remove(); 399 | }; 400 | Chosen.prototype.result_select = function() { 401 | var high, high_id, item, position; 402 | if (this.result_highlight) { 403 | high = this.result_highlight; 404 | high_id = high.attr("id"); 405 | this.result_clear_highlight(); 406 | high.addClass("result-selected"); 407 | if (this.is_multiple) { 408 | this.result_deactivate(high); 409 | } else { 410 | this.result_single_selected = high; 411 | } 412 | position = high_id.substr(high_id.lastIndexOf("_") + 1); 413 | item = this.results_data[position]; 414 | item.selected = true; 415 | this.form_field.options[item.options_index].selected = true; 416 | if (this.is_multiple) { 417 | this.choice_build(item); 418 | } else { 419 | this.selected_item.find("span").first().text(item.text); 420 | } 421 | this.results_hide(); 422 | this.search_field.val(""); 423 | this.form_field_jq.trigger("change"); 424 | return this.search_field_scale(); 425 | } 426 | }; 427 | Chosen.prototype.result_activate = function(el) { 428 | return el.addClass("active-result").show(); 429 | }; 430 | Chosen.prototype.result_deactivate = function(el) { 431 | return el.removeClass("active-result").hide(); 432 | }; 433 | Chosen.prototype.result_deselect = function(pos) { 434 | var result, result_data; 435 | result_data = this.results_data[pos]; 436 | result_data.selected = false; 437 | this.form_field.options[result_data.options_index].selected = false; 438 | result = $("#" + this.container_id + "_o_" + pos); 439 | result.removeClass("result-selected").addClass("active-result").show(); 440 | this.result_clear_highlight(); 441 | this.winnow_results(); 442 | this.form_field_jq.trigger("change"); 443 | return this.search_field_scale(); 444 | }; 445 | Chosen.prototype.results_search = function(evt) { 446 | if (this.results_showing) { 447 | return this.winnow_results(); 448 | } else { 449 | return this.results_show(); 450 | } 451 | }; 452 | Chosen.prototype.winnow_results = function() { 453 | var found, option, part, parts, regex, result_id, results, searchText, startTime, startpos, text, zregex, _i, _j, _len, _len2, _ref; 454 | startTime = new Date(); 455 | this.no_results_clear(); 456 | results = 0; 457 | searchText = this.search_field.val() === this.default_text ? "" : $.trim(this.search_field.val()); 458 | regex = new RegExp('^' + searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); 459 | zregex = new RegExp(searchText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"), 'i'); 460 | _ref = this.results_data; 461 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 462 | option = _ref[_i]; 463 | if (!option.disabled && !option.empty) { 464 | if (option.group) { 465 | $('#' + option.dom_id).hide(); 466 | } else if (!(this.is_multiple && option.selected)) { 467 | found = false; 468 | result_id = option.dom_id; 469 | if (regex.test(option.text)) { 470 | found = true; 471 | results += 1; 472 | } else if (option.text.indexOf(" ") >= 0 || option.text.indexOf("[") === 0) { 473 | parts = option.text.replace(/\[|\]/g, "").split(" "); 474 | if (parts.length) { 475 | for (_j = 0, _len2 = parts.length; _j < _len2; _j++) { 476 | part = parts[_j]; 477 | if (regex.test(part)) { 478 | found = true; 479 | results += 1; 480 | } 481 | } 482 | } 483 | } 484 | if (found) { 485 | if (searchText.length) { 486 | startpos = option.text.search(zregex); 487 | text = option.text.substr(0, startpos + searchText.length) + '' + option.text.substr(startpos + searchText.length); 488 | text = text.substr(0, startpos) + '' + text.substr(startpos); 489 | } else { 490 | text = option.text; 491 | } 492 | if ($("#" + result_id).html !== text) { 493 | $("#" + result_id).html(text); 494 | } 495 | this.result_activate($("#" + result_id)); 496 | if (option.group_array_index != null) { 497 | $("#" + this.results_data[option.group_array_index].dom_id).show(); 498 | } 499 | } else { 500 | if (this.result_highlight && result_id === this.result_highlight.attr('id')) { 501 | this.result_clear_highlight(); 502 | } 503 | this.result_deactivate($("#" + result_id)); 504 | } 505 | } 506 | } 507 | } 508 | if (results < 1 && searchText.length) { 509 | return this.no_results(searchText); 510 | } else { 511 | return this.winnow_results_set_highlight(); 512 | } 513 | }; 514 | Chosen.prototype.winnow_results_clear = function() { 515 | var li, lis, _i, _len, _results; 516 | this.search_field.val(""); 517 | lis = this.search_results.find("li"); 518 | _results = []; 519 | for (_i = 0, _len = lis.length; _i < _len; _i++) { 520 | li = lis[_i]; 521 | li = $(li); 522 | _results.push(li.hasClass("group-result") ? li.show() : !this.is_multiple || !li.hasClass("result-selected") ? this.result_activate(li) : void 0); 523 | } 524 | return _results; 525 | }; 526 | Chosen.prototype.winnow_results_set_highlight = function() { 527 | var do_high; 528 | if (!this.result_highlight) { 529 | do_high = this.search_results.find(".active-result").first(); 530 | if (do_high) { 531 | return this.result_do_highlight(do_high); 532 | } 533 | } 534 | }; 535 | Chosen.prototype.no_results = function(terms) { 536 | var no_results_html; 537 | no_results_html = $('
      • No results match ""
      • '); 538 | no_results_html.find("span").first().text(terms); 539 | return this.search_results.append(no_results_html); 540 | }; 541 | Chosen.prototype.no_results_clear = function() { 542 | return this.search_results.find(".no-results").remove(); 543 | }; 544 | Chosen.prototype.keydown_arrow = function() { 545 | var first_active, next_sib; 546 | if (!this.result_highlight) { 547 | first_active = this.search_results.find("li.active-result").first(); 548 | if (first_active) { 549 | this.result_do_highlight($(first_active)); 550 | } 551 | } else if (this.results_showing) { 552 | next_sib = this.result_highlight.nextAll("li.active-result").first(); 553 | if (next_sib) { 554 | this.result_do_highlight(next_sib); 555 | } 556 | } 557 | if (!this.results_showing) { 558 | return this.results_show(); 559 | } 560 | }; 561 | Chosen.prototype.keyup_arrow = function() { 562 | var prev_sibs; 563 | if (!this.results_showing && !this.is_multiple) { 564 | return this.results_show(); 565 | } else if (this.result_highlight) { 566 | prev_sibs = this.result_highlight.prevAll("li.active-result"); 567 | if (prev_sibs.length) { 568 | return this.result_do_highlight(prev_sibs.first()); 569 | } else { 570 | if (this.choices > 0) { 571 | this.results_hide(); 572 | } 573 | return this.result_clear_highlight(); 574 | } 575 | } 576 | }; 577 | Chosen.prototype.keydown_backstroke = function() { 578 | if (this.pending_backstroke) { 579 | this.choice_destroy(this.pending_backstroke.find("a").first()); 580 | return this.clear_backstroke(); 581 | } else { 582 | this.pending_backstroke = this.search_container.siblings("li.search-choice").last(); 583 | return this.pending_backstroke.addClass("search-choice-focus"); 584 | } 585 | }; 586 | Chosen.prototype.clear_backstroke = function() { 587 | if (this.pending_backstroke) { 588 | this.pending_backstroke.removeClass("search-choice-focus"); 589 | } 590 | return this.pending_backstroke = null; 591 | }; 592 | Chosen.prototype.keyup_checker = function(evt) { 593 | var stroke, _ref; 594 | stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; 595 | this.search_field_scale(); 596 | switch (stroke) { 597 | case 8: 598 | if (this.is_multiple && this.backstroke_length < 1 && this.choices > 0) { 599 | return this.keydown_backstroke(); 600 | } else if (!this.pending_backstroke) { 601 | this.result_clear_highlight(); 602 | return this.results_search(); 603 | } 604 | break; 605 | case 13: 606 | evt.preventDefault(); 607 | if (this.results_showing) { 608 | return this.result_select(); 609 | } 610 | break; 611 | case 27: 612 | if (this.results_showing) { 613 | return this.results_hide(); 614 | } 615 | break; 616 | case 9: 617 | case 38: 618 | case 40: 619 | case 16: 620 | break; 621 | default: 622 | return this.results_search(); 623 | } 624 | }; 625 | Chosen.prototype.keydown_checker = function(evt) { 626 | var stroke, _ref; 627 | stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; 628 | this.search_field_scale(); 629 | if (stroke !== 8 && this.pending_backstroke) { 630 | this.clear_backstroke(); 631 | } 632 | switch (stroke) { 633 | case 8: 634 | this.backstroke_length = this.search_field.val().length; 635 | break; 636 | case 9: 637 | this.mouse_on_container = false; 638 | break; 639 | case 13: 640 | evt.preventDefault(); 641 | break; 642 | case 38: 643 | evt.preventDefault(); 644 | this.keyup_arrow(); 645 | break; 646 | case 40: 647 | this.keydown_arrow(); 648 | break; 649 | } 650 | }; 651 | Chosen.prototype.search_field_scale = function() { 652 | var dd_top, div, h, style, style_block, styles, w, _i, _len; 653 | if (this.is_multiple) { 654 | h = 0; 655 | w = 0; 656 | style_block = "position:absolute; left: -1000px; top: -1000px; display:none;"; 657 | styles = ['font-size', 'font-style', 'font-weight', 'font-family', 'line-height', 'text-transform', 'letter-spacing']; 658 | for (_i = 0, _len = styles.length; _i < _len; _i++) { 659 | style = styles[_i]; 660 | style_block += style + ":" + this.search_field.css(style) + ";"; 661 | } 662 | div = $('
        ', { 663 | 'style': style_block 664 | }); 665 | div.text(this.search_field.val()); 666 | $('body').append(div); 667 | w = div.width() + 25; 668 | div.remove(); 669 | if (w > this.f_width - 10) { 670 | w = this.f_width - 10; 671 | } 672 | this.search_field.css({ 673 | 'width': w + 'px' 674 | }); 675 | dd_top = this.container.height(); 676 | return this.dropdown.css({ 677 | "top": dd_top + "px" 678 | }); 679 | } 680 | }; 681 | Chosen.prototype.generate_field_id = function() { 682 | var new_id; 683 | new_id = this.generate_random_id(); 684 | this.form_field.id = new_id; 685 | return new_id; 686 | }; 687 | Chosen.prototype.generate_random_id = function() { 688 | var string; 689 | string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char(); 690 | while ($("#" + string).length > 0) { 691 | string += this.generate_random_char(); 692 | } 693 | return string; 694 | }; 695 | Chosen.prototype.generate_random_char = function() { 696 | var chars, newchar, rand; 697 | chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"; 698 | rand = Math.floor(Math.random() * chars.length); 699 | return newchar = chars.substring(rand, rand + 1); 700 | }; 701 | return Chosen; 702 | })(); 703 | get_side_border_padding = function(elmt) { 704 | var side_border_padding; 705 | return side_border_padding = elmt.outerWidth() - elmt.width(); 706 | }; 707 | root.get_side_border_padding = get_side_border_padding; 708 | SelectParser = (function() { 709 | function SelectParser() { 710 | this.options_index = 0; 711 | this.parsed = []; 712 | } 713 | SelectParser.prototype.add_node = function(child) { 714 | if (child.nodeName === "OPTGROUP") { 715 | return this.add_group(child); 716 | } else { 717 | return this.add_option(child); 718 | } 719 | }; 720 | SelectParser.prototype.add_group = function(group) { 721 | var group_position, option, _i, _len, _ref, _results; 722 | group_position = this.parsed.length; 723 | this.parsed.push({ 724 | array_index: group_position, 725 | group: true, 726 | label: group.label, 727 | children: 0, 728 | disabled: group.disabled 729 | }); 730 | _ref = group.childNodes; 731 | _results = []; 732 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 733 | option = _ref[_i]; 734 | _results.push(this.add_option(option, group_position, group.disabled)); 735 | } 736 | return _results; 737 | }; 738 | SelectParser.prototype.add_option = function(option, group_position, group_disabled) { 739 | if (option.nodeName === "OPTION") { 740 | if (option.text !== "") { 741 | if (group_position != null) { 742 | this.parsed[group_position].children += 1; 743 | } 744 | this.parsed.push({ 745 | array_index: this.parsed.length, 746 | options_index: this.options_index, 747 | value: option.value, 748 | text: option.text, 749 | selected: option.selected, 750 | disabled: group_disabled === true ? group_disabled : option.disabled, 751 | group_array_index: group_position 752 | }); 753 | } else { 754 | this.parsed.push({ 755 | array_index: this.parsed.length, 756 | options_index: this.options_index, 757 | empty: true 758 | }); 759 | } 760 | return this.options_index += 1; 761 | } 762 | }; 763 | return SelectParser; 764 | })(); 765 | SelectParser.select_to_array = function(select) { 766 | var child, parser, _i, _len, _ref; 767 | parser = new SelectParser(); 768 | _ref = select.childNodes; 769 | for (_i = 0, _len = _ref.length; _i < _len; _i++) { 770 | child = _ref[_i]; 771 | parser.add_node(child); 772 | } 773 | return parser.parsed; 774 | }; 775 | root.SelectParser = SelectParser; 776 | }).call(this); 777 | -------------------------------------------------------------------------------- /samples/play2/todolist/public/swagger-ui/stylesheets/screen.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | font-size: 100%; 18 | font: inherit; 19 | vertical-align: baseline; } 20 | 21 | body { 22 | line-height: 1; } 23 | 24 | ol, ul { 25 | list-style: none; } 26 | 27 | table { 28 | border-collapse: collapse; 29 | border-spacing: 0; } 30 | 31 | caption, th, td { 32 | text-align: left; 33 | font-weight: normal; 34 | vertical-align: middle; } 35 | 36 | q, blockquote { 37 | quotes: none; } 38 | q:before, q:after, blockquote:before, blockquote:after { 39 | content: ""; 40 | content: none; } 41 | 42 | a img { 43 | border: none; } 44 | 45 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section, summary { 46 | display: block; } 47 | 48 | h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { 49 | text-decoration: none; } 50 | h1 a:hover, h2 a:hover, h3 a:hover, h4 a:hover, h5 a:hover, h6 a:hover { 51 | text-decoration: underline; } 52 | h1 span.divider, h2 span.divider, h3 span.divider, h4 span.divider, h5 span.divider, h6 span.divider { 53 | color: #aaaaaa; } 54 | 55 | h1 { 56 | color: #547f00; 57 | color: black; 58 | font-size: 1.5em; 59 | line-height: 1.3em; 60 | padding: 10px 0 10px 0; 61 | font-family: "Droid Sans", sans-serif; 62 | font-weight: bold; } 63 | 64 | h2 { 65 | color: #89bf04; 66 | color: black; 67 | font-size: 1.3em; 68 | padding: 10px 0 10px 0; } 69 | h2 a { 70 | color: black; } 71 | h2 span.sub { 72 | font-size: 0.7em; 73 | color: #999999; 74 | font-style: italic; } 75 | h2 span.sub a { 76 | color: #777777; } 77 | 78 | h3 { 79 | color: black; 80 | font-size: 1.1em; 81 | padding: 10px 0 10px 0; } 82 | 83 | div.heading_with_menu { 84 | float: none; 85 | clear: both; 86 | overflow: hidden; 87 | display: block; } 88 | div.heading_with_menu h1, div.heading_with_menu h2, div.heading_with_menu h3, div.heading_with_menu h4, div.heading_with_menu h5, div.heading_with_menu h6 { 89 | display: block; 90 | clear: none; 91 | float: left; 92 | -moz-box-sizing: border-box; 93 | -webkit-box-sizing: border-box; 94 | -ms-box-sizing: border-box; 95 | box-sizing: border-box; 96 | width: 60%; } 97 | div.heading_with_menu ul { 98 | display: block; 99 | clear: none; 100 | float: right; 101 | -moz-box-sizing: border-box; 102 | -webkit-box-sizing: border-box; 103 | -ms-box-sizing: border-box; 104 | box-sizing: border-box; 105 | margin-top: 10px; } 106 | 107 | p { 108 | line-height: 1.4em; 109 | padding: 0 0 10px 0; 110 | color: #333333; } 111 | 112 | ol { 113 | margin: 0px 0 10px 0; 114 | padding: 0 0 0 18px; 115 | list-style-type: decimal; } 116 | ol li { 117 | padding: 5px 0px; 118 | font-size: 0.9em; 119 | color: #333333; } 120 | 121 | .markdown h3 { 122 | color: #547f00; } 123 | .markdown h4 { 124 | color: #666666; } 125 | .markdown pre { 126 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 127 | background-color: #fcf6db; 128 | border: 1px solid black; 129 | border-color: #e5e0c6; 130 | padding: 10px; 131 | margin: 0 0 10px 0; } 132 | .markdown pre code { 133 | line-height: 1.6em; } 134 | .markdown p code, .markdown li code { 135 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 136 | background-color: #f0f0f0; 137 | color: black; 138 | padding: 1px 3px; } 139 | .markdown ol, .markdown ul { 140 | font-family: "Droid Sans", sans-serif; 141 | margin: 5px 0 10px 0; 142 | padding: 0 0 0 18px; 143 | list-style-type: disc; } 144 | .markdown ol li, .markdown ul li { 145 | padding: 3px 0px; 146 | line-height: 1.4em; 147 | color: #333333; } 148 | 149 | div.gist { 150 | margin: 20px 0 25px 0 !important; } 151 | 152 | p.big, div.big p { 153 | font-size: 1 em; 154 | margin-bottom: 10px; } 155 | 156 | span.weak { 157 | color: #666666; } 158 | span.blank, span.empty { 159 | color: #888888; 160 | font-style: italic; } 161 | 162 | a { 163 | color: #547f00; } 164 | 165 | strong { 166 | font-family: "Droid Sans", sans-serif; 167 | font-weight: bold; 168 | font-weight: bold; } 169 | 170 | .code { 171 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; } 172 | 173 | pre { 174 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 175 | background-color: #fcf6db; 176 | border: 1px solid black; 177 | border-color: #e5e0c6; 178 | padding: 10px; 179 | /* white-space: pre-line */ } 180 | pre code { 181 | line-height: 1.6em; } 182 | 183 | .required { 184 | font-weight: bold; } 185 | 186 | table.fullwidth { 187 | width: 100%; } 188 | table thead tr th { 189 | padding: 5px; 190 | font-size: 0.9em; 191 | color: #666666; 192 | border-bottom: 1px solid #999999; } 193 | table tbody tr.offset { 194 | background-color: #f5f5f5; } 195 | table tbody tr td { 196 | padding: 6px; 197 | font-size: 0.9em; 198 | border-bottom: 1px solid #cccccc; 199 | vertical-align: top; 200 | line-height: 1.3em; } 201 | table tbody tr:last-child td { 202 | border-bottom: none; } 203 | table tbody tr.offset { 204 | background-color: #f0f0f0; } 205 | 206 | form.form_box { 207 | background-color: #ebf3f9; 208 | border: 1px solid black; 209 | border-color: #c3d9ec; 210 | padding: 10px; } 211 | form.form_box label { 212 | color: #0f6ab4 !important; } 213 | form.form_box input[type=submit] { 214 | display: block; 215 | padding: 10px; } 216 | form.form_box p { 217 | font-size: 0.9em; 218 | padding: 0 0 15px 0; 219 | color: #7e7b6d; } 220 | form.form_box p a { 221 | color: #646257; } 222 | form.form_box p strong { 223 | color: black; } 224 | form.form_box p.weak { 225 | font-size: 0.8em; } 226 | form.formtastic fieldset.inputs ol li p.inline-hints { 227 | margin-left: 0; 228 | font-style: italic; 229 | font-size: 0.9em; 230 | margin: 0; } 231 | form.formtastic fieldset.inputs ol li label { 232 | display: block; 233 | clear: both; 234 | width: auto; 235 | padding: 0 0 3px 0; 236 | color: #666666; } 237 | form.formtastic fieldset.inputs ol li label abbr { 238 | padding-left: 3px; 239 | color: #888888; } 240 | form.formtastic fieldset.inputs ol li.required label { 241 | color: black; } 242 | form.formtastic fieldset.inputs ol li.string input, form.formtastic fieldset.inputs ol li.url input, form.formtastic fieldset.inputs ol li.numeric input { 243 | display: block; 244 | padding: 4px; 245 | width: auto; 246 | clear: both; } 247 | form.formtastic fieldset.inputs ol li.string input.title, form.formtastic fieldset.inputs ol li.url input.title, form.formtastic fieldset.inputs ol li.numeric input.title { 248 | font-size: 1.3em; } 249 | form.formtastic fieldset.inputs ol li.text textarea { 250 | font-family: "Droid Sans", sans-serif; 251 | height: 250px; 252 | padding: 4px; 253 | display: block; 254 | clear: both; } 255 | form.formtastic fieldset.inputs ol li.select select { 256 | display: block; 257 | clear: both; } 258 | form.formtastic fieldset.inputs ol li.boolean { 259 | float: none; 260 | clear: both; 261 | overflow: hidden; 262 | display: block; } 263 | form.formtastic fieldset.inputs ol li.boolean input { 264 | display: block; 265 | float: left; 266 | clear: none; 267 | margin: 0 5px 0 0; } 268 | form.formtastic fieldset.inputs ol li.boolean label { 269 | display: block; 270 | float: left; 271 | clear: none; 272 | margin: 0; 273 | padding: 0; } 274 | form.formtastic fieldset.buttons { 275 | margin: 0; 276 | padding: 0; } 277 | form.fullwidth ol li.string input, form.fullwidth ol li.url input, form.fullwidth ol li.text textarea, form.fullwidth ol li.numeric input { 278 | width: 500px !important; } 279 | 280 | body { 281 | font-family: "Droid Sans", sans-serif; } 282 | body #content_message { 283 | margin: 10px 15px; 284 | font-style: italic; 285 | color: #999999; } 286 | body #header { 287 | background-color: #89bf04; 288 | padding: 14px; } 289 | body #header a#logo { 290 | font-size: 1.5em; 291 | font-weight: bold; 292 | text-decoration: none; 293 | background: transparent url(http://swagger.wordnik.com/images/logo_small.png) no-repeat left center; 294 | padding: 20px 0 20px 40px; 295 | color: white; } 296 | body #header form#api_selector { 297 | display: block; 298 | clear: none; 299 | float: right; } 300 | body #header form#api_selector .input { 301 | display: block; 302 | clear: none; 303 | float: left; 304 | margin: 0 10px 0 0; } 305 | body #header form#api_selector .input input { 306 | font-size: 0.9em; 307 | padding: 3px; 308 | margin: 0; } 309 | body #header form#api_selector .input input#input_baseUrl { 310 | width: 400px; } 311 | body #header form#api_selector .input input#input_apiKey { 312 | width: 200px; } 313 | body #header form#api_selector .input a#explore { 314 | display: block; 315 | text-decoration: none; 316 | font-weight: bold; 317 | padding: 6px 8px; 318 | font-size: 0.9em; 319 | color: white; 320 | background-color: #547f00; 321 | -moz-border-radius: 4px; 322 | -webkit-border-radius: 4px; 323 | -o-border-radius: 4px; 324 | -ms-border-radius: 4px; 325 | -khtml-border-radius: 4px; 326 | border-radius: 4px; } 327 | body #header form#api_selector .input a#explore:hover { 328 | background-color: #547f00; } 329 | body p#colophon { 330 | margin: 0 15px 40px 15px; 331 | padding: 10px 0; 332 | font-size: 0.8em; 333 | border-top: 1px solid #dddddd; 334 | font-family: "Droid Sans", sans-serif; 335 | color: #999999; 336 | font-style: italic; } 337 | body p#colophon a { 338 | text-decoration: none; 339 | color: #547f00; } 340 | body ul#resources { 341 | padding: 0 15px; 342 | font-family: "Droid Sans", sans-serif; 343 | font-size: 0.9em; } 344 | body ul#resources li.resource { 345 | border-bottom: 1px solid #dddddd; } 346 | body ul#resources li.resource:last-child { 347 | border-bottom: none; } 348 | body ul#resources li.resource div.heading { 349 | border: 1px solid transparent; 350 | float: none; 351 | clear: both; 352 | overflow: hidden; 353 | display: block; } 354 | body ul#resources li.resource div.heading h2 { 355 | color: #999999; 356 | padding-left: 0px; 357 | display: block; 358 | clear: none; 359 | float: left; 360 | font-family: "Droid Sans", sans-serif; 361 | font-weight: bold; } 362 | body ul#resources li.resource div.heading h2 a { 363 | color: #999999; } 364 | body ul#resources li.resource div.heading h2 a:hover { 365 | color: black; } 366 | body ul#resources li.resource div.heading ul.options { 367 | float: none; 368 | clear: both; 369 | overflow: hidden; 370 | margin: 0; 371 | padding: 0; 372 | display: block; 373 | clear: none; 374 | float: right; 375 | margin: 14px 10px 0 0; } 376 | body ul#resources li.resource div.heading ul.options li { 377 | float: left; 378 | clear: none; 379 | margin: 0; 380 | padding: 2px 10px; 381 | border-right: 1px solid #dddddd; } 382 | body ul#resources li.resource div.heading ul.options li:first-child, body ul#resources li.resource div.heading ul.options li.first { 383 | padding-left: 0; } 384 | body ul#resources li.resource div.heading ul.options li:last-child, body ul#resources li.resource div.heading ul.options li.last { 385 | padding-right: 0; 386 | border-right: none; } 387 | body ul#resources li.resource div.heading ul.options li { 388 | color: #666666; 389 | font-size: 0.9em; } 390 | body ul#resources li.resource div.heading ul.options li a { 391 | color: #aaaaaa; 392 | text-decoration: none; } 393 | body ul#resources li.resource div.heading ul.options li a:hover { 394 | text-decoration: underline; 395 | color: black; } 396 | body ul#resources li.resource:hover div.heading h2 a, body ul#resources li.resource.active div.heading h2 a { 397 | color: black; } 398 | body ul#resources li.resource:hover div.heading ul.options li a, body ul#resources li.resource.active div.heading ul.options li a { 399 | color: #555555; } 400 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get { 401 | float: none; 402 | clear: both; 403 | overflow: hidden; 404 | display: block; 405 | margin: 0 0 10px 0; 406 | padding: 0 0 0 0px; } 407 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading { 408 | float: none; 409 | clear: both; 410 | overflow: hidden; 411 | display: block; 412 | margin: 0 0 0 0; 413 | padding: 0; 414 | background-color: #e7f0f7; 415 | border: 1px solid black; 416 | border-color: #c3d9ec; } 417 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 { 418 | display: block; 419 | clear: none; 420 | float: left; 421 | width: auto; 422 | margin: 0; 423 | padding: 0; 424 | line-height: 1.1em; 425 | color: black; } 426 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span { 427 | margin: 0; 428 | padding: 0; } 429 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.http_method a { 430 | text-transform: uppercase; 431 | background-color: #0f6ab4; 432 | text-decoration: none; 433 | color: white; 434 | display: inline-block; 435 | width: 50px; 436 | font-size: 0.7em; 437 | text-align: center; 438 | padding: 7px 0 4px 0; 439 | -moz-border-radius: 2px; 440 | -webkit-border-radius: 2px; 441 | -o-border-radius: 2px; 442 | -ms-border-radius: 2px; 443 | -khtml-border-radius: 2px; 444 | border-radius: 2px; } 445 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path { 446 | padding-left: 10px; } 447 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a { 448 | color: black; 449 | text-decoration: none; } 450 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading h3 span.path a:hover { 451 | text-decoration: underline; } 452 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options { 453 | float: none; 454 | clear: both; 455 | overflow: hidden; 456 | margin: 0; 457 | padding: 0; 458 | display: block; 459 | clear: none; 460 | float: right; 461 | margin: 6px 10px 0 0; } 462 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { 463 | float: left; 464 | clear: none; 465 | margin: 0; 466 | padding: 2px 10px; 467 | border-right: 1px solid #dddddd; } 468 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.first { 469 | padding-left: 0; } 470 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li.last { 471 | padding-right: 0; 472 | border-right: none; } 473 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li { 474 | border-right-color: #c3d9ec; 475 | color: #0f6ab4; 476 | font-size: 0.9em; } 477 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a { 478 | color: #0f6ab4; 479 | text-decoration: none; } 480 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.heading ul.options li a.active { 481 | text-decoration: underline; } 482 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content { 483 | background-color: #ebf3f9; 484 | border: 1px solid black; 485 | border-color: #c3d9ec; 486 | border-top: none; 487 | padding: 10px; 488 | -moz-border-radius-bottomleft: 6px; 489 | -webkit-border-bottom-left-radius: 6px; 490 | -o-border-bottom-left-radius: 6px; 491 | -ms-border-bottom-left-radius: 6px; 492 | -khtml-border-bottom-left-radius: 6px; 493 | border-bottom-left-radius: 6px; 494 | -moz-border-radius-bottomright: 6px; 495 | -webkit-border-bottom-right-radius: 6px; 496 | -o-border-bottom-right-radius: 6px; 497 | -ms-border-bottom-right-radius: 6px; 498 | -khtml-border-bottom-right-radius: 6px; 499 | border-bottom-right-radius: 6px; 500 | margin: 0 0 20px 0; } 501 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content h4 { 502 | color: #0f6ab4; 503 | font-size: 1.1em; 504 | margin: 0; 505 | padding: 15px 0 5px 0px; } 506 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content form input[type='text'].error { 507 | outline: 2px solid black; 508 | outline-color: #cc0000; } 509 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header { 510 | float: none; 511 | clear: both; 512 | overflow: hidden; 513 | display: block; } 514 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header input.submit { 515 | display: block; 516 | clear: none; 517 | float: left; 518 | padding: 6px 8px; } 519 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header img { 520 | display: block; 521 | display: block; 522 | clear: none; 523 | float: right; } 524 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.sandbox_header a { 525 | padding: 4px 0 0 10px; 526 | color: #6fa5d2; 527 | display: inline-block; 528 | font-size: 0.9em; } 529 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.response div.block { 530 | background-color: #fcf6db; 531 | border: 1px solid black; 532 | border-color: #e5e0c6; } 533 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.get div.content div.response div.block pre { 534 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 535 | padding: 10px; 536 | font-size: 0.9em; 537 | max-height: 400px; 538 | overflow-y: auto; } 539 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post { 540 | float: none; 541 | clear: both; 542 | overflow: hidden; 543 | display: block; 544 | margin: 0 0 10px 0; 545 | padding: 0 0 0 0px; } 546 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading { 547 | float: none; 548 | clear: both; 549 | overflow: hidden; 550 | display: block; 551 | margin: 0 0 0 0; 552 | padding: 0; 553 | background-color: #e7f6ec; 554 | border: 1px solid black; 555 | border-color: #c3e8d1; } 556 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 { 557 | display: block; 558 | clear: none; 559 | float: left; 560 | width: auto; 561 | margin: 0; 562 | padding: 0; 563 | line-height: 1.1em; 564 | color: black; } 565 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span { 566 | margin: 0; 567 | padding: 0; } 568 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.http_method a { 569 | text-transform: uppercase; 570 | background-color: #10a54a; 571 | text-decoration: none; 572 | color: white; 573 | display: inline-block; 574 | width: 50px; 575 | font-size: 0.7em; 576 | text-align: center; 577 | padding: 7px 0 4px 0; 578 | -moz-border-radius: 2px; 579 | -webkit-border-radius: 2px; 580 | -o-border-radius: 2px; 581 | -ms-border-radius: 2px; 582 | -khtml-border-radius: 2px; 583 | border-radius: 2px; } 584 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path { 585 | padding-left: 10px; } 586 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a { 587 | color: black; 588 | text-decoration: none; } 589 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading h3 span.path a:hover { 590 | text-decoration: underline; } 591 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options { 592 | float: none; 593 | clear: both; 594 | overflow: hidden; 595 | margin: 0; 596 | padding: 0; 597 | display: block; 598 | clear: none; 599 | float: right; 600 | margin: 6px 10px 0 0; } 601 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { 602 | float: left; 603 | clear: none; 604 | margin: 0; 605 | padding: 2px 10px; 606 | border-right: 1px solid #dddddd; } 607 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.first { 608 | padding-left: 0; } 609 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li.last { 610 | padding-right: 0; 611 | border-right: none; } 612 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li { 613 | border-right-color: #c3e8d1; 614 | color: #10a54a; 615 | font-size: 0.9em; } 616 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a { 617 | color: #10a54a; 618 | text-decoration: none; } 619 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.heading ul.options li a.active { 620 | text-decoration: underline; } 621 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content { 622 | background-color: #ebf7f0; 623 | border: 1px solid black; 624 | border-color: #c3e8d1; 625 | border-top: none; 626 | padding: 10px; 627 | -moz-border-radius-bottomleft: 6px; 628 | -webkit-border-bottom-left-radius: 6px; 629 | -o-border-bottom-left-radius: 6px; 630 | -ms-border-bottom-left-radius: 6px; 631 | -khtml-border-bottom-left-radius: 6px; 632 | border-bottom-left-radius: 6px; 633 | -moz-border-radius-bottomright: 6px; 634 | -webkit-border-bottom-right-radius: 6px; 635 | -o-border-bottom-right-radius: 6px; 636 | -ms-border-bottom-right-radius: 6px; 637 | -khtml-border-bottom-right-radius: 6px; 638 | border-bottom-right-radius: 6px; 639 | margin: 0 0 20px 0; } 640 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content h4 { 641 | color: #10a54a; 642 | font-size: 1.1em; 643 | margin: 0; 644 | padding: 15px 0 5px 0px; } 645 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content form input[type='text'].error { 646 | outline: 2px solid black; 647 | outline-color: #cc0000; } 648 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header { 649 | float: none; 650 | clear: both; 651 | overflow: hidden; 652 | display: block; } 653 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header input.submit { 654 | display: block; 655 | clear: none; 656 | float: left; 657 | padding: 6px 8px; } 658 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header img { 659 | display: block; 660 | display: block; 661 | clear: none; 662 | float: right; } 663 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.sandbox_header a { 664 | padding: 4px 0 0 10px; 665 | color: #6fc992; 666 | display: inline-block; 667 | font-size: 0.9em; } 668 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.response div.block { 669 | background-color: #fcf6db; 670 | border: 1px solid black; 671 | border-color: #e5e0c6; } 672 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.post div.content div.response div.block pre { 673 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 674 | padding: 10px; 675 | font-size: 0.9em; 676 | max-height: 400px; 677 | overflow-y: auto; } 678 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put { 679 | float: none; 680 | clear: both; 681 | overflow: hidden; 682 | display: block; 683 | margin: 0 0 10px 0; 684 | padding: 0 0 0 0px; } 685 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading { 686 | float: none; 687 | clear: both; 688 | overflow: hidden; 689 | display: block; 690 | margin: 0 0 0 0; 691 | padding: 0; 692 | background-color: #f9f2e9; 693 | border: 1px solid black; 694 | border-color: #f0e0ca; } 695 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 { 696 | display: block; 697 | clear: none; 698 | float: left; 699 | width: auto; 700 | margin: 0; 701 | padding: 0; 702 | line-height: 1.1em; 703 | color: black; } 704 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span { 705 | margin: 0; 706 | padding: 0; } 707 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.http_method a { 708 | text-transform: uppercase; 709 | background-color: #c5862b; 710 | text-decoration: none; 711 | color: white; 712 | display: inline-block; 713 | width: 50px; 714 | font-size: 0.7em; 715 | text-align: center; 716 | padding: 7px 0 4px 0; 717 | -moz-border-radius: 2px; 718 | -webkit-border-radius: 2px; 719 | -o-border-radius: 2px; 720 | -ms-border-radius: 2px; 721 | -khtml-border-radius: 2px; 722 | border-radius: 2px; } 723 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path { 724 | padding-left: 10px; } 725 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a { 726 | color: black; 727 | text-decoration: none; } 728 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading h3 span.path a:hover { 729 | text-decoration: underline; } 730 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options { 731 | float: none; 732 | clear: both; 733 | overflow: hidden; 734 | margin: 0; 735 | padding: 0; 736 | display: block; 737 | clear: none; 738 | float: right; 739 | margin: 6px 10px 0 0; } 740 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { 741 | float: left; 742 | clear: none; 743 | margin: 0; 744 | padding: 2px 10px; 745 | border-right: 1px solid #dddddd; } 746 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.first { 747 | padding-left: 0; } 748 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li.last { 749 | padding-right: 0; 750 | border-right: none; } 751 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li { 752 | border-right-color: #f0e0ca; 753 | color: #c5862b; 754 | font-size: 0.9em; } 755 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a { 756 | color: #c5862b; 757 | text-decoration: none; } 758 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.heading ul.options li a.active { 759 | text-decoration: underline; } 760 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content { 761 | background-color: #faf5ee; 762 | border: 1px solid black; 763 | border-color: #f0e0ca; 764 | border-top: none; 765 | padding: 10px; 766 | -moz-border-radius-bottomleft: 6px; 767 | -webkit-border-bottom-left-radius: 6px; 768 | -o-border-bottom-left-radius: 6px; 769 | -ms-border-bottom-left-radius: 6px; 770 | -khtml-border-bottom-left-radius: 6px; 771 | border-bottom-left-radius: 6px; 772 | -moz-border-radius-bottomright: 6px; 773 | -webkit-border-bottom-right-radius: 6px; 774 | -o-border-bottom-right-radius: 6px; 775 | -ms-border-bottom-right-radius: 6px; 776 | -khtml-border-bottom-right-radius: 6px; 777 | border-bottom-right-radius: 6px; 778 | margin: 0 0 20px 0; } 779 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content h4 { 780 | color: #c5862b; 781 | font-size: 1.1em; 782 | margin: 0; 783 | padding: 15px 0 5px 0px; } 784 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content form input[type='text'].error { 785 | outline: 2px solid black; 786 | outline-color: #cc0000; } 787 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header { 788 | float: none; 789 | clear: both; 790 | overflow: hidden; 791 | display: block; } 792 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header input.submit { 793 | display: block; 794 | clear: none; 795 | float: left; 796 | padding: 6px 8px; } 797 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header img { 798 | display: block; 799 | display: block; 800 | clear: none; 801 | float: right; } 802 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.sandbox_header a { 803 | padding: 4px 0 0 10px; 804 | color: #dcb67f; 805 | display: inline-block; 806 | font-size: 0.9em; } 807 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.response div.block { 808 | background-color: #fcf6db; 809 | border: 1px solid black; 810 | border-color: #e5e0c6; } 811 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.put div.content div.response div.block pre { 812 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 813 | padding: 10px; 814 | font-size: 0.9em; 815 | max-height: 400px; 816 | overflow-y: auto; } 817 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete { 818 | float: none; 819 | clear: both; 820 | overflow: hidden; 821 | display: block; 822 | margin: 0 0 10px 0; 823 | padding: 0 0 0 0px; } 824 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading { 825 | float: none; 826 | clear: both; 827 | overflow: hidden; 828 | display: block; 829 | margin: 0 0 0 0; 830 | padding: 0; 831 | background-color: #f5e8e8; 832 | border: 1px solid black; 833 | border-color: #e8c6c7; } 834 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 { 835 | display: block; 836 | clear: none; 837 | float: left; 838 | width: auto; 839 | margin: 0; 840 | padding: 0; 841 | line-height: 1.1em; 842 | color: black; } 843 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span { 844 | margin: 0; 845 | padding: 0; } 846 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.http_method a { 847 | text-transform: uppercase; 848 | background-color: #a41e22; 849 | text-decoration: none; 850 | color: white; 851 | display: inline-block; 852 | width: 50px; 853 | font-size: 0.7em; 854 | text-align: center; 855 | padding: 7px 0 4px 0; 856 | -moz-border-radius: 2px; 857 | -webkit-border-radius: 2px; 858 | -o-border-radius: 2px; 859 | -ms-border-radius: 2px; 860 | -khtml-border-radius: 2px; 861 | border-radius: 2px; } 862 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path { 863 | padding-left: 10px; } 864 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a { 865 | color: black; 866 | text-decoration: none; } 867 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading h3 span.path a:hover { 868 | text-decoration: underline; } 869 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options { 870 | float: none; 871 | clear: both; 872 | overflow: hidden; 873 | margin: 0; 874 | padding: 0; 875 | display: block; 876 | clear: none; 877 | float: right; 878 | margin: 6px 10px 0 0; } 879 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { 880 | float: left; 881 | clear: none; 882 | margin: 0; 883 | padding: 2px 10px; 884 | border-right: 1px solid #dddddd; } 885 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:first-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.first { 886 | padding-left: 0; } 887 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li:last-child, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li.last { 888 | padding-right: 0; 889 | border-right: none; } 890 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li { 891 | border-right-color: #e8c6c7; 892 | color: #a41e22; 893 | font-size: 0.9em; } 894 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a { 895 | color: #a41e22; 896 | text-decoration: none; } 897 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:hover, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a:active, body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.heading ul.options li a.active { 898 | text-decoration: underline; } 899 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content { 900 | background-color: #f7eded; 901 | border: 1px solid black; 902 | border-color: #e8c6c7; 903 | border-top: none; 904 | padding: 10px; 905 | -moz-border-radius-bottomleft: 6px; 906 | -webkit-border-bottom-left-radius: 6px; 907 | -o-border-bottom-left-radius: 6px; 908 | -ms-border-bottom-left-radius: 6px; 909 | -khtml-border-bottom-left-radius: 6px; 910 | border-bottom-left-radius: 6px; 911 | -moz-border-radius-bottomright: 6px; 912 | -webkit-border-bottom-right-radius: 6px; 913 | -o-border-bottom-right-radius: 6px; 914 | -ms-border-bottom-right-radius: 6px; 915 | -khtml-border-bottom-right-radius: 6px; 916 | border-bottom-right-radius: 6px; 917 | margin: 0 0 20px 0; } 918 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content h4 { 919 | color: #a41e22; 920 | font-size: 1.1em; 921 | margin: 0; 922 | padding: 15px 0 5px 0px; } 923 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content form input[type='text'].error { 924 | outline: 2px solid black; 925 | outline-color: #cc0000; } 926 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header { 927 | float: none; 928 | clear: both; 929 | overflow: hidden; 930 | display: block; } 931 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header input.submit { 932 | display: block; 933 | clear: none; 934 | float: left; 935 | padding: 6px 8px; } 936 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header img { 937 | display: block; 938 | display: block; 939 | clear: none; 940 | float: right; } 941 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.sandbox_header a { 942 | padding: 4px 0 0 10px; 943 | color: #c8787a; 944 | display: inline-block; 945 | font-size: 0.9em; } 946 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.response div.block { 947 | background-color: #fcf6db; 948 | border: 1px solid black; 949 | border-color: #e5e0c6; } 950 | body ul#resources li.resource ul.endpoints li.endpoint ul.operations li.operation.delete div.content div.response div.block pre { 951 | font-family: "Anonymous Pro", "Menlo", "Consolas", "Bitstream Vera Sans Mono", "Courier New", monospace; 952 | padding: 10px; 953 | font-size: 0.9em; 954 | max-height: 400px; 955 | overflow-y: auto; } 956 | --------------------------------------------------------------------------------