Merge pull request #1095 from swagger-api/develop_2.0
merge from develop 2.0 for release
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
* text eol=lf
|
||||
|
||||
dist/**/* binary
|
||||
1
.gitignore
vendored
@@ -10,3 +10,4 @@ swagger-ui.sublime-workspace
|
||||
.idea
|
||||
.project
|
||||
node_modules/*
|
||||
/nbproject/private/
|
||||
5
.jshintignore
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules
|
||||
src/main/javascript/doc.js
|
||||
dist
|
||||
lib
|
||||
.log
|
||||
39
.jshintrc
Normal file
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"esnext": true,
|
||||
"bitwise": true,
|
||||
"curly": true,
|
||||
"eqeqeq": true,
|
||||
"immed": true,
|
||||
"indent": 2,
|
||||
"latedef": false,
|
||||
"newcap": true,
|
||||
"noarg": true,
|
||||
"quotmark": "single",
|
||||
"regexp": true,
|
||||
"undef": true,
|
||||
"unused": true,
|
||||
"strict": true,
|
||||
"trailing": true,
|
||||
"smarttabs": true,
|
||||
"validthis": true,
|
||||
"globals": {
|
||||
|
||||
// Libraries
|
||||
"_": false,
|
||||
"$": false,
|
||||
"Backbone": false,
|
||||
"Handlebars": false,
|
||||
"jQuery": false,
|
||||
"marked": false,
|
||||
"SwaggerClient": false,
|
||||
"hljs": false,
|
||||
"SwaggerUi": false,
|
||||
"define": false,
|
||||
|
||||
// Global object
|
||||
// TODO: remove these
|
||||
"Docs": false
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,10 @@
|
||||
sudo: false
|
||||
language: node_js
|
||||
node_js:
|
||||
- '0.10'
|
||||
- '0.12'
|
||||
install:
|
||||
- export DISPLAY=:99.0
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- npm install
|
||||
- npm i -g jshint
|
||||
- npm install
|
||||
|
||||
49
README.md
@@ -30,6 +30,9 @@ Swagger UI Version | Release Date | Swagger Spec compatibility | Notes | Status
|
||||
### Download
|
||||
You can use the swagger-ui code AS-IS! No need to build or recompile--just clone this repo and use the pre-built files in the `dist` folder. If you like swagger-ui as-is, stop here.
|
||||
|
||||
##### Browser support
|
||||
Swagger UI works in all evergreen desktop browsers (Chrome, Safari, Firefox). Internet Explorer support is version 8 (IE8) and above.
|
||||
|
||||
### Build
|
||||
You can rebuild swagger-ui on your own to tweak it or just so you can say you did. To do so, follow these steps:
|
||||
|
||||
@@ -57,24 +60,24 @@ Once you open the Swagger UI, it will load the [Swagger Petstore](http://petstor
|
||||
You may choose to customize Swagger UI for your organization. Here is an overview of whats in its various directories:
|
||||
|
||||
- dist: Contains a distribution which you can deploy on a server or load from your local machine.
|
||||
- dist/lang: The swagger localisation
|
||||
- lib: Contains javascript dependencies which swagger-ui depends on
|
||||
- node_modules: Contains node modules which swagger-ui uses for its development.
|
||||
- src
|
||||
- src/main/coffeescript: main code in CoffeeScript
|
||||
- src/main/templates: [handlebars](http://handlebarsjs.com/) templates used to render swagger-ui
|
||||
- src/main/html: the html files, some images and css
|
||||
- src/main/javascript: some legacy javascript referenced by CoffeeScript code
|
||||
- src/main/javascript: main code
|
||||
|
||||
### SwaggerUi
|
||||
To use swagger-ui you should take a look at the [source of swagger-ui html page](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html) and customize it. This basically requires you to instantiate a SwaggerUi object and call load() on it as below:
|
||||
|
||||
```javascript
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
var swaggerUi = new SwaggerUi({
|
||||
url:"http://petstore.swagger.io/v2/swagger.json",
|
||||
dom_id:"swagger-ui-container"
|
||||
});
|
||||
|
||||
window.swaggerUi.load();
|
||||
swaggerUi.load();
|
||||
```
|
||||
|
||||
##### Parameters
|
||||
@@ -87,11 +90,13 @@ validatorUrl | By default, Swagger-UI attempts to validate specs against swagger
|
||||
dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger.
|
||||
booleanValues | SwaggerUI renders boolean data types as a dropdown. By default it provides a 'true' and 'false' string as the possible choices. You can use this parameter to change the values in dropdown to be something else, for example 0 and 1 by setting booleanValues to new Array(0, 1).
|
||||
docExpansion | Controls how the API listing is displayed. It can be set to 'none' (default), 'list' (shows operations for each resource), or 'full' (fully expanded: shows operations and their details).
|
||||
sorter | Apply a sort to the API list. It can be 'alpha' (sort paths alphanumerically) or 'method' (sort operations by HTTP method). Default is the order returned by the server unchanged.
|
||||
apisSorter | Apply a sort to the API/tags list. It can be 'alpha' (sort by name) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||
operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged.
|
||||
onComplete | This is a callback function parameter which can be passed to be notified of when SwaggerUI has completed rendering successfully.
|
||||
onFailure | This is a callback function parameter which can be passed to be notified of when SwaggerUI encountered a failure was unable to render.
|
||||
highlightSizeThreshold | Any size response below this threshold will be highlighted syntactically, attempting to highlight large responses can lead to browser hangs, not including a threshold will default to highlight all returned responses.
|
||||
supportedSubmitMethods | An array of of the HTTP operations that will have the 'Try it out!` option. An empty array disables all operations. This does not filter the operations from the display.
|
||||
oauth2RedirectUrl | OAuth redirect URL
|
||||
|
||||
* All other parameters are explained in greater detail below
|
||||
|
||||
@@ -104,11 +109,11 @@ swagger-ui supports invocation of all HTTP methods APIs including GET, PUT, POST
|
||||
Header params are supported through a pluggable mechanism in [swagger-js](https://github.com/swagger-api/swagger-js). You can see the [index.html](https://github.com/swagger-api/swagger-ui/blob/master/dist/index.html) for a sample of how to dynamically set headers:
|
||||
|
||||
```js
|
||||
// add a new ApiKeyAuthorization when the api-key changes in the ui.
|
||||
// add a new SwaggerClient.ApiKeyAuthorization when the api-key changes in the ui.
|
||||
$('#input_apiKey').change(function() {
|
||||
var key = $('#input_apiKey')[0].value;
|
||||
if(key && key.trim() != "") {
|
||||
window.authorizations.add("key", new ApiKeyAuthorization("api_key", key, "header"));
|
||||
swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("api_key", key, "header"));
|
||||
}
|
||||
})
|
||||
```
|
||||
@@ -119,11 +124,36 @@ This will add header `api_key` with value `key` on every call to the server. Yo
|
||||
If you have some header parameters which you need to send with every request, use the headers as below:
|
||||
|
||||
```js
|
||||
window.authorizations.add("key", new ApiKeyAuthorization("Authorization", "XXXX", "header"));
|
||||
swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("Authorization", "XXXX", "header"));
|
||||
```
|
||||
|
||||
Note! You can pass multiple header params on a single request, just use unique names for them (`key` is used in the above example).
|
||||
|
||||
### Localization and translation
|
||||
The localization files are in the dist/lang directory.
|
||||
|
||||
To enable translation you should append next two lines in your Swagger's index.html (or another entry point you use)
|
||||
```html
|
||||
<script src='lang/translator.js' type='text/javascript'></script>
|
||||
<script src='lang/en.js' type='text/javascript'></script>
|
||||
```
|
||||
The first line script is a translator and the second one is your language lexemes.
|
||||
|
||||
If you wish to append support for new language you just need to create lang/your_lang.js and fill it like it's done in existing files.
|
||||
|
||||
To append new lexemex for translation you shoul do two things:
|
||||
1. Add lexeme into the language file.
|
||||
Example of new line: "new sentence":"translation of new sentence".
|
||||
2. Mark this lexeme in source html with attribute data-sw-translate.
|
||||
Example of changed source:
|
||||
```html
|
||||
<anyHtmlTag data-sw-translate>new sentence</anyHtmlTag>
|
||||
or <anyHtmlTag data-sw-translate value='new sentence'/>
|
||||
```
|
||||
.
|
||||
|
||||
At this moment only inner html, title-attribute and value-attribute are going to be translated.
|
||||
|
||||
## CORS Support
|
||||
|
||||
CORS is a technique to prevent websites from doing bad things with your personal data. Most browsers + javascript toolkits not only support CORS but enforce it, which has implications for your API server which supports Swagger.
|
||||
@@ -191,7 +221,8 @@ Create your own fork of [swagger-api/swagger-ui](https://github.com/swagger-api/
|
||||
|
||||
To share your changes, [submit a pull request](https://github.com/swagger-api/swagger-ui/pull/new/master).
|
||||
|
||||
Since the javascript files are compiled from coffeescript, please submit changes in the *.coffee files! We have to reject changes only in the .js files as they will be lost on each build of the ui.
|
||||
## Change Log
|
||||
Plsee see [releases](https://github.com/swagger-api/swagger-ui/releases) for change log.
|
||||
|
||||
## License
|
||||
|
||||
|
||||
26
bower.json
Normal file
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"main": "dist/index.html",
|
||||
"version": "2.1.8-M1",
|
||||
"authors": [
|
||||
"Mohsen Azimi <me@azimi.me>"
|
||||
],
|
||||
"description": "Swagger UI",
|
||||
"moduleType": [
|
||||
"globals"
|
||||
],
|
||||
"keywords": [
|
||||
"Swagger",
|
||||
"API"
|
||||
],
|
||||
"license": "Copyright 2015 Reverb Technologies, Inc.",
|
||||
"homepage": "http://swagger.io",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
]
|
||||
}
|
||||
1155
dist/css/print.css
vendored
Normal file
BIN
dist/fonts/droid-sans-v6-latin-700.eot
vendored
BIN
dist/fonts/droid-sans-v6-latin-700.ttf
vendored
BIN
dist/fonts/droid-sans-v6-latin-regular.ttf
vendored
BIN
dist/images/explorer_icons.png
vendored
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
BIN
dist/images/favicon-16x16.png
vendored
Executable file
BIN
dist/images/favicon-32x32.png
vendored
Executable file
BIN
dist/images/favicon.ico
vendored
Executable file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
dist/images/logo_small.png
vendored
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 769 B |
BIN
dist/images/pet_store_api.png
vendored
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 823 B |
BIN
dist/images/wordnik_api.png
vendored
|
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 979 B |
199
dist/index.html
vendored
@@ -1,98 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Swagger UI</title>
|
||||
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='print' 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-2.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-client.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/marked.js' type='text/javascript'></script>
|
||||
|
||||
<!-- enabling this will enable oauth2 implicit scope support -->
|
||||
<script src='lib/swagger-oauth.js' type='text/javascript'></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var url = window.location.search.match(/url=([^&]+)/);
|
||||
if (url && url.length > 1) {
|
||||
url = decodeURIComponent(url[1]);
|
||||
} else {
|
||||
url = "http://petstore.swagger.io/v2/swagger.json";
|
||||
}
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: url,
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
if(typeof initOAuth == "function") {
|
||||
/*
|
||||
initOAuth({
|
||||
clientId: "your-client-id",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name"
|
||||
});
|
||||
*/
|
||||
}
|
||||
$('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e)
|
||||
});
|
||||
},
|
||||
onFailure: function(data) {
|
||||
log("Unable to Load SwaggerUI");
|
||||
},
|
||||
docExpansion: "none",
|
||||
sorter : "alpha"
|
||||
});
|
||||
|
||||
function addApiKeyAuthorization() {
|
||||
var key = $('#input_apiKey')[0].value;
|
||||
log("key: " + key);
|
||||
if(key && key.trim() != "") {
|
||||
log("added key " + key);
|
||||
window.authorizations.add("api_key", new ApiKeyAuthorization("api_key", key, "query"));
|
||||
}
|
||||
}
|
||||
|
||||
$('#input_apiKey').change(function() {
|
||||
addApiKeyAuthorization();
|
||||
});
|
||||
|
||||
// if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
|
||||
/*
|
||||
var apiKey = "myApiKeyXXXX123456789";
|
||||
$('#input_apiKey').val(apiKey);
|
||||
addApiKeyAuthorization();
|
||||
*/
|
||||
|
||||
window.swaggerUi.load();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id='header'>
|
||||
<div class="swagger-ui-wrap">
|
||||
<a id="logo" href="http://swagger.io">swagger</a>
|
||||
<form id='api_selector'>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message-bar" class="swagger-ui-wrap"> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Swagger UI</title>
|
||||
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
|
||||
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<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-2.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='swagger-ui.js' type='text/javascript'></script>
|
||||
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
|
||||
<script src='lib/marked.js' type='text/javascript'></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var url = window.location.search.match(/url=([^&]+)/);
|
||||
if (url && url.length > 1) {
|
||||
url = decodeURIComponent(url[1]);
|
||||
} else {
|
||||
url = "http://petstore.swagger.io/v2/swagger.json";
|
||||
}
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: url,
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
if(typeof initOAuth == "function") {
|
||||
/*
|
||||
initOAuth({
|
||||
clientId: "your-client-id",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name"
|
||||
});
|
||||
*/
|
||||
}
|
||||
$('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e)
|
||||
});
|
||||
},
|
||||
onFailure: function(data) {
|
||||
log("Unable to Load SwaggerUI");
|
||||
},
|
||||
docExpansion: "none",
|
||||
sorter : "alpha"
|
||||
});
|
||||
|
||||
function addApiKeyAuthorization() {
|
||||
var key = encodeURIComponent($('#input_apiKey')[0].value);
|
||||
log("key: " + key);
|
||||
if(key && key.trim() != "") {
|
||||
var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "query");
|
||||
window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
|
||||
log("added key " + key);
|
||||
}
|
||||
}
|
||||
|
||||
$('#input_apiKey').change(addApiKeyAuthorization);
|
||||
|
||||
// if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
|
||||
/*
|
||||
var apiKey = "myApiKeyXXXX123456789";
|
||||
$('#input_apiKey').val(apiKey);
|
||||
addApiKeyAuthorization();
|
||||
*/
|
||||
|
||||
window.swaggerUi.load();
|
||||
|
||||
function log() {
|
||||
if ('console' in window) {
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id='header'>
|
||||
<div class="swagger-ui-wrap">
|
||||
<a id="logo" href="http://swagger.io">swagger</a>
|
||||
<form id='api_selector'>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message-bar" class="swagger-ui-wrap"> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
2
dist/lib/jquery-1.8.0.min.js
vendored
2765
dist/lib/shred.bundle.js
vendored
193
dist/lib/shred/content.js
vendored
@@ -1,193 +0,0 @@
|
||||
|
||||
// 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;
|
||||
3294
dist/lib/swagger-client.js
vendored
25
dist/lib/swagger-oauth.js
vendored
@@ -97,18 +97,19 @@ function handleLogin() {
|
||||
var authSchemes = window.swaggerUi.api.authSchemes;
|
||||
var host = window.location;
|
||||
var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/"));
|
||||
var redirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
|
||||
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
|
||||
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl;
|
||||
var url = null;
|
||||
|
||||
for (var key in authSchemes) {
|
||||
if (authSchemes.hasOwnProperty(key)) {
|
||||
var flow = authSchemes[key].flow;
|
||||
|
||||
|
||||
if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) {
|
||||
var dets = authSchemes[key];
|
||||
url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
|
||||
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
|
||||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
|
||||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
|
||||
}
|
||||
else if(authSchemes[key].grantTypes) {
|
||||
// 1.2 support
|
||||
@@ -135,11 +136,14 @@ function handleLogin() {
|
||||
|
||||
for(k =0; k < o.length; k++) {
|
||||
var scope = $(o[k]).attr('scope');
|
||||
|
||||
|
||||
if (scopes.indexOf(scope) === -1)
|
||||
scopes.push(scope);
|
||||
}
|
||||
|
||||
// Implicit auth recommends a state parameter.
|
||||
var state = Math.random ();
|
||||
|
||||
window.enabledScopes=scopes;
|
||||
|
||||
redirect_uri = redirectUrl;
|
||||
@@ -147,7 +151,8 @@ function handleLogin() {
|
||||
url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
|
||||
url += '&realm=' + encodeURIComponent(realm);
|
||||
url += '&client_id=' + encodeURIComponent(clientId);
|
||||
url += '&scope=' + encodeURIComponent(scopes);
|
||||
url += '&scope=' + encodeURIComponent(scopes.join(' '));
|
||||
url += '&state=' + encodeURIComponent(state);
|
||||
|
||||
window.open(url);
|
||||
});
|
||||
@@ -198,7 +203,7 @@ function initOAuth(opts) {
|
||||
});
|
||||
}
|
||||
|
||||
function processOAuthCode(data) {
|
||||
window.processOAuthCode = function processOAuthCode(data) {
|
||||
var params = {
|
||||
'client_id': clientId,
|
||||
'code': data.code,
|
||||
@@ -210,18 +215,18 @@ function processOAuthCode(data) {
|
||||
url : window.swaggerUi.tokenUrl,
|
||||
type: "POST",
|
||||
data: params,
|
||||
success:function(data, textStatus, jqXHR)
|
||||
success:function(data, textStatus, jqXHR)
|
||||
{
|
||||
onOAuthComplete(data);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown)
|
||||
error: function(jqXHR, textStatus, errorThrown)
|
||||
{
|
||||
onOAuthComplete("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onOAuthComplete(token) {
|
||||
window.onOAuthComplete = function onOAuthComplete(token) {
|
||||
if(token) {
|
||||
if(token.error) {
|
||||
var checkbox = $('input[type=checkbox],.secured')
|
||||
@@ -268,7 +273,7 @@ function onOAuthComplete(token) {
|
||||
// all scopes are satisfied
|
||||
$(o).find('.api-ic').addClass('ic-info');
|
||||
$(o).find('.api-ic').removeClass('ic-warning');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
1
dist/lib/underscore-min.map
vendored
Normal file
22887
dist/swagger-ui.js
vendored
10
dist/swagger-ui.min.js
vendored
45
gulpfile.js
@@ -2,9 +2,7 @@
|
||||
|
||||
var gulp = require('gulp');
|
||||
var es = require('event-stream');
|
||||
var gutil = require('gulp-util');
|
||||
var clean = require('gulp-clean');
|
||||
var coffee = require('gulp-coffee');
|
||||
var concat = require('gulp-concat');
|
||||
var uglify = require('gulp-uglify');
|
||||
var rename = require('gulp-rename');
|
||||
@@ -16,6 +14,7 @@ var watch = require('gulp-watch');
|
||||
var connect = require('gulp-connect');
|
||||
var header = require('gulp-header');
|
||||
var pkg = require('./package.json');
|
||||
var order = require('gulp-order');
|
||||
var banner = ['/**',
|
||||
' * <%= pkg.name %> - <%= pkg.description %>',
|
||||
' * @version v<%= pkg.version %>',
|
||||
@@ -31,7 +30,7 @@ gulp.task('clean', function() {
|
||||
return gulp
|
||||
.src('./dist', {read: false})
|
||||
.pipe(clean({force: true}))
|
||||
.on('error', gutil.log);
|
||||
.on('error', log);
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -46,17 +45,7 @@ function templates() {
|
||||
namespace: 'Handlebars.templates',
|
||||
noRedeclare: true, // Avoid duplicate declarations
|
||||
}))
|
||||
.on('error', gutil.log);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes CoffeeScript files
|
||||
*/
|
||||
function coffeescript () {
|
||||
return gulp
|
||||
.src(['./src/main/coffeescript/**/*.coffee'])
|
||||
.pipe(coffee({bare: true}))
|
||||
.on('error', gutil.log);
|
||||
.on('error', log);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -65,16 +54,21 @@ function coffeescript () {
|
||||
gulp.task('dist', ['clean'], function() {
|
||||
|
||||
return es.merge(
|
||||
gulp.src('./src/main/javascript/doc.js'),
|
||||
coffeescript(),
|
||||
gulp.src([
|
||||
'./src/main/javascript/**/*.js',
|
||||
'./node_modules/swagger-client/browser/swagger-client.js'
|
||||
]),
|
||||
templates()
|
||||
)
|
||||
.pipe(order(['scripts.js', 'templates.js']))
|
||||
.pipe(concat('swagger-ui.js'))
|
||||
.pipe(wrap('(function(){<%= contents %>}).call(this);'))
|
||||
.pipe(header(banner, { pkg: pkg } ))
|
||||
.pipe(gulp.dest('./dist'))
|
||||
.pipe(uglify())
|
||||
.on('error', log)
|
||||
.pipe(rename({extname: '.min.js'}))
|
||||
.on('error', gutil.log)
|
||||
.on('error', log)
|
||||
.pipe(gulp.dest('./dist'))
|
||||
.pipe(connect.reload());
|
||||
});
|
||||
@@ -87,10 +81,11 @@ gulp.task('less', ['clean'], function() {
|
||||
return gulp
|
||||
.src([
|
||||
'./src/main/less/screen.less',
|
||||
'./src/main/less/print.less',
|
||||
'./src/main/less/reset.less'
|
||||
])
|
||||
.pipe(less())
|
||||
.on('error', gutil.log)
|
||||
.on('error', log)
|
||||
.pipe(gulp.dest('./src/main/html/css/'))
|
||||
.pipe(connect.reload());
|
||||
});
|
||||
@@ -103,22 +98,22 @@ gulp.task('copy', ['less'], function() {
|
||||
|
||||
// copy JavaScript files inside lib folder
|
||||
gulp
|
||||
.src(['./lib/**/*.js'])
|
||||
.src(['./lib/**/*.{js,map}'])
|
||||
.pipe(gulp.dest('./dist/lib'))
|
||||
.on('error', gutil.log)
|
||||
.on('error', log);
|
||||
|
||||
// copy all files inside html folder
|
||||
gulp
|
||||
.src(['./src/main/html/**/*'])
|
||||
.pipe(gulp.dest('./dist'))
|
||||
.on('error', gutil.log)
|
||||
.on('error', log);
|
||||
});
|
||||
|
||||
/**
|
||||
* Watch for changes and recompile
|
||||
*/
|
||||
gulp.task('watch', function() {
|
||||
return watch(['./src/**/*.{coffee,js,less}'], function() {
|
||||
return watch(['./src/**/*.{js,less,handlebars}'], function() {
|
||||
gulp.start('default');
|
||||
});
|
||||
});
|
||||
@@ -133,6 +128,10 @@ gulp.task('connect', function() {
|
||||
});
|
||||
});
|
||||
|
||||
function log(error) {
|
||||
console.error(error.toString && error.toString());
|
||||
}
|
||||
|
||||
|
||||
gulp.task('default', ['dist', 'copy']);
|
||||
gulp.task('serve', ['connect', 'watch'])
|
||||
gulp.task('serve', ['connect', 'watch']);
|
||||
|
||||
2
lib/jquery-1.8.0.min.js
vendored
2765
lib/shred.bundle.js
@@ -1,193 +0,0 @@
|
||||
|
||||
// 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;
|
||||
@@ -97,18 +97,19 @@ function handleLogin() {
|
||||
var authSchemes = window.swaggerUi.api.authSchemes;
|
||||
var host = window.location;
|
||||
var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/"));
|
||||
var redirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
|
||||
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html';
|
||||
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl;
|
||||
var url = null;
|
||||
|
||||
for (var key in authSchemes) {
|
||||
if (authSchemes.hasOwnProperty(key)) {
|
||||
var flow = authSchemes[key].flow;
|
||||
|
||||
|
||||
if(authSchemes[key].type === 'oauth2' && flow && (flow === 'implicit' || flow === 'accessCode')) {
|
||||
var dets = authSchemes[key];
|
||||
url = dets.authorizationUrl + '?response_type=' + (flow === 'implicit' ? 'token' : 'code');
|
||||
window.swaggerUi.tokenName = dets.tokenName || 'access_token';
|
||||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
|
||||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null);
|
||||
}
|
||||
else if(authSchemes[key].grantTypes) {
|
||||
// 1.2 support
|
||||
@@ -135,11 +136,14 @@ function handleLogin() {
|
||||
|
||||
for(k =0; k < o.length; k++) {
|
||||
var scope = $(o[k]).attr('scope');
|
||||
|
||||
|
||||
if (scopes.indexOf(scope) === -1)
|
||||
scopes.push(scope);
|
||||
}
|
||||
|
||||
// Implicit auth recommends a state parameter.
|
||||
var state = Math.random ();
|
||||
|
||||
window.enabledScopes=scopes;
|
||||
|
||||
redirect_uri = redirectUrl;
|
||||
@@ -147,7 +151,8 @@ function handleLogin() {
|
||||
url += '&redirect_uri=' + encodeURIComponent(redirectUrl);
|
||||
url += '&realm=' + encodeURIComponent(realm);
|
||||
url += '&client_id=' + encodeURIComponent(clientId);
|
||||
url += '&scope=' + encodeURIComponent(scopes);
|
||||
url += '&scope=' + encodeURIComponent(scopes.join(' '));
|
||||
url += '&state=' + encodeURIComponent(state);
|
||||
|
||||
window.open(url);
|
||||
});
|
||||
@@ -198,7 +203,7 @@ function initOAuth(opts) {
|
||||
});
|
||||
}
|
||||
|
||||
function processOAuthCode(data) {
|
||||
window.processOAuthCode = function processOAuthCode(data) {
|
||||
var params = {
|
||||
'client_id': clientId,
|
||||
'code': data.code,
|
||||
@@ -210,18 +215,18 @@ function processOAuthCode(data) {
|
||||
url : window.swaggerUi.tokenUrl,
|
||||
type: "POST",
|
||||
data: params,
|
||||
success:function(data, textStatus, jqXHR)
|
||||
success:function(data, textStatus, jqXHR)
|
||||
{
|
||||
onOAuthComplete(data);
|
||||
},
|
||||
error: function(jqXHR, textStatus, errorThrown)
|
||||
error: function(jqXHR, textStatus, errorThrown)
|
||||
{
|
||||
onOAuthComplete("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function onOAuthComplete(token) {
|
||||
window.onOAuthComplete = function onOAuthComplete(token) {
|
||||
if(token) {
|
||||
if(token.error) {
|
||||
var checkbox = $('input[type=checkbox],.secured')
|
||||
@@ -268,7 +273,7 @@ function onOAuthComplete(token) {
|
||||
// all scopes are satisfied
|
||||
$(o).find('.api-ic').addClass('ic-info');
|
||||
$(o).find('.api-ic').removeClass('ic-warning');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
$(o).find('.api-ic').removeClass('ic-error');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
1
lib/underscore-min.map
Normal file
54
package.json
@@ -1,48 +1,50 @@
|
||||
{
|
||||
"name": "swagger-ui",
|
||||
"author": "Tony Tam <fehguy@gmail.com>",
|
||||
"description": "Swagger UI is a dependency-free collection of HTML, Javascript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API",
|
||||
"version": "2.1.8-M1",
|
||||
"contributors": [{
|
||||
"name": "Mohsen Azimi",
|
||||
"email": "me@azimi.me"
|
||||
}],
|
||||
"description": "Swagger UI is a dependency-free collection of HTML, JavaScript, and CSS assets that dynamically generate beautiful documentation from a Swagger-compliant API",
|
||||
"version": "2.1.0-M2",
|
||||
"homepage": "http://swagger.io",
|
||||
"license": "Apache 2.0",
|
||||
"scripts": {
|
||||
"build": "./node_modules/gulp/bin/gulp.js;",
|
||||
"serve": "./node_modules/gulp/bin/gulp.js serve;",
|
||||
"test": "./node_modules/gulp/bin/gulp.js; ./node_modules/mocha/bin/mocha"
|
||||
"build": "gulp",
|
||||
"serve": "gulp serve",
|
||||
"prejshint": "gulp",
|
||||
"jshint": "jshint .",
|
||||
"pretest": "npm run jshint",
|
||||
"test": "mocha"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/swagger-api/swagger-ui.git"
|
||||
},
|
||||
"readmeFilename": "README.md",
|
||||
"dependencies": {
|
||||
"shred": "0.8.10",
|
||||
"btoa": "1.1.1",
|
||||
"swagger-client": "2.1.9-M1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"chai": "^1.10.0",
|
||||
"cors": "2.1.1",
|
||||
"docco": "0.4.x",
|
||||
"event-stream": "^3.2.1",
|
||||
"express": "3.x",
|
||||
"gulp": "^3.8.10",
|
||||
"chai": "^2.1.0",
|
||||
"cors": "^2.5.3",
|
||||
"docco": "^0.7.0",
|
||||
"event-stream": "^3.2.2",
|
||||
"express": "^4.12.0",
|
||||
"gulp": "^3.8.11",
|
||||
"gulp-clean": "^0.3.1",
|
||||
"gulp-coffee": "^2.2.0",
|
||||
"gulp-concat": "^2.4.3",
|
||||
"gulp-concat": "^2.5.2",
|
||||
"gulp-connect": "^2.2.0",
|
||||
"gulp-declare": "^0.3.0",
|
||||
"gulp-handlebars": "^3.0.1",
|
||||
"gulp-header": "1.2.2",
|
||||
"gulp-less": "^2.0.1",
|
||||
"gulp-header": "^1.2.2",
|
||||
"gulp-less": "^3.0.1",
|
||||
"gulp-order": "^1.1.1",
|
||||
"gulp-rename": "^1.2.0",
|
||||
"gulp-uglify": "^1.1.0",
|
||||
"gulp-util": "^3.0.2",
|
||||
"gulp-watch": "^4.1.0",
|
||||
"gulp-wrap": "^0.10.1",
|
||||
"http-server": "^0.7.4",
|
||||
"less": "~1.4.2",
|
||||
"gulp-watch": "^4.1.1",
|
||||
"gulp-wrap": "^0.11.0",
|
||||
"http-server": "git+https://github.com/nodeapps/http-server.git",
|
||||
"less": "^2.4.0",
|
||||
"mocha": "^2.1.0",
|
||||
"selenium-webdriver": "^2.44.0"
|
||||
"selenium-webdriver": "^2.45.0",
|
||||
"swagger-client": "2.1.0-M2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,130 +0,0 @@
|
||||
class SwaggerUi extends Backbone.Router
|
||||
|
||||
# Defaults
|
||||
dom_id: "swagger_ui"
|
||||
|
||||
# Attributes
|
||||
options: null
|
||||
api: null
|
||||
headerView: null
|
||||
mainView: null
|
||||
|
||||
# SwaggerUi accepts all the same options as SwaggerApi
|
||||
initialize: (options={}) ->
|
||||
# Allow dom_id to be overridden
|
||||
if options.dom_id?
|
||||
@dom_id = options.dom_id
|
||||
delete options.dom_id
|
||||
|
||||
if not options.supportedSubmitMethods?
|
||||
options.supportedSubmitMethods = ['get','put','post','delete','head','options','patch']
|
||||
|
||||
# Create an empty div which contains the dom_id
|
||||
$('body').append('<div id="' + @dom_id + '"></div>') if not $('#' + @dom_id)?
|
||||
|
||||
@options = options
|
||||
|
||||
# Set the callbacks
|
||||
@options.success = =>
|
||||
@render()
|
||||
@options.progress = (d) => @showMessage(d)
|
||||
@options.failure = (d) =>
|
||||
@onLoadFailure(d)
|
||||
|
||||
# Create view to handle the header inputs
|
||||
@headerView = new HeaderView({el: $('#header')})
|
||||
|
||||
# Event handler for when the baseUrl/apiKey is entered by user
|
||||
@headerView.on 'update-swagger-ui', (data) => @updateSwaggerUi(data)
|
||||
|
||||
# Set an option after initializing
|
||||
setOption: (option,value) ->
|
||||
@options[option] = value
|
||||
|
||||
# Get the value of a previously set option
|
||||
getOption: (option) ->
|
||||
@options[option]
|
||||
|
||||
# Event handler for when url/key is received from user
|
||||
updateSwaggerUi: (data) ->
|
||||
@options.url = data.url
|
||||
@load()
|
||||
|
||||
# Create an api and render
|
||||
load: ->
|
||||
# Initialize the API object
|
||||
@mainView?.clear()
|
||||
url = @options.url
|
||||
if url && url.indexOf("http") isnt 0
|
||||
url = @buildUrl(window.location.href.toString(), url)
|
||||
|
||||
@options.url = url
|
||||
@headerView.update(url)
|
||||
|
||||
@api = new SwaggerClient(@options)
|
||||
|
||||
# collapse all sections
|
||||
collapseAll:() ->
|
||||
Docs.collapseEndpointListForResource('')
|
||||
|
||||
# list operations for all sections
|
||||
listAll:() ->
|
||||
Docs.collapseOperationsForResource('')
|
||||
|
||||
# expand operations for all sections
|
||||
expandAll:() ->
|
||||
Docs.expandOperationsForResource('')
|
||||
|
||||
# This is bound to success handler for SwaggerApi
|
||||
# so it gets called when SwaggerApi completes loading
|
||||
render:() ->
|
||||
@showMessage('Finished Loading Resource Information. Rendering Swagger UI...')
|
||||
@mainView = new MainView({model: @api, el: $('#' + @dom_id), swaggerOptions: @options}).render()
|
||||
@showMessage()
|
||||
switch @options.docExpansion
|
||||
when "full" then @expandAll()
|
||||
when "list" then @listAll()
|
||||
@renderGFM()
|
||||
@options.onComplete(@api, @) if @options.onComplete
|
||||
setTimeout(
|
||||
=>
|
||||
Docs.shebang()
|
||||
100
|
||||
)
|
||||
|
||||
buildUrl: (base, url) ->
|
||||
if url.indexOf("/") is 0
|
||||
parts = base.split("/")
|
||||
base = parts[0] + "//" + parts[2]
|
||||
base + url
|
||||
else
|
||||
endOfPath = base.length
|
||||
if base.indexOf("?") > -1
|
||||
endOfPath = Math.min(endOfPath, base.indexOf("?"))
|
||||
if base.indexOf("#") > -1
|
||||
endOfPath = Math.min(endOfPath, base.indexOf("#"))
|
||||
base = base.substring(0, endOfPath);
|
||||
if base.indexOf( "/", base.length - 1 ) isnt -1
|
||||
return base + url
|
||||
return base + "/" + url
|
||||
|
||||
# Shows message on topbar of the ui
|
||||
showMessage: (data = '') ->
|
||||
$('#message-bar').removeClass 'message-fail'
|
||||
$('#message-bar').addClass 'message-success'
|
||||
$('#message-bar').html data
|
||||
|
||||
# shows message in red
|
||||
onLoadFailure: (data = '') ->
|
||||
$('#message-bar').removeClass 'message-success'
|
||||
$('#message-bar').addClass 'message-fail'
|
||||
val = $('#message-bar').html data
|
||||
@options.onFailure(data) if @options.onFailure?
|
||||
val
|
||||
|
||||
# Renders GFM for elements with 'markdown' class
|
||||
renderGFM: (data = '') ->
|
||||
$('.markdown').each (index) ->
|
||||
$(this).html(marked($(this).html()))
|
||||
|
||||
window.SwaggerUi = SwaggerUi
|
||||
@@ -1,5 +0,0 @@
|
||||
Handlebars.registerHelper('sanitize', (html) ->
|
||||
# Strip the script tags from the html, and return it as a Handlebars.SafeString
|
||||
html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
||||
return new Handlebars.SafeString(html)
|
||||
)
|
||||
@@ -1,31 +0,0 @@
|
||||
class ApiKeyButton extends Backbone.View
|
||||
initialize: ->
|
||||
|
||||
render: ->
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
@
|
||||
|
||||
events:
|
||||
"click #apikey_button" : "toggleApiKeyContainer"
|
||||
"click #apply_api_key" : "applyApiKey"
|
||||
|
||||
applyApiKey: ->
|
||||
window.authorizations.add(@model.name, new ApiKeyAuthorization(@model.name, $("#input_apiKey_entry").val(), @model.in))
|
||||
window.swaggerUi.load()
|
||||
elem = $('#apikey_container').show()
|
||||
|
||||
toggleApiKeyContainer: ->
|
||||
if $('#apikey_container').length > 0
|
||||
elem = $('#apikey_container').first()
|
||||
if elem.is ':visible'
|
||||
elem.hide()
|
||||
else
|
||||
# hide others
|
||||
$('.auth_container').hide()
|
||||
elem.show()
|
||||
|
||||
template: ->
|
||||
Handlebars.templates.apikey_button_view
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
class BasicAuthButton extends Backbone.View
|
||||
initialize: ->
|
||||
|
||||
render: ->
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
@
|
||||
|
||||
events:
|
||||
"click #basic_auth_button" : "togglePasswordContainer"
|
||||
"click #apply_basic_auth" : "applyPassword"
|
||||
|
||||
applyPassword: ->
|
||||
username = $(".input_username").val()
|
||||
password = $(".input_password").val()
|
||||
window.authorizations.add(@model.type, new PasswordAuthorization("basic", username, password))
|
||||
window.swaggerUi.load()
|
||||
elem = $('#basic_auth_container').hide()
|
||||
|
||||
|
||||
togglePasswordContainer: ->
|
||||
if $('#basic_auth_container').length > 0
|
||||
elem = $('#basic_auth_container').show()
|
||||
if elem.is ':visible'
|
||||
elem.slideUp()
|
||||
else
|
||||
# hide others
|
||||
$('.auth_container').hide()
|
||||
elem.show()
|
||||
|
||||
template: ->
|
||||
Handlebars.templates.basic_auth_button_view
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
class ContentTypeView extends Backbone.View
|
||||
initialize: ->
|
||||
|
||||
render: ->
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
$('label[for=contentType]', $(@el)).text('Response Content Type')
|
||||
|
||||
@
|
||||
|
||||
template: ->
|
||||
Handlebars.templates.content_type
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
class HeaderView extends Backbone.View
|
||||
events: {
|
||||
'click #show-pet-store-icon' : 'showPetStore'
|
||||
'click #show-wordnik-dev-icon' : 'showWordnikDev'
|
||||
'click #explore' : 'showCustom'
|
||||
'keyup #input_baseUrl' : 'showCustomOnKeyup'
|
||||
'keyup #input_apiKey' : 'showCustomOnKeyup'
|
||||
}
|
||||
|
||||
initialize: ->
|
||||
|
||||
showPetStore: (e) ->
|
||||
@trigger(
|
||||
'update-swagger-ui'
|
||||
{url:"http://petstore.swagger.wordnik.com/api/api-docs"}
|
||||
)
|
||||
|
||||
showWordnikDev: (e) ->
|
||||
@trigger(
|
||||
'update-swagger-ui'
|
||||
{url:"http://api.wordnik.com/v4/resources.json"}
|
||||
)
|
||||
|
||||
showCustomOnKeyup: (e) ->
|
||||
@showCustom() if e.keyCode is 13
|
||||
|
||||
showCustom: (e) ->
|
||||
e?.preventDefault()
|
||||
@trigger(
|
||||
'update-swagger-ui'
|
||||
{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', {url:url} if trigger
|
||||
@@ -1,74 +0,0 @@
|
||||
class MainView extends Backbone.View
|
||||
sorters = {
|
||||
'alpha' : (a,b) -> return a.path.localeCompare(b.path),
|
||||
'method' : (a,b) -> return a.method.localeCompare(b.method),
|
||||
}
|
||||
|
||||
initialize: (opts={}) ->
|
||||
# set up the UI for input
|
||||
@model.auths = []
|
||||
for key, value of @model.securityDefinitions
|
||||
auth = {name: key, type: value.type, value: value}
|
||||
@model.auths.push auth
|
||||
|
||||
if @model.swaggerVersion is "2.0"
|
||||
if "validatorUrl" of opts.swaggerOptions
|
||||
# Validator URL specified explicitly
|
||||
@model.validatorUrl = opts.swaggerOptions.validatorUrl
|
||||
else if @model.url.indexOf("localhost") > 0
|
||||
# Localhost override
|
||||
@model.validatorUrl = null
|
||||
else
|
||||
# Default validator
|
||||
@model.validatorUrl = "http://online.swagger.io/validator"
|
||||
|
||||
render: ->
|
||||
if @model.securityDefinitions
|
||||
for name of @model.securityDefinitions
|
||||
auth = @model.securityDefinitions[name]
|
||||
if auth.type is "apiKey" and $("#apikey_button").length is 0
|
||||
button = new ApiKeyButton({model: auth}).render().el
|
||||
$('.auth_main_container').append button
|
||||
if auth.type is "basicAuth" and $("#basic_auth_button").length is 0
|
||||
button = new BasicAuthButton({model: auth}).render().el
|
||||
$('.auth_main_container').append button
|
||||
|
||||
# Render the outer container for resources
|
||||
$(@el).html(Handlebars.templates.main(@model))
|
||||
|
||||
# Render each resource
|
||||
|
||||
resources = {}
|
||||
counter = 0
|
||||
for resource in @model.apisArray
|
||||
id = resource.name
|
||||
while typeof resources[id] isnt 'undefined'
|
||||
id = id + "_" + counter
|
||||
counter += 1
|
||||
resource.id = id
|
||||
resources[id] = resource
|
||||
@addResource resource, @model.auths
|
||||
|
||||
$('.propWrap').hover(
|
||||
->
|
||||
$('.optionsWrapper', $(this)).show()
|
||||
,->
|
||||
$('.optionsWrapper', $(this)).hide()
|
||||
)
|
||||
@
|
||||
|
||||
addResource: (resource, auths) ->
|
||||
# Render a resource and add it to resources li
|
||||
resource.id = resource.id.replace(/\s/g, '_')
|
||||
resourceView = new ResourceView({
|
||||
model: resource,
|
||||
tagName: 'li',
|
||||
id: 'resource_' + resource.id,
|
||||
className: 'resource',
|
||||
auths: auths,
|
||||
swaggerOptions: @options.swaggerOptions
|
||||
})
|
||||
$('#resources').append resourceView.render().el
|
||||
|
||||
clear: ->
|
||||
$(@el).html ''
|
||||
@@ -1,458 +0,0 @@
|
||||
class OperationView extends Backbone.View
|
||||
invocationUrl: null
|
||||
|
||||
events: {
|
||||
'submit .sandbox' : 'submitOperation'
|
||||
'click .submit' : 'submitOperation'
|
||||
'click .response_hider' : 'hideResponse'
|
||||
'click .toggleOperation' : 'toggleOperationContent'
|
||||
'mouseenter .api-ic' : 'mouseEnter'
|
||||
'mouseout .api-ic' : 'mouseExit'
|
||||
}
|
||||
|
||||
initialize: (opts={}) ->
|
||||
@auths = opts.auths
|
||||
@parentId = @model.parentId
|
||||
@nickname = @model.nickname
|
||||
@
|
||||
|
||||
mouseEnter: (e) ->
|
||||
elem = $(@el).find '.content'
|
||||
x = e.pageX
|
||||
y = e.pageY
|
||||
scX = $(window).scrollLeft()
|
||||
scY = $(window).scrollTop()
|
||||
scMaxX = scX + $(window).width()
|
||||
scMaxY = scY + $(window).height()
|
||||
wd = elem.width()
|
||||
hgh = elem.height()
|
||||
|
||||
if (x + wd > scMaxX)
|
||||
x = scMaxX - wd
|
||||
if (x < scX)
|
||||
x = scX
|
||||
if (y + hgh > scMaxY)
|
||||
y = scMaxY - hgh
|
||||
if (y < scY)
|
||||
y = scY
|
||||
pos = {}
|
||||
pos.top = y
|
||||
pos.left = x
|
||||
elem.css(pos)
|
||||
$(e.currentTarget.parentNode).find('#api_information_panel').show()
|
||||
|
||||
mouseExit: (e) ->
|
||||
$(e.currentTarget.parentNode).find('#api_information_panel').hide()
|
||||
|
||||
render: ->
|
||||
isMethodSubmissionSupported = jQuery.inArray(@model.method, @model.supportedSubmitMethods()) >= 0
|
||||
@model.isReadOnly = true unless isMethodSubmissionSupported
|
||||
|
||||
# 1.2 syntax for description was `notes`
|
||||
@model.description = (@model.description || @model.notes)
|
||||
if @model.description
|
||||
@model.description = @model.description.replace(/(?:\r\n|\r|\n)/g, '<br />')
|
||||
@model.oauth = null
|
||||
modelAuths = @model.authorizations || @model.security
|
||||
if modelAuths
|
||||
if Array.isArray modelAuths
|
||||
for auths in modelAuths
|
||||
for key, auth of auths
|
||||
for a of @auths
|
||||
auth = @auths[a]
|
||||
if auth.type == 'oauth2'
|
||||
@model.oauth = {}
|
||||
@model.oauth.scopes = []
|
||||
for k, v of auth.value.scopes
|
||||
scopeIndex = auths[key].indexOf k
|
||||
if scopeIndex >= 0
|
||||
o = {scope: k, description: v}
|
||||
@model.oauth.scopes.push o
|
||||
else
|
||||
for k, v of modelAuths
|
||||
if k == "oauth2"
|
||||
if @model.oauth == null
|
||||
@model.oauth = {}
|
||||
if @model.oauth.scopes is undefined
|
||||
@model.oauth.scopes = []
|
||||
for o in v
|
||||
@model.oauth.scopes.push o
|
||||
|
||||
if typeof @model.responses isnt 'undefined'
|
||||
@model.responseMessages = []
|
||||
for code, value of @model.responses
|
||||
schema = null
|
||||
schemaObj = @model.responses[code].schema
|
||||
if schemaObj and schemaObj['$ref']
|
||||
schema = schemaObj['$ref']
|
||||
if schema.indexOf('#/definitions/') is 0
|
||||
schema = schema.substring('#/definitions/'.length)
|
||||
@model.responseMessages.push {code: code, message: value.description, responseModel: schema }
|
||||
|
||||
if typeof @model.responseMessages is 'undefined'
|
||||
@model.responseMessages = []
|
||||
|
||||
# 2.0
|
||||
signatureModel = null
|
||||
if @model.successResponse
|
||||
successResponse = @model.successResponse
|
||||
for key of successResponse
|
||||
value = successResponse[key]
|
||||
@model.successCode = key
|
||||
if typeof value is 'object' and typeof value.createJSONSample is 'function'
|
||||
signatureModel =
|
||||
sampleJSON: JSON.stringify(value.createJSONSample(), undefined, 2)
|
||||
isParam: false
|
||||
signature: value.getMockSignature()
|
||||
# 1.2
|
||||
else if @model.responseClassSignature and @model.responseClassSignature != 'string'
|
||||
signatureModel =
|
||||
sampleJSON: @model.responseSampleJSON
|
||||
isParam: false
|
||||
signature: @model.responseClassSignature
|
||||
|
||||
|
||||
$(@el).html(Handlebars.templates.operation(@model))
|
||||
|
||||
if signatureModel
|
||||
responseSignatureView = new SignatureView({model: signatureModel, tagName: 'div'})
|
||||
$('.model-signature', $(@el)).append responseSignatureView.render().el
|
||||
else
|
||||
@model.responseClassSignature = 'string'
|
||||
$('.model-signature', $(@el)).html(@model.type)
|
||||
|
||||
contentTypeModel =
|
||||
isParam: false
|
||||
|
||||
contentTypeModel.consumes = @model.consumes
|
||||
contentTypeModel.produces = @model.produces
|
||||
|
||||
for param in @model.parameters
|
||||
type = param.type || param.dataType || ''
|
||||
if typeof type is 'undefined'
|
||||
schema = param.schema
|
||||
if schema and schema['$ref']
|
||||
ref = schema['$ref']
|
||||
if ref.indexOf('#/definitions/') is 0
|
||||
type = ref.substring('#/definitions/'.length)
|
||||
else
|
||||
type = ref
|
||||
if type and type.toLowerCase() == 'file'
|
||||
if !contentTypeModel.consumes
|
||||
contentTypeModel.consumes = 'multipart/form-data'
|
||||
param.type = type
|
||||
|
||||
responseContentTypeView = new ResponseContentTypeView({model: contentTypeModel})
|
||||
$('.response-content-type', $(@el)).append responseContentTypeView.render().el
|
||||
|
||||
# Render each parameter
|
||||
@addParameter param, contentTypeModel.consumes for param in @model.parameters
|
||||
|
||||
# Render each response code
|
||||
@addStatusCode statusCode for statusCode in @model.responseMessages
|
||||
|
||||
@
|
||||
|
||||
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
|
||||
|
||||
addStatusCode: (statusCode) ->
|
||||
# Render status codes
|
||||
statusCodeView = new StatusCodeView({model: statusCode, tagName: 'tr'})
|
||||
$('.operation-status', $(@el)).append statusCodeView.render().el
|
||||
|
||||
submitOperation: (e) ->
|
||||
e?.preventDefault()
|
||||
# Check for errors
|
||||
form = $('.sandbox', $(@el))
|
||||
error_free = true
|
||||
form.find("input.required").each ->
|
||||
$(@).removeClass "error"
|
||||
if jQuery.trim($(@).val()) is ""
|
||||
$(@).addClass "error"
|
||||
$(@).wiggle
|
||||
callback: => $(@).focus()
|
||||
error_free = false
|
||||
form.find("textarea.required").each ->
|
||||
$(@).removeClass "error"
|
||||
if jQuery.trim($(@).val()) is ""
|
||||
$(@).addClass "error"
|
||||
$(@).wiggle
|
||||
callback: => $(@).focus()
|
||||
error_free = false
|
||||
|
||||
# if error free submit it
|
||||
if error_free
|
||||
map = {}
|
||||
opts = {parent: @}
|
||||
|
||||
isFileUpload = false
|
||||
|
||||
for o in form.find("input")
|
||||
if(o.value? && jQuery.trim(o.value).length > 0)
|
||||
map[o.name] = o.value
|
||||
if o.type is "file"
|
||||
map[o.name] = o.files[0]
|
||||
isFileUpload = true
|
||||
|
||||
for o in form.find("textarea")
|
||||
if(o.value? && jQuery.trim(o.value).length > 0)
|
||||
map[o.name] = o.value
|
||||
|
||||
for o in form.find("select")
|
||||
val = this.getSelectedValue o
|
||||
if(val? && jQuery.trim(val).length > 0)
|
||||
map[o.name] = val
|
||||
|
||||
opts.responseContentType = $("div select[name=responseContentType]", $(@el)).val()
|
||||
opts.requestContentType = $("div select[name=parameterContentType]", $(@el)).val()
|
||||
|
||||
$(".response_throbber", $(@el)).show()
|
||||
if isFileUpload
|
||||
@handleFileUpload map, form
|
||||
else
|
||||
@model.do(map, opts, @showCompleteStatus, @showErrorStatus, @)
|
||||
|
||||
success: (response, parent) ->
|
||||
parent.showCompleteStatus response
|
||||
|
||||
handleFileUpload: (map, form) ->
|
||||
for o in form.serializeArray()
|
||||
if(o.value? && jQuery.trim(o.value).length > 0)
|
||||
map[o.name] = o.value
|
||||
|
||||
# requires HTML5 compatible browser
|
||||
bodyParam = new FormData()
|
||||
params = 0
|
||||
|
||||
# add params
|
||||
for param in @model.parameters
|
||||
if param.paramType is 'form' or param.in is 'formData'
|
||||
if param.type.toLowerCase() isnt 'file' and map[param.name] != undefined
|
||||
bodyParam.append(param.name, map[param.name])
|
||||
|
||||
# headers in operation
|
||||
headerParams = {}
|
||||
for param in @model.parameters
|
||||
if param.paramType is 'header'
|
||||
headerParams[param.name] = map[param.name]
|
||||
|
||||
# add files
|
||||
for el in form.find('input[type~="file"]')
|
||||
if typeof el.files[0] isnt 'undefined'
|
||||
bodyParam.append($(el).attr('name'), el.files[0])
|
||||
params += 1
|
||||
|
||||
@invocationUrl =
|
||||
if @model.supportHeaderParams()
|
||||
headerParams = @model.getHeaderParams(map)
|
||||
delete headerParams['Content-Type']
|
||||
@model.urlify(map, false)
|
||||
else
|
||||
@model.urlify(map, true)
|
||||
|
||||
$(".request_url", $(@el)).html("<pre></pre>")
|
||||
$(".request_url pre", $(@el)).text(@invocationUrl);
|
||||
|
||||
obj =
|
||||
type: @model.method
|
||||
url: @invocationUrl
|
||||
headers: headerParams
|
||||
data: bodyParam
|
||||
dataType: 'json'
|
||||
contentType: false
|
||||
processData: false
|
||||
error: (data, textStatus, error) =>
|
||||
@showErrorStatus(@wrap(data), @)
|
||||
success: (data) =>
|
||||
@showResponse(data, @)
|
||||
complete: (data) =>
|
||||
@showCompleteStatus(@wrap(data), @)
|
||||
|
||||
# apply authorizations
|
||||
if window.authorizations
|
||||
window.authorizations.apply obj
|
||||
|
||||
if params is 0
|
||||
obj.data.append("fake", "true");
|
||||
|
||||
jQuery.ajax(obj)
|
||||
false
|
||||
# end of file-upload nastiness
|
||||
|
||||
# wraps a jquery response as a shred response
|
||||
|
||||
wrap: (data) ->
|
||||
headers = {}
|
||||
headerArray = data.getAllResponseHeaders().split("\r")
|
||||
for i in headerArray
|
||||
h = i.match(/^([^:]*?):(.*)$/)
|
||||
if(!h)
|
||||
h = []
|
||||
h.shift()
|
||||
if (h[0] != undefined && h[1] != undefined)
|
||||
headers[h[0].trim()] = h[1].trim()
|
||||
|
||||
o = {}
|
||||
o.content = {}
|
||||
o.content.data = data.responseText
|
||||
o.headers = headers
|
||||
o.request = {}
|
||||
o.request.url = @invocationUrl
|
||||
o.status = data.status
|
||||
o
|
||||
|
||||
getSelectedValue: (select) ->
|
||||
if !select.multiple
|
||||
select.value
|
||||
else
|
||||
options = []
|
||||
options.push opt.value for opt in select.options when opt.selected
|
||||
if options.length > 0
|
||||
options
|
||||
else
|
||||
null
|
||||
|
||||
# handler for hide response link
|
||||
hideResponse: (e) ->
|
||||
e?.preventDefault()
|
||||
$(".response", $(@el)).slideUp()
|
||||
$(".response_hider", $(@el)).fadeOut()
|
||||
|
||||
|
||||
# Show response from server
|
||||
showResponse: (response) ->
|
||||
prettyJson = JSON.stringify(response, null, "\t").replace(/\n/g, "<br>")
|
||||
$(".response_body", $(@el)).html escape(prettyJson)
|
||||
|
||||
# Show error from server
|
||||
showErrorStatus: (data, parent) ->
|
||||
parent.showStatus data
|
||||
|
||||
# show the status codes
|
||||
showCompleteStatus: (data, parent) ->
|
||||
parent.showStatus data
|
||||
|
||||
# Adapted from http://stackoverflow.com/a/2893259/454004
|
||||
formatXml: (xml) ->
|
||||
reg = /(>)(<)(\/*)/g
|
||||
wsexp = /[ ]*(.*)[ ]+\n/g
|
||||
contexp = /(<.+>)(.+\n)/g
|
||||
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2')
|
||||
pad = 0
|
||||
formatted = ''
|
||||
lines = xml.split('\n')
|
||||
indent = 0
|
||||
lastType = 'other'
|
||||
# 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions
|
||||
transitions =
|
||||
'single->single': 0
|
||||
'single->closing': -1
|
||||
'single->opening': 0
|
||||
'single->other': 0
|
||||
'closing->single': 0
|
||||
'closing->closing': -1
|
||||
'closing->opening': 0
|
||||
'closing->other': 0
|
||||
'opening->single': 1
|
||||
'opening->closing': 0
|
||||
'opening->opening': 1
|
||||
'opening->other': 1
|
||||
'other->single': 0
|
||||
'other->closing': -1
|
||||
'other->opening': 0
|
||||
'other->other': 0
|
||||
|
||||
for ln in lines
|
||||
do (ln) ->
|
||||
|
||||
types =
|
||||
# is this line a single tag? ex. <br />
|
||||
single: Boolean(ln.match(/<.+\/>/))
|
||||
# is this a closing tag? ex. </a>
|
||||
closing: Boolean(ln.match(/<\/.+>/))
|
||||
# is this even a tag (that's not <!something>)
|
||||
opening: Boolean(ln.match(/<[^!?].*>/))
|
||||
|
||||
[type] = (key for key, value of types when value)
|
||||
type = if type is undefined then 'other' else type
|
||||
|
||||
fromTo = lastType + '->' + type
|
||||
lastType = type
|
||||
padding = ''
|
||||
|
||||
indent += transitions[fromTo]
|
||||
padding = (' ' for j in [0...(indent)]).join('')
|
||||
if fromTo == 'opening->closing'
|
||||
#substr removes line break (\n) from prev loop
|
||||
formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'
|
||||
else
|
||||
formatted += padding + ln + '\n'
|
||||
|
||||
formatted
|
||||
|
||||
|
||||
# puts the response data in UI
|
||||
showStatus: (response) ->
|
||||
if response.content is undefined
|
||||
content = response.data
|
||||
url = response.url
|
||||
else
|
||||
content = response.content.data
|
||||
url = response.request.url
|
||||
headers = response.headers
|
||||
|
||||
# if server is nice, and sends content-type back, we can use it
|
||||
contentType = null
|
||||
if headers
|
||||
contentType = headers["Content-Type"] or headers["content-type"]
|
||||
if contentType
|
||||
contentType = contentType.split(";")[0].trim()
|
||||
|
||||
$(".response_body", $(@el)).removeClass 'json'
|
||||
$(".response_body", $(@el)).removeClass 'xml'
|
||||
|
||||
if !content
|
||||
code = $('<code />').text("no content")
|
||||
pre = $('<pre class="json" />').append(code)
|
||||
else if contentType is "application/json" || /\+json$/.test(contentType)
|
||||
json = null
|
||||
try
|
||||
json = JSON.stringify(JSON.parse(content), null, " ")
|
||||
catch e
|
||||
json = "can't parse JSON. Raw result:\n\n" + content
|
||||
code = $('<code />').text(json)
|
||||
pre = $('<pre class="json" />').append(code)
|
||||
else if contentType is "application/xml" || /\+xml$/.test(contentType)
|
||||
code = $('<code />').text(@formatXml(content))
|
||||
pre = $('<pre class="xml" />').append(code)
|
||||
else if contentType is "text/html"
|
||||
code = $('<code />').html(_.escape(content))
|
||||
pre = $('<pre class="xml" />').append(code)
|
||||
else if /^image\//.test(contentType)
|
||||
pre = $('<img>').attr('src',url)
|
||||
else
|
||||
# don't know what to render!
|
||||
code = $('<code />').text(content)
|
||||
pre = $('<pre class="json" />').append(code)
|
||||
|
||||
response_body = pre
|
||||
$(".request_url", $(@el)).html("<pre></pre>")
|
||||
$(".request_url pre", $(@el)).text(url);
|
||||
$(".response_code", $(@el)).html "<pre>" + response.status + "</pre>"
|
||||
$(".response_body", $(@el)).html response_body
|
||||
$(".response_headers", $(@el)).html "<pre>" + _.escape(JSON.stringify(response.headers, null, " ")).replace(/\n/g, "<br>") + "</pre>"
|
||||
$(".response", $(@el)).slideDown()
|
||||
$(".response_hider", $(@el)).show()
|
||||
$(".response_throbber", $(@el)).hide()
|
||||
response_body_el = $('.response_body', $(@el))[0]
|
||||
# only highlight the response if response is less than threshold, default state is highlight response
|
||||
opts = @options.swaggerOptions
|
||||
if opts.highlightSizeThreshold && response.data.length > opts.highlightSizeThreshold then response_body_el else hljs.highlightBlock(response_body_el)
|
||||
|
||||
toggleOperationContent: ->
|
||||
elem = $('#' + Docs.escapeResourceName(@parentId + "_" + @nickname + "_content"))
|
||||
if elem.is(':visible') then Docs.collapseOperation(elem) else Docs.expandOperation(elem)
|
||||
@@ -1,14 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
class ParameterView extends Backbone.View
|
||||
initialize: ->
|
||||
Handlebars.registerHelper 'isArray',
|
||||
(param, opts) ->
|
||||
if param.type.toLowerCase() == 'array' || param.allowMultiple
|
||||
opts.fn(@)
|
||||
else
|
||||
opts.inverse(@)
|
||||
|
||||
render: ->
|
||||
type = @model.type || @model.dataType
|
||||
|
||||
if typeof type is 'undefined'
|
||||
schema = @model.schema
|
||||
if schema and schema['$ref']
|
||||
ref = schema['$ref']
|
||||
if ref.indexOf('#/definitions/') is 0
|
||||
type = ref.substring('#/definitions/'.length)
|
||||
else
|
||||
type = ref
|
||||
|
||||
@model.type = type
|
||||
@model.paramType = @model.in || @model.paramType
|
||||
@model.isBody = true if @model.paramType == 'body' or @model.in == 'body'
|
||||
@model.isFile = true if type and type.toLowerCase() == 'file'
|
||||
@model.default = (@model.default || @model.defaultValue)
|
||||
|
||||
if@model.allowableValues
|
||||
@model.isList = true
|
||||
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
signatureModel =
|
||||
sampleJSON: @model.sampleJSON
|
||||
isParam: true
|
||||
signature: @model.signature
|
||||
|
||||
if @model.sampleJSON
|
||||
signatureView = new SignatureView({model: signatureModel, tagName: 'div'})
|
||||
$('.model-signature', $(@el)).append signatureView.render().el
|
||||
else
|
||||
$('.model-signature', $(@el)).html(@model.signature)
|
||||
|
||||
isParam = false
|
||||
|
||||
if @model.isBody
|
||||
isParam = true
|
||||
|
||||
contentTypeModel =
|
||||
isParam: isParam
|
||||
|
||||
contentTypeModel.consumes = @model.consumes
|
||||
|
||||
if isParam
|
||||
parameterContentTypeView = new ParameterContentTypeView({model: contentTypeModel})
|
||||
$('.parameter-content-type', $(@el)).append parameterContentTypeView.render().el
|
||||
|
||||
else
|
||||
responseContentTypeView = new ResponseContentTypeView({model: contentTypeModel})
|
||||
$('.response-content-type', $(@el)).append responseContentTypeView.render().el
|
||||
|
||||
@
|
||||
|
||||
# Return an appropriate template based on if the parameter is a list, readonly, required
|
||||
template: ->
|
||||
if @model.isList
|
||||
Handlebars.templates.param_list
|
||||
else
|
||||
if @options.readOnly
|
||||
if @model.required
|
||||
Handlebars.templates.param_readonly_required
|
||||
else
|
||||
Handlebars.templates.param_readonly
|
||||
else
|
||||
if @model.required
|
||||
Handlebars.templates.param_required
|
||||
else
|
||||
Handlebars.templates.param
|
||||
@@ -1,58 +0,0 @@
|
||||
class ResourceView extends Backbone.View
|
||||
initialize: (opts={}) ->
|
||||
@auths = opts.auths
|
||||
if "" is @model.description
|
||||
@model.description = null
|
||||
if @model.description?
|
||||
@model.summary = @model.description
|
||||
|
||||
render: ->
|
||||
methods = {}
|
||||
|
||||
|
||||
$(@el).html(Handlebars.templates.resource(@model))
|
||||
|
||||
# Render each operation
|
||||
for operation in @model.operationsArray
|
||||
counter = 0
|
||||
|
||||
id = operation.nickname
|
||||
while typeof methods[id] isnt 'undefined'
|
||||
id = id + "_" + counter
|
||||
counter += 1
|
||||
|
||||
methods[id] = operation
|
||||
|
||||
operation.nickname = id
|
||||
operation.parentId = @model.id
|
||||
@addOperation operation
|
||||
|
||||
$('.toggleEndpointList', @el).click(this.callDocs.bind(this, 'toggleEndpointListForResource'))
|
||||
$('.collapseResource', @el).click(this.callDocs.bind(this, 'collapseOperationsForResource'))
|
||||
$('.expandResource', @el).click(this.callDocs.bind(this, 'expandOperationsForResource'))
|
||||
|
||||
return @
|
||||
|
||||
addOperation: (operation) ->
|
||||
|
||||
operation.number = @number
|
||||
|
||||
# Render an operation and add it to operations li
|
||||
operationView = new OperationView({
|
||||
model: operation,
|
||||
tagName: 'li',
|
||||
className: 'endpoint',
|
||||
swaggerOptions: @options.swaggerOptions,
|
||||
auths: @auths
|
||||
})
|
||||
$('.endpoints', $(@el)).append operationView.render().el
|
||||
|
||||
@number++
|
||||
|
||||
#
|
||||
# Generic Event handler (`Docs` is global)
|
||||
#
|
||||
|
||||
callDocs: (fnName, e) ->
|
||||
e.preventDefault()
|
||||
Docs[fnName](e.currentTarget.getAttribute('data-id'))
|
||||
@@ -1,14 +0,0 @@
|
||||
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
|
||||
@@ -1,51 +0,0 @@
|
||||
class SignatureView extends Backbone.View
|
||||
events: {
|
||||
'click a.description-link' : 'switchToDescription'
|
||||
'click a.snippet-link' : 'switchToSnippet'
|
||||
'mousedown .snippet' : 'snippetToTextArea'
|
||||
}
|
||||
|
||||
initialize: ->
|
||||
|
||||
render: ->
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
@switchToSnippet()
|
||||
|
||||
@isParam = @model.isParam
|
||||
|
||||
if @isParam
|
||||
$('.notice', $(@el)).text('Click to set as parameter value')
|
||||
|
||||
@
|
||||
|
||||
template: ->
|
||||
Handlebars.templates.signature
|
||||
|
||||
# handler for show signature
|
||||
switchToDescription: (e) ->
|
||||
e?.preventDefault()
|
||||
$(".snippet", $(@el)).hide()
|
||||
$(".description", $(@el)).show()
|
||||
$('.description-link', $(@el)).addClass('selected')
|
||||
$('.snippet-link', $(@el)).removeClass('selected')
|
||||
|
||||
# handler for show sample
|
||||
switchToSnippet: (e) ->
|
||||
e?.preventDefault()
|
||||
$(".description", $(@el)).hide()
|
||||
$(".snippet", $(@el)).show()
|
||||
$('.snippet-link', $(@el)).addClass('selected')
|
||||
$('.description-link', $(@el)).removeClass('selected')
|
||||
|
||||
# handler for snippet to text area
|
||||
snippetToTextArea: (e) ->
|
||||
if @isParam
|
||||
e?.preventDefault()
|
||||
textArea = $('textarea', $(@el.parentNode.parentNode.parentNode))
|
||||
if $.trim(textArea.val()) == ''
|
||||
textArea.val(@model.sampleJSON)
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
class StatusCodeView extends Backbone.View
|
||||
initialize: ->
|
||||
|
||||
render: ->
|
||||
template = @template()
|
||||
$(@el).html(template(@model))
|
||||
|
||||
if swaggerUi.api.models.hasOwnProperty @model.responseModel
|
||||
responseModel =
|
||||
sampleJSON: JSON.stringify(swaggerUi.api.models[@model.responseModel].createJSONSample(), null, 2)
|
||||
isParam: false
|
||||
signature: swaggerUi.api.models[@model.responseModel].getMockSignature()
|
||||
|
||||
responseModelView = new SignatureView({model: responseModel, tagName: 'div'})
|
||||
$('.model-signature', @$el).append responseModelView.render().el
|
||||
else
|
||||
$('.model-signature', @$el).html ''
|
||||
@
|
||||
|
||||
template: ->
|
||||
Handlebars.templates.status_code
|
||||
|
||||
1155
src/main/html/css/print.css
Normal file
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
BIN
src/main/html/images/favicon-16x16.png
Executable file
BIN
src/main/html/images/favicon-32x32.png
Executable file
BIN
src/main/html/images/favicon.ico
Executable file
|
After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 769 B |
|
Before Width: | Height: | Size: 824 B After Width: | Height: | Size: 823 B |
|
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 979 B |
@@ -1,98 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Swagger UI</title>
|
||||
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='print' 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-2.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-client.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/marked.js' type='text/javascript'></script>
|
||||
|
||||
<!-- enabling this will enable oauth2 implicit scope support -->
|
||||
<script src='lib/swagger-oauth.js' type='text/javascript'></script>
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var url = window.location.search.match(/url=([^&]+)/);
|
||||
if (url && url.length > 1) {
|
||||
url = decodeURIComponent(url[1]);
|
||||
} else {
|
||||
url = "http://petstore.swagger.io/v2/swagger.json";
|
||||
}
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: url,
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
if(typeof initOAuth == "function") {
|
||||
/*
|
||||
initOAuth({
|
||||
clientId: "your-client-id",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name"
|
||||
});
|
||||
*/
|
||||
}
|
||||
$('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e)
|
||||
});
|
||||
},
|
||||
onFailure: function(data) {
|
||||
log("Unable to Load SwaggerUI");
|
||||
},
|
||||
docExpansion: "none",
|
||||
sorter : "alpha"
|
||||
});
|
||||
|
||||
function addApiKeyAuthorization() {
|
||||
var key = $('#input_apiKey')[0].value;
|
||||
log("key: " + key);
|
||||
if(key && key.trim() != "") {
|
||||
log("added key " + key);
|
||||
window.authorizations.add("api_key", new ApiKeyAuthorization("api_key", key, "query"));
|
||||
}
|
||||
}
|
||||
|
||||
$('#input_apiKey').change(function() {
|
||||
addApiKeyAuthorization();
|
||||
});
|
||||
|
||||
// if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
|
||||
/*
|
||||
var apiKey = "myApiKeyXXXX123456789";
|
||||
$('#input_apiKey').val(apiKey);
|
||||
addApiKeyAuthorization();
|
||||
*/
|
||||
|
||||
window.swaggerUi.load();
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id='header'>
|
||||
<div class="swagger-ui-wrap">
|
||||
<a id="logo" href="http://swagger.io">swagger</a>
|
||||
<form id='api_selector'>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message-bar" class="swagger-ui-wrap"> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Swagger UI</title>
|
||||
<link rel="icon" type="image/png" href="images/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="images/favicon-16x16.png" sizes="16x16" />
|
||||
<link href='css/typography.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/screen.css' media='screen' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/reset.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<link href='css/print.css' media='print' rel='stylesheet' type='text/css'/>
|
||||
<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-2.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='swagger-ui.js' type='text/javascript'></script>
|
||||
<script src='lib/highlight.7.3.pack.js' type='text/javascript'></script>
|
||||
<script src='lib/marked.js' type='text/javascript'></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
var url = window.location.search.match(/url=([^&]+)/);
|
||||
if (url && url.length > 1) {
|
||||
url = decodeURIComponent(url[1]);
|
||||
} else {
|
||||
url = "http://petstore.swagger.io/v2/swagger.json";
|
||||
}
|
||||
window.swaggerUi = new SwaggerUi({
|
||||
url: url,
|
||||
dom_id: "swagger-ui-container",
|
||||
supportedSubmitMethods: ['get', 'post', 'put', 'delete', 'patch'],
|
||||
onComplete: function(swaggerApi, swaggerUi){
|
||||
if(typeof initOAuth == "function") {
|
||||
/*
|
||||
initOAuth({
|
||||
clientId: "your-client-id",
|
||||
realm: "your-realms",
|
||||
appName: "your-app-name"
|
||||
});
|
||||
*/
|
||||
}
|
||||
$('pre code').each(function(i, e) {
|
||||
hljs.highlightBlock(e)
|
||||
});
|
||||
},
|
||||
onFailure: function(data) {
|
||||
log("Unable to Load SwaggerUI");
|
||||
},
|
||||
docExpansion: "none",
|
||||
sorter : "alpha"
|
||||
});
|
||||
|
||||
function addApiKeyAuthorization() {
|
||||
var key = encodeURIComponent($('#input_apiKey')[0].value);
|
||||
log("key: " + key);
|
||||
if(key && key.trim() != "") {
|
||||
var apiKeyAuth = new SwaggerClient.ApiKeyAuthorization("api_key", key, "query");
|
||||
window.swaggerUi.api.clientAuthorizations.add("api_key", apiKeyAuth);
|
||||
log("added key " + key);
|
||||
}
|
||||
}
|
||||
|
||||
$('#input_apiKey').change(addApiKeyAuthorization);
|
||||
|
||||
// if you have an apiKey you would like to pre-populate on the page for demonstration purposes...
|
||||
/*
|
||||
var apiKey = "myApiKeyXXXX123456789";
|
||||
$('#input_apiKey').val(apiKey);
|
||||
addApiKeyAuthorization();
|
||||
*/
|
||||
|
||||
window.swaggerUi.load();
|
||||
|
||||
function log() {
|
||||
if ('console' in window) {
|
||||
console.log.apply(console, arguments);
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body class="swagger-section">
|
||||
<div id='header'>
|
||||
<div class="swagger-ui-wrap">
|
||||
<a id="logo" href="http://swagger.io">swagger</a>
|
||||
<form id='api_selector'>
|
||||
<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>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="message-bar" class="swagger-ui-wrap"> </div>
|
||||
<div id="swagger-ui-container" class="swagger-ui-wrap"></div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
256
src/main/javascript/SwaggerUi.js
Normal file
@@ -0,0 +1,256 @@
|
||||
'use strict';
|
||||
|
||||
window.SwaggerUi = Backbone.Router.extend({
|
||||
|
||||
dom_id: 'swagger_ui',
|
||||
|
||||
// Attributes
|
||||
options: null,
|
||||
api: null,
|
||||
headerView: null,
|
||||
mainView: null,
|
||||
|
||||
// SwaggerUi accepts all the same options as SwaggerApi
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
|
||||
// Allow dom_id to be overridden
|
||||
if (options.dom_id) {
|
||||
this.dom_id = options.dom_id;
|
||||
delete options.dom_id;
|
||||
}
|
||||
|
||||
if (!options.supportedSubmitMethods){
|
||||
options.supportedSubmitMethods = [
|
||||
'get',
|
||||
'put',
|
||||
'post',
|
||||
'delete',
|
||||
'head',
|
||||
'options',
|
||||
'patch'
|
||||
];
|
||||
}
|
||||
|
||||
if (typeof options.oauth2RedirectUrl === 'string') {
|
||||
window.oAuthRedirectUrl = options.redirectUrl;
|
||||
}
|
||||
|
||||
// Create an empty div which contains the dom_id
|
||||
if (! $('#' + this.dom_id).length){
|
||||
$('body').append('<div id="' + this.dom_id + '"></div>') ;
|
||||
}
|
||||
|
||||
this.options = options;
|
||||
|
||||
// set marked options
|
||||
marked.setOptions({gfm: true});
|
||||
|
||||
// Set the callbacks
|
||||
var that = this;
|
||||
this.options.success = function() { return that.render(); };
|
||||
this.options.progress = function(d) { return that.showMessage(d); };
|
||||
this.options.failure = function(d) { return that.onLoadFailure(d); };
|
||||
|
||||
// Create view to handle the header inputs
|
||||
this.headerView = new SwaggerUi.Views.HeaderView({el: $('#header')});
|
||||
|
||||
// Event handler for when the baseUrl/apiKey is entered by user
|
||||
this.headerView.on('update-swagger-ui', function(data) {
|
||||
return that.updateSwaggerUi(data);
|
||||
});
|
||||
},
|
||||
|
||||
// Set an option after initializing
|
||||
setOption: function(option, value) {
|
||||
this.options[option] = value;
|
||||
},
|
||||
|
||||
// Get the value of a previously set option
|
||||
getOption: function(option) {
|
||||
return this.options[option];
|
||||
},
|
||||
|
||||
// Event handler for when url/key is received from user
|
||||
updateSwaggerUi: function(data){
|
||||
this.options.url = data.url;
|
||||
this.load();
|
||||
},
|
||||
|
||||
// Create an api and render
|
||||
load: function(){
|
||||
// Initialize the API object
|
||||
if (this.mainView) {
|
||||
this.mainView.clear();
|
||||
}
|
||||
var url = this.options.url;
|
||||
if (url && url.indexOf('http') !== 0) {
|
||||
url = this.buildUrl(window.location.href.toString(), url);
|
||||
}
|
||||
|
||||
this.options.url = url;
|
||||
this.headerView.update(url);
|
||||
|
||||
this.api = new SwaggerClient(this.options);
|
||||
},
|
||||
|
||||
// collapse all sections
|
||||
collapseAll: function(){
|
||||
Docs.collapseEndpointListForResource('');
|
||||
},
|
||||
|
||||
// list operations for all sections
|
||||
listAll: function(){
|
||||
Docs.collapseOperationsForResource('');
|
||||
},
|
||||
|
||||
// expand operations for all sections
|
||||
expandAll: function(){
|
||||
Docs.expandOperationsForResource('');
|
||||
},
|
||||
|
||||
// This is bound to success handler for SwaggerApi
|
||||
// so it gets called when SwaggerApi completes loading
|
||||
render: function(){
|
||||
this.showMessage('Finished Loading Resource Information. Rendering Swagger UI...');
|
||||
this.mainView = new SwaggerUi.Views.MainView({
|
||||
model: this.api,
|
||||
el: $('#' + this.dom_id),
|
||||
swaggerOptions: this.options,
|
||||
router: this
|
||||
}).render();
|
||||
this.showMessage();
|
||||
switch (this.options.docExpansion) {
|
||||
case 'full':
|
||||
this.expandAll(); break;
|
||||
case 'list':
|
||||
this.listAll(); break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
this.renderGFM();
|
||||
|
||||
if (this.options.onComplete){
|
||||
this.options.onComplete(this.api, this);
|
||||
}
|
||||
|
||||
setTimeout(Docs.shebang.bind(this), 100);
|
||||
},
|
||||
|
||||
buildUrl: function(base, url){
|
||||
if (url.indexOf('/') === 0) {
|
||||
var parts = base.split('/');
|
||||
base = parts[0] + '//' + parts[2];
|
||||
return base + url;
|
||||
} else {
|
||||
var endOfPath = base.length;
|
||||
|
||||
if (base.indexOf('?') > -1){
|
||||
endOfPath = Math.min(endOfPath, base.indexOf('?'));
|
||||
}
|
||||
|
||||
if (base.indexOf('#') > -1){
|
||||
endOfPath = Math.min(endOfPath, base.indexOf('#'));
|
||||
}
|
||||
|
||||
base = base.substring(0, endOfPath);
|
||||
|
||||
if (base.indexOf('/', base.length - 1 ) !== -1){
|
||||
return base + url;
|
||||
}
|
||||
|
||||
return base + '/' + url;
|
||||
}
|
||||
},
|
||||
|
||||
// Shows message on topbar of the ui
|
||||
showMessage: function(data){
|
||||
if (data === undefined) {
|
||||
data = '';
|
||||
}
|
||||
$('#message-bar').removeClass('message-fail');
|
||||
$('#message-bar').addClass('message-success');
|
||||
$('#message-bar').html(data);
|
||||
},
|
||||
|
||||
// shows message in red
|
||||
onLoadFailure: function(data){
|
||||
if (data === undefined) {
|
||||
data = '';
|
||||
}
|
||||
$('#message-bar').removeClass('message-success');
|
||||
$('#message-bar').addClass('message-fail');
|
||||
|
||||
var val = $('#message-bar').html(data);
|
||||
|
||||
if (this.options.onFailure) {
|
||||
this.options.onFailure(data);
|
||||
}
|
||||
|
||||
return val;
|
||||
},
|
||||
|
||||
// Renders GFM for elements with 'markdown' class
|
||||
renderGFM: function(){
|
||||
$('.markdown').each(function(){
|
||||
$(this).html(marked($(this).html()));
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
window.SwaggerUi.Views = {};
|
||||
|
||||
// don't break backward compatibility with previous versions and warn users to upgrade their code
|
||||
(function(){
|
||||
window.authorizations = {
|
||||
add: function() {
|
||||
warn('Using window.authorizations is deprecated. Please use SwaggerUi.api.clientAuthorizations.add().');
|
||||
|
||||
if (typeof window.swaggerUi === 'undefined') {
|
||||
throw new TypeError('window.swaggerUi is not defined');
|
||||
}
|
||||
|
||||
if (window.swaggerUi instanceof SwaggerUi) {
|
||||
window.swaggerUi.api.clientAuthorizations.add.apply(window.swaggerUi.api.clientAuthorizations, arguments);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.ApiKeyAuthorization = function() {
|
||||
warn('window.ApiKeyAuthorization is deprecated. Please use SwaggerClient.ApiKeyAuthorization.');
|
||||
SwaggerClient.ApiKeyAuthorization.apply(window, arguments);
|
||||
};
|
||||
|
||||
window.PasswordAuthorization = function() {
|
||||
warn('window.PasswordAuthorization is deprecated. Please use SwaggerClient.PasswordAuthorization.');
|
||||
SwaggerClient.PasswordAuthorization.apply(window, arguments);
|
||||
};
|
||||
|
||||
function warn(message) {
|
||||
if ('console' in window && typeof window.console.warn === 'function') {
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
// UMD
|
||||
(function (root, factory) {
|
||||
if (typeof define === 'function' && define.amd) {
|
||||
// AMD. Register as an anonymous module.
|
||||
define(['b'], function (b) {
|
||||
return (root.SwaggerUi = factory(b));
|
||||
});
|
||||
} else if (typeof exports === 'object') {
|
||||
// Node. Does not work with strict CommonJS, but
|
||||
// only CommonJS-like enviroments that support module.exports,
|
||||
// like Node.
|
||||
module.exports = factory(require('b'));
|
||||
} else {
|
||||
// Browser globals
|
||||
root.SwaggerUi = factory(root.b);
|
||||
}
|
||||
}(this, function () {
|
||||
return SwaggerUi;
|
||||
}));
|
||||
@@ -1,194 +1,197 @@
|
||||
$(function() {
|
||||
|
||||
// Helper function for vertically aligning DOM elements
|
||||
// http://www.seodenver.com/simple-vertical-align-plugin-for-jquery/
|
||||
$.fn.vAlign = function() {
|
||||
return this.each(function(i){
|
||||
var ah = $(this).height();
|
||||
var ph = $(this).parent().height();
|
||||
var mh = (ph - ah) / 2;
|
||||
$(this).css('margin-top', mh);
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.stretchFormtasticInputWidthToParent = function() {
|
||||
return this.each(function(i){
|
||||
var p_width = $(this).closest("form").innerWidth();
|
||||
var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest("form").css('padding-right'), 10);
|
||||
var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10);
|
||||
$(this).css('width', p_width - p_padding - this_padding);
|
||||
});
|
||||
};
|
||||
|
||||
$('form.formtastic li.string input, form.formtastic textarea').stretchFormtasticInputWidthToParent();
|
||||
|
||||
// Vertically center these paragraphs
|
||||
// Parent may need a min-height for this to work..
|
||||
$('ul.downplayed li div.content p').vAlign();
|
||||
|
||||
// When a sandbox form is submitted..
|
||||
$("form.sandbox").submit(function(){
|
||||
|
||||
var error_free = true;
|
||||
|
||||
// Cycle through the forms required inputs
|
||||
$(this).find("input.required").each(function() {
|
||||
|
||||
// Remove any existing error styles from the input
|
||||
$(this).removeClass('error');
|
||||
|
||||
// Tack the error style on if the input is empty..
|
||||
if ($(this).val() == '') {
|
||||
$(this).addClass('error');
|
||||
$(this).wiggle();
|
||||
error_free = false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return error_free;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function clippyCopiedCallback(a) {
|
||||
$('#api_key_copied').fadeIn().delay(1000).fadeOut();
|
||||
|
||||
// var b = $("#clippy_tooltip_" + a);
|
||||
// b.length != 0 && (b.attr("title", "copied!").trigger("tipsy.reload"), setTimeout(function() {
|
||||
// b.attr("title", "copy to clipboard")
|
||||
// },
|
||||
// 500))
|
||||
}
|
||||
|
||||
// Logging function that accounts for browsers that don't have window.console
|
||||
log = function(){
|
||||
log.history = log.history || [];
|
||||
log.history.push(arguments);
|
||||
if(this.console){
|
||||
console.log( Array.prototype.slice.call(arguments)[0] );
|
||||
}
|
||||
};
|
||||
|
||||
// Handle browsers that do console incorrectly (IE9 and below, see http://stackoverflow.com/a/5539378/7913)
|
||||
if (Function.prototype.bind && console && typeof console.log == "object") {
|
||||
[
|
||||
"log","info","warn","error","assert","dir","clear","profile","profileEnd"
|
||||
].forEach(function (method) {
|
||||
console[method] = this.bind(console[method], console);
|
||||
}, Function.prototype.call);
|
||||
}
|
||||
|
||||
var Docs = {
|
||||
|
||||
shebang: function() {
|
||||
|
||||
// If shebang has an operation nickname in it..
|
||||
// e.g. /docs/#!/words/get_search
|
||||
var fragments = $.param.fragment().split('/');
|
||||
fragments.shift(); // get rid of the bang
|
||||
|
||||
switch (fragments.length) {
|
||||
case 1:
|
||||
// Expand all operations for the resource and scroll to it
|
||||
var dom_id = 'resource_' + fragments[0];
|
||||
|
||||
Docs.expandEndpointListForResource(fragments[0]);
|
||||
$("#"+dom_id).slideto({highlight: false});
|
||||
break;
|
||||
case 2:
|
||||
// Refer to the endpoint DOM element, e.g. #words_get_search
|
||||
|
||||
// Expand Resource
|
||||
Docs.expandEndpointListForResource(fragments[0]);
|
||||
$("#"+dom_id).slideto({highlight: false});
|
||||
|
||||
// Expand operation
|
||||
var li_dom_id = fragments.join('_');
|
||||
var li_content_dom_id = li_dom_id + "_content";
|
||||
|
||||
|
||||
Docs.expandOperation($('#'+li_content_dom_id));
|
||||
$('#'+li_dom_id).slideto({highlight: false});
|
||||
break;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
toggleEndpointListForResource: function(resource) {
|
||||
var elem = $('li#resource_' + Docs.escapeResourceName(resource) + ' ul.endpoints');
|
||||
if (elem.is(':visible')) {
|
||||
Docs.collapseEndpointListForResource(resource);
|
||||
} else {
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
}
|
||||
},
|
||||
|
||||
// Expand resource
|
||||
expandEndpointListForResource: function(resource) {
|
||||
var resource = Docs.escapeResourceName(resource);
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints').slideDown();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + resource).addClass('active');
|
||||
|
||||
var elem = $('li#resource_' + resource + ' ul.endpoints');
|
||||
elem.slideDown();
|
||||
},
|
||||
|
||||
// Collapse resource and mark as explicitly closed
|
||||
collapseEndpointListForResource: function(resource) {
|
||||
var resource = Docs.escapeResourceName(resource);
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints').slideUp();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + resource).removeClass('active');
|
||||
|
||||
var elem = $('li#resource_' + resource + ' ul.endpoints');
|
||||
elem.slideUp();
|
||||
},
|
||||
|
||||
expandOperationsForResource: function(resource) {
|
||||
// Make sure the resource container is open..
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints li.operation div.content').slideDown();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() {
|
||||
Docs.expandOperation($(this));
|
||||
});
|
||||
},
|
||||
|
||||
collapseOperationsForResource: function(resource) {
|
||||
// Make sure the resource container is open..
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints li.operation div.content').slideUp();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() {
|
||||
Docs.collapseOperation($(this));
|
||||
});
|
||||
},
|
||||
|
||||
escapeResourceName: function(resource) {
|
||||
return resource.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g, "\\$&");
|
||||
},
|
||||
|
||||
expandOperation: function(elem) {
|
||||
elem.slideDown();
|
||||
},
|
||||
|
||||
collapseOperation: function(elem) {
|
||||
elem.slideUp();
|
||||
}
|
||||
};
|
||||
'use strict';
|
||||
|
||||
|
||||
$(function() {
|
||||
|
||||
// Helper function for vertically aligning DOM elements
|
||||
// http://www.seodenver.com/simple-vertical-align-plugin-for-jquery/
|
||||
$.fn.vAlign = function() {
|
||||
return this.each(function(){
|
||||
var ah = $(this).height();
|
||||
var ph = $(this).parent().height();
|
||||
var mh = (ph - ah) / 2;
|
||||
$(this).css('margin-top', mh);
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.stretchFormtasticInputWidthToParent = function() {
|
||||
return this.each(function(){
|
||||
var p_width = $(this).closest("form").innerWidth();
|
||||
var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest('form').css('padding-right'), 10);
|
||||
var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10);
|
||||
$(this).css('width', p_width - p_padding - this_padding);
|
||||
});
|
||||
};
|
||||
|
||||
$('form.formtastic li.string input, form.formtastic textarea').stretchFormtasticInputWidthToParent();
|
||||
|
||||
// Vertically center these paragraphs
|
||||
// Parent may need a min-height for this to work..
|
||||
$('ul.downplayed li div.content p').vAlign();
|
||||
|
||||
// When a sandbox form is submitted..
|
||||
$("form.sandbox").submit(function(){
|
||||
|
||||
var error_free = true;
|
||||
|
||||
// Cycle through the forms required inputs
|
||||
$(this).find("input.required").each(function() {
|
||||
|
||||
// Remove any existing error styles from the input
|
||||
$(this).removeClass('error');
|
||||
|
||||
// Tack the error style on if the input is empty..
|
||||
if ($(this).val() === '') {
|
||||
$(this).addClass('error');
|
||||
$(this).wiggle();
|
||||
error_free = false;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
return error_free;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function clippyCopiedCallback() {
|
||||
$('#api_key_copied').fadeIn().delay(1000).fadeOut();
|
||||
|
||||
// var b = $("#clippy_tooltip_" + a);
|
||||
// b.length != 0 && (b.attr("title", "copied!").trigger("tipsy.reload"), setTimeout(function() {
|
||||
// b.attr("title", "copy to clipboard")
|
||||
// },
|
||||
// 500))
|
||||
}
|
||||
|
||||
// Logging function that accounts for browsers that don't have window.console
|
||||
function log(){
|
||||
log.history = log.history || [];
|
||||
log.history.push(arguments);
|
||||
if(this.console){
|
||||
console.log( Array.prototype.slice.call(arguments)[0] );
|
||||
}
|
||||
}
|
||||
|
||||
// Handle browsers that do console incorrectly (IE9 and below, see http://stackoverflow.com/a/5539378/7913)
|
||||
if (Function.prototype.bind && console && typeof console.log === "object") {
|
||||
[
|
||||
"log","info","warn","error","assert","dir","clear","profile","profileEnd"
|
||||
].forEach(function (method) {
|
||||
console[method] = this.bind(console[method], console);
|
||||
}, Function.prototype.call);
|
||||
}
|
||||
|
||||
window.Docs = {
|
||||
|
||||
shebang: function() {
|
||||
|
||||
// If shebang has an operation nickname in it..
|
||||
// e.g. /docs/#!/words/get_search
|
||||
var fragments = $.param.fragment().split('/');
|
||||
fragments.shift(); // get rid of the bang
|
||||
|
||||
switch (fragments.length) {
|
||||
case 1:
|
||||
// Expand all operations for the resource and scroll to it
|
||||
var dom_id = 'resource_' + fragments[0];
|
||||
|
||||
Docs.expandEndpointListForResource(fragments[0]);
|
||||
$("#"+dom_id).slideto({highlight: false});
|
||||
break;
|
||||
case 2:
|
||||
// Refer to the endpoint DOM element, e.g. #words_get_search
|
||||
|
||||
// Expand Resource
|
||||
Docs.expandEndpointListForResource(fragments[0]);
|
||||
$("#"+dom_id).slideto({highlight: false});
|
||||
|
||||
// Expand operation
|
||||
var li_dom_id = fragments.join('_');
|
||||
var li_content_dom_id = li_dom_id + "_content";
|
||||
|
||||
|
||||
Docs.expandOperation($('#'+li_content_dom_id));
|
||||
$('#'+li_dom_id).slideto({highlight: false});
|
||||
break;
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
toggleEndpointListForResource: function(resource) {
|
||||
var elem = $('li#resource_' + Docs.escapeResourceName(resource) + ' ul.endpoints');
|
||||
if (elem.is(':visible')) {
|
||||
Docs.collapseEndpointListForResource(resource);
|
||||
} else {
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
}
|
||||
},
|
||||
|
||||
// Expand resource
|
||||
expandEndpointListForResource: function(resource) {
|
||||
var resource = Docs.escapeResourceName(resource);
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints').slideDown();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + resource).addClass('active');
|
||||
|
||||
var elem = $('li#resource_' + resource + ' ul.endpoints');
|
||||
elem.slideDown();
|
||||
},
|
||||
|
||||
// Collapse resource and mark as explicitly closed
|
||||
collapseEndpointListForResource: function(resource) {
|
||||
var resource = Docs.escapeResourceName(resource);
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints').slideUp();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + resource).removeClass('active');
|
||||
|
||||
var elem = $('li#resource_' + resource + ' ul.endpoints');
|
||||
elem.slideUp();
|
||||
},
|
||||
|
||||
expandOperationsForResource: function(resource) {
|
||||
// Make sure the resource container is open..
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints li.operation div.content').slideDown();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() {
|
||||
Docs.expandOperation($(this));
|
||||
});
|
||||
},
|
||||
|
||||
collapseOperationsForResource: function(resource) {
|
||||
// Make sure the resource container is open..
|
||||
Docs.expandEndpointListForResource(resource);
|
||||
|
||||
if (resource == '') {
|
||||
$('.resource ul.endpoints li.operation div.content').slideUp();
|
||||
return;
|
||||
}
|
||||
|
||||
$('li#resource_' + Docs.escapeResourceName(resource) + ' li.operation div.content').each(function() {
|
||||
Docs.collapseOperation($(this));
|
||||
});
|
||||
},
|
||||
|
||||
escapeResourceName: function(resource) {
|
||||
return resource.replace(/[!"#$%&'()*+,.\/:;<=>?@\[\\\]\^`{|}~]/g, "\\$&");
|
||||
},
|
||||
|
||||
expandOperation: function(elem) {
|
||||
elem.slideDown();
|
||||
},
|
||||
|
||||
collapseOperation: function(elem) {
|
||||
elem.slideUp();
|
||||
}
|
||||
};
|
||||
|
||||
7
src/main/javascript/helpers/handlebars.js
Normal file
@@ -0,0 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
Handlebars.registerHelper('sanitize', function(html) {
|
||||
// Strip the script tags from the html, and return it as a Handlebars.SafeString
|
||||
html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
|
||||
return new Handlebars.SafeString(html);
|
||||
});
|
||||
54
src/main/javascript/view/ApiKeyButton.js
Normal file
@@ -0,0 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ApiKeyButton = Backbone.View.extend({ // TODO: append this to global SwaggerUi
|
||||
|
||||
events:{
|
||||
'click #apikey_button' : 'toggleApiKeyContainer',
|
||||
'click #apply_api_key' : 'applyApiKey'
|
||||
},
|
||||
|
||||
initialize: function(opts){
|
||||
this.options = opts || {};
|
||||
this.router = this.options.router;
|
||||
},
|
||||
|
||||
render: function(){
|
||||
var template = this.template();
|
||||
$(this.el).html(template(this.model));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
applyApiKey: function(){
|
||||
var keyAuth = new SwaggerClient.ApiKeyAuthorization(
|
||||
this.model.name,
|
||||
$('#input_apiKey_entry').val(),
|
||||
this.model.in
|
||||
);
|
||||
this.router.api.clientAuthorizations.add(this.model.name, keyAuth);
|
||||
this.router.load();
|
||||
$('#apikey_container').show();
|
||||
},
|
||||
|
||||
toggleApiKeyContainer: function(){
|
||||
if ($('#apikey_container').length) {
|
||||
|
||||
var elem = $('#apikey_container').first();
|
||||
|
||||
if (elem.is(':visible')){
|
||||
elem.hide();
|
||||
} else {
|
||||
|
||||
// hide others
|
||||
$('.auth_container').hide();
|
||||
elem.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: function(){
|
||||
return Handlebars.templates.apikey_button_view;
|
||||
}
|
||||
|
||||
});
|
||||
49
src/main/javascript/view/BasicAuthButton.js
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.BasicAuthButton = Backbone.View.extend({
|
||||
|
||||
|
||||
initialize: function (opts) {
|
||||
this.options = opts || {};
|
||||
this.router = this.options.router;
|
||||
},
|
||||
|
||||
render: function(){
|
||||
var template = this.template();
|
||||
$(this.el).html(template(this.model));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
events: {
|
||||
'click #basic_auth_button' : 'togglePasswordContainer',
|
||||
'click #apply_basic_auth' : 'applyPassword'
|
||||
},
|
||||
|
||||
applyPassword: function(){
|
||||
var username = $('.input_username').val();
|
||||
var password = $('.input_password').val();
|
||||
var basicAuth = new SwaggerClient.PasswordAuthorization('basic', username, password);
|
||||
this.router.api.clientAuthorizations.add(this.model.type, basicAuth);
|
||||
this.router.load();
|
||||
$('#basic_auth_container').hide();
|
||||
},
|
||||
|
||||
togglePasswordContainer: function(){
|
||||
if ($('#basic_auth_container').length) {
|
||||
var elem = $('#basic_auth_container').show();
|
||||
if (elem.is(':visible')){
|
||||
elem.slideUp();
|
||||
} else {
|
||||
// hide others
|
||||
$('.auth_container').hide();
|
||||
elem.show();
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
template: function(){
|
||||
return Handlebars.templates.basic_auth_button_view;
|
||||
}
|
||||
|
||||
});
|
||||
13
src/main/javascript/view/ContentTypeView.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ContentTypeView = Backbone.View.extend({
|
||||
initialize: function() {},
|
||||
|
||||
render: function(){
|
||||
$(this.el).html(Handlebars.templates.content_type(this.model));
|
||||
|
||||
$('label[for=contentType]', $(this.el)).text('Response Content Type');
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
55
src/main/javascript/view/HeaderView.js
Normal file
@@ -0,0 +1,55 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.HeaderView = Backbone.View.extend({
|
||||
events: {
|
||||
'click #show-pet-store-icon' : 'showPetStore',
|
||||
'click #show-wordnik-dev-icon' : 'showWordnikDev',
|
||||
'click #explore' : 'showCustom',
|
||||
'keyup #input_baseUrl' : 'showCustomOnKeyup',
|
||||
'keyup #input_apiKey' : 'showCustomOnKeyup'
|
||||
},
|
||||
|
||||
initialize: function(){},
|
||||
|
||||
showPetStore: function(){
|
||||
this.trigger('update-swagger-ui', {
|
||||
url:'http://petstore.swagger.wordnik.com/api/api-docs'
|
||||
});
|
||||
},
|
||||
|
||||
showWordnikDev: function(){
|
||||
this.trigger('update-swagger-ui', {
|
||||
url: 'http://api.wordnik.com/v4/resources.json'
|
||||
});
|
||||
},
|
||||
|
||||
showCustomOnKeyup: function(e){
|
||||
if (e.keyCode === 13) {
|
||||
this.showCustom();
|
||||
}
|
||||
},
|
||||
|
||||
showCustom: function(e){
|
||||
if (e) {
|
||||
e.preventDefault();
|
||||
}
|
||||
|
||||
this.trigger('update-swagger-ui', {
|
||||
url: $('#input_baseUrl').val(),
|
||||
apiKey: $('#input_apiKey').val()
|
||||
});
|
||||
},
|
||||
|
||||
update: function(url, apiKey, trigger){
|
||||
if (trigger === undefined) {
|
||||
trigger = false;
|
||||
}
|
||||
|
||||
$('#input_baseUrl').val(url);
|
||||
|
||||
//$('#input_apiKey').val(apiKey);
|
||||
if (trigger) {
|
||||
this.trigger('update-swagger-ui', {url:url});
|
||||
}
|
||||
}
|
||||
});
|
||||
139
src/main/javascript/view/MainView.js
Normal file
@@ -0,0 +1,139 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.MainView = Backbone.View.extend({
|
||||
apisSorter : {
|
||||
alpha : function(a,b){ return a.name.localeCompare(b.name); }
|
||||
},
|
||||
operationsSorters : {
|
||||
alpha : function(a,b){ return a.path.localeCompare(b.path); },
|
||||
method : function(a,b){ return a.method.localeCompare(b.method); }
|
||||
},
|
||||
initialize: function(opts){
|
||||
var sorterOption, sorterFn, key, value;
|
||||
opts = opts || {};
|
||||
|
||||
this.router = opts.router;
|
||||
|
||||
// Sort APIs
|
||||
if (opts.swaggerOptions.apisSorter) {
|
||||
sorterOption = opts.swaggerOptions.apisSorter;
|
||||
if (_.isFunction(sorterOption)) {
|
||||
sorterFn = sorterOption;
|
||||
} else {
|
||||
sorterFn = this.apisSorter[sorterOption];
|
||||
}
|
||||
if (_.isFunction(sorterFn)) {
|
||||
this.model.apisArray.sort(sorterFn);
|
||||
}
|
||||
}
|
||||
// Sort operations of each API
|
||||
if (opts.swaggerOptions.operationsSorter) {
|
||||
sorterOption = opts.swaggerOptions.operationsSorter;
|
||||
if (_.isFunction(sorterOption)) {
|
||||
sorterFn = sorterOption;
|
||||
} else {
|
||||
sorterFn = this.operationsSorters[sorterOption];
|
||||
}
|
||||
if (_.isFunction(sorterFn)) {
|
||||
for (key in this.model.apisArray) {
|
||||
this.model.apisArray[key].operationsArray.sort(sorterFn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set up the UI for input
|
||||
this.model.auths = [];
|
||||
|
||||
for (key in this.model.securityDefinitions) {
|
||||
value = this.model.securityDefinitions[key];
|
||||
|
||||
this.model.auths.push({
|
||||
name: key,
|
||||
type: value.type,
|
||||
value: value
|
||||
});
|
||||
}
|
||||
|
||||
if (this.model.swaggerVersion === '2.0') {
|
||||
if ('validatorUrl' in opts.swaggerOptions) {
|
||||
|
||||
// Validator URL specified explicitly
|
||||
this.model.validatorUrl = opts.swaggerOptions.validatorUrl;
|
||||
|
||||
} else if (this.model.url.indexOf('localhost') > 0) {
|
||||
|
||||
// Localhost override
|
||||
this.model.validatorUrl = null;
|
||||
|
||||
} else {
|
||||
|
||||
// Default validator
|
||||
this.model.validatorUrl = 'http://online.swagger.io/validator';
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
render: function(){
|
||||
if (this.model.securityDefinitions) {
|
||||
for (var name in this.model.securityDefinitions) {
|
||||
var auth = this.model.securityDefinitions[name];
|
||||
var button;
|
||||
|
||||
if (auth.type === 'apiKey' && $('#apikey_button').length === 0) {
|
||||
button = new SwaggerUi.Views.ApiKeyButton({model: auth, router: this.router}).render().el;
|
||||
$('.auth_main_container').append(button);
|
||||
}
|
||||
|
||||
if (auth.type === 'basicAuth' && $('#basic_auth_button').length === 0) {
|
||||
button = new SwaggerUi.Views.BasicAuthButton({model: auth, router: this.router}).render().el;
|
||||
$('.auth_main_container').append(button);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render the outer container for resources
|
||||
$(this.el).html(Handlebars.templates.main(this.model));
|
||||
|
||||
// Render each resource
|
||||
|
||||
var resources = {};
|
||||
var counter = 0;
|
||||
for (var i = 0; i < this.model.apisArray.length; i++) {
|
||||
var resource = this.model.apisArray[i];
|
||||
var id = resource.name;
|
||||
while (typeof resources[id] !== 'undefined') {
|
||||
id = id + '_' + counter;
|
||||
counter += 1;
|
||||
}
|
||||
resource.id = id;
|
||||
resources[id] = resource;
|
||||
this.addResource(resource, this.model.auths);
|
||||
}
|
||||
|
||||
$('.propWrap').hover(function onHover(){
|
||||
$('.optionsWrapper', $(this)).show();
|
||||
}, function offhover(){
|
||||
$('.optionsWrapper', $(this)).hide();
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
addResource: function(resource, auths){
|
||||
// Render a resource and add it to resources li
|
||||
resource.id = resource.id.replace(/\s/g, '_');
|
||||
var resourceView = new SwaggerUi.Views.ResourceView({
|
||||
model: resource,
|
||||
router: this.router,
|
||||
tagName: 'li',
|
||||
id: 'resource_' + resource.id,
|
||||
className: 'resource',
|
||||
auths: auths,
|
||||
swaggerOptions: this.options.swaggerOptions
|
||||
});
|
||||
$('#resources').append(resourceView.render().el);
|
||||
},
|
||||
|
||||
clear: function(){
|
||||
$(this.el).html('');
|
||||
}
|
||||
});
|
||||
665
src/main/javascript/view/OperationView.js
Normal file
@@ -0,0 +1,665 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.OperationView = Backbone.View.extend({
|
||||
invocationUrl: null,
|
||||
|
||||
events: {
|
||||
'submit .sandbox' : 'submitOperation',
|
||||
'click .submit' : 'submitOperation',
|
||||
'click .response_hider' : 'hideResponse',
|
||||
'click .toggleOperation' : 'toggleOperationContent',
|
||||
'mouseenter .api-ic' : 'mouseEnter',
|
||||
'mouseout .api-ic' : 'mouseExit',
|
||||
},
|
||||
|
||||
initialize: function(opts) {
|
||||
opts = opts || {};
|
||||
this.router = opts.router;
|
||||
this.auths = opts.auths;
|
||||
this.parentId = this.model.parentId;
|
||||
this.nickname = this.model.nickname;
|
||||
this.model.encodedParentId = encodeURIComponent(this.parentId);
|
||||
return this;
|
||||
},
|
||||
|
||||
mouseEnter: function(e) {
|
||||
var elem = $(this.el).find('.content');
|
||||
var x = e.pageX;
|
||||
var y = e.pageY;
|
||||
var scX = $(window).scrollLeft();
|
||||
var scY = $(window).scrollTop();
|
||||
var scMaxX = scX + $(window).width();
|
||||
var scMaxY = scY + $(window).height();
|
||||
var wd = elem.width();
|
||||
var hgh = elem.height();
|
||||
|
||||
if (x + wd > scMaxX) {
|
||||
x = scMaxX - wd;
|
||||
}
|
||||
|
||||
if (x < scX) {
|
||||
x = scX;
|
||||
}
|
||||
|
||||
if (y + hgh > scMaxY) {
|
||||
y = scMaxY - hgh;
|
||||
}
|
||||
|
||||
if (y < scY) {
|
||||
y = scY;
|
||||
}
|
||||
|
||||
var pos = {};
|
||||
pos.top = y;
|
||||
pos.left = x;
|
||||
elem.css(pos);
|
||||
$(e.currentTarget.parentNode).find('#api_information_panel').show();
|
||||
},
|
||||
|
||||
mouseExit: function(e) {
|
||||
$(e.currentTarget.parentNode).find('#api_information_panel').hide();
|
||||
},
|
||||
|
||||
// Note: copied from CoffeeScript compiled file
|
||||
// TODO: redactor
|
||||
render: function() {
|
||||
var a, auth, auths, code, contentTypeModel, isMethodSubmissionSupported, k, key, l, len, len1, len2, len3, len4, m, modelAuths, n, o, p, param, q, ref, ref1, ref2, ref3, ref4, ref5, responseContentTypeView, responseSignatureView, schema, schemaObj, scopeIndex, signatureModel, statusCode, successResponse, type, v, value;
|
||||
isMethodSubmissionSupported = jQuery.inArray(this.model.method, this.model.supportedSubmitMethods()) >= 0;
|
||||
if (!isMethodSubmissionSupported) {
|
||||
this.model.isReadOnly = true;
|
||||
}
|
||||
this.model.description = this.model.description || this.model.notes;
|
||||
this.model.oauth = null;
|
||||
modelAuths = this.model.authorizations || this.model.security;
|
||||
if (modelAuths) {
|
||||
if (Array.isArray(modelAuths)) {
|
||||
for (l = 0, len = modelAuths.length; l < len; l++) {
|
||||
auths = modelAuths[l];
|
||||
for (key in auths) {
|
||||
auth = auths[key];
|
||||
for (a in this.auths) {
|
||||
auth = this.auths[a];
|
||||
if (auth.type === 'oauth2') {
|
||||
this.model.oauth = {};
|
||||
this.model.oauth.scopes = [];
|
||||
ref1 = auth.value.scopes;
|
||||
for (k in ref1) {
|
||||
v = ref1[k];
|
||||
scopeIndex = auths[key].indexOf(k);
|
||||
if (scopeIndex >= 0) {
|
||||
o = {
|
||||
scope: k,
|
||||
description: v
|
||||
};
|
||||
this.model.oauth.scopes.push(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (k in modelAuths) {
|
||||
v = modelAuths[k];
|
||||
if (k === 'oauth2') {
|
||||
if (this.model.oauth === null) {
|
||||
this.model.oauth = {};
|
||||
}
|
||||
if (this.model.oauth.scopes === void 0) {
|
||||
this.model.oauth.scopes = [];
|
||||
}
|
||||
for (m = 0, len1 = v.length; m < len1; m++) {
|
||||
o = v[m];
|
||||
this.model.oauth.scopes.push(o);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (typeof this.model.responses !== 'undefined') {
|
||||
this.model.responseMessages = [];
|
||||
ref2 = this.model.responses;
|
||||
for (code in ref2) {
|
||||
value = ref2[code];
|
||||
schema = null;
|
||||
schemaObj = this.model.responses[code].schema;
|
||||
if (schemaObj && schemaObj.$ref) {
|
||||
schema = schemaObj.$ref;
|
||||
if (schema.indexOf('#/definitions/') === 0) {
|
||||
schema = schema.substring('#/definitions/'.length);
|
||||
}
|
||||
}
|
||||
this.model.responseMessages.push({
|
||||
code: code,
|
||||
message: value.description,
|
||||
responseModel: schema
|
||||
});
|
||||
}
|
||||
}
|
||||
if (typeof this.model.responseMessages === 'undefined') {
|
||||
this.model.responseMessages = [];
|
||||
}
|
||||
signatureModel = null;
|
||||
if (this.model.successResponse) {
|
||||
successResponse = this.model.successResponse;
|
||||
for (key in successResponse) {
|
||||
value = successResponse[key];
|
||||
this.model.successCode = key;
|
||||
if (typeof value === 'object' && typeof value.createJSONSample === 'function') {
|
||||
signatureModel = {
|
||||
sampleJSON: JSON.stringify(value.createJSONSample(), void 0, 2),
|
||||
isParam: false,
|
||||
signature: value.getMockSignature()
|
||||
};
|
||||
}
|
||||
}
|
||||
} else if (this.model.responseClassSignature && this.model.responseClassSignature !== 'string') {
|
||||
signatureModel = {
|
||||
sampleJSON: this.model.responseSampleJSON,
|
||||
isParam: false,
|
||||
signature: this.model.responseClassSignature
|
||||
};
|
||||
}
|
||||
$(this.el).html(Handlebars.templates.operation(this.model));
|
||||
if (signatureModel) {
|
||||
responseSignatureView = new SwaggerUi.Views.SignatureView({
|
||||
model: signatureModel,
|
||||
router: this.router,
|
||||
tagName: 'div'
|
||||
});
|
||||
$('.model-signature', $(this.el)).append(responseSignatureView.render().el);
|
||||
} else {
|
||||
this.model.responseClassSignature = 'string';
|
||||
$('.model-signature', $(this.el)).html(this.model.type);
|
||||
}
|
||||
contentTypeModel = {
|
||||
isParam: false
|
||||
};
|
||||
contentTypeModel.consumes = this.model.consumes;
|
||||
contentTypeModel.produces = this.model.produces;
|
||||
ref3 = this.model.parameters;
|
||||
for (n = 0, len2 = ref3.length; n < len2; n++) {
|
||||
param = ref3[n];
|
||||
type = param.type || param.dataType || '';
|
||||
if (typeof type === 'undefined') {
|
||||
schema = param.schema;
|
||||
if (schema && schema.$ref) {
|
||||
ref = schema.$ref;
|
||||
if (ref.indexOf('#/definitions/') === 0) {
|
||||
type = ref.substring('#/definitions/'.length);
|
||||
} else {
|
||||
type = ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (type && type.toLowerCase() === 'file') {
|
||||
if (!contentTypeModel.consumes) {
|
||||
contentTypeModel.consumes = 'multipart/form-data';
|
||||
}
|
||||
}
|
||||
param.type = type;
|
||||
}
|
||||
responseContentTypeView = new SwaggerUi.Views.ResponseContentTypeView({
|
||||
model: contentTypeModel,
|
||||
router: this.router
|
||||
});
|
||||
$('.response-content-type', $(this.el)).append(responseContentTypeView.render().el);
|
||||
ref4 = this.model.parameters;
|
||||
for (p = 0, len3 = ref4.length; p < len3; p++) {
|
||||
param = ref4[p];
|
||||
this.addParameter(param, contentTypeModel.consumes);
|
||||
}
|
||||
ref5 = this.model.responseMessages;
|
||||
for (q = 0, len4 = ref5.length; q < len4; q++) {
|
||||
statusCode = ref5[q];
|
||||
this.addStatusCode(statusCode);
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
addParameter: function(param, consumes) {
|
||||
// Render a parameter
|
||||
param.consumes = consumes;
|
||||
var paramView = new SwaggerUi.Views.ParameterView({
|
||||
model: param,
|
||||
tagName: 'tr',
|
||||
readOnly: this.model.isReadOnly
|
||||
});
|
||||
$('.operation-params', $(this.el)).append(paramView.render().el);
|
||||
},
|
||||
|
||||
addStatusCode: function(statusCode) {
|
||||
// Render status codes
|
||||
var statusCodeView = new SwaggerUi.Views.StatusCodeView({
|
||||
model: statusCode,
|
||||
tagName: 'tr',
|
||||
router: this.router
|
||||
});
|
||||
$('.operation-status', $(this.el)).append(statusCodeView.render().el);
|
||||
},
|
||||
|
||||
// Note: copied from CoffeeScript compiled file
|
||||
// TODO: redactor
|
||||
submitOperation: function(e) {
|
||||
var error_free, form, isFileUpload, l, len, len1, len2, m, map, n, o, opts, ref1, ref2, ref3, val;
|
||||
if (e !== null) {
|
||||
e.preventDefault();
|
||||
}
|
||||
form = $('.sandbox', $(this.el));
|
||||
error_free = true;
|
||||
form.find('input.required').each(function() {
|
||||
$(this).removeClass('error');
|
||||
if (jQuery.trim($(this).val()) === '') {
|
||||
$(this).addClass('error');
|
||||
$(this).wiggle({
|
||||
callback: (function(_this) {
|
||||
return function() {
|
||||
$(_this).focus();
|
||||
};
|
||||
})(this)
|
||||
});
|
||||
error_free = false;
|
||||
}
|
||||
});
|
||||
form.find('textarea.required').each(function() {
|
||||
$(this).removeClass('error');
|
||||
if (jQuery.trim($(this).val()) === '') {
|
||||
$(this).addClass('error');
|
||||
$(this).wiggle({
|
||||
callback: (function(_this) {
|
||||
return function() {
|
||||
return $(_this).focus();
|
||||
};
|
||||
})(this)
|
||||
});
|
||||
error_free = false;
|
||||
}
|
||||
});
|
||||
if (error_free) {
|
||||
map = {};
|
||||
opts = {
|
||||
parent: this
|
||||
};
|
||||
isFileUpload = false;
|
||||
ref1 = form.find('input');
|
||||
for (l = 0, len = ref1.length; l < len; l++) {
|
||||
o = ref1[l];
|
||||
if ((o.value !== null) && jQuery.trim(o.value).length > 0) {
|
||||
map[o.name] = o.value;
|
||||
}
|
||||
if (o.type === 'file') {
|
||||
map[o.name] = o.files[0];
|
||||
isFileUpload = true;
|
||||
}
|
||||
}
|
||||
ref2 = form.find('textarea');
|
||||
for (m = 0, len1 = ref2.length; m < len1; m++) {
|
||||
o = ref2[m];
|
||||
if ((o.value !== null) && jQuery.trim(o.value).length > 0) {
|
||||
map[o.name] = o.value;
|
||||
}
|
||||
}
|
||||
ref3 = form.find('select');
|
||||
for (n = 0, len2 = ref3.length; n < len2; n++) {
|
||||
o = ref3[n];
|
||||
val = this.getSelectedValue(o);
|
||||
if ((val !== null) && jQuery.trim(val).length > 0) {
|
||||
map[o.name] = val;
|
||||
}
|
||||
}
|
||||
opts.responseContentType = $('div select[name=responseContentType]', $(this.el)).val();
|
||||
opts.requestContentType = $('div select[name=parameterContentType]', $(this.el)).val();
|
||||
$('.response_throbber', $(this.el)).show();
|
||||
if (isFileUpload) {
|
||||
return this.handleFileUpload(map, form);
|
||||
} else {
|
||||
return this.model['do'](map, opts, this.showCompleteStatus, this.showErrorStatus, this);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
success: function(response, parent) {
|
||||
parent.showCompleteStatus(response);
|
||||
},
|
||||
|
||||
// Note: This is compiled code
|
||||
// TODO: Refactor
|
||||
handleFileUpload: function(map, form) {
|
||||
var bodyParam, el, headerParams, l, len, len1, len2, len3, m, n, o, obj, p, param, params, ref1, ref2, ref3, ref4;
|
||||
ref1 = form.serializeArray();
|
||||
for (l = 0, len = ref1.length; l < len; l++) {
|
||||
o = ref1[l];
|
||||
if ((o.value !== null) && jQuery.trim(o.value).length > 0) {
|
||||
map[o.name] = o.value;
|
||||
}
|
||||
}
|
||||
bodyParam = new FormData();
|
||||
params = 0;
|
||||
ref2 = this.model.parameters;
|
||||
for (m = 0, len1 = ref2.length; m < len1; m++) {
|
||||
param = ref2[m];
|
||||
if (param.paramType === 'form' || param['in'] === 'formData') {
|
||||
if (param.type.toLowerCase() !== 'file' && map[param.name] !== void 0) {
|
||||
bodyParam.append(param.name, map[param.name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
headerParams = {};
|
||||
ref3 = this.model.parameters;
|
||||
for (n = 0, len2 = ref3.length; n < len2; n++) {
|
||||
param = ref3[n];
|
||||
if (param.paramType === 'header') {
|
||||
headerParams[param.name] = map[param.name];
|
||||
}
|
||||
}
|
||||
ref4 = form.find('input[type~="file"]');
|
||||
for (p = 0, len3 = ref4.length; p < len3; p++) {
|
||||
el = ref4[p];
|
||||
if (typeof el.files[0] !== 'undefined') {
|
||||
bodyParam.append($(el).attr('name'), el.files[0]);
|
||||
params += 1;
|
||||
}
|
||||
}
|
||||
this.invocationUrl = this.model.supportHeaderParams() ? (headerParams = this.model.getHeaderParams(map), delete headerParams['Content-Type'], this.model.urlify(map, false)) : this.model.urlify(map, true);
|
||||
$('.request_url', $(this.el)).html('<pre></pre>');
|
||||
$('.request_url pre', $(this.el)).text(this.invocationUrl);
|
||||
obj = {
|
||||
type: this.model.method,
|
||||
url: this.invocationUrl,
|
||||
headers: headerParams,
|
||||
data: bodyParam,
|
||||
dataType: 'json',
|
||||
contentType: false,
|
||||
processData: false,
|
||||
error: (function(_this) {
|
||||
return function(data) {
|
||||
return _this.showErrorStatus(_this.wrap(data), _this);
|
||||
};
|
||||
})(this),
|
||||
success: (function(_this) {
|
||||
return function(data) {
|
||||
return _this.showResponse(data, _this);
|
||||
};
|
||||
})(this),
|
||||
complete: (function(_this) {
|
||||
return function(data) {
|
||||
return _this.showCompleteStatus(_this.wrap(data), _this);
|
||||
};
|
||||
})(this)
|
||||
};
|
||||
if (window.authorizations) {
|
||||
window.authorizations.apply(obj);
|
||||
}
|
||||
jQuery.ajax(obj);
|
||||
return false;
|
||||
// end of file-upload nastiness
|
||||
},
|
||||
// wraps a jquery response as a shred response
|
||||
|
||||
wrap: function(data) {
|
||||
var h, headerArray, headers, i, l, len, o;
|
||||
headers = {};
|
||||
headerArray = data.getAllResponseHeaders().split('\r');
|
||||
for (l = 0, len = headerArray.length; l < len; l++) {
|
||||
i = headerArray[l];
|
||||
h = i.match(/^([^:]*?):(.*)$/);
|
||||
if (!h) {
|
||||
h = [];
|
||||
}
|
||||
h.shift();
|
||||
if (h[0] !== void 0 && h[1] !== void 0) {
|
||||
headers[h[0].trim()] = h[1].trim();
|
||||
}
|
||||
}
|
||||
o = {};
|
||||
o.content = {};
|
||||
o.content.data = data.responseText;
|
||||
o.headers = headers;
|
||||
o.request = {};
|
||||
o.request.url = this.invocationUrl;
|
||||
o.status = data.status;
|
||||
return o;
|
||||
},
|
||||
|
||||
getSelectedValue: function(select) {
|
||||
if (!select.multiple) {
|
||||
return select.value;
|
||||
} else {
|
||||
var options = [];
|
||||
for (var l = 0, len = select.options.length; l < len; l++) {
|
||||
var opt = select.options[l];
|
||||
if (opt.selected) {
|
||||
options.push(opt.value);
|
||||
}
|
||||
}
|
||||
if (options.length > 0) {
|
||||
return options;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// handler for hide response link
|
||||
hideResponse: function(e) {
|
||||
if (e) { e.preventDefault(); }
|
||||
$('.response', $(this.el)).slideUp();
|
||||
$('.response_hider', $(this.el)).fadeOut();
|
||||
},
|
||||
|
||||
// Show response from server
|
||||
showResponse: function(response) {
|
||||
var prettyJson = JSON.stringify(response, null, '\t').replace(/\n/g, '<br>');
|
||||
$('.response_body', $(this.el)).html(_.escape(prettyJson));
|
||||
},
|
||||
|
||||
// Show error from server
|
||||
showErrorStatus: function(data, parent) {
|
||||
parent.showStatus(data);
|
||||
},
|
||||
|
||||
// show the status codes
|
||||
showCompleteStatus: function(data, parent){
|
||||
parent.showStatus(data);
|
||||
},
|
||||
|
||||
// Adapted from http://stackoverflow.com/a/2893259/454004
|
||||
// Note: directly ported from CoffeeScript
|
||||
// TODO: Cleanup CoffeeScript artifacts
|
||||
formatXml: function(xml) {
|
||||
var contexp, fn, formatted, indent, l, lastType, len, lines, ln, pad, reg, transitions, wsexp;
|
||||
reg = /(>)(<)(\/*)/g;
|
||||
wsexp = /[ ]*(.*)[ ]+\n/g;
|
||||
contexp = /(<.+>)(.+\n)/g;
|
||||
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2');
|
||||
pad = 0;
|
||||
formatted = '';
|
||||
lines = xml.split('\n');
|
||||
indent = 0;
|
||||
lastType = 'other';
|
||||
transitions = {
|
||||
'single->single': 0,
|
||||
'single->closing': -1,
|
||||
'single->opening': 0,
|
||||
'single->other': 0,
|
||||
'closing->single': 0,
|
||||
'closing->closing': -1,
|
||||
'closing->opening': 0,
|
||||
'closing->other': 0,
|
||||
'opening->single': 1,
|
||||
'opening->closing': 0,
|
||||
'opening->opening': 1,
|
||||
'opening->other': 1,
|
||||
'other->single': 0,
|
||||
'other->closing': -1,
|
||||
'other->opening': 0,
|
||||
'other->other': 0
|
||||
};
|
||||
fn = function(ln) {
|
||||
var fromTo, j, key, padding, type, types, value;
|
||||
types = {
|
||||
single: Boolean(ln.match(/<.+\/>/)),
|
||||
closing: Boolean(ln.match(/<\/.+>/)),
|
||||
opening: Boolean(ln.match(/<[^!?].*>/))
|
||||
};
|
||||
type = ((function() {
|
||||
var results;
|
||||
results = [];
|
||||
for (key in types) {
|
||||
value = types[key];
|
||||
if (value) {
|
||||
results.push(key);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
})())[0];
|
||||
type = type === void 0 ? 'other' : type;
|
||||
fromTo = lastType + '->' + type;
|
||||
lastType = type;
|
||||
padding = '';
|
||||
indent += transitions[fromTo];
|
||||
padding = ((function() {
|
||||
var m, ref1, results;
|
||||
results = [];
|
||||
for (j = m = 0, ref1 = indent; 0 <= ref1 ? m < ref1 : m > ref1; j = 0 <= ref1 ? ++m : --m) {
|
||||
results.push(' ');
|
||||
}
|
||||
return results;
|
||||
})()).join('');
|
||||
if (fromTo === 'opening->closing') {
|
||||
formatted = formatted.substr(0, formatted.length - 1) + ln + '\n';
|
||||
} else {
|
||||
formatted += padding + ln + '\n';
|
||||
}
|
||||
};
|
||||
for (l = 0, len = lines.length; l < len; l++) {
|
||||
ln = lines[l];
|
||||
fn(ln);
|
||||
}
|
||||
return formatted;
|
||||
},
|
||||
|
||||
// puts the response data in UI
|
||||
showStatus: function(response) {
|
||||
var url, content;
|
||||
if (response.content === undefined) {
|
||||
content = response.data;
|
||||
url = response.url;
|
||||
} else {
|
||||
content = response.content.data;
|
||||
url = response.request.url;
|
||||
}
|
||||
var headers = response.headers;
|
||||
|
||||
// if server is nice, and sends content-type back, we can use it
|
||||
var contentType = null;
|
||||
if (headers) {
|
||||
contentType = headers['Content-Type'] || headers['content-type'];
|
||||
if (contentType) {
|
||||
contentType = contentType.split(';')[0].trim();
|
||||
}
|
||||
}
|
||||
$('.response_body', $(this.el)).removeClass('json');
|
||||
$('.response_body', $(this.el)).removeClass('xml');
|
||||
|
||||
var supportsAudioPlayback = function(contentType){
|
||||
var audioElement = document.createElement('audio');
|
||||
return !!(audioElement.canPlayType && audioElement.canPlayType(contentType).replace(/no/, ''));
|
||||
};
|
||||
|
||||
var pre;
|
||||
var code;
|
||||
if (!content) {
|
||||
code = $('<code />').text('no content');
|
||||
pre = $('<pre class="json" />').append(code);
|
||||
|
||||
// JSON
|
||||
} else if (contentType === 'application/json' || /\+json$/.test(contentType)) {
|
||||
var json = null;
|
||||
try {
|
||||
json = JSON.stringify(JSON.parse(content), null, ' ');
|
||||
} catch (_error) {
|
||||
json = 'can\'t parse JSON. Raw result:\n\n' + content;
|
||||
}
|
||||
code = $('<code />').text(json);
|
||||
pre = $('<pre class="json" />').append(code);
|
||||
|
||||
// XML
|
||||
} else if (contentType === 'application/xml' || /\+xml$/.test(contentType)) {
|
||||
code = $('<code />').text(this.formatXml(content));
|
||||
pre = $('<pre class="xml" />').append(code);
|
||||
|
||||
// HTML
|
||||
} else if (contentType === 'text/html') {
|
||||
code = $('<code />').html(_.escape(content));
|
||||
pre = $('<pre class="xml" />').append(code);
|
||||
|
||||
// Image
|
||||
} else if (/^image\//.test(contentType)) {
|
||||
pre = $('<img>').attr('src', url);
|
||||
|
||||
// Audio
|
||||
} else if (/^audio\//.test(contentType) && supportsAudioPlayback(contentType)) {
|
||||
pre = $('<audio controls>').append($('<source>').attr('src', url).attr('type', contentType));
|
||||
|
||||
// Download
|
||||
} else if (headers['Content-Disposition'].test(/attachment/) ||
|
||||
headers['content-disposition'].test(/attachment/) ||
|
||||
headers['Content-Description'].test(/File Transfer/) ||
|
||||
headers['content-description'].test(/File Transfer/)) {
|
||||
|
||||
if ('Blob' in window) {
|
||||
var type = contentType || 'text/html';
|
||||
var blob = new Blob([content], {type: type});
|
||||
var a = document.createElement('a');
|
||||
var href = window.URL.createObjectURL(blob);
|
||||
var fileName = response.url.substr(response.url.lastIndexOf('/') + 1);
|
||||
var download = [type, fileName, href].join(':');
|
||||
|
||||
a.setAttribute('href', href);
|
||||
a.setAttribute('download', download);
|
||||
a.innerText = 'Download ' + fileName;
|
||||
|
||||
pre = $('<div/>').append(a);
|
||||
} else {
|
||||
pre = $('<pre class="json" />').append('Download headers detected but your browser does not support downloading binary via XHR (Blob).');
|
||||
}
|
||||
|
||||
// Location header based redirect download
|
||||
} else if(headers.location || headers.Location) {
|
||||
window.location = response.url;
|
||||
|
||||
// Anything else (CORS)
|
||||
} else {
|
||||
code = $('<code />').text(content);
|
||||
pre = $('<pre class="json" />').append(code);
|
||||
}
|
||||
var response_body = pre;
|
||||
$('.request_url', $(this.el)).html('<pre></pre>');
|
||||
$('.request_url pre', $(this.el)).text(url);
|
||||
$('.response_code', $(this.el)).html('<pre>' + response.status + '</pre>');
|
||||
$('.response_body', $(this.el)).html(response_body);
|
||||
$('.response_headers', $(this.el)).html('<pre>' + _.escape(JSON.stringify(response.headers, null, ' ')).replace(/\n/g, '<br>') + '</pre>');
|
||||
$('.response', $(this.el)).slideDown();
|
||||
$('.response_hider', $(this.el)).show();
|
||||
$('.response_throbber', $(this.el)).hide();
|
||||
var response_body_el = $('.response_body', $(this.el))[0];
|
||||
|
||||
// only highlight the response if response is less than threshold, default state is highlight response
|
||||
var opts = this.options.swaggerOptions;
|
||||
if (opts.highlightSizeThreshold && response.data.length > opts.highlightSizeThreshold) {
|
||||
return response_body_el;
|
||||
} else {
|
||||
return hljs.highlightBlock(response_body_el);
|
||||
}
|
||||
},
|
||||
|
||||
toggleOperationContent: function() {
|
||||
var elem = $('#' + Docs.escapeResourceName(this.parentId + '_' + this.nickname + '_content'));
|
||||
if (elem.is(':visible')){
|
||||
Docs.collapseOperation(elem);
|
||||
} else {
|
||||
Docs.expandOperation(elem);
|
||||
}
|
||||
}
|
||||
});
|
||||
14
src/main/javascript/view/ParameterContentTypeView.js
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ParameterContentTypeView = Backbone.View.extend({
|
||||
initialize: function () {},
|
||||
|
||||
render: function(){
|
||||
$(this.el).html(Handlebars.templates.parameter_content_type(this.model));
|
||||
|
||||
$('label[for=parameterContentType]', $(this.el)).text('Parameter content type:');
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
101
src/main/javascript/view/ParameterView.js
Normal file
@@ -0,0 +1,101 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ParameterView = Backbone.View.extend({
|
||||
initialize: function(){
|
||||
Handlebars.registerHelper('isArray', function(param, opts) {
|
||||
if (param.type.toLowerCase() === 'array' || param.allowMultiple) {
|
||||
opts.fn(this);
|
||||
} else {
|
||||
opts.inverse(this);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var type = this.model.type || this.model.dataType;
|
||||
|
||||
if (typeof type === 'undefined') {
|
||||
var schema = this.model.schema;
|
||||
if (schema && schema.$ref) {
|
||||
var ref = schema.$ref;
|
||||
if (ref.indexOf('#/definitions/') === 0) {
|
||||
type = ref.substring('#/definitions/'.length);
|
||||
} else {
|
||||
type = ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.model.type = type;
|
||||
this.model.paramType = this.model.in || this.model.paramType;
|
||||
this.model.isBody = this.model.paramType === 'body' || this.model.in === 'body';
|
||||
this.model.isFile = type && type.toLowerCase() === 'file';
|
||||
this.model.default = (this.model.default || this.model.defaultValue);
|
||||
|
||||
if (this.model.allowableValues) {
|
||||
this.model.isList = true;
|
||||
}
|
||||
|
||||
var template = this.template();
|
||||
$(this.el).html(template(this.model));
|
||||
|
||||
var signatureModel = {
|
||||
sampleJSON: this.model.sampleJSON,
|
||||
isParam: true,
|
||||
signature: this.model.signature
|
||||
};
|
||||
|
||||
if (this.model.sampleJSON) {
|
||||
var signatureView = new SwaggerUi.Views.SignatureView({model: signatureModel, tagName: 'div'});
|
||||
$('.model-signature', $(this.el)).append(signatureView.render().el);
|
||||
}
|
||||
else {
|
||||
$('.model-signature', $(this.el)).html(this.model.signature);
|
||||
}
|
||||
|
||||
var isParam = false;
|
||||
|
||||
if (this.model.isBody) {
|
||||
isParam = true;
|
||||
}
|
||||
|
||||
var contentTypeModel = {
|
||||
isParam: isParam
|
||||
};
|
||||
|
||||
contentTypeModel.consumes = this.model.consumes;
|
||||
|
||||
if (isParam) {
|
||||
var parameterContentTypeView = new SwaggerUi.Views.ParameterContentTypeView({model: contentTypeModel});
|
||||
$('.parameter-content-type', $(this.el)).append(parameterContentTypeView.render().el);
|
||||
}
|
||||
|
||||
else {
|
||||
var responseContentTypeView = new SwaggerUi.Views.ResponseContentTypeView({model: contentTypeModel});
|
||||
$('.response-content-type', $(this.el)).append(responseContentTypeView.render().el);
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// Return an appropriate template based on if the parameter is a list, readonly, required
|
||||
template: function(){
|
||||
if (this.model.isList) {
|
||||
return Handlebars.templates.param_list;
|
||||
} else {
|
||||
if (this.options.readOnly) {
|
||||
if (this.model.required) {
|
||||
return Handlebars.templates.param_readonly_required;
|
||||
} else {
|
||||
return Handlebars.templates.param_readonly;
|
||||
}
|
||||
} else {
|
||||
if (this.model.required) {
|
||||
return Handlebars.templates.param_required;
|
||||
} else {
|
||||
return Handlebars.templates.param;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
73
src/main/javascript/view/ResourceView.js
Normal file
@@ -0,0 +1,73 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ResourceView = Backbone.View.extend({
|
||||
initialize: function(opts) {
|
||||
opts = opts || {};
|
||||
this.router = opts.router;
|
||||
this.auths = opts.auths;
|
||||
if ('' === this.model.description) {
|
||||
this.model.description = null;
|
||||
}
|
||||
if (this.model.description) {
|
||||
this.model.summary = this.model.description;
|
||||
}
|
||||
},
|
||||
|
||||
render: function(){
|
||||
var methods = {};
|
||||
|
||||
|
||||
$(this.el).html(Handlebars.templates.resource(this.model));
|
||||
|
||||
// Render each operation
|
||||
for (var i = 0; i < this.model.operationsArray.length; i++) {
|
||||
var operation = this.model.operationsArray[i];
|
||||
var counter = 0;
|
||||
var id = operation.nickname;
|
||||
|
||||
while (typeof methods[id] !== 'undefined') {
|
||||
id = id + '_' + counter;
|
||||
counter += 1;
|
||||
}
|
||||
|
||||
methods[id] = operation;
|
||||
|
||||
operation.nickname = id;
|
||||
operation.parentId = this.model.id;
|
||||
this.addOperation(operation);
|
||||
}
|
||||
|
||||
$('.toggleEndpointList', this.el).click(this.callDocs.bind(this, 'toggleEndpointListForResource'));
|
||||
$('.collapseResource', this.el).click(this.callDocs.bind(this, 'collapseOperationsForResource'));
|
||||
$('.expandResource', this.el).click(this.callDocs.bind(this, 'expandOperationsForResource'));
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
addOperation: function(operation) {
|
||||
|
||||
operation.number = this.number;
|
||||
|
||||
// Render an operation and add it to operations li
|
||||
var operationView = new SwaggerUi.Views.OperationView({
|
||||
model: operation,
|
||||
router: this.router,
|
||||
tagName: 'li',
|
||||
className: 'endpoint',
|
||||
swaggerOptions: this.options.swaggerOptions,
|
||||
auths: this.auths
|
||||
});
|
||||
|
||||
$('.endpoints', $(this.el)).append(operationView.render().el);
|
||||
|
||||
this.number++;
|
||||
|
||||
},
|
||||
// Generic Event handler (`Docs` is global)
|
||||
|
||||
|
||||
callDocs: function(fnName, e) {
|
||||
e.preventDefault();
|
||||
Docs[fnName](e.currentTarget.getAttribute('data-id'));
|
||||
}
|
||||
});
|
||||
13
src/main/javascript/view/ResponseContentTypeView.js
Normal file
@@ -0,0 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.ResponseContentTypeView = Backbone.View.extend({
|
||||
initialize: function(){},
|
||||
|
||||
render: function(){
|
||||
$(this.el).html(Handlebars.templates.response_content_type(this.model));
|
||||
|
||||
$('label[for=responseContentType]', $(this.el)).text('Response Content Type');
|
||||
|
||||
return this;
|
||||
}
|
||||
});
|
||||
60
src/main/javascript/view/SignatureView.js
Normal file
@@ -0,0 +1,60 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.SignatureView = Backbone.View.extend({
|
||||
events: {
|
||||
'click a.description-link' : 'switchToDescription',
|
||||
'click a.snippet-link' : 'switchToSnippet',
|
||||
'mousedown .snippet' : 'snippetToTextArea'
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
|
||||
},
|
||||
|
||||
render: function(){
|
||||
|
||||
$(this.el).html(Handlebars.templates.signature(this.model));
|
||||
|
||||
this.switchToSnippet();
|
||||
|
||||
this.isParam = this.model.isParam;
|
||||
|
||||
if (this.isParam) {
|
||||
$('.notice', $(this.el)).text('Click to set as parameter value');
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
// handler for show signature
|
||||
switchToDescription: function(e){
|
||||
if (e) { e.preventDefault(); }
|
||||
|
||||
$('.snippet', $(this.el)).hide();
|
||||
$('.description', $(this.el)).show();
|
||||
$('.description-link', $(this.el)).addClass('selected');
|
||||
$('.snippet-link', $(this.el)).removeClass('selected');
|
||||
},
|
||||
|
||||
// handler for show sample
|
||||
switchToSnippet: function(e){
|
||||
if (e) { e.preventDefault(); }
|
||||
|
||||
$('.description', $(this.el)).hide();
|
||||
$('.snippet', $(this.el)).show();
|
||||
$('.snippet-link', $(this.el)).addClass('selected');
|
||||
$('.description-link', $(this.el)).removeClass('selected');
|
||||
},
|
||||
|
||||
// handler for snippet to text area
|
||||
snippetToTextArea: function(e) {
|
||||
if (this.isParam) {
|
||||
if (e) { e.preventDefault(); }
|
||||
|
||||
var textArea = $('textarea', $(this.el.parentNode.parentNode.parentNode));
|
||||
if ($.trim(textArea.val()) === '') {
|
||||
textArea.val(this.model.sampleJSON);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
26
src/main/javascript/view/StatusCodeView.js
Normal file
@@ -0,0 +1,26 @@
|
||||
'use strict';
|
||||
|
||||
SwaggerUi.Views.StatusCodeView = Backbone.View.extend({
|
||||
initialize: function (opts) {
|
||||
this.options = opts || {};
|
||||
this.router = this.options.router;
|
||||
},
|
||||
|
||||
render: function(){
|
||||
$(this.el).html(Handlebars.templates.status_code(this.model));
|
||||
|
||||
if (this.router.api.models.hasOwnProperty(this.model.responseModel)) {
|
||||
var responseModel = {
|
||||
sampleJSON: JSON.stringify(this.router.api.models[this.model.responseModel].createJSONSample(), null, 2),
|
||||
isParam: false,
|
||||
signature: this.router.api.models[this.model.responseModel].getMockSignature(),
|
||||
};
|
||||
|
||||
var responseModelView = new SwaggerUi.Views.SignatureView({model: responseModel, tagName: 'div'});
|
||||
$('.model-signature', this.$el).append(responseModelView.render().el);
|
||||
} else {
|
||||
$('.model-signature', this.$el).html('');
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
41
src/main/less/print.less
Normal file
@@ -0,0 +1,41 @@
|
||||
@import 'src/main/less/highlight_default.less';
|
||||
@import 'src/main/less/specs.less';
|
||||
@import 'src/main/less/auth.less';
|
||||
|
||||
#header {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.swagger-section {
|
||||
|
||||
.swagger-ui-wrap {
|
||||
|
||||
.model-signature pre {
|
||||
max-height: none;
|
||||
}
|
||||
|
||||
.body-textarea {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
input.parameter {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
ul#resources {
|
||||
li.resource {
|
||||
div.heading ul.options {
|
||||
display: none;
|
||||
}
|
||||
ul.endpoints {
|
||||
display: block !important;
|
||||
li.endpoint ul.operations li.operation div.content {
|
||||
display: block !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,11 @@
|
||||
{{#if info}}
|
||||
<div class="info_title">{{info.title}}</div>
|
||||
<div class="info_description markdown">{{{info.description}}}</div>
|
||||
{{#if externalDocs}}
|
||||
<h5>More documentations</h5>
|
||||
<p>{{externalDocs.description}}</p>
|
||||
<a href="{{externalDocs.url}}" target="_blank">{{externalDocs.url}}</a>
|
||||
{{/if}}
|
||||
{{#if info.termsOfServiceUrl}}<div class="info_tos"><a href="{{info.termsOfServiceUrl}}">Terms of service</a></div>{{/if}}
|
||||
{{#if info.contact.name}}<div class='info_name'>Created by {{info.contact.name}}</div>{{/if}}
|
||||
{{#if info.contact.url}}<div class='info_url'>See more at <a href="{{info.contact.url}}">{{info.contact.url}}</a></div>{{/if}}
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
<div class='heading'>
|
||||
<h3>
|
||||
<span class='http_method'>
|
||||
<a href='#!/{{parentId}}/{{nickname}}' class="toggleOperation">{{method}}</a>
|
||||
<a href='#!/{{encodedParentId}}/{{nickname}}' class="toggleOperation">{{method}}</a>
|
||||
</span>
|
||||
<span class='path'>
|
||||
<a href='#!/{{parentId}}/{{nickname}}' class="toggleOperation {{#if deprecated}}deprecated{{/if}}">{{path}}</a>
|
||||
<a href='#!/{{encodedParentId}}/{{nickname}}' class="toggleOperation {{#if deprecated}}deprecated{{/if}}">{{path}}</a>
|
||||
</span>
|
||||
</h3>
|
||||
<ul class='options'>
|
||||
<li>
|
||||
<a href='#!/{{parentId}}/{{nickname}}' class="toggleOperation">{{{summary}}}</a>
|
||||
<a href='#!/{{encodedParentId}}/{{nickname}}' class="toggleOperation">{{{summary}}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -22,7 +22,7 @@
|
||||
{{/if}}
|
||||
{{#if description}}
|
||||
<h4>Implementation Notes</h4>
|
||||
<p class="markdown">{{{description}}}</p>
|
||||
<div class="markdown">{{{description}}}</div>
|
||||
{{/if}}
|
||||
{{#oauth}}
|
||||
<div class="auth">
|
||||
@@ -74,10 +74,11 @@
|
||||
<th>HTTP Status Code</th>
|
||||
<th>Reason</th>
|
||||
<th>Response Model</th>
|
||||
<th>Headers</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="operation-status">
|
||||
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
{{#if required}}
|
||||
<td class='code required'>{{name}}</td>
|
||||
{{/if}}
|
||||
<td class='code'>{{name}}</td>
|
||||
<td>
|
||||
<select {{#isArray this}} multiple='multiple'{{/isArray}} class='parameter' name='{{name}}'>
|
||||
|
||||
@@ -16,9 +16,11 @@
|
||||
Expand Operations
|
||||
</a>
|
||||
</li>
|
||||
{{#url}}<li>
|
||||
{{#if url}}
|
||||
<li>
|
||||
<a href='{{url}}'>Raw</a>
|
||||
</li>{{/url}}
|
||||
</li>
|
||||
{{/if}}
|
||||
</ul>
|
||||
</div>
|
||||
<ul class='endpoints' id='{{id}}_endpoint_list' style='display:none'>
|
||||
|
||||
@@ -1,3 +1,16 @@
|
||||
<td width='15%' class='code'>{{code}}</td>
|
||||
<td>{{{message}}}</td>
|
||||
<td width='50%'><span class="model-signature" /></td>
|
||||
<td width='50%'><span class="model-signature" /></td>
|
||||
<td class="headers">
|
||||
<table>
|
||||
<tbody>
|
||||
{{#each headers}}
|
||||
<tr>
|
||||
<td>{{@key}}</td>
|
||||
<td>{{this.description}}</td>
|
||||
<td>{{this.type}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</td>
|
||||
10
test/.jshintrc
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../.jshintrc",
|
||||
"expr": true,
|
||||
"jasmine": true,
|
||||
"globals": {
|
||||
"before": false,
|
||||
"after": false,
|
||||
"expect": true
|
||||
}
|
||||
}
|
||||
10
test/e2e/driver.js
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Web driver manager
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var webdriver = require('selenium-webdriver');
|
||||
|
||||
var driver = new webdriver.Builder().withCapabilities(webdriver.Capabilities.firefox()).build();
|
||||
|
||||
module.exports = driver;
|
||||
38
test/e2e/servers.js
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Swagger UI and Specs Servers
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var path = require('path');
|
||||
var createServer = require('http-server').createServer;
|
||||
|
||||
var dist = path.join(__dirname, '..', '..', 'dist');
|
||||
var specs = path.join(__dirname, '..', '..', 'test', 'specs');
|
||||
var DOCS_PORT = 8080;
|
||||
var SPEC_SERVER_PORT = 8081;
|
||||
|
||||
var driver = require('./driver');
|
||||
|
||||
var swaggerUI;
|
||||
var specServer;
|
||||
|
||||
module.exports.start = function (specsLocation, done) {
|
||||
swaggerUI = createServer({ root: dist, cors: true });
|
||||
specServer = createServer({ root: specs, cors: true });
|
||||
|
||||
swaggerUI.listen(DOCS_PORT);
|
||||
specServer.listen(SPEC_SERVER_PORT);
|
||||
|
||||
var swaggerSpecLocation = encodeURIComponent('http://localhost:' + SPEC_SERVER_PORT + specsLocation);
|
||||
var url = 'http://localhost:' + DOCS_PORT + '/index.html?url=' + swaggerSpecLocation;
|
||||
|
||||
setTimeout(function(){
|
||||
driver.get(url);
|
||||
done();
|
||||
}, process.env.TRAVIS ? 20000 : 3000);
|
||||
};
|
||||
|
||||
module.exports.close = function() {
|
||||
swaggerUI.close();
|
||||
specServer.close();
|
||||
};
|
||||
@@ -1,17 +1,9 @@
|
||||
var webdriver = require('selenium-webdriver');
|
||||
var createServer = require('http-server').createServer;
|
||||
'use strict';
|
||||
|
||||
var expect = require('chai').expect;
|
||||
var path = require('path')
|
||||
|
||||
var dist = path.join(__dirname, '..', '..', 'dist');
|
||||
var specs = path.join(__dirname, '..', '..', 'test', 'specs');
|
||||
var DOCS_PORT = 8080;
|
||||
var SPEC_SERVER_PORT = 8081
|
||||
|
||||
var headers = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
|
||||
};
|
||||
var driver = require('./driver');
|
||||
var servers = require('./servers');
|
||||
var webdriver = require('selenium-webdriver');
|
||||
|
||||
var elements = [
|
||||
'swagger-ui-container',
|
||||
@@ -23,21 +15,12 @@ var elements = [
|
||||
'header'
|
||||
];
|
||||
|
||||
describe('swagger 1.x spec tests', function (done) {
|
||||
describe('swagger 1.x spec tests', function () {
|
||||
this.timeout(10 * 1000);
|
||||
var swaggerUI, specServer, driver;
|
||||
|
||||
before(function () {
|
||||
swaggerUI = createServer({ root: dist, headers: headers });
|
||||
specServer = createServer({ root: specs, headers: headers });
|
||||
driver = new webdriver.Builder().
|
||||
withCapabilities(webdriver.Capabilities.firefox()).build();
|
||||
|
||||
swaggerUI.listen(DOCS_PORT);
|
||||
specServer.listen(SPEC_SERVER_PORT);
|
||||
|
||||
var swaggerSpecLocation = encodeURIComponent('http://localhost:' + SPEC_SERVER_PORT + '/v1.2/petstore/api-docs')
|
||||
driver.get('http://localhost:' + DOCS_PORT + '/index.html?url=' + swaggerSpecLocation);
|
||||
before(function (done) {
|
||||
this.timeout(25 * 1000);
|
||||
servers.start('/v1.2/petstore/api-docs.json', done);
|
||||
});
|
||||
|
||||
afterEach(function(){
|
||||
@@ -46,8 +29,9 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
var errors = [];
|
||||
browserLogs.forEach(function(log){
|
||||
// 900 and above is "error" level. Console should not have any errors
|
||||
if (log.level.value > 900)
|
||||
if (log.level.value > 900) {
|
||||
console.log('browser error message:', log.message); errors.push(log);
|
||||
}
|
||||
});
|
||||
expect(errors).to.be.empty;
|
||||
done();
|
||||
@@ -65,7 +49,7 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
|
||||
elements.forEach(function (id) {
|
||||
it('should render element: ' + id, function (done) {
|
||||
var locator = webdriver.By.id(id)
|
||||
var locator = webdriver.By.id(id);
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
@@ -73,7 +57,8 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
});
|
||||
});
|
||||
|
||||
it('should find the contact name element', function(done){
|
||||
// TODO: enable me
|
||||
xit('should find the contact name element', function(done){
|
||||
var locator = webdriver.By.css('.info_name');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
@@ -82,15 +67,16 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the pet link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='pet']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="pet"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should find the pet resource description', function(done){
|
||||
var locator = webdriver.By.xpath("//div[contains(., 'Operations about pets')]");
|
||||
// TODO: enable me
|
||||
xit('should find the pet resource description', function(done){
|
||||
var locator = webdriver.By.xpath('//div[contains(., "Operations about pets")]');
|
||||
driver.findElements(locator).then(function (elements) {
|
||||
expect(elements.length).to.not.equal(0);
|
||||
done();
|
||||
@@ -98,7 +84,7 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the user link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='user']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="user"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
@@ -106,16 +92,14 @@ describe('swagger 1.x spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the store link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='store']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="store"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
after(function() {
|
||||
swaggerUI.close();
|
||||
specServer.close();
|
||||
driver.quit();
|
||||
after(function(){
|
||||
servers.close();
|
||||
});
|
||||
});
|
||||
@@ -1,17 +1,10 @@
|
||||
var webdriver = require('selenium-webdriver');
|
||||
var createServer = require('http-server').createServer;
|
||||
'use strict';
|
||||
|
||||
var expect = require('chai').expect;
|
||||
var path = require('path')
|
||||
var webdriver = require('selenium-webdriver');
|
||||
var driver = require('./driver');
|
||||
var servers = require('./servers');
|
||||
|
||||
var dist = path.join(__dirname, '..', '..', 'dist');
|
||||
var specs = path.join(__dirname, '..', '..', 'test', 'specs');
|
||||
var DOCS_PORT = 8080;
|
||||
var SPEC_SERVER_PORT = 8081
|
||||
|
||||
var headers = {
|
||||
'Access-Control-Allow-Origin': '*',
|
||||
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
|
||||
};
|
||||
|
||||
var elements = [
|
||||
'swagger-ui-container',
|
||||
@@ -23,21 +16,12 @@ var elements = [
|
||||
'header'
|
||||
];
|
||||
|
||||
describe('swagger 2.0 spec tests', function (done) {
|
||||
describe('swagger 2.0 spec tests', function () {
|
||||
this.timeout(10 * 1000);
|
||||
var swaggerUI, specServer, driver;
|
||||
|
||||
before(function () {
|
||||
swaggerUI = createServer({ root: dist, headers: headers });
|
||||
specServer = createServer({ root: specs, headers: headers });
|
||||
driver = new webdriver.Builder().
|
||||
withCapabilities(webdriver.Capabilities.firefox()).build();
|
||||
|
||||
swaggerUI.listen(DOCS_PORT);
|
||||
specServer.listen(SPEC_SERVER_PORT);
|
||||
|
||||
var swaggerSpecLocation = encodeURIComponent('http://localhost:' + SPEC_SERVER_PORT + '/v2/petstore.json')
|
||||
driver.get('http://localhost:' + DOCS_PORT + '/index.html?url=' + swaggerSpecLocation);
|
||||
before(function (done) {
|
||||
this.timeout(25 * 1000);
|
||||
servers.start('/v2/petstore.json', done);
|
||||
});
|
||||
|
||||
afterEach(function(){
|
||||
@@ -46,8 +30,9 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
var errors = [];
|
||||
browserLogs.forEach(function(log){
|
||||
// 900 and above is "error" level. Console should not have any errors
|
||||
if (log.level.value > 900)
|
||||
if (log.level.value > 900) {
|
||||
console.log('browser error message:', log.message); errors.push(log);
|
||||
}
|
||||
});
|
||||
expect(errors).to.be.empty;
|
||||
done();
|
||||
@@ -98,7 +83,7 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the pet link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='pet']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="pet"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
@@ -106,7 +91,7 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the pet resource description', function(done){
|
||||
var locator = webdriver.By.xpath("//div[contains(., 'Everything about your Pets')]");
|
||||
var locator = webdriver.By.xpath('//div[contains(., "Everything about your Pets")]');
|
||||
driver.findElements(locator).then(function (elements) {
|
||||
expect(elements.length).to.not.equal(0);
|
||||
done();
|
||||
@@ -114,7 +99,7 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the user link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='user']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="user"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
@@ -122,7 +107,7 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
});
|
||||
|
||||
it('should find the store link', function(done){
|
||||
var locator = webdriver.By.xpath("//*[@data-id='store']");
|
||||
var locator = webdriver.By.xpath('//*[@data-id="store"]');
|
||||
driver.isElementPresent(locator).then(function (isPresent) {
|
||||
expect(isPresent).to.be.true;
|
||||
done();
|
||||
@@ -130,8 +115,6 @@ describe('swagger 2.0 spec tests', function (done) {
|
||||
});
|
||||
|
||||
after(function() {
|
||||
swaggerUI.close();
|
||||
specServer.close();
|
||||
driver.quit();
|
||||
servers.close();
|
||||
});
|
||||
});
|
||||
@@ -1 +1 @@
|
||||
--recursive
|
||||
--recursive --timeout 5000
|
||||
@@ -3,15 +3,15 @@
|
||||
"swaggerVersion": "1.2",
|
||||
"apis": [
|
||||
{
|
||||
"path": "http://localhost:8081/v1.2/petstore/pet",
|
||||
"path": "http://localhost:8081/v1.2/petstore/pet.json",
|
||||
"description": "Operations about pets"
|
||||
},
|
||||
{
|
||||
"path": "http://localhost:8081/v1.2/petstore/user",
|
||||
"path": "http://localhost:8081/v1.2/petstore/user.json",
|
||||
"description": "Operations about user"
|
||||
},
|
||||
{
|
||||
"path": "http://localhost:8081/v1.2/petstore/store",
|
||||
"path": "http://localhost:8081/v1.2/petstore/store.json",
|
||||
"description": "Operations about store"
|
||||
}
|
||||
],
|
||||
@@ -31,18 +31,18 @@
|
||||
"grantTypes": {
|
||||
"implicit": {
|
||||
"loginEndpoint": {
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/dialog"
|
||||
"url": "http://petstore.swagger.io/oauth/dialog"
|
||||
},
|
||||
"tokenName": "access_token"
|
||||
},
|
||||
"authorization_code": {
|
||||
"tokenRequestEndpoint": {
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/requestToken",
|
||||
"url": "http://petstore.swagger.io/oauth/requestToken",
|
||||
"clientIdName": "client_id",
|
||||
"clientSecretName": "client_secret"
|
||||
},
|
||||
"tokenEndpoint": {
|
||||
"url": "http://petstore.swagger.wordnik.com/oauth/token",
|
||||
"url": "http://petstore.swagger.io/oauth/token",
|
||||
"tokenName": "access_code"
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
},
|
||||
"info": {
|
||||
"title": "Swagger Sample App",
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger \n at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> or on irc.freenode.net, #swagger. For this sample,\n you can use the api key \"special-key\" to test the authorization filters",
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger \n at <a href=\"http://swagger.io\">http://swagger.io</a> or on irc.freenode.net, #swagger. For this sample,\n you can use the api key \"special-key\" to test the authorization filters",
|
||||
"termsOfServiceUrl": "http://helloreverb.com/terms/",
|
||||
"contact": "apiteam@wordnik.com",
|
||||
"license": "Apache 2.0",
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"apiVersion": "1.0.0",
|
||||
"swaggerVersion": "1.2",
|
||||
"basePath": "http://petstore.swagger.wordnik.com/api",
|
||||
"basePath": "http://petstore.swagger.io/api",
|
||||
"resourcePath": "/pet",
|
||||
"produces": [
|
||||
"application/json",
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"apiVersion": "1.0.0",
|
||||
"swaggerVersion": "1.2",
|
||||
"basePath": "http://petstore.swagger.wordnik.com/api",
|
||||
"basePath": "http://petstore.swagger.io/api",
|
||||
"resourcePath": "/store",
|
||||
"produces": [
|
||||
"application/json"
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"apiVersion": "1.0.0",
|
||||
"swaggerVersion": "1.2",
|
||||
"basePath": "http://petstore.swagger.wordnik.com/api",
|
||||
"basePath": "http://petstore.swagger.io/api",
|
||||
"resourcePath": "/user",
|
||||
"produces": [
|
||||
"application/json"
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"swagger": "2.0",
|
||||
"info": {
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger at <a href=\"http://swagger.wordnik.com\">http://swagger.wordnik.com</a> or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters",
|
||||
"description": "This is a sample server Petstore server. You can find out more about Swagger at <a href=\"http://swagger.io\">http://swagger.io</a> or on irc.freenode.net, #swagger. For this sample, you can use the api key \"special-key\" to test the authorization filters",
|
||||
"version": "1.0.0",
|
||||
"title": "Swagger Petstore",
|
||||
"termsOfService": "http://helloreverb.com/terms/",
|
||||
@@ -15,7 +15,7 @@
|
||||
"url": "http://www.apache.org/licenses/LICENSE-2.0.html"
|
||||
}
|
||||
},
|
||||
"host": "petstore.swagger.wordnik.com",
|
||||
"host": "petstore.swagger.io",
|
||||
"basePath": "/v2",
|
||||
"schemes": [
|
||||
"http"
|
||||
@@ -742,7 +742,7 @@
|
||||
},
|
||||
"petstore_auth": {
|
||||
"type": "oauth2",
|
||||
"authorizationUrl": "http://petstore.swagger.wordnik.com/api/oauth/dialog",
|
||||
"authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog",
|
||||
"flow": "implicit"
|
||||
}
|
||||
},
|
||||
|
||||