merged from develop branch

This commit is contained in:
Tony Tam
2013-08-14 10:51:15 -07:00
34 changed files with 11051 additions and 5255 deletions

1
.gitignore vendored
View File

@@ -19,3 +19,4 @@ reports/*
swagger-ui.sublime-workspace
.idea
.project
node_modules/*

View File

@@ -12,6 +12,8 @@ sourceFiles = [
'view/ParameterView'
'view/SignatureView'
'view/ContentTypeView'
'view/ResponseContentTypeView'
'view/ParameterContentTypeView'
]

23
dist/css/screen.css vendored
View File

@@ -1757,3 +1757,26 @@ pre code {
.message-fail {
color: #cc0000;
}
.info_title {
padding-bottom: 10px;
font-weight: bold;
font-size: 25px;
}
.info_description {
padding-bottom: 10px;
font-size: 15px;
}
.info_tos {
padding-bottom: 5px;
}
.info_license {
padding-bottom: 5px;
}
.info_contact {
padding-bottom: 5px;
}

26
dist/index.html vendored
View File

@@ -5,30 +5,27 @@
<link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='css/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<script type="text/javascript" src="lib/shred.bundle.js" /></script>
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
<script src='lib/jquery.ba-bbq.min.js' type='text/javascript'></script>
<script src='lib/handlebars-1.0.rc.1.js' type='text/javascript'></script>
<script src='lib/handlebars-1.0.0.js' type='text/javascript'></script>
<script src='lib/underscore-min.js' type='text/javascript'></script>
<script src='lib/backbone-min.js' type='text/javascript'></script>
<script src='lib/swagger.js' type='text/javascript'></script>
<script src='swagger-ui.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
window.swaggerUi = new SwaggerUi({
discoveryUrl:"http://petstore.swagger.wordnik.com/api/api-docs",
apiKey:"special-key",
dom_id:"swagger-ui-container",
supportHeaderParams: false,
supportedSubmitMethods: ['get', 'post', 'put'],
url: "http://petstore.swagger.wordnik.com/api/api-docs",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
if(console) {
console.log("Loaded SwaggerUI")
console.log(swaggerApi);
console.log(swaggerUi);
}
$('pre code').each(function(i, e) {hljs.highlightBlock(e)});
},
@@ -41,6 +38,14 @@
docExpansion: "none"
});
$('#input_apiKey').change(function() {
var key = $('#input_apiKey')[0].value;
console.log("key: " + key);
if(key && key.trim() != "") {
console.log("added key " + key);
window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query"));
}
})
window.swaggerUi.load();
});
@@ -59,8 +64,7 @@
<div class='input icon-btn'>
<img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis">
</div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl"
type="text"/></div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
<div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
<div class='input'><a id="explore" href="#">Explore</a></div>
</form>

2278
dist/lib/handlebars-1.0.0.js vendored Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2765
dist/lib/shred.bundle.js vendored Normal file

File diff suppressed because it is too large Load Diff

193
dist/lib/shred/content.js vendored Normal file
View File

@@ -0,0 +1,193 @@
// The purpose of the `Content` object is to abstract away the data conversions
// to and from raw content entities as strings. For example, you want to be able
// to pass in a Javascript object and have it be automatically converted into a
// JSON string if the `content-type` is set to a JSON-based media type.
// Conversely, you want to be able to transparently get back a Javascript object
// in the response if the `content-type` is a JSON-based media-type.
// One limitation of the current implementation is that it [assumes the `charset` is UTF-8](https://github.com/spire-io/shred/issues/5).
// The `Content` constructor takes an options object, which *must* have either a
// `body` or `data` property and *may* have a `type` property indicating the
// media type. If there is no `type` attribute, a default will be inferred.
var Content = function(options) {
this.body = options.body;
this.data = options.data;
this.type = options.type;
};
Content.prototype = {
// Treat `toString()` as asking for the `content.body`. That is, the raw content entity.
//
// toString: function() { return this.body; }
//
// Commented out, but I've forgotten why. :/
};
// `Content` objects have the following attributes:
Object.defineProperties(Content.prototype,{
// - **type**. Typically accessed as `content.type`, reflects the `content-type`
// header associated with the request or response. If not passed as an options
// to the constructor or set explicitly, it will infer the type the `data`
// attribute, if possible, and, failing that, will default to `text/plain`.
type: {
get: function() {
if (this._type) {
return this._type;
} else {
if (this._data) {
switch(typeof this._data) {
case "string": return "text/plain";
case "object": return "application/json";
}
}
}
return "text/plain";
},
set: function(value) {
this._type = value;
return this;
},
enumerable: true
},
// - **data**. Typically accessed as `content.data`, reflects the content entity
// converted into Javascript data. This can be a string, if the `type` is, say,
// `text/plain`, but can also be a Javascript object. The conversion applied is
// based on the `processor` attribute. The `data` attribute can also be set
// directly, in which case the conversion will be done the other way, to infer
// the `body` attribute.
data: {
get: function() {
if (this._body) {
return this.processor.parser(this._body);
} else {
return this._data;
}
},
set: function(data) {
if (this._body&&data) Errors.setDataWithBody(this);
this._data = data;
return this;
},
enumerable: true
},
// - **body**. Typically accessed as `content.body`, reflects the content entity
// as a UTF-8 string. It is the mirror of the `data` attribute. If you set the
// `data` attribute, the `body` attribute will be inferred and vice-versa. If
// you attempt to set both, an exception is raised.
body: {
get: function() {
if (this._data) {
return this.processor.stringify(this._data);
} else {
return this._body.toString();
}
},
set: function(body) {
if (this._data&&body) Errors.setBodyWithData(this);
this._body = body;
return this;
},
enumerable: true
},
// - **processor**. The functions that will be used to convert to/from `data` and
// `body` attributes. You can add processors. The two that are built-in are for
// `text/plain`, which is basically an identity transformation and
// `application/json` and other JSON-based media types (including custom media
// types with `+json`). You can add your own processors. See below.
processor: {
get: function() {
var processor = Content.processors[this.type];
if (processor) {
return processor;
} else {
// Return the first processor that matches any part of the
// content type. ex: application/vnd.foobar.baz+json will match json.
var main = this.type.split(";")[0];
var parts = main.split(/\+|\//);
for (var i=0, l=parts.length; i < l; i++) {
processor = Content.processors[parts[i]]
}
return processor || {parser:identity,stringify:toString};
}
},
enumerable: true
},
// - **length**. Typically accessed as `content.length`, returns the length in
// bytes of the raw content entity.
length: {
get: function() {
if (typeof Buffer !== 'undefined') {
return Buffer.byteLength(this.body);
}
return this.body.length;
}
}
});
Content.processors = {};
// The `registerProcessor` function allows you to add your own processors to
// convert content entities. Each processor consists of a Javascript object with
// two properties:
// - **parser**. The function used to parse a raw content entity and convert it
// into a Javascript data type.
// - **stringify**. The function used to convert a Javascript data type into a
// raw content entity.
Content.registerProcessor = function(types,processor) {
// You can pass an array of types that will trigger this processor, or just one.
// We determine the array via duck-typing here.
if (types.forEach) {
types.forEach(function(type) {
Content.processors[type] = processor;
});
} else {
// If you didn't pass an array, we just use what you pass in.
Content.processors[types] = processor;
}
};
// Register the identity processor, which is used for text-based media types.
var identity = function(x) { return x; }
, toString = function(x) { return x.toString(); }
Content.registerProcessor(
["text/html","text/plain","text"],
{ parser: identity, stringify: toString });
// Register the JSON processor, which is used for JSON-based media types.
Content.registerProcessor(
["application/json; charset=utf-8","application/json","json"],
{
parser: function(string) {
return JSON.parse(string);
},
stringify: function(data) {
return JSON.stringify(data); }});
var qs = require('querystring');
// Register the post processor, which is used for JSON-based media types.
Content.registerProcessor(
["application/x-www-form-urlencoded"],
{ parser : qs.parse, stringify : qs.stringify });
// Error functions are defined separately here in an attempt to make the code
// easier to read.
var Errors = {
setDataWithBody: function(object) {
throw new Error("Attempt to set data attribute of a content object " +
"when the body attributes was already set.");
},
setBodyWithData: function(object) {
throw new Error("Attempt to set body attribute of a content object " +
"when the data attributes was already set.");
}
}
module.exports = Content;

791
dist/lib/swagger.js vendored

File diff suppressed because it is too large Load Diff

1628
dist/swagger-ui.js vendored

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

2765
lib/shred.bundle.js Normal file

File diff suppressed because it is too large Load Diff

193
lib/shred/content.js Normal file
View File

@@ -0,0 +1,193 @@
// The purpose of the `Content` object is to abstract away the data conversions
// to and from raw content entities as strings. For example, you want to be able
// to pass in a Javascript object and have it be automatically converted into a
// JSON string if the `content-type` is set to a JSON-based media type.
// Conversely, you want to be able to transparently get back a Javascript object
// in the response if the `content-type` is a JSON-based media-type.
// One limitation of the current implementation is that it [assumes the `charset` is UTF-8](https://github.com/spire-io/shred/issues/5).
// The `Content` constructor takes an options object, which *must* have either a
// `body` or `data` property and *may* have a `type` property indicating the
// media type. If there is no `type` attribute, a default will be inferred.
var Content = function(options) {
this.body = options.body;
this.data = options.data;
this.type = options.type;
};
Content.prototype = {
// Treat `toString()` as asking for the `content.body`. That is, the raw content entity.
//
// toString: function() { return this.body; }
//
// Commented out, but I've forgotten why. :/
};
// `Content` objects have the following attributes:
Object.defineProperties(Content.prototype,{
// - **type**. Typically accessed as `content.type`, reflects the `content-type`
// header associated with the request or response. If not passed as an options
// to the constructor or set explicitly, it will infer the type the `data`
// attribute, if possible, and, failing that, will default to `text/plain`.
type: {
get: function() {
if (this._type) {
return this._type;
} else {
if (this._data) {
switch(typeof this._data) {
case "string": return "text/plain";
case "object": return "application/json";
}
}
}
return "text/plain";
},
set: function(value) {
this._type = value;
return this;
},
enumerable: true
},
// - **data**. Typically accessed as `content.data`, reflects the content entity
// converted into Javascript data. This can be a string, if the `type` is, say,
// `text/plain`, but can also be a Javascript object. The conversion applied is
// based on the `processor` attribute. The `data` attribute can also be set
// directly, in which case the conversion will be done the other way, to infer
// the `body` attribute.
data: {
get: function() {
if (this._body) {
return this.processor.parser(this._body);
} else {
return this._data;
}
},
set: function(data) {
if (this._body&&data) Errors.setDataWithBody(this);
this._data = data;
return this;
},
enumerable: true
},
// - **body**. Typically accessed as `content.body`, reflects the content entity
// as a UTF-8 string. It is the mirror of the `data` attribute. If you set the
// `data` attribute, the `body` attribute will be inferred and vice-versa. If
// you attempt to set both, an exception is raised.
body: {
get: function() {
if (this._data) {
return this.processor.stringify(this._data);
} else {
return this._body.toString();
}
},
set: function(body) {
if (this._data&&body) Errors.setBodyWithData(this);
this._body = body;
return this;
},
enumerable: true
},
// - **processor**. The functions that will be used to convert to/from `data` and
// `body` attributes. You can add processors. The two that are built-in are for
// `text/plain`, which is basically an identity transformation and
// `application/json` and other JSON-based media types (including custom media
// types with `+json`). You can add your own processors. See below.
processor: {
get: function() {
var processor = Content.processors[this.type];
if (processor) {
return processor;
} else {
// Return the first processor that matches any part of the
// content type. ex: application/vnd.foobar.baz+json will match json.
var main = this.type.split(";")[0];
var parts = main.split(/\+|\//);
for (var i=0, l=parts.length; i < l; i++) {
processor = Content.processors[parts[i]]
}
return processor || {parser:identity,stringify:toString};
}
},
enumerable: true
},
// - **length**. Typically accessed as `content.length`, returns the length in
// bytes of the raw content entity.
length: {
get: function() {
if (typeof Buffer !== 'undefined') {
return Buffer.byteLength(this.body);
}
return this.body.length;
}
}
});
Content.processors = {};
// The `registerProcessor` function allows you to add your own processors to
// convert content entities. Each processor consists of a Javascript object with
// two properties:
// - **parser**. The function used to parse a raw content entity and convert it
// into a Javascript data type.
// - **stringify**. The function used to convert a Javascript data type into a
// raw content entity.
Content.registerProcessor = function(types,processor) {
// You can pass an array of types that will trigger this processor, or just one.
// We determine the array via duck-typing here.
if (types.forEach) {
types.forEach(function(type) {
Content.processors[type] = processor;
});
} else {
// If you didn't pass an array, we just use what you pass in.
Content.processors[types] = processor;
}
};
// Register the identity processor, which is used for text-based media types.
var identity = function(x) { return x; }
, toString = function(x) { return x.toString(); }
Content.registerProcessor(
["text/html","text/plain","text"],
{ parser: identity, stringify: toString });
// Register the JSON processor, which is used for JSON-based media types.
Content.registerProcessor(
["application/json; charset=utf-8","application/json","json"],
{
parser: function(string) {
return JSON.parse(string);
},
stringify: function(data) {
return JSON.stringify(data); }});
var qs = require('querystring');
// Register the post processor, which is used for JSON-based media types.
Content.registerProcessor(
["application/x-www-form-urlencoded"],
{ parser : qs.parse, stringify : qs.stringify });
// Error functions are defined separately here in an attempt to make the code
// easier to read.
var Errors = {
setDataWithBody: function(object) {
throw new Error("Attempt to set data attribute of a content object " +
"when the body attributes was already set.");
},
setBodyWithData: function(object) {
throw new Error("Attempt to set body attribute of a content object " +
"when the data attributes was already set.");
}
}
module.exports = Content;

1111
lib/swagger.js Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "swagger-ui",
"version": "1.1.15",
"version": "2.0.0",
"description": "Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API",
"scripts": {
"build": "PATH=$PATH:./node_modules/.bin cake dist",
@@ -19,7 +19,6 @@
"readmeFilename": "README.md",
"dependencies": {
"coffee-script": "~1.5.0",
"swagger-client": "1.0.4",
"handlebars": "~1.0.10"
}
}

View File

@@ -34,16 +34,22 @@ class SwaggerUi extends Backbone.Router
# Event handler for when url/key is received from user
updateSwaggerUi: (data) ->
@options.discoveryUrl = data.discoveryUrl
@options.apiKey = data.apiKey
@options.url = data.url
@load()
# Create an api and render
load: ->
# Initialize the API object
@mainView?.clear()
@headerView.update(@options.discoveryUrl, @options.apiKey)
url = @options.url
if url.indexOf("http") isnt 0
url = @buildUrl(window.location.href.toString(), url)
@options.url = url
@headerView.update(url)
@api = new SwaggerApi(@options)
@api.build()
@api
# This is bound to success handler for SwaggerApi
# so it gets called when SwaggerApi completes loading
@@ -61,6 +67,16 @@ class SwaggerUi extends Backbone.Router
400
)
buildUrl: (base, url) ->
console.log "base is " + base
parts = base.split("/")
base = parts[0] + "//" + parts[2]
if url.indexOf("/") is 0
base + url
else
base + "/" + url
# Shows message on topbar of the ui
showMessage: (data = '') ->
$('#message-bar').removeClass 'message-fail'

View File

@@ -5,11 +5,6 @@ class ContentTypeView extends Backbone.View
template = @template()
$(@el).html(template(@model))
@isParam = @model.isParam
if @isParam
$('label[for=contentType]', $(@el)).text('Parameter content type:')
else
$('label[for=contentType]', $(@el)).text('Response Content Type')
@

View File

@@ -9,17 +9,16 @@ class HeaderView extends Backbone.View
initialize: ->
showPetStore: (e) ->
@trigger(
'update-swagger-ui'
{discoveryUrl:"http://petstore.swagger.wordnik.com/api/api-docs.json", apiKey:"special-key"}
{url:"http://petstore.swagger.wordnik.com/api/api-docs.json"}
)
showWordnikDev: (e) ->
@trigger(
'update-swagger-ui'
{discoveryUrl:"http://api.wordnik.com/v4/resources.json", apiKey:""}
{url:"http://api.wordnik.com/v4/resources.json"}
)
showCustomOnKeyup: (e) ->
@@ -29,10 +28,10 @@ class HeaderView extends Backbone.View
e?.preventDefault()
@trigger(
'update-swagger-ui'
{discoveryUrl: $('#input_baseUrl').val(), apiKey: $('#input_apiKey').val()}
{url: $('#input_baseUrl').val(), apiKey: $('#input_apiKey').val()}
)
update: (url, apiKey, trigger = false) ->
$('#input_baseUrl').val url
$('#input_apiKey').val apiKey
@trigger 'update-swagger-ui', {discoveryUrl:url, apiKey:apiKey} if trigger
#$('#input_apiKey').val apiKey
@trigger 'update-swagger-ui', {url:url} if trigger

View File

@@ -9,7 +9,7 @@ class OperationView extends Backbone.View
initialize: ->
render: ->
isMethodSubmissionSupported = jQuery.inArray(@model.httpMethod, @model.supportedSubmitMethods()) >= 0
isMethodSubmissionSupported = true #jQuery.inArray(@model.method, @model.supportedSubmitMethods) >= 0
@model.isReadOnly = true unless isMethodSubmissionSupported
$(@el).html(Handlebars.templates.operation(@model))
@@ -23,31 +23,35 @@ class OperationView extends Backbone.View
responseSignatureView = new SignatureView({model: signatureModel, tagName: 'div'})
$('.model-signature', $(@el)).append responseSignatureView.render().el
else
$('.model-signature', $(@el)).html(@model.responseClass)
$('.model-signature', $(@el)).html(@model.type)
contentTypeModel =
isParam: false
# support old syntax
if @model.supportedContentTypes
contentTypeModel.produces = @model.supportedContentTypes
if @model.produces
contentTypeModel.consumes = @model.consumes
contentTypeModel.produces = @model.produces
contentTypeView = new ContentTypeView({model: contentTypeModel})
$('.content-type', $(@el)).append contentTypeView.render().el
for param in @model.parameters
type = param.type || param.dataType
if type.toLowerCase() == 'file'
if !contentTypeModel.consumes
console.log "set content type "
contentTypeModel.consumes = 'multipart/form-data'
responseContentTypeView = new ResponseContentTypeView({model: contentTypeModel})
$('.response-content-type', $(@el)).append responseContentTypeView.render().el
# Render each parameter
@addParameter param for param in @model.parameters
@addParameter param, contentTypeModel.consumes for param in @model.parameters
# Render each response code
@addStatusCode statusCode for statusCode in @model.errorResponses
@addStatusCode statusCode for statusCode in @model.responseMessages
@
addParameter: (param) ->
addParameter: (param, consumes) ->
# Render a parameter
param.consumes = consumes
paramView = new ParameterView({model: param, tagName: 'tr', readOnly: @model.isReadOnly})
$('.operation-params', $(@el)).append paramView.render().el
@@ -72,103 +76,27 @@ class OperationView extends Backbone.View
# if error free submit it
if error_free
map = {}
for o in form.serializeArray()
opts = {parent: @}
#for o in form.serializeArray()
#if(o.value? && jQuery.trim(o.value).length > 0)
#map[o.name] = o.value
for o in form.find("input")
if(o.value? && jQuery.trim(o.value).length > 0)
map[o.name] = o.value
map[o.name] = encodeURI(o.value)
isFileUpload = form.children().find('input[type~="file"]').size() != 0
for o in form.find("textarea")
if(o.value? && jQuery.trim(o.value).length > 0)
map["body"] = o.value
isFormPost = false
consumes = "application/json"
if @model.consumes and @model.consumes.length > 0
# honor the consumes setting above everything else
consumes = @model.consumes[0]
else
for o in @model.parameters
if o.paramType == 'form'
isFormPost = true
consumes = false
opts.responseContentType = $("div select[name=responseContentType]", $(@el)).val()
opts.requestContentType = $("div select[name=parameterContentType]", $(@el)).val()
if isFileUpload
consumes = false
else if @model.httpMethod.toLowerCase() == "post" and isFormPost is false
consumes = "application/json"
@model.do(map, opts, @showCompleteStatus, @showErrorStatus, @)
if isFileUpload
# requires HTML5 compatible browser
bodyParam = new FormData()
success: (response, parent) ->
parent.showCompleteStatus response
# add params except file
for param in @model.parameters
if (param.paramType is 'body' or 'form') and param.name isnt 'file' and param.name isnt 'File' and map[param.name]?
bodyParam.append(param.name, map[param.name])
# add files
$.each form.children().find('input[type~="file"]'), (i, el) ->
bodyParam.append($(el).attr('name'), el.files[0])
console.log(bodyParam)
else if isFormPost
bodyParam = new FormData()
for param in @model.parameters
if map[param.name]?
bodyParam.append(param.name, map[param.name])
else
bodyParam = null
for param in @model.parameters
if param.paramType is 'body'
bodyParam = map[param.name]
log "bodyParam = " + bodyParam
headerParams = null
invocationUrl =
if @model.supportHeaderParams()
headerParams = @model.getHeaderParams(map)
@model.urlify(map, false)
else
@model.urlify(map, true)
log 'submitting ' + invocationUrl
$(".request_url", $(@el)).html "<pre>" + invocationUrl + "</pre>"
$(".response_throbber", $(@el)).show()
obj =
type: @model.httpMethod
url: invocationUrl
headers: headerParams
data: bodyParam
contentType: consumes
dataType: 'json'
processData: false
error: (xhr, textStatus, error) =>
@showErrorStatus(xhr, textStatus, error)
success: (data) =>
@showResponse(data)
complete: (data) =>
@showCompleteStatus(data)
paramContentTypeField = $("td select[name=contentType]", $(@el)).val()
if paramContentTypeField
obj.contentType = paramContentTypeField
log 'content type = ' + obj.contentType
if not (obj.data or (obj.type is 'GET' or obj.type is 'DELETE')) and obj.contentType is not "application/x-www-form-urlencoded"
obj.contentType = false
log 'content type is now = ' + obj.contentType
responseContentTypeField = $('.content > .content-type > div > select[name=contentType]', $(@el)).val()
if responseContentTypeField
obj.headers = if obj.headers? then obj.headers else {}
obj.headers.accept = responseContentTypeField
jQuery.ajax(obj)
false
# $.getJSON(invocationUrl, (r) => @showResponse(r)).complete((r) => @showCompleteStatus(r)).error (r) => @showErrorStatus(r)
# handler for hide response link
hideResponse: (e) ->
@@ -182,14 +110,13 @@ class OperationView extends Backbone.View
prettyJson = JSON.stringify(response, null, "\t").replace(/\n/g, "<br>")
$(".response_body", $(@el)).html escape(prettyJson)
# Show error from server
showErrorStatus: (data) ->
@showStatus data
showErrorStatus: (data, parent) ->
parent.showStatus data
# show the status codes
showCompleteStatus: (data) ->
@showStatus data
showCompleteStatus: (data, parent) ->
parent.showStatus data
# Adapted from http://stackoverflow.com/a/2893259/454004
formatXml: (xml) ->
@@ -252,21 +179,39 @@ class OperationView extends Backbone.View
# puts the response data in UI
showStatus: (data) ->
try
code = $('<code />').text(JSON.stringify(JSON.parse(data.responseText), null, 2))
content = data.content.data
headers = data.getHeaders()
# if server is nice, and sends content-type back, we can use it
contentType = headers["Content-Type"]
if content == undefined
code = $('<code />').text("no content")
pre = $('<pre class="json" />').append(code)
catch error
code = $('<code />').text(@formatXml(data.responseText))
else if contentType.indexOf("application/json") == 0
code = $('<code />').text(JSON.stringify(JSON.parse(content), null, 2))
pre = $('<pre class="json" />').append(code)
else if contentType.indexOf("application/xml") == 0
code = $('<code />').text(@formatXml(content))
pre = $('<pre class="xml" />').append(code)
else if contentType.indexOf("text/html") == 0
code = $('<code />').html(content)
pre = $('<pre class="xml" />').append(code)
else
# don't know what to render!
code = $('<code />').text(content)
pre = $('<pre class="json" />').append(code)
response_body = pre
$(".request_url").html "<pre>" + data.request.url + "</pre>"
$(".response_code", $(@el)).html "<pre>" + data.status + "</pre>"
$(".response_body", $(@el)).html response_body
$(".response_headers", $(@el)).html "<pre>" + data.getAllResponseHeaders() + "</pre>"
$(".response_headers", $(@el)).html "<pre>" + JSON.stringify(data.getHeaders()) + "</pre>"
$(".response", $(@el)).slideDown()
$(".response_hider", $(@el)).show()
$(".response_throbber", $(@el)).hide()
hljs.highlightBlock($('.response_body', $(@el))[0])
toggleOperationContent: ->
elem = $('#' + Docs.escapeResourceName(@model.resourceName) + "_" + @model.nickname + "_" + @model.httpMethod + "_" + @model.number + "_content")
elem = $('#' + Docs.escapeResourceName(@model.resourceName) + "_" + @model.nickname + "_" + @model.method + "_" + @model.number + "_content")
if elem.is(':visible') then Docs.collapseOperation(elem) else Docs.expandOperation(elem)

View File

@@ -0,0 +1,14 @@
class ParameterContentTypeView extends Backbone.View
initialize: ->
render: ->
template = @template()
$(@el).html(template(@model))
$('label[for=parameterContentType]', $(@el)).text('Parameter content type:')
@
template: ->
Handlebars.templates.parameter_content_type

View File

@@ -2,8 +2,9 @@ class ParameterView extends Backbone.View
initialize: ->
render: ->
type = @model.type || @model.dataType
@model.isBody = true if @model.paramType == 'body'
@model.isFile = true if @model.dataType == 'file'
@model.isFile = true if type.toLowerCase() == 'file'
template = @template()
$(@el).html(template(@model))
@@ -19,18 +20,23 @@ class ParameterView extends Backbone.View
else
$('.model-signature', $(@el)).html(@model.signature)
isParam = false
if @model.isBody
isParam = true
contentTypeModel =
isParam: false
isParam: isParam
# support old syntax
if @model.supportedContentTypes
contentTypeModel.produces = @model.supportedContentTypes
contentTypeModel.consumes = @model.consumes
if @model.produces
contentTypeModel.produces = @model.produces
if isParam
parameterContentTypeView = new ParameterContentTypeView({model: contentTypeModel})
$('.parameter-content-type', $(@el)).append parameterContentTypeView.render().el
contentTypeView = new ContentTypeView({model: contentTypeModel})
$('.content-type', $(@el)).append contentTypeView.render().el
else
responseContentTypeView = new ResponseContentTypeView({model: contentTypeModel})
$('.response-content-type', $(@el)).append responseContentTypeView.render().el
@

View File

@@ -0,0 +1,14 @@
class ResponseContentTypeView extends Backbone.View
initialize: ->
render: ->
template = @template()
$(@el).html(template(@model))
$('label[for=responseContentType]', $(@el)).text('Response Content Type')
@
template: ->
Handlebars.templates.response_content_type

View File

@@ -1757,3 +1757,26 @@ pre code {
.message-fail {
color: #cc0000;
}
.info_title {
padding-bottom: 10px;
font-weight: bold;
font-size: 25px;
}
.info_description {
padding-bottom: 10px;
font-size: 15px;
}
.info_tos {
padding-bottom: 5px;
}
.info_license {
padding-bottom: 5px;
}
.info_contact {
padding-bottom: 5px;
}

View File

@@ -5,6 +5,7 @@
<link href='//fonts.googleapis.com/css?family=Droid+Sans:400,700' rel='stylesheet' type='text/css'/>
<link href='css/hightlight.default.css' media='screen' rel='stylesheet' type='text/css'/>
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
<script type="text/javascript" src="lib/shred.bundle.js" /></script>
<script src='lib/jquery-1.8.0.min.js' type='text/javascript'></script>
<script src='lib/jquery.slideto.min.js' type='text/javascript'></script>
<script src='lib/jquery.wiggle.min.js' type='text/javascript'></script>
@@ -15,20 +16,16 @@
<script src='lib/swagger.js' type='text/javascript'></script>
<script src='swagger-ui.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
window.swaggerUi = new SwaggerUi({
discoveryUrl:"http://petstore.swagger.wordnik.com/api/api-docs.json",
apiKey:"special-key",
dom_id:"swagger-ui-container",
supportHeaderParams: false,
supportedSubmitMethods: ['get', 'post', 'put'],
url: "http://petstore.swagger.wordnik.com/api/api-docs",
dom_id: "swagger-ui-container",
supportedSubmitMethods: ['get', 'post', 'put', 'delete'],
onComplete: function(swaggerApi, swaggerUi){
if(console) {
console.log("Loaded SwaggerUI")
console.log(swaggerApi);
console.log(swaggerUi);
}
$('pre code').each(function(i, e) {hljs.highlightBlock(e)});
},
@@ -41,6 +38,14 @@
docExpansion: "none"
});
$('#input_apiKey').change(function() {
var key = $('#input_apiKey')[0].value;
console.log("key: " + key);
if(key && key.trim() != "") {
console.log("added key " + key);
window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "query"));
}
})
window.swaggerUi.load();
});
@@ -59,8 +64,7 @@
<div class='input icon-btn'>
<img id="show-wordnik-dev-icon" src="images/wordnik_api.png" title="Show Wordnik Developer Apis">
</div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl"
type="text"/></div>
<div class='input'><input placeholder="http://example.com/api" id="input_baseUrl" name="baseUrl" type="text"/></div>
<div class='input'><input placeholder="api_key" id="input_apiKey" name="apiKey" type="text"/></div>
<div class='input'><a id="explore" href="#">Explore</a></div>
</form>

View File

@@ -1,4 +1,12 @@
<div class='info' id='api_info'>
{{#if info}}
<div class="info_title">{{info.title}}</div>
<div class="info_description">{{{info.description}}}</div>
{{#if info.termsOfServiceUrl}}<div class="info_tos"><a href="{{info.termsOfServiceUrl}}">Terms of service</a></div>{{/if}}
{{#if info.contact}}<div class='info_contact'><a href="mailto:{{info.contact}}">Contact the developer</a></div>{{/if}}
{{#if info.license}}<div class='info_license'><a href='{{info.licenseUrl}}'>{{info.license}}</a></div>{{/if}}
{{/if}}
</div>
<div class='container' id='resources_container'>
<ul id='resources'>
</ul>

View File

@@ -1,31 +1,31 @@
<ul class='operations' >
<li class='{{httpMethod}} operation' id='{{resourceName}}_{{nickname}}_{{httpMethod}}_{{number}}'>
<li class='{{method}} operation' id='{{resourceName}}_{{nickname}}_{{method}}_{{number}}'>
<div class='heading'>
<h3>
<span class='http_method'>
<a href='#!/{{resourceName}}/{{nickname}}_{{httpMethod}}_{{number}}' class="toggleOperation">{{httpMethod}}</a>
<a href='#!/{{resourceName}}/{{nickname}}_{{method}}_{{number}}' class="toggleOperation">{{method}}</a>
</span>
<span class='path'>
<a href='#!/{{resourceName}}/{{nickname}}_{{httpMethod}}_{{number}}' class="toggleOperation">{{path}}</a>
<a href='#!/{{resourceName}}/{{nickname}}_{{method}}_{{number}}' class="toggleOperation">{{path}}</a>
</span>
</h3>
<ul class='options'>
<li>
<a href='#!/{{resourceName}}/{{nickname}}_{{httpMethod}}_{{number}}' class="toggleOperation">{{{summary}}}</a>
<a href='#!/{{resourceName}}/{{nickname}}_{{method}}_{{number}}' class="toggleOperation">{{{summary}}}</a>
</li>
</ul>
</div>
<div class='content' id='{{resourceName}}_{{nickname}}_{{httpMethod}}_{{number}}_content' style='display:none'>
<div class='content' id='{{resourceName}}_{{nickname}}_{{method}}_{{number}}_content' style='display:none'>
{{#if notes}}
<h4>Implementation Notes</h4>
<p>{{{notes}}}</p>
{{/if}}
{{#if responseClass}}
{{#if type}}
<h4>Response Class</h4>
<p><span class="model-signature" /></p>
<br/>
<div class="content-type" />
<div class="response-content-type" />
{{/if}}
<form accept-charset='UTF-8' class='sandbox'>
<div style='margin:0;padding:0;display:inline'></div>

View File

@@ -4,13 +4,14 @@
{{#if isBody}}
{{#if isFile}}
<input type="file" name='{{name}}'/>
<div class="parameter-content-type" />
{{else}}
{{#if defaultValue}}
<textarea class='body-textarea' name='{{name}}'>{{defaultValue}}</textarea>
{{else}}
<textarea class='body-textarea' name='{{name}}'></textarea>
<br />
<div class="content-type" />
<div class="parameter-content-type" />
{{/if}}
{{/if}}
{{else}}
@@ -27,4 +28,3 @@
<td>
<span class="model-signature"></span>
</td>

View File

@@ -9,7 +9,7 @@
{{else}}
<textarea class='body-textarea' placeholder='(required)' name='{{name}}'></textarea>
<br />
<div class="content-type" />
<div class="parameter-content-type" />
{{/if}}
{{/if}}
{{else}}

View File

@@ -0,0 +1,10 @@
<label for="parameterContentType"></label>
<select name="parameterContentType">
{{#if consumes}}
{{#each consumes}}
<option value="{{{this}}}">{{{this}}}</option>
{{/each}}
{{else}}
<option value="application/json">application/json</option>
{{/if}}
</select>

View File

@@ -1,6 +1,6 @@
<div class='heading'>
<h2>
<a href='#!/{{name}}' onclick="Docs.toggleEndpointListForResource('{{name}}');">/{{name}}</a>
<a href='#!/{{name}}' onclick="Docs.toggleEndpointListForResource('{{name}}');">{{name}}</a>
</h2>
<ul class='options'>
<li>

View File

@@ -0,0 +1,10 @@
<label for="responseContentType"></label>
<select name="responseContentType">
{{#if produces}}
{{#each produces}}
<option value="{{{this}}}">{{{this}}}</option>
{{/each}}
{{else}}
<option value="application/json">application/json</option>
{{/if}}
</select>

View File

@@ -1,5 +1,4 @@
window.api_key = 'a2a73e7b926c924fad7001ca3111acd55af2ffabf50eb4ae5'
window.discoveryUrl = "http://api.wordnik.com/v4/resources.json"
window.url = "http://api.wordnik.com/v4/resources.json"
describe 'SwaggerUi', ->
@@ -8,7 +7,7 @@ describe 'SwaggerUi', ->
beforeEach ->
window.ui = new SwaggerUi
api_key: window.api_key
discoveryUrl: window.discoveryUrl
url: window.url
waitsFor ->
ui.ready