swagger-ui
Advanced tools
Comparing version 2.1.5-M2 to 2.1.5
{ | ||
"name": "swagger-ui", | ||
"main": "dist/index.html", | ||
"version": "2.1.5-M2", | ||
"authors": [ | ||
@@ -16,3 +15,3 @@ "Mohsen Azimi <me@azimi.me>" | ||
], | ||
"license": "Copyright 2015 Reverb Technologies, Inc.", | ||
"license": "Copyright 2016 SmartBear Software", | ||
"homepage": "http://swagger.io", | ||
@@ -19,0 +18,0 @@ "private": true, |
@@ -1,8 +0,3 @@ | ||
## Pull Requests | ||
Plase make your pull requests are made to the [**`develop_2.0`**](https://github.com/swagger-api/swagger-ui/tree/develop_2.0) branch at this time. | ||
SwaggerUI uses [SwaggerJS](https://github.com/swagger-api/swagger-js) library for many internal operations. If you see errors in swagger-client.js code, you should probably open the issue in [SwaggerJS](https://github.com/swagger-api/swagger-js) repository. | ||
## Issues | ||
SwaggerUI uses [SwaggerJS](https://github.com/swagger-api/swagger-js) library for many internal operations. If you see errors in | ||
[`swagger-client.js`](lib/swagger-client.js) file, you should probably open the issue in [SwaggerJS](https://github.com/swagger-api/swagger-js) repository. | ||
Please open issues related to Swagger specifications in [Swagger Specs](https://github.com/swagger-api/swagger-spec) repository. | ||
Please open issues related to OpenAPI Specifications in [OpenAPI Specs](https://github.com/OAI/OpenAPI-Specification) repository. |
@@ -6,4 +6,6 @@ var appName; | ||
var realm; | ||
var oauth2KeyName; | ||
var redirect_uri; | ||
var clientSecret; | ||
var scopeSeparator; | ||
var additionalQueryStringParams; | ||
@@ -20,3 +22,2 @@ function handleLogin() { | ||
if(auth.type === 'oauth2' && auth.scopes) { | ||
oauth2KeyName = key; | ||
var scope; | ||
@@ -33,3 +34,3 @@ if(Array.isArray(auth.scopes)) { | ||
for(scope in auth.scopes) { | ||
scopes.push({scope: scope, description: auth.scopes[scope]}); | ||
scopes.push({scope: scope, description: auth.scopes[scope], OAuthSchemeKey: key}); | ||
} | ||
@@ -46,2 +47,3 @@ } | ||
$('.api-popup-dialog').remove(); | ||
popupDialog = $( | ||
@@ -64,8 +66,12 @@ [ | ||
//TODO: only display applicable scopes (will need to pass them into handleLogin) | ||
popup = popupDialog.find('ul.api-popup-scopes').empty(); | ||
for (i = 0; i < scopes.length; i ++) { | ||
scope = scopes[i]; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"' +'" oauthtype="' + scope.OAuthSchemeKey +'"/>' + '<label for="scope_' + i + '">' + scope.scope ; | ||
if (scope.description) { | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
if ($.map(auths, function(n, i) { return i; }).length > 1) //if we have more than one scheme, display schemes | ||
str += '<br/><span class="api-scope-desc">' + scope.description + ' ('+ scope.OAuthSchemeKey+')' +'</span>'; | ||
else | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
} | ||
@@ -108,5 +114,21 @@ str += '</label></li>'; | ||
var url = null; | ||
for (var key in authSchemes) { | ||
if (authSchemes.hasOwnProperty(key)) { | ||
var scopes = [] | ||
var o = popup.find('input:checked'); | ||
var OAuthSchemeKeys = []; | ||
var state; | ||
for(k =0; k < o.length; k++) { | ||
var scope = $(o[k]).attr('scope'); | ||
if (scopes.indexOf(scope) === -1) | ||
scopes.push(scope); | ||
var OAuthSchemeKey = $(o[k]).attr('oauthtype'); | ||
if (OAuthSchemeKeys.indexOf(OAuthSchemeKey) === -1) | ||
OAuthSchemeKeys.push(OAuthSchemeKey); | ||
} | ||
//TODO: merge not replace if scheme is different from any existing | ||
//(needs to be aware of schemes to do so correctly) | ||
window.enabledScopes=scopes; | ||
for (var key in authSchemes) { | ||
if (authSchemes.hasOwnProperty(key) && OAuthSchemeKeys.indexOf(key) != -1) { //only look at keys that match this scope. | ||
var flow = authSchemes[key].flow; | ||
@@ -119,3 +141,10 @@ | ||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null); | ||
state = key; | ||
} | ||
else if(authSchemes[key].type === 'oauth2' && flow && (flow === 'application')) { | ||
var dets = authSchemes[key]; | ||
window.swaggerUi.tokenName = dets.tokenName || 'access_token'; | ||
clientCredentialsFlow(scopes, dets.tokenUrl, key); | ||
return; | ||
} | ||
else if(authSchemes[key].grantTypes) { | ||
@@ -141,17 +170,3 @@ // 1.2 support | ||
} | ||
var scopes = [] | ||
var o = $('.api-popup-scopes').find('input:checked'); | ||
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; | ||
@@ -162,4 +177,7 @@ | ||
url += '&client_id=' + encodeURIComponent(clientId); | ||
url += '&scope=' + encodeURIComponent(scopes.join(' ')); | ||
url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); | ||
url += '&state=' + encodeURIComponent(state); | ||
for (var key in additionalQueryStringParams) { | ||
url += '&' + key + '=' + encodeURIComponent(additionalQueryStringParams[key]); | ||
} | ||
@@ -176,4 +194,4 @@ window.open(url); | ||
function handleLogout() { | ||
for(key in window.authorizations.authz){ | ||
window.authorizations.remove(key) | ||
for(key in window.swaggerUi.api.clientAuthorizations.authz){ | ||
window.swaggerUi.api.clientAuthorizations.remove(key) | ||
} | ||
@@ -197,3 +215,6 @@ window.enabledScopes = null; | ||
clientId = (o.clientId||errors.push('missing client id')); | ||
clientSecret = (o.clientSecret||null); | ||
realm = (o.realm||errors.push('missing realm')); | ||
scopeSeparator = (o.scopeSeparator||' '); | ||
additionalQueryStringParams = (o.additionalQueryStringParams||{}); | ||
@@ -217,3 +238,36 @@ if(errors.length > 0){ | ||
function clientCredentialsFlow(scopes, tokenUrl, OAuthSchemeKey) { | ||
var params = { | ||
'client_id': clientId, | ||
'client_secret': clientSecret, | ||
'scope': scopes.join(' '), | ||
'grant_type': 'client_credentials' | ||
} | ||
$.ajax( | ||
{ | ||
url : tokenUrl, | ||
type: "POST", | ||
data: params, | ||
success:function(data, textStatus, jqXHR) | ||
{ | ||
onOAuthComplete(data,OAuthSchemeKey); | ||
}, | ||
error: function(jqXHR, textStatus, errorThrown) | ||
{ | ||
onOAuthComplete(""); | ||
} | ||
}); | ||
} | ||
window.processOAuthCode = function processOAuthCode(data) { | ||
var OAuthSchemeKey = data.state; | ||
// redirect_uri is required in auth code flow | ||
// see https://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1.3 | ||
var host = window.location; | ||
var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); | ||
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; | ||
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl; | ||
var params = { | ||
@@ -223,4 +277,9 @@ 'client_id': clientId, | ||
'grant_type': 'authorization_code', | ||
'redirect_uri': redirect_uri | ||
'redirect_uri': redirectUrl | ||
}; | ||
if (clientSecret) { | ||
params.client_secret = clientSecret; | ||
} | ||
$.ajax( | ||
@@ -233,3 +292,3 @@ { | ||
{ | ||
onOAuthComplete(data); | ||
onOAuthComplete(data, OAuthSchemeKey); | ||
}, | ||
@@ -241,5 +300,5 @@ error: function(jqXHR, textStatus, errorThrown) | ||
}); | ||
} | ||
}; | ||
window.onOAuthComplete = function onOAuthComplete(token) { | ||
window.onOAuthComplete = function onOAuthComplete(token,OAuthSchemeKey) { | ||
if(token) { | ||
@@ -254,7 +313,10 @@ if(token.error) { | ||
else { | ||
var b = token[window.swaggerUi.tokenName]; | ||
var b = token[window.swaggerUi.tokenName]; | ||
if (!OAuthSchemeKey){ | ||
OAuthSchemeKey = token.state; | ||
} | ||
if(b){ | ||
// if all roles are satisfied | ||
var o = null; | ||
$.each($('.auth #api_information_panel'), function(k, v) { | ||
$.each($('.auth .api-ic .api_information_panel'), function(k, v) { | ||
var children = v; | ||
@@ -276,3 +338,3 @@ if(children && children.childNodes) { | ||
if(diff.length > 0){ | ||
o = v.parentNode; | ||
o = v.parentNode.parentNode; | ||
$(o.parentNode).find('.api-ic.ic-on').addClass('ic-off'); | ||
@@ -286,3 +348,3 @@ $(o.parentNode).find('.api-ic.ic-on').removeClass('ic-on'); | ||
else { | ||
o = v.parentNode; | ||
o = v.parentNode.parentNode; | ||
$(o.parentNode).find('.api-ic.ic-off').addClass('ic-on'); | ||
@@ -298,6 +360,7 @@ $(o.parentNode).find('.api-ic.ic-off').removeClass('ic-off'); | ||
}); | ||
window.swaggerUi.api.clientAuthorizations.add(oauth2KeyName, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); | ||
window.swaggerUi.api.clientAuthorizations.add(window.OAuthSchemeKey, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); | ||
window.swaggerUi.load(); | ||
} | ||
} | ||
} | ||
} | ||
}; |
@@ -16,5 +16,6 @@ 'use strict'; | ||
var header = require('gulp-header'); | ||
var pkg = require('./package.json'); | ||
var order = require('gulp-order'); | ||
var jshint = require('gulp-jshint'); | ||
var pkg = require('./package.json'); | ||
var banner = ['/**', | ||
@@ -39,17 +40,2 @@ ' * <%= pkg.name %> - <%= pkg.description %>', | ||
/** | ||
* Processes Handlebars templates | ||
*/ | ||
function templates() { | ||
return gulp | ||
.src(['./src/main/template/**/*']) | ||
.pipe(handlebars()) | ||
.pipe(wrap('Handlebars.template(<%= contents %>)')) | ||
.pipe(declare({ | ||
namespace: 'Handlebars.templates', | ||
noRedeclare: true, // Avoid duplicate declarations | ||
})) | ||
.on('error', log); | ||
} | ||
/** | ||
* JShint all *.js files | ||
@@ -66,10 +52,19 @@ */ | ||
*/ | ||
gulp.task('dist', ['clean','lint'], function() { | ||
gulp.task('dist', ['clean', 'lint'], _dist); | ||
function _dist() { | ||
return es.merge( | ||
gulp.src([ | ||
gulp.src([ | ||
'./node_modules/es5-shim/es5-shim.js', | ||
'./src/main/javascript/**/*.js', | ||
'./node_modules/swagger-client/browser/swagger-client.js' | ||
]), | ||
templates() | ||
gulp | ||
.src(['./src/main/template/**/*']) | ||
.pipe(handlebars()) | ||
.pipe(wrap('Handlebars.template(<%= contents %>)')) | ||
.pipe(declare({ | ||
namespace: 'Handlebars.templates', | ||
noRedeclare: true, // Avoid duplicate declarations | ||
})) | ||
.on('error', log) | ||
) | ||
@@ -79,3 +74,3 @@ .pipe(order(['scripts.js', 'templates.js'])) | ||
.pipe(wrap('(function(){<%= contents %>}).call(this);')) | ||
.pipe(header(banner, { pkg: pkg } )) | ||
.pipe(header(banner, { pkg: pkg })) | ||
.pipe(gulp.dest('./dist')) | ||
@@ -88,3 +83,4 @@ .pipe(uglify()) | ||
.pipe(connect.reload()); | ||
}); | ||
} | ||
gulp.task('dev-dist', ['lint', 'dev-copy'], _dist); | ||
@@ -94,4 +90,4 @@ /** | ||
*/ | ||
gulp.task('less', ['clean'], function() { | ||
gulp.task('less', ['clean'], _less); | ||
function _less() { | ||
return gulp | ||
@@ -101,22 +97,29 @@ .src([ | ||
'./src/main/less/print.less', | ||
'./src/main/less/reset.less' | ||
'./src/main/less/reset.less', | ||
'./src/main/less/style.less' | ||
]) | ||
.pipe(less()) | ||
.on('error', log) | ||
.on('error', function(err){ log(err); this.emit('end');}) | ||
.pipe(gulp.dest('./src/main/html/css/')) | ||
.pipe(connect.reload()); | ||
}); | ||
} | ||
gulp.task('dev-less', _less); | ||
/** | ||
* Copy lib and html folders | ||
*/ | ||
gulp.task('copy', ['less'], function() { | ||
gulp.task('copy', ['less'], _copy); | ||
function _copy() { | ||
// copy JavaScript files inside lib folder | ||
gulp | ||
.src(['./lib/**/*.{js,map}']) | ||
.src(['./lib/**/*.{js,map}', './node_modules/es5-shim/es5-shim.js']) | ||
.pipe(gulp.dest('./dist/lib')) | ||
.on('error', log); | ||
// copy `lang` for translations | ||
gulp | ||
.src(['./lang/**/*.js']) | ||
.pipe(gulp.dest('./dist/lang')) | ||
.on('error', log); | ||
// copy all files inside html folder | ||
@@ -127,2 +130,11 @@ gulp | ||
.on('error', log); | ||
} | ||
gulp.task('dev-copy', ['dev-less', 'copy-local-specs'], _copy); | ||
gulp.task('copy-local-specs', function () { | ||
// copy the test specs | ||
return gulp | ||
.src(['./test/specs/**/*']) | ||
.pipe(gulp.dest('./dist/specs')) | ||
.on('error', log); | ||
}); | ||
@@ -133,6 +145,11 @@ | ||
*/ | ||
gulp.task('watch', function() { | ||
return watch(['./src/**/*.{js,less,handlebars}'], function() { | ||
gulp.start('default'); | ||
}); | ||
gulp.task('watch', ['copy-local-specs'], function() { | ||
return watch([ | ||
'./src/**/*.{js,less,handlebars}', | ||
'./src/main/html/*.html', | ||
'./test/specs/**/*.{json,yaml}' | ||
], | ||
function() { | ||
gulp.start('dev-dist'); | ||
}); | ||
}); | ||
@@ -154,4 +171,6 @@ | ||
gulp.task('default', ['dist', 'copy']); | ||
gulp.task('serve', ['connect', 'watch']); | ||
gulp.task('dev', ['default'], function () { | ||
gulp.start('serve'); | ||
}); |
@@ -0,1 +1,3 @@ | ||
'use strict'; | ||
var pack = require('./package'); | ||
@@ -7,2 +9,2 @@ var path = require('path'); | ||
dist: path.resolve(__dirname, 'dist') | ||
}; | ||
}; |
@@ -24,2 +24,3 @@ 'use strict'; | ||
"Hide Response":"Hide Response", | ||
"Headers":"Headers", | ||
"Try it out!":"Try it out!", | ||
@@ -31,4 +32,6 @@ "Show/Hide":"Show/Hide", | ||
"can't parse JSON. Raw result":"can't parse JSON. Raw result", | ||
"Example Value":"Example Value", | ||
"Model Schema":"Model Schema", | ||
"Model":"Model", | ||
"Click to set as parameter value":"Click to set as parameter value", | ||
"apply":"apply", | ||
@@ -43,2 +46,3 @@ "Username":"Username", | ||
"Response Content Type":"Response Content Type", | ||
"Parameter content type:":"Parameter content type:", | ||
"fetching resource":"fetching resource", | ||
@@ -48,3 +52,2 @@ "fetching resource list":"fetching resource list", | ||
"Show Swagger Petstore Example Apis":"Show Swagger Petstore Example Apis", | ||
"Show Wordnik Developer Apis":"Show Wordnik Developer Apis", | ||
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Can't read from server. It may not have the appropriate access-control-origin settings.", | ||
@@ -57,2 +60,2 @@ "Please specify the protocol for":"Please specify the protocol for", | ||
"server returned":"server returned" | ||
}); | ||
}); |
@@ -5,3 +5,3 @@ 'use strict'; | ||
window.SwaggerTranslator.learn({ | ||
"Warning: Deprecated":"Ворнинг: Депрекейтед", | ||
"Warning: Deprecated":"Предупреждение: Устарело", | ||
"Implementation Notes":"Заметки", | ||
@@ -24,2 +24,3 @@ "Response Class":"Пример ответа", | ||
"Hide Response":"Спрятать ответ", | ||
"Headers":"Заголовки", | ||
"Response Messages":"Что может прийти в ответ", | ||
@@ -32,4 +33,6 @@ "Try it out!":"Попробовать!", | ||
"can't parse JSON. Raw result":"Не удается распарсить ответ:", | ||
"Example Value":"Пример", | ||
"Model Schema":"Структура", | ||
"Model":"Описание", | ||
"Click to set as parameter value":"Нажмите, чтобы испльзовать в качестве значения параметра", | ||
"apply":"применить", | ||
@@ -44,9 +47,9 @@ "Username":"Имя пользователя", | ||
"Response Content Type":"Content Type ответа", | ||
"Parameter content type:":"Content Type параметра:", | ||
"fetching resource":"Получение ресурса", | ||
"fetching resource list":"Получение ресурсов", | ||
"Explore":"Поехали", | ||
"Explore":"Показать", | ||
"Show Swagger Petstore Example Apis":"Показать примеры АПИ", | ||
"Show Wordnik Developer Apis":"Показать АПИ Wordnik Developer", | ||
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, какая-то лажа с настройками доступа", | ||
"Please specify the protocol for":"Пожалуйста, укажите протогол для", | ||
"Can't read from server. It may not have the appropriate access-control-origin settings.":"Не удается получить ответ от сервера. Возможно, проблема с настройками доступа", | ||
"Please specify the protocol for":"Пожалуйста, укажите протокол для", | ||
"Can't read swagger JSON from":"Не получается прочитать swagger json из", | ||
@@ -57,2 +60,2 @@ "Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим", | ||
"server returned":"сервер сказал" | ||
}); | ||
}); |
@@ -10,3 +10,3 @@ 'use strict'; | ||
* | ||
* If you wish to translate some new texsts you should do two things: | ||
* If you wish to translate some new texts you should do two things: | ||
* 1. Add a new phrase pair ("New Phrase": "New Translation") into your language file (for example lang/ru.js). It will be great if you add it in other language files too. | ||
@@ -21,6 +21,7 @@ * 2. Mark that text it templates this way <anyHtmlTag data-sw-translate>New Phrase</anyHtmlTag> or <anyHtmlTag data-sw-translate value='New Phrase'/>. | ||
translate: function() { | ||
translate: function(sel) { | ||
var $this = this; | ||
sel = sel || '[data-sw-translate]'; | ||
$('[data-sw-translate]').each(function() { | ||
$(sel).each(function() { | ||
$(this).html($this._tryTranslate($(this).html())); | ||
@@ -34,3 +35,3 @@ | ||
_tryTranslate: function(word) { | ||
return this._words[word] !== undefined ? this._words[word] : word; | ||
return this._words[$.trim(word)] !== undefined ? this._words[$.trim(word)] : word; | ||
}, | ||
@@ -37,0 +38,0 @@ |
@@ -6,4 +6,6 @@ var appName; | ||
var realm; | ||
var oauth2KeyName; | ||
var redirect_uri; | ||
var clientSecret; | ||
var scopeSeparator; | ||
var additionalQueryStringParams; | ||
@@ -20,3 +22,2 @@ function handleLogin() { | ||
if(auth.type === 'oauth2' && auth.scopes) { | ||
oauth2KeyName = key; | ||
var scope; | ||
@@ -33,3 +34,3 @@ if(Array.isArray(auth.scopes)) { | ||
for(scope in auth.scopes) { | ||
scopes.push({scope: scope, description: auth.scopes[scope]}); | ||
scopes.push({scope: scope, description: auth.scopes[scope], OAuthSchemeKey: key}); | ||
} | ||
@@ -46,2 +47,3 @@ } | ||
$('.api-popup-dialog').remove(); | ||
popupDialog = $( | ||
@@ -64,8 +66,12 @@ [ | ||
//TODO: only display applicable scopes (will need to pass them into handleLogin) | ||
popup = popupDialog.find('ul.api-popup-scopes').empty(); | ||
for (i = 0; i < scopes.length; i ++) { | ||
scope = scopes[i]; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"/>' + '<label for="scope_' + i + '">' + scope.scope; | ||
str = '<li><input type="checkbox" id="scope_' + i + '" scope="' + scope.scope + '"' +'" oauthtype="' + scope.OAuthSchemeKey +'"/>' + '<label for="scope_' + i + '">' + scope.scope ; | ||
if (scope.description) { | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
if ($.map(auths, function(n, i) { return i; }).length > 1) //if we have more than one scheme, display schemes | ||
str += '<br/><span class="api-scope-desc">' + scope.description + ' ('+ scope.OAuthSchemeKey+')' +'</span>'; | ||
else | ||
str += '<br/><span class="api-scope-desc">' + scope.description + '</span>'; | ||
} | ||
@@ -108,5 +114,21 @@ str += '</label></li>'; | ||
var url = null; | ||
for (var key in authSchemes) { | ||
if (authSchemes.hasOwnProperty(key)) { | ||
var scopes = [] | ||
var o = popup.find('input:checked'); | ||
var OAuthSchemeKeys = []; | ||
var state; | ||
for(k =0; k < o.length; k++) { | ||
var scope = $(o[k]).attr('scope'); | ||
if (scopes.indexOf(scope) === -1) | ||
scopes.push(scope); | ||
var OAuthSchemeKey = $(o[k]).attr('oauthtype'); | ||
if (OAuthSchemeKeys.indexOf(OAuthSchemeKey) === -1) | ||
OAuthSchemeKeys.push(OAuthSchemeKey); | ||
} | ||
//TODO: merge not replace if scheme is different from any existing | ||
//(needs to be aware of schemes to do so correctly) | ||
window.enabledScopes=scopes; | ||
for (var key in authSchemes) { | ||
if (authSchemes.hasOwnProperty(key) && OAuthSchemeKeys.indexOf(key) != -1) { //only look at keys that match this scope. | ||
var flow = authSchemes[key].flow; | ||
@@ -119,3 +141,10 @@ | ||
window.swaggerUi.tokenUrl = (flow === 'accessCode' ? dets.tokenUrl : null); | ||
state = key; | ||
} | ||
else if(authSchemes[key].type === 'oauth2' && flow && (flow === 'application')) { | ||
var dets = authSchemes[key]; | ||
window.swaggerUi.tokenName = dets.tokenName || 'access_token'; | ||
clientCredentialsFlow(scopes, dets.tokenUrl, key); | ||
return; | ||
} | ||
else if(authSchemes[key].grantTypes) { | ||
@@ -141,17 +170,3 @@ // 1.2 support | ||
} | ||
var scopes = [] | ||
var o = $('.api-popup-scopes').find('input:checked'); | ||
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; | ||
@@ -162,4 +177,7 @@ | ||
url += '&client_id=' + encodeURIComponent(clientId); | ||
url += '&scope=' + encodeURIComponent(scopes.join(' ')); | ||
url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); | ||
url += '&state=' + encodeURIComponent(state); | ||
for (var key in additionalQueryStringParams) { | ||
url += '&' + key + '=' + encodeURIComponent(additionalQueryStringParams[key]); | ||
} | ||
@@ -176,4 +194,4 @@ window.open(url); | ||
function handleLogout() { | ||
for(key in window.authorizations.authz){ | ||
window.authorizations.remove(key) | ||
for(key in window.swaggerUi.api.clientAuthorizations.authz){ | ||
window.swaggerUi.api.clientAuthorizations.remove(key) | ||
} | ||
@@ -197,3 +215,6 @@ window.enabledScopes = null; | ||
clientId = (o.clientId||errors.push('missing client id')); | ||
clientSecret = (o.clientSecret||null); | ||
realm = (o.realm||errors.push('missing realm')); | ||
scopeSeparator = (o.scopeSeparator||' '); | ||
additionalQueryStringParams = (o.additionalQueryStringParams||{}); | ||
@@ -217,3 +238,36 @@ if(errors.length > 0){ | ||
function clientCredentialsFlow(scopes, tokenUrl, OAuthSchemeKey) { | ||
var params = { | ||
'client_id': clientId, | ||
'client_secret': clientSecret, | ||
'scope': scopes.join(' '), | ||
'grant_type': 'client_credentials' | ||
} | ||
$.ajax( | ||
{ | ||
url : tokenUrl, | ||
type: "POST", | ||
data: params, | ||
success:function(data, textStatus, jqXHR) | ||
{ | ||
onOAuthComplete(data,OAuthSchemeKey); | ||
}, | ||
error: function(jqXHR, textStatus, errorThrown) | ||
{ | ||
onOAuthComplete(""); | ||
} | ||
}); | ||
} | ||
window.processOAuthCode = function processOAuthCode(data) { | ||
var OAuthSchemeKey = data.state; | ||
// redirect_uri is required in auth code flow | ||
// see https://tools.ietf.org/html/draft-ietf-oauth-v2-31#section-4.1.3 | ||
var host = window.location; | ||
var pathname = location.pathname.substring(0, location.pathname.lastIndexOf("/")); | ||
var defaultRedirectUrl = host.protocol + '//' + host.host + pathname + '/o2c.html'; | ||
var redirectUrl = window.oAuthRedirectUrl || defaultRedirectUrl; | ||
var params = { | ||
@@ -223,4 +277,9 @@ 'client_id': clientId, | ||
'grant_type': 'authorization_code', | ||
'redirect_uri': redirect_uri | ||
'redirect_uri': redirectUrl | ||
}; | ||
if (clientSecret) { | ||
params.client_secret = clientSecret; | ||
} | ||
$.ajax( | ||
@@ -233,3 +292,3 @@ { | ||
{ | ||
onOAuthComplete(data); | ||
onOAuthComplete(data, OAuthSchemeKey); | ||
}, | ||
@@ -241,5 +300,5 @@ error: function(jqXHR, textStatus, errorThrown) | ||
}); | ||
} | ||
}; | ||
window.onOAuthComplete = function onOAuthComplete(token) { | ||
window.onOAuthComplete = function onOAuthComplete(token,OAuthSchemeKey) { | ||
if(token) { | ||
@@ -254,7 +313,10 @@ if(token.error) { | ||
else { | ||
var b = token[window.swaggerUi.tokenName]; | ||
var b = token[window.swaggerUi.tokenName]; | ||
if (!OAuthSchemeKey){ | ||
OAuthSchemeKey = token.state; | ||
} | ||
if(b){ | ||
// if all roles are satisfied | ||
var o = null; | ||
$.each($('.auth #api_information_panel'), function(k, v) { | ||
$.each($('.auth .api-ic .api_information_panel'), function(k, v) { | ||
var children = v; | ||
@@ -276,3 +338,3 @@ if(children && children.childNodes) { | ||
if(diff.length > 0){ | ||
o = v.parentNode; | ||
o = v.parentNode.parentNode; | ||
$(o.parentNode).find('.api-ic.ic-on').addClass('ic-off'); | ||
@@ -286,3 +348,3 @@ $(o.parentNode).find('.api-ic.ic-on').removeClass('ic-on'); | ||
else { | ||
o = v.parentNode; | ||
o = v.parentNode.parentNode; | ||
$(o.parentNode).find('.api-ic.ic-off').addClass('ic-on'); | ||
@@ -298,6 +360,7 @@ $(o.parentNode).find('.api-ic.ic-off').removeClass('ic-off'); | ||
}); | ||
window.swaggerUi.api.clientAuthorizations.add(oauth2KeyName, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); | ||
window.swaggerUi.api.clientAuthorizations.add(window.OAuthSchemeKey, new SwaggerClient.ApiKeyAuthorization('Authorization', 'Bearer ' + b, 'header')); | ||
window.swaggerUi.load(); | ||
} | ||
} | ||
} | ||
} | ||
}; |
@@ -11,5 +11,5 @@ { | ||
"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.5-M2", | ||
"version": "2.1.5", | ||
"homepage": "http://swagger.io", | ||
"license": "Apache 2.0", | ||
"license": "Apache-2.0", | ||
"main": "dist/swagger-ui.js", | ||
@@ -33,2 +33,3 @@ "scripts": { | ||
"docco": "^0.7.0", | ||
"es5-shim": "^4.5.9", | ||
"event-stream": "^3.2.2", | ||
@@ -50,9 +51,17 @@ "express": "^4.12.0", | ||
"gulp-wrap": "^0.11.0", | ||
"http-server": "git+https://github.com/nodeapps/http-server.git", | ||
"http-server": "^0.8.0", | ||
"jshint-stylish": "^1.0.1", | ||
"karma": "0.13.19", | ||
"karma-chai": "0.1.0", | ||
"karma-chrome-launcher": "0.2.2", | ||
"karma-mocha": "0.2.1", | ||
"karma-phantomjs-launcher": "0.2.3", | ||
"karma-sinon-chai": "1.1.0", | ||
"less": "^2.4.0", | ||
"mocha": "^2.1.0", | ||
"phantomjs": "1.9.19", | ||
"selenium-webdriver": "^2.45.0", | ||
"swagger-client": "2.1.6-M2" | ||
"sinon-chai": "2.8.0", | ||
"swagger-client": "2.1.16" | ||
} | ||
} |
# Swagger UI | ||
[![Build Status](https://travis-ci.org/swagger-api/swagger-ui.svg?branch=master)](https://travis-ci.org/swagger-api/swagger-ui) | ||
[![NPM version](https://badge.fury.io/js/swagger-ui.svg)](http://badge.fury.io/js/swagger-ui) | ||
[![Dependency Status](https://david-dm.org/swagger-api/swagger-ui/status.svg)](https://david-dm.org/swagger-api/swagger-ui) | ||
[![devDependency Status](https://david-dm.org/swagger-api/swagger-ui/dev-status.svg)](https://david-dm.org/swagger-api/swagger-ui#info=devDependencies) | ||
Swagger UI is part of the Swagger project. The Swagger project allows you to produce, visualize and consume your OWN RESTful services. No proxy or 3rd party services required. Do it your own way. | ||
@@ -15,11 +19,12 @@ | ||
Check out [Swagger-Spec](https://github.com/swagger-api/swagger-spec) for additional information about the Swagger project, including additional libraries with support for other languages and more. | ||
Check out [Swagger-Spec](https://github.com/OAI/OpenAPI-Specification) for additional information about the Swagger project, including additional libraries with support for other languages and more. | ||
## Compatibility | ||
The Swagger Specification has undergone 4 revisions since initial creation in 2010. Compatibility between swagger-ui and the Swagger specification is as follows: | ||
The OpenAPI Specification has undergone 4 revisions since initial creation in 2010. Compatibility between swagger-ui and the OpenAPI Specification is as follows: | ||
Swagger UI Version | Release Date | Swagger Spec compatibility | Notes | Status | ||
Swagger UI Version | Release Date | OpenAPI Spec compatibility | Notes | Status | ||
------------------ | ------------ | -------------------------- | ----- | ------ | ||
2.1.1-M2 | 2015-04-16 | 1.1, 1.2, 2.0 | [master](https://github.com/swagger-api/swagger-ui) | | ||
2.1.4 | 2016-07-20 | 1.1, 1.2, 2.0 | [tag v.2.1.5](https://github.com/swagger-api/swagger-ui/tree/v2.1.5) | | ||
2.1.4 | 2016-01-06 | 1.1, 1.2, 2.0 | [tag v.2.1.4](https://github.com/swagger-api/swagger-ui/tree/v2.1.4) | | ||
2.0.24 | 2014-09-12 | 1.1, 1.2 | [tag v2.0.24](https://github.com/swagger-api/swagger-ui/tree/v2.0.24) | | ||
@@ -40,8 +45,10 @@ 1.0.13 | 2013-03-08 | 1.1, 1.2 | [tag v1.0.13](https://github.com/swagger-api/swagger-ui/tree/v1.0.13) | | ||
### Windows Users: Please install [Python](https://www.python.org/downloads/windows/) before follow below guidelines for node-gyp rebuild to run. | ||
1. `npm install` | ||
2. `gulp` | ||
2. `npm run build` | ||
3. You should see the distribution under the dist folder. Open [`./dist/index.html`](./dist/index.html) to launch Swagger UI in a browser | ||
### Development | ||
Use `gulp watch` to make a new build and watch for changes in files. | ||
Use `npm run serve` to make a new build, watch for changes, and serve the result at http://localhost:8080/. | ||
@@ -54,6 +61,6 @@ ### Build using Docker | ||
docker build -t swagger-ui-builder . | ||
docker run -p 127.0.0.1:8080:8080 swagger-ui-builder | ||
docker run -p 80:8080 swagger-ui-builder | ||
``` | ||
This will start Swagger UI at `http://localhost:8080`. | ||
This will start Swagger UI at `http://localhost`. | ||
@@ -64,3 +71,3 @@ ### Use | ||
### Customize | ||
You may choose to customize Swagger UI for your organization. Here is an overview of whats in its various directories: | ||
You may choose to customize Swagger UI for your organization. Here is an overview of what's in its various directories: | ||
@@ -92,4 +99,5 @@ - dist: Contains a distribution which you can deploy on a server or load from your local machine. | ||
--- | --- | ||
url | The url pointing to `swagger.json` (Swagger 2.0) or the resource listing (earlier versions) as per [Swagger Spec](https://github.com/swagger-api/swagger-spec/). | ||
spec | A JSON object describing the Swagger specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them. Works for Swagger 2.0 specs only. | ||
url | The url pointing to `swagger.json` (Swagger 2.0) or the resource listing (earlier versions) as per [OpenAPI Spec](https://github.com/OAI/OpenAPI-Specification/). | ||
authorizations | An authorization object to be passed to swagger-js. Setting it here will trigger inclusion of any authorization or custom signing logic when fetching the swagger description file. Note the object structure should be `{ key: AuthorizationObject }` | ||
spec | A JSON object describing the OpenAPI Specification. When used, the `url` parameter will not be parsed. This is useful for testing manually-generated specifications without hosting them. Works for Swagger 2.0 specs only. | ||
validatorUrl | By default, Swagger-UI attempts to validate specs against swagger.io's online validator. You can use this parameter to set a different validator URL, for example for locally deployed validators ([Validator Badge](https://github.com/swagger-api/validator-badge)). Setting it to `null` will disable validation. This parameter is relevant for Swagger 2.0 specs only. | ||
@@ -101,7 +109,10 @@ dom_id | The id of a dom element inside which SwaggerUi will put the user interface for swagger. | ||
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. | ||
defaultModelRendering | Controls how models are shown when the API is first rendered. (The user can always switch the rendering for a given model by clicking the 'Model' and 'Model Schema' links.) It can be set to 'model' or 'schema', and the default is 'schema'. | ||
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. | ||
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 | ||
showRequestHeaders | Whether or not to show the headers that were sent when making a request via the 'Try it out!' option. Defaults to `false`. | ||
jsonEditor | Enables a graphical view for editing complex bodies. Defaults to `false`. | ||
@@ -123,3 +134,3 @@ * All other parameters are explained in greater detail below | ||
if(key && key.trim() != "") { | ||
swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorization("api_key", key, "header")); | ||
swaggerUi.api.clientAuthorizations.add("auth_name", new SwaggerClient.ApiKeyAuthorization("api_key", key, "header")); | ||
} | ||
@@ -129,3 +140,3 @@ }) | ||
This will add header `api_key` with value `key` on every call to the server. You can substitute `query` to send the values as a query param. | ||
This will add the header `api_key` with value `key` on calls that have the `auth_name` security scheme as part of their swaggerDefinitions. You can substitute `query` to send the values as a query param. | ||
@@ -153,3 +164,3 @@ ### Custom Header Parameters - (For Basic auth etc) | ||
To append new lexemex for translation you shoul do two things: | ||
To append new lexemex for translation you should do two things: | ||
1. Add lexeme into the language file. | ||
@@ -168,2 +179,3 @@ Example of new line: "new sentence":"translation of new sentence". | ||
## CORS Support | ||
### OR: How to deal with "Can't read from server. It may not have the appropriate access-control-origin settings." | ||
@@ -177,3 +189,3 @@ 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. | ||
1. swagger-ui is hosted on the same server as the application itself (same host *and* port). | ||
2. The application is located behind a proxy that enables the requires CORS headers. This may already be covered within your organization. | ||
2. The application is located behind a proxy that enables the required CORS headers. This may already be covered within your organization. | ||
@@ -237,7 +249,7 @@ Otherwise, CORS support needs to be enabled for: | ||
## Change Log | ||
Plsee see [releases](https://github.com/swagger-api/swagger-ui/releases) for change log. | ||
Please see [releases](https://github.com/swagger-api/swagger-ui/releases) for change log. | ||
## License | ||
Copyright 2011-2015 Reverb technologies, Inc. | ||
Copyright 2016 SmartBear Software | ||
@@ -253,1 +265,4 @@ Licensed under the Apache License, Version 2.0 (the "License"); | ||
limitations under the License. | ||
--- | ||
<img src="http://swagger.io/wp-content/uploads/2016/02/logo.jpg"/> |
@@ -96,7 +96,9 @@ 'use strict'; | ||
case 1: | ||
// Expand all operations for the resource and scroll to it | ||
var dom_id = 'resource_' + fragments[0]; | ||
if (fragments[0].length > 0) { // prevent matching "#/" | ||
// 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}); | ||
Docs.expandEndpointListForResource(fragments[0]); | ||
$("#"+dom_id).slideto({highlight: false}); | ||
} | ||
break; | ||
@@ -110,12 +112,11 @@ case 2: | ||
// Expand operation | ||
var li_dom_id = fragments.join('_'); | ||
var li_content_dom_id = li_dom_id + "_content"; | ||
// 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; | ||
Docs.expandOperation($('#'+li_content_dom_id)); | ||
$('#'+li_dom_id).slideto({highlight: false}); | ||
break; | ||
} | ||
}, | ||
@@ -126,4 +127,6 @@ | ||
if (elem.is(':visible')) { | ||
$.bbq.pushState('#/', 2); | ||
Docs.collapseEndpointListForResource(resource); | ||
} else { | ||
$.bbq.pushState('#/' + resource, 2); | ||
Docs.expandEndpointListForResource(resource); | ||
@@ -130,0 +133,0 @@ } |
'use strict'; | ||
/*jslint eqeq: true*/ | ||
@@ -10,6 +11,15 @@ Handlebars.registerHelper('sanitize', function(html) { | ||
Handlebars.registerHelper('renderTextParam', function(param) { | ||
var result, type = 'text'; | ||
var isArray = param.type.toLowerCase() === 'array' || param.allowMultiple; | ||
var result, type = 'text', idAtt = ''; | ||
var paramType = param.type || param.schema.type || ''; | ||
var isArray = paramType.toLowerCase() === 'array' || param.allowMultiple; | ||
var defaultValue = isArray && Array.isArray(param.default) ? param.default.join('\n') : param.default; | ||
var dataVendorExtensions = Object.keys(param).filter(function(property) { | ||
// filter X-data- properties | ||
return property.match(/^X-data-/i) !== null; | ||
}).reduce(function(result, property) { | ||
// remove X- from property name, so it results in html attributes like data-foo='bar' | ||
return result += ' ' + property.substring(2, property.length) + '=\'' + param[property] + '\''; | ||
}, ''); | ||
if (typeof defaultValue === 'undefined') { | ||
@@ -20,7 +30,15 @@ defaultValue = ''; | ||
if(param.format && param.format === 'password') { | ||
type = 'password'; | ||
type = 'password'; | ||
} | ||
if(param.valueId) { | ||
idAtt = ' id=\'' + param.valueId + '\''; | ||
} | ||
if (typeof defaultValue === 'string' || defaultValue instanceof String) { | ||
defaultValue = defaultValue.replace(/'/g,'''); | ||
} | ||
if(isArray) { | ||
result = '<textarea class=\'body-textarea' + (param.required ? ' required' : '') + '\' name=\'' + param.name + '\''; | ||
result = '<textarea class=\'body-textarea' + (param.required ? ' required' : '') + '\' name=\'' + param.name + '\'' + idAtt + dataVendorExtensions; | ||
result += ' placeholder=\'Provide multiple values in new lines' + (param.required ? ' (at least one required).' : '.') + '\'>'; | ||
@@ -34,3 +52,3 @@ result += defaultValue + '</textarea>'; | ||
result = '<input class=\'' + parameterClass + '\' minlength=\'' + (param.required ? 1 : 0) + '\''; | ||
result += ' name=\'' + param.name +'\' placeholder=\'' + (param.required ? '(required)' : '') + '\''; | ||
result += ' name=\'' + param.name +'\' placeholder=\'' + (param.required ? '(required)' : '') + '\'' + idAtt + dataVendorExtensions; | ||
result += ' type=\'' + type + '\' value=\'' + defaultValue + '\'/>'; | ||
@@ -40,1 +58,25 @@ } | ||
}); | ||
Handlebars.registerHelper('ifCond', function (v1, operator, v2, options) { | ||
switch (operator) { | ||
case '==': | ||
return (v1 == v2) ? options.fn(this) : options.inverse(this); | ||
case '===': | ||
return (v1 === v2) ? options.fn(this) : options.inverse(this); | ||
case '<': | ||
return (v1 < v2) ? options.fn(this) : options.inverse(this); | ||
case '<=': | ||
return (v1 <= v2) ? options.fn(this) : options.inverse(this); | ||
case '>': | ||
return (v1 > v2) ? options.fn(this) : options.inverse(this); | ||
case '>=': | ||
return (v1 >= v2) ? options.fn(this) : options.inverse(this); | ||
case '&&': | ||
return (v1 && v2) ? options.fn(this) : options.inverse(this); | ||
case '||': | ||
return (v1 || v2) ? options.fn(this) : options.inverse(this); | ||
default: | ||
return options.inverse(this); | ||
} | ||
}); |
@@ -0,1 +1,2 @@ | ||
/*global JSONEditor*/ | ||
'use strict'; | ||
@@ -16,3 +17,8 @@ | ||
options = options || {}; | ||
if(!options.highlightSizeThreshold) { | ||
if (options.defaultModelRendering !== 'model') { | ||
options.defaultModelRendering = 'schema'; | ||
} | ||
if (!options.highlightSizeThreshold) { | ||
options.highlightSizeThreshold = 100000; | ||
@@ -40,3 +46,3 @@ } | ||
if (typeof options.oauth2RedirectUrl === 'string') { | ||
window.oAuthRedirectUrl = options.redirectUrl; | ||
window.oAuthRedirectUrl = options.oauth2RedirectUrl; | ||
} | ||
@@ -67,2 +73,12 @@ | ||
}); | ||
// JSon Editor custom theming | ||
JSONEditor.defaults.iconlibs.swagger = JSONEditor.AbstractIconLib.extend({ | ||
mapping: { | ||
collapse: 'collapse', | ||
expand: 'expand' | ||
}, | ||
icon_prefix: 'swagger-' | ||
}); | ||
}, | ||
@@ -92,2 +108,6 @@ | ||
} | ||
if (this.authView) { | ||
this.authView.remove(); | ||
} | ||
var url = this.options.url; | ||
@@ -98,3 +118,3 @@ if (url && url.indexOf('http') !== 0) { | ||
if(this.api) { | ||
this.options.authorizations = this.api.clientAuthorizations; | ||
this.options.authorizations = this.api.clientAuthorizations.authz; | ||
} | ||
@@ -125,2 +145,3 @@ this.options.url = url; | ||
render: function(){ | ||
var authsModel; | ||
this.showMessage('Finished Loading Resource Information. Rendering Swagger UI...'); | ||
@@ -133,2 +154,14 @@ this.mainView = new SwaggerUi.Views.MainView({ | ||
}).render(); | ||
if (!_.isEmpty(this.api.securityDefinitions)){ | ||
authsModel = _.map(this.api.securityDefinitions, function (auth, name) { | ||
var result = {}; | ||
result[name] = auth; | ||
return result; | ||
}); | ||
this.authView = new SwaggerUi.Views.AuthButtonView({ | ||
data: SwaggerUi.utils.parseSecurityDefinitions(authsModel), | ||
router: this | ||
}); | ||
$('#auth_container').append(this.authView.render().el); | ||
} | ||
this.showMessage(); | ||
@@ -183,5 +216,9 @@ switch (this.options.docExpansion) { | ||
} | ||
$('#message-bar').removeClass('message-fail'); | ||
$('#message-bar').addClass('message-success'); | ||
$('#message-bar').html(data); | ||
var $msgbar = $('#message-bar'); | ||
$msgbar.removeClass('message-fail'); | ||
$msgbar.addClass('message-success'); | ||
$msgbar.text(data); | ||
if(window.SwaggerTranslator) { | ||
window.SwaggerTranslator.translate($msgbar); | ||
} | ||
}, | ||
@@ -197,3 +234,3 @@ | ||
var val = $('#message-bar').html(data); | ||
var val = $('#message-bar').text(data); | ||
@@ -212,2 +249,6 @@ if (this.options.onFailure) { | ||
}); | ||
$('.propDesc', '.model-signature .description').each(function () { | ||
$(this).html(marked($(this).html())).addClass('markdown'); | ||
}); | ||
} | ||
@@ -218,2 +259,6 @@ | ||
window.SwaggerUi.Views = {}; | ||
window.SwaggerUi.Models = {}; | ||
window.SwaggerUi.Collections = {}; | ||
window.SwaggerUi.partials = {}; | ||
window.SwaggerUi.utils = {}; | ||
@@ -263,3 +308,3 @@ // don't break backward compatibility with previous versions and warn users to upgrade their code | ||
// Node. Does not work with strict CommonJS, but | ||
// only CommonJS-like enviroments that support module.exports, | ||
// only CommonJS-like environments that support module.exports, | ||
// like Node. | ||
@@ -273,2 +318,2 @@ module.exports = factory(require('b')); | ||
return SwaggerUi; | ||
})); | ||
})); |
@@ -7,8 +7,6 @@ 'use strict'; | ||
render: function(){ | ||
this.model.contentTypeId = 'ct' + Math.random(); | ||
$(this.el).html(Handlebars.templates.content_type(this.model)); | ||
$('label[for=contentType]', $(this.el)).text('Response Content Type'); | ||
return this; | ||
} | ||
}); |
@@ -6,3 +6,2 @@ 'use strict'; | ||
'click #show-pet-store-icon' : 'showPetStore', | ||
'click #show-wordnik-dev-icon' : 'showWordnikDev', | ||
'click #explore' : 'showCustom', | ||
@@ -21,8 +20,2 @@ 'keyup #input_baseUrl' : 'showCustomOnKeyup', | ||
showWordnikDev: function(){ | ||
this.trigger('update-swagger-ui', { | ||
url: 'http://api.wordnik.com/v4/resources.json' | ||
}); | ||
}, | ||
showCustomOnKeyup: function(e){ | ||
@@ -40,4 +33,3 @@ if (e.keyCode === 13) { | ||
this.trigger('update-swagger-ui', { | ||
url: $('#input_baseUrl').val(), | ||
apiKey: $('#input_apiKey').val() | ||
url: $('#input_baseUrl').val() | ||
}); | ||
@@ -53,3 +45,2 @@ }, | ||
//$('#input_apiKey').val(apiKey); | ||
if (trigger) { | ||
@@ -56,0 +47,0 @@ this.trigger('update-swagger-ui', {url:url}); |
@@ -57,43 +57,38 @@ 'use strict'; | ||
if (this.model.swaggerVersion === '2.0') { | ||
if ('validatorUrl' in opts.swaggerOptions) { | ||
if ('validatorUrl' in opts.swaggerOptions) { | ||
// Validator URL specified explicitly | ||
this.model.validatorUrl = opts.swaggerOptions.validatorUrl; | ||
} else if (this.model.url.indexOf('localhost') > 0 || this.model.url.indexOf('127.0.0.1') > 0) { | ||
// Localhost override | ||
this.model.validatorUrl = null; | ||
} else { | ||
// Default validator | ||
if(window.location.protocol === 'https:') { | ||
this.model.validatorUrl = 'https://online.swagger.io/validator'; | ||
} | ||
else { | ||
this.model.validatorUrl = 'http://online.swagger.io/validator'; | ||
} | ||
} | ||
// 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 | ||
if(window.location.protocol.indexOf('http') === 0) { | ||
this.model.validatorUrl = window.location.protocol + '//online.swagger.io/validator'; | ||
} | ||
// JSonEditor requires type='object' to be present on defined types, we add it if it's missing | ||
// is there any valid case were it should not be added ? | ||
var def; | ||
for(def in this.model.definitions){ | ||
if (!this.model.definitions[def].type){ | ||
this.model.definitions[def].type = 'object'; | ||
} | ||
} | ||
}, | ||
render: function(){ | ||
if (this.model.securityDefinitions) { | ||
for (var name in this.model.securityDefinitions) { | ||
var auth = this.model.securityDefinitions[name]; | ||
var button; | ||
render: function () { | ||
$(this.el).html(Handlebars.templates.main(this.model)); | ||
this.info = this.$('.info')[0]; | ||
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); | ||
} | ||
} | ||
if (this.info) { | ||
this.info.addEventListener('click', this.onLinkClick, true); | ||
} | ||
// Render the outer container for resources | ||
$(this.el).html(Handlebars.templates.main(this.model)); | ||
this.model.securityDefinitions = this.model.securityDefinitions || {}; | ||
@@ -127,2 +122,7 @@ // Render each resource | ||
resource.id = resource.id.replace(/\s/g, '_'); | ||
// Make all definitions available at the root of the resource so that they can | ||
// be loaded by the JSonEditor | ||
resource.definitions = this.model.definitions; | ||
var resourceView = new SwaggerUi.Views.ResourceView({ | ||
@@ -142,3 +142,12 @@ model: resource, | ||
$(this.el).html(''); | ||
}, | ||
onLinkClick: function (e) { | ||
var el = e.target; | ||
if (el.tagName === 'A' && el.href && !el.target) { | ||
e.preventDefault(); | ||
window.open(el.href, '_blank'); | ||
} | ||
} | ||
}); |
@@ -12,3 +12,4 @@ 'use strict'; | ||
'mouseenter .api-ic' : 'mouseEnter', | ||
'mouseout .api-ic' : 'mouseExit', | ||
'dblclick .curl' : 'selectText', | ||
'change [name=responseContentType]' : 'showSnippet' | ||
}, | ||
@@ -23,5 +24,31 @@ | ||
this.model.encodedParentId = encodeURIComponent(this.parentId); | ||
if (opts.swaggerOptions) { | ||
this.model.defaultRendering = opts.swaggerOptions.defaultModelRendering; | ||
if (opts.swaggerOptions.showRequestHeaders) { | ||
this.model.showRequestHeaders = true; | ||
} | ||
} | ||
return this; | ||
}, | ||
selectText: function(event) { | ||
var doc = document, | ||
text = event.target.firstChild, | ||
range, | ||
selection; | ||
if (doc.body.createTextRange) { | ||
range = document.body.createTextRange(); | ||
range.moveToElementText(text); | ||
range.select(); | ||
} else if (window.getSelection) { | ||
selection = window.getSelection(); | ||
range = document.createRange(); | ||
range.selectNodeContents(text); | ||
selection.removeAllRanges(); | ||
selection.addRange(range); | ||
} | ||
}, | ||
mouseEnter: function(e) { | ||
@@ -58,13 +85,8 @@ var elem = $(this.el).find('.content'); | ||
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; | ||
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, produces, isXML, isJSON; | ||
isMethodSubmissionSupported = jQuery.inArray(this.model.method, this.model.supportedSubmitMethods()) >= 0; | ||
@@ -82,18 +104,19 @@ if (!isMethodSubmissionSupported) { | ||
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); | ||
if (key === auth.name) { | ||
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); | ||
} | ||
} | ||
@@ -132,4 +155,4 @@ } | ||
schema = schemaObj.$ref; | ||
if (schema.indexOf('#/definitions/') === 0) { | ||
schema = schema.substring('#/definitions/'.length); | ||
if (schema.indexOf('#/definitions/') !== -1) { | ||
schema = schema.replace(/^.*#\/definitions\//, ''); | ||
} | ||
@@ -140,3 +163,5 @@ } | ||
message: value.description, | ||
responseModel: schema | ||
responseModel: schema, | ||
headers: value.headers, | ||
schema: schemaObj | ||
}); | ||
@@ -149,2 +174,6 @@ } | ||
signatureModel = null; | ||
produces = this.model.produces; | ||
isXML = this.contains(produces, 'xml'); | ||
isJSON = isXML ? this.contains(produces, 'json') : true; | ||
if (this.model.successResponse) { | ||
@@ -156,7 +185,14 @@ successResponse = this.model.successResponse; | ||
if (typeof value === 'object' && typeof value.createJSONSample === 'function') { | ||
this.model.successDescription = value.description; | ||
this.model.headers = this.parseResponseHeaders(value.headers); | ||
signatureModel = { | ||
sampleJSON: JSON.stringify(value.createJSONSample(), void 0, 2), | ||
sampleJSON: isJSON ? JSON.stringify(SwaggerUi.partials.signature.createJSONSample(value), void 0, 2) : false, | ||
isParam: false, | ||
signature: value.getMockSignature() | ||
sampleXML: isXML ? SwaggerUi.partials.signature.createXMLSample(value.name, value.definition, value.models) : false, | ||
signature: SwaggerUi.partials.signature.getModelSignature(value.name, value.definition, value.models, value.modelPropertyMacro) | ||
}; | ||
} else { | ||
signatureModel = { | ||
signature: SwaggerUi.partials.signature.getPrimitiveSignature(value) | ||
}; | ||
} | ||
@@ -173,2 +209,3 @@ } | ||
if (signatureModel) { | ||
signatureModel.defaultRendering = this.model.defaultRendering; | ||
responseSignatureView = new SwaggerUi.Views.SignatureView({ | ||
@@ -224,14 +261,104 @@ model: signatureModel, | ||
statusCode = ref5[q]; | ||
statusCode.isXML = isXML; | ||
statusCode.isJSON = isJSON; | ||
if (!_.isUndefined(statusCode.headers)) { | ||
statusCode.headers = this.parseHeadersType(statusCode.headers); | ||
} | ||
this.addStatusCode(statusCode); | ||
} | ||
if (Array.isArray(this.model.security)) { | ||
var authsModel = SwaggerUi.utils.parseSecurityDefinitions(this.model.security); | ||
authsModel.isLogout = !_.isEmpty(window.swaggerUi.api.clientAuthorizations.authz); | ||
this.authView = new SwaggerUi.Views.AuthButtonView({ | ||
data: authsModel, | ||
router: this.router, | ||
isOperation: true, | ||
model: { | ||
scopes: authsModel.scopes | ||
} | ||
}); | ||
this.$('.authorize-wrapper').append(this.authView.render().el); | ||
} | ||
this.showSnippet(); | ||
return this; | ||
}, | ||
parseHeadersType: function (headers) { | ||
var map = { | ||
'string': { | ||
'date-time': 'dateTime', | ||
'date' : 'date' | ||
} | ||
}; | ||
_.forEach(headers, function (header) { | ||
var value; | ||
header = header || {}; | ||
value = map[header.type] && map[header.type][header.format]; | ||
if (!_.isUndefined(value)) { | ||
header.type = value; | ||
} | ||
}); | ||
return headers; | ||
}, | ||
contains: function (produces, type) { | ||
return produces.filter(function (val) { | ||
if (val.indexOf(type) > -1) { | ||
return true; | ||
} | ||
}).length; | ||
}, | ||
parseResponseHeaders: function (data) { | ||
var HEADERS_SEPARATOR = '; '; | ||
var headers = _.clone(data); | ||
_.forEach(headers, function (header) { | ||
var other = []; | ||
_.forEach(header, function (value, key) { | ||
var properties = ['type', 'description']; | ||
if (properties.indexOf(key.toLowerCase()) === -1) { | ||
other.push(key + ': ' + value); | ||
} | ||
}); | ||
other.join(HEADERS_SEPARATOR); | ||
header.other = other; | ||
}); | ||
return headers; | ||
}, | ||
addParameter: function(param, consumes) { | ||
// Render a parameter | ||
param.consumes = consumes; | ||
param.defaultRendering = this.model.defaultRendering; | ||
// Copy this param JSON spec so that it will be available for JsonEditor | ||
if(param.schema){ | ||
$.extend(true, param.schema, this.model.definitions[param.type]); | ||
param.schema.definitions = this.model.definitions; | ||
// This is required for JsonEditor to display the root properly | ||
if(!param.schema.type){ | ||
param.schema.type = 'object'; | ||
} | ||
// This is the title that will be used by JsonEditor for the root | ||
// Since we already display the parameter's name in the Parameter column | ||
// We set this to space, we can't set it to null or space otherwise JsonEditor | ||
// will replace it with the text "root" which won't look good on screen | ||
if(!param.schema.title){ | ||
param.schema.title = ' '; | ||
} | ||
} | ||
var paramView = new SwaggerUi.Views.ParameterView({ | ||
model: param, | ||
tagName: 'tr', | ||
readOnly: this.model.isReadOnly | ||
readOnly: this.model.isReadOnly, | ||
swaggerOptions: this.options.swaggerOptions | ||
}); | ||
@@ -243,2 +370,3 @@ $('.operation-params', $(this.el)).append(paramView.render().el); | ||
// Render status codes | ||
statusCode.defaultRendering = this.model.defaultRendering; | ||
var statusCodeView = new SwaggerUi.Views.StatusCodeView({ | ||
@@ -255,3 +383,3 @@ model: statusCode, | ||
submitOperation: function(e) { | ||
var error_free, form, isFileUpload, l, len, len1, len2, m, map, n, o, opts, ref1, ref2, ref3, val; | ||
var error_free, form, isFileUpload, map, opts; | ||
if (e !== null) { | ||
@@ -276,3 +404,3 @@ e.preventDefault(); | ||
}); | ||
form.find('textarea.required').each(function() { | ||
form.find('textarea.required:visible').each(function() { | ||
$(this).removeClass('error'); | ||
@@ -306,7 +434,8 @@ if (jQuery.trim($(this).val()) === '') { | ||
if (error_free) { | ||
map = {}; | ||
map = this.getInputMap(form); | ||
isFileUpload = this.isFileUpload(form); | ||
opts = { | ||
parent: this | ||
}; | ||
if(this.options.swaggerOptions) { | ||
if (this.options.swaggerOptions) { | ||
for(var key in this.options.swaggerOptions) { | ||
@@ -316,30 +445,12 @@ opts[key] = this.options.swaggerOptions[key]; | ||
} | ||
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; | ||
var pi; | ||
for(pi = 0; pi < this.model.parameters.length; pi++){ | ||
var p = this.model.parameters[pi]; | ||
if( p.jsonEditor && p.jsonEditor.isEnabled()){ | ||
var json = p.jsonEditor.getValue(); | ||
map[p.name] = JSON.stringify(json); | ||
} | ||
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]; | ||
val = this.getTextAreaValue(o); | ||
if ((val !== null) && jQuery.trim(val).length > 0) { | ||
map[o.name] = val; | ||
} | ||
} | ||
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(); | ||
@@ -349,4 +460,11 @@ opts.requestContentType = $('div select[name=parameterContentType]', $(this.el)).val(); | ||
if (isFileUpload) { | ||
return this.handleFileUpload(map, form); | ||
$('.request_url', $(this.el)).html('<pre></pre>'); | ||
$('.request_url pre', $(this.el)).text(this.invocationUrl); | ||
opts.useJQuery = true; | ||
map.parameterContentType = 'multipart/form-data'; | ||
this.map = map; | ||
return this.model.execute(map, opts, this.showCompleteStatus, this.showErrorStatus, this); | ||
} else { | ||
this.map = map; | ||
return this.model.execute(map, opts, this.showCompleteStatus, this.showErrorStatus, this); | ||
@@ -357,11 +475,6 @@ } | ||
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, p, param, params, ref1, ref2, ref3, ref4; | ||
ref1 = form.serializeArray(); | ||
getInputMap: function (form) { | ||
var map, ref1, l, len, o, ref2, m, len1, val, ref3, n, len2; | ||
map = {}; | ||
ref1 = form.find('input'); | ||
for (l = 0, len = ref1.length; l < len; l++) { | ||
@@ -372,67 +485,45 @@ o = ref1[l]; | ||
} | ||
if (o.type === 'file') { | ||
map[o.name] = o.files[0]; | ||
} | ||
} | ||
bodyParam = new FormData(); | ||
params = 0; | ||
ref2 = this.model.parameters; | ||
ref2 = form.find('textarea'); | ||
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]); | ||
} | ||
o = ref2[m]; | ||
val = this.getTextAreaValue(o); | ||
if ((val !== null) && jQuery.trim(val).length > 0) { | ||
map[o.name] = val; | ||
} | ||
} | ||
headerParams = {}; | ||
ref3 = this.model.parameters; | ||
ref3 = form.find('select'); | ||
for (n = 0, len2 = ref3.length; n < len2; n++) { | ||
param = ref3[n]; | ||
if (param.paramType === 'header') { | ||
headerParams[param.name] = map[param.name]; | ||
o = ref3[n]; | ||
val = this.getSelectedValue(o); | ||
if ((val !== null) && jQuery.trim(val).length > 0) { | ||
map[o.name] = val; | ||
} | ||
} | ||
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; | ||
return map; | ||
}, | ||
isFileUpload: function (form) { | ||
var ref1, l, len, o; | ||
var isFileUpload = false; | ||
ref1 = form.find('input'); | ||
for (l = 0, len = ref1.length; l < len; l++) { | ||
o = ref1[l]; | ||
if (o.type === 'file') { | ||
isFileUpload = true; | ||
} | ||
} | ||
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); | ||
return isFileUpload; | ||
}, | ||
// TODO: don't use jQuery. Use SwaggerJS for handling the call. | ||
var 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) | ||
}; | ||
jQuery.ajax(obj); | ||
return false; | ||
// end of file-upload nastiness | ||
success: function(response, parent) { | ||
parent.showCompleteStatus(response); | ||
}, | ||
// wraps a jquery response as a shred response | ||
wrap: function(data) { | ||
var h, headerArray, headers, i, l, len, o; | ||
var h, headerArray, headers, i, l, len, o; | ||
headers = {}; | ||
@@ -511,3 +602,3 @@ headerArray = data.getAllResponseHeaders().split('\r'); | ||
contexp = /(<.+>)(.+\n)/g; | ||
xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); | ||
xml = xml.replace(/\r\n/g, '\n').replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); | ||
pad = 0; | ||
@@ -615,3 +706,3 @@ formatted = ''; | ||
// JSON | ||
// JSON | ||
} else if (contentType === 'application/json' || /\+json$/.test(contentType)) { | ||
@@ -627,3 +718,3 @@ var json = null; | ||
// XML | ||
// XML | ||
} else if (contentType === 'application/xml' || /\+xml$/.test(contentType)) { | ||
@@ -633,3 +724,3 @@ code = $('<code />').text(this.formatXml(content)); | ||
// HTML | ||
// HTML | ||
} else if (contentType === 'text/html') { | ||
@@ -639,3 +730,3 @@ code = $('<code />').html(_.escape(content)); | ||
// Plain Text | ||
// Plain Text | ||
} else if (/text\/plain/.test(contentType)) { | ||
@@ -646,15 +737,15 @@ code = $('<code />').text(content); | ||
// Image | ||
// Image | ||
} else if (/^image\//.test(contentType)) { | ||
pre = $('<img>').attr('src', url); | ||
// Audio | ||
// Audio | ||
} else if (/^audio\//.test(contentType) && supportsAudioPlayback(contentType)) { | ||
pre = $('<audio controls>').append($('<source>').attr('src', url).attr('type', contentType)); | ||
// Download | ||
// Download | ||
} else if (headers['Content-Disposition'] && (/attachment/).test(headers['Content-Disposition']) || | ||
headers['content-disposition'] && (/attachment/).test(headers['content-disposition']) || | ||
headers['Content-Description'] && (/File Transfer/).test(headers['Content-Description']) || | ||
headers['content-description'] && (/File Transfer/).test(headers['content-description'])) { | ||
headers['content-disposition'] && (/attachment/).test(headers['content-disposition']) || | ||
headers['Content-Description'] && (/File Transfer/).test(headers['Content-Description']) || | ||
headers['content-description'] && (/File Transfer/).test(headers['content-description'])) { | ||
@@ -669,2 +760,11 @@ if ('Blob' in window) { | ||
// Use filename from response header | ||
var disposition = headers['content-disposition'] || headers['Content-Disposition']; | ||
if(typeof disposition !== 'undefined') { | ||
var responseFilename = /filename=([^;]*);?/.exec(disposition); | ||
if(responseFilename !== null && responseFilename.length > 1) { | ||
download = responseFilename[1]; | ||
} | ||
} | ||
a.setAttribute('href', href); | ||
@@ -679,7 +779,7 @@ a.setAttribute('download', download); | ||
// Location header based redirect download | ||
// Location header based redirect download | ||
} else if(headers.location || headers.Location) { | ||
window.location = response.url; | ||
// Anything else (CORS) | ||
// Anything else (CORS) | ||
} else { | ||
@@ -698,7 +798,23 @@ code = $('<code />').text(content); | ||
$('.response_throbber', $(this.el)).hide(); | ||
var response_body_el = $('.response_body', $(this.el))[0]; | ||
// adds curl output | ||
var curlCommand = this.model.asCurl(this.map, {responseContentType: contentType}); | ||
curlCommand = curlCommand.replace('!', '!'); | ||
$( 'div.curl', $(this.el)).html('<pre>' + _.escape(curlCommand) + '</pre>'); | ||
// 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) { | ||
if (opts.showRequestHeaders) { | ||
var form = $('.sandbox', $(this.el)), | ||
map = this.getInputMap(form), | ||
requestHeaders = this.model.getHeaderParams(map); | ||
delete requestHeaders['Content-Type']; | ||
$('.request_headers', $(this.el)).html('<pre>' + _.escape(JSON.stringify(requestHeaders, null, ' ')).replace(/\n/g, '<br>') + '</pre>'); | ||
} | ||
var response_body_el = $('.response_body', $(this.el))[0]; | ||
// only highlight the response if response is less than threshold, default state is highlight response | ||
if (opts.highlightSizeThreshold && typeof response.data !== 'undefined' && response.data.length > opts.highlightSizeThreshold) { | ||
return response_body_el; | ||
@@ -710,5 +826,7 @@ } else { | ||
toggleOperationContent: function() { | ||
toggleOperationContent: function (event) { | ||
var elem = $('#' + Docs.escapeResourceName(this.parentId + '_' + this.nickname + '_content')); | ||
if (elem.is(':visible')){ | ||
$.bbq.pushState('#/', 2); | ||
event.preventDefault(); | ||
Docs.collapseOperation(elem); | ||
@@ -740,2 +858,20 @@ } else { | ||
showSnippet: function () { | ||
var contentTypeEl = this.$('[name=responseContentType]'); | ||
var xmlSnippetEl = this.$('.operation-status .snippet_xml, .response-class .snippet_xml'); | ||
var jsonSnippetEl = this.$('.operation-status .snippet_json, .response-class .snippet_json'); | ||
var contentType; | ||
if (!contentTypeEl.length) { return; } | ||
contentType = contentTypeEl.val(); | ||
if (contentType.indexOf('xml') > -1) { | ||
xmlSnippetEl.show(); | ||
jsonSnippetEl.hide(); | ||
} else { | ||
jsonSnippetEl.show(); | ||
xmlSnippetEl.hide(); | ||
} | ||
}, | ||
getParamByName: function(name) { | ||
@@ -742,0 +878,0 @@ var i; |
@@ -7,6 +7,4 @@ 'use strict'; | ||
render: function(){ | ||
this.model.parameterContentTypeId = 'pct' + Math.random(); | ||
$(this.el).html(Handlebars.templates.parameter_content_type(this.model)); | ||
$('label[for=parameterContentType]', $(this.el)).text('Parameter content type:'); | ||
return this; | ||
@@ -13,0 +11,0 @@ } |
'use strict'; | ||
SwaggerUi.Views.ParameterView = Backbone.View.extend({ | ||
events: { | ||
'change [name=parameterContentType]' : 'toggleParameterSnippet' | ||
}, | ||
initialize: function(){ | ||
Handlebars.registerHelper('isArray', function(param, opts) { | ||
if (param.type.toLowerCase() === 'array' || param.allowMultiple) { | ||
var paramType = param.type && param.type.toLowerCase(); | ||
if (paramType === 'array' || param.allowMultiple) { | ||
return opts.fn(this); | ||
@@ -16,6 +21,11 @@ } else { | ||
var type = this.model.type || this.model.dataType; | ||
var modelType = this.model.modelSignature.type; | ||
var modelDefinitions = this.model.modelSignature.definitions; | ||
var schema = this.model.schema || {}; | ||
var consumes = this.model.consumes || []; | ||
var sampleJSON, signatureView; | ||
if (typeof type === 'undefined') { | ||
var schema = this.model.schema; | ||
if (schema && schema.$ref) { | ||
if (schema.$ref) { | ||
var ref = schema.$ref; | ||
@@ -34,4 +44,11 @@ if (ref.indexOf('#/definitions/') === 0) { | ||
this.model.isFile = type && type.toLowerCase() === 'file'; | ||
this.model.default = (this.model.default || this.model.defaultValue); | ||
// Allow for default === false | ||
if(typeof this.model.default === 'undefined') { | ||
this.model.default = this.model.defaultValue; | ||
} | ||
this.model.hasDefault = (typeof this.model.default !== 'undefined'); | ||
this.model.valueId = 'm' + this.model.name + Math.random(); | ||
if (this.model.allowableValues) { | ||
@@ -41,2 +58,6 @@ this.model.isList = true; | ||
var isXML = this.contains(consumes, 'xml'); | ||
var isJSON = isXML ? this.contains(consumes, 'json') : true; | ||
sampleJSON = SwaggerUi.partials.signature.createParameterJSONSample(modelType, modelDefinitions); | ||
var template = this.template(); | ||
@@ -46,9 +67,11 @@ $(this.el).html(template(this.model)); | ||
var signatureModel = { | ||
sampleJSON: this.model.sampleJSON, | ||
sampleJSON: isJSON ? sampleJSON : false, | ||
sampleXML: sampleJSON && isXML ? SwaggerUi.partials.signature.createXMLSample('', schema, modelDefinitions, true) : false, | ||
isParam: true, | ||
signature: this.model.signature | ||
signature: SwaggerUi.partials.signature.getParameterModelSignature(modelType, modelDefinitions), | ||
defaultRendering: this.model.defaultRendering | ||
}; | ||
if (this.model.sampleJSON) { | ||
var signatureView = new SwaggerUi.Views.SignatureView({model: signatureModel, tagName: 'div'}); | ||
if (sampleJSON) { | ||
signatureView = new SwaggerUi.Views.SignatureView({model: signatureModel, tagName: 'div'}); | ||
$('.model-signature', $(this.el)).append(signatureView.render().el); | ||
@@ -62,2 +85,33 @@ } | ||
if( this.options.swaggerOptions.jsonEditor && this.model.isBody && this.model.schema){ | ||
var $self = $(this.el); | ||
this.model.jsonEditor = | ||
/* global JSONEditor */ | ||
new JSONEditor($('.editor_holder', $self)[0], | ||
{schema: this.model.schema, startval : this.model.default, | ||
ajax:true, | ||
disable_properties:true, | ||
disable_edit_json:true, | ||
iconlib: 'swagger' }); | ||
// This is so that the signature can send back the sample to the json editor | ||
// TODO: SignatureView should expose an event "onSampleClicked" instead | ||
signatureModel.jsonEditor = this.model.jsonEditor; | ||
$('.body-textarea', $self).hide(); | ||
$('.editor_holder', $self).show(); | ||
$('.parameter-content-type', $self) | ||
.change(function(e){ | ||
if(e.target.value === 'application/xml'){ | ||
$('.body-textarea', $self).show(); | ||
$('.editor_holder', $self).hide(); | ||
this.model.jsonEditor.disable(); | ||
} | ||
else { | ||
$('.body-textarea', $self).hide(); | ||
$('.editor_holder', $self).show(); | ||
this.model.jsonEditor.enable(); | ||
} | ||
}); | ||
} | ||
if (this.model.isBody) { | ||
@@ -76,2 +130,3 @@ isParam = true; | ||
$('.parameter-content-type', $(this.el)).append(parameterContentTypeView.render().el); | ||
this.toggleParameterSnippet(); | ||
} | ||
@@ -82,2 +137,3 @@ | ||
$('.response-content-type', $(this.el)).append(responseContentTypeView.render().el); | ||
this.toggleResponseSnippet(); | ||
} | ||
@@ -88,2 +144,35 @@ | ||
contains: function (consumes, type) { | ||
return consumes.filter(function (val) { | ||
if (val.indexOf(type) > -1) { | ||
return true; | ||
} | ||
}).length; | ||
}, | ||
toggleParameterSnippet: function () { | ||
var contentType = this.$('[name=parameterContentType]').val(); | ||
this.toggleSnippet(contentType); | ||
}, | ||
toggleResponseSnippet: function () { | ||
var contentEl = this.$('[name=responseContentType]'); | ||
if (!contentEl.length) { return; } | ||
this.toggleSnippet(contentEl.val()); | ||
}, | ||
toggleSnippet: function (type) { | ||
type = type || ''; | ||
if (type.indexOf('xml') > -1) { | ||
this.$('.snippet_xml').show(); | ||
this.$('.snippet_json').hide(); | ||
} else { | ||
this.$('.snippet_json').show(); | ||
this.$('.snippet_xml').hide(); | ||
} | ||
}, | ||
// Return an appropriate template based on if the parameter is a list, readonly, required | ||
@@ -90,0 +179,0 @@ template: function(){ |
@@ -37,2 +37,3 @@ 'use strict'; | ||
operation.parentId = this.model.id; | ||
operation.definitions = this.model.definitions; // make Json Schema available for JSonEditor in this operation | ||
this.addOperation(operation); | ||
@@ -39,0 +40,0 @@ } |
@@ -7,8 +7,6 @@ 'use strict'; | ||
render: function(){ | ||
this.model.responseContentTypeId = 'rct' + Math.random(); | ||
$(this.el).html(Handlebars.templates.response_content_type(this.model)); | ||
$('label[for=responseContentType]', $(this.el)).text('Response Content Type'); | ||
return this; | ||
} | ||
}); |
@@ -7,7 +7,7 @@ 'use strict'; | ||
'click a.snippet-link' : 'switchToSnippet', | ||
'mousedown .snippet' : 'snippetToTextArea' | ||
'mousedown .snippet_json' : 'jsonSnippetMouseDown', | ||
'mousedown .snippet_xml' : 'xmlSnippetMouseDown' | ||
}, | ||
initialize: function () { | ||
}, | ||
@@ -19,8 +19,6 @@ | ||
this.switchToSnippet(); | ||
this.isParam = this.model.isParam; | ||
if (this.isParam) { | ||
$('.notice', $(this.el)).text('Click to set as parameter value'); | ||
if (this.model.defaultRendering === 'model') { | ||
this.switchToDescription(); | ||
} else { | ||
this.switchToSnippet(); | ||
} | ||
@@ -45,4 +43,4 @@ | ||
$('.snippet', $(this.el)).show(); | ||
$('.description', $(this.el)).hide(); | ||
$('.snippet', $(this.el)).show(); | ||
$('.snippet-link', $(this.el)).addClass('selected'); | ||
@@ -53,12 +51,30 @@ $('.description-link', $(this.el)).removeClass('selected'); | ||
// handler for snippet to text area | ||
snippetToTextArea: function(e) { | ||
if (this.isParam) { | ||
if (e) { e.preventDefault(); } | ||
snippetToTextArea: function(val) { | ||
var textArea = $('textarea', $(this.el.parentNode.parentNode.parentNode)); | ||
var textArea = $('textarea', $(this.el.parentNode.parentNode.parentNode)); | ||
if ($.trim(textArea.val()) === '') { | ||
textArea.val(this.model.sampleJSON); | ||
// Fix for bug in IE 10/11 which causes placeholder text to be copied to "value" | ||
if ($.trim(textArea.val()) === '' || textArea.prop('placeholder') === textArea.val()) { | ||
textArea.val(val); | ||
// TODO move this code outside of the view and expose an event instead | ||
if( this.model.jsonEditor && this.model.jsonEditor.isEnabled()){ | ||
this.model.jsonEditor.setValue(JSON.parse(this.model.sampleJSON)); | ||
} | ||
} | ||
}, | ||
jsonSnippetMouseDown: function (e) { | ||
if (this.model.isParam) { | ||
if (e) { e.preventDefault(); } | ||
this.snippetToTextArea(this.model.sampleJSON); | ||
} | ||
}, | ||
xmlSnippetMouseDown: function (e) { | ||
if (this.model.isParam) { | ||
if (e) { e.preventDefault(); } | ||
this.snippetToTextArea(this.model.sampleXML); | ||
} | ||
} | ||
}); |
@@ -10,18 +10,24 @@ 'use strict'; | ||
render: function(){ | ||
var responseModel, responseModelView; | ||
var value = this.router.api.models[this.model.responseModel]; | ||
$(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), | ||
responseModel = { | ||
sampleJSON: JSON.stringify(SwaggerUi.partials.signature.createJSONSample(value), void 0, 2), | ||
sampleXML: this.model.isXML ? SwaggerUi.partials.signature.createXMLSample('', this.model.schema, this.router.api.models) : false, | ||
isParam: false, | ||
signature: this.router.api.models[this.model.responseModel].getMockSignature(), | ||
signature: SwaggerUi.partials.signature.getModelSignature(this.model.responseModel, value, this.router.api.models), | ||
defaultRendering: this.model.defaultRendering | ||
}; | ||
var responseModelView = new SwaggerUi.Views.SignatureView({model: responseModel, tagName: 'div'}); | ||
$('.model-signature', this.$el).append(responseModelView.render().el); | ||
} else { | ||
$('.model-signature', this.$el).html(''); | ||
responseModel = { | ||
signature: SwaggerUi.partials.signature.getPrimitiveSignature(this.model.schema) | ||
}; | ||
} | ||
responseModelView = new SwaggerUi.Views.SignatureView({model: responseModel, tagName: 'div'}); | ||
$('.model-signature', this.$el).append(responseModelView.render().el); | ||
return this; | ||
} | ||
}); |
@@ -31,4 +31,8 @@ /* | ||
driver.get(url); | ||
done(); | ||
}, process.env.TRAVIS ? 20000 : 3000); | ||
setTimeout(function() { | ||
done(); | ||
}, 2000); | ||
console.log('waiting for UI to load'); | ||
}, process.env.TRAVIS ? 20000 : 5000); | ||
console.log('waiting for server to start'); | ||
}; | ||
@@ -35,0 +39,0 @@ |
@@ -7,2 +7,3 @@ 'use strict'; | ||
var webdriver = require('selenium-webdriver'); | ||
var until = webdriver.until; | ||
@@ -43,8 +44,4 @@ var elements = [ | ||
it('should have "Swagger UI" in title', function (done) { | ||
driver.sleep(200); | ||
driver.getTitle().then(function(title) { | ||
expect(title).to.contain('Swagger UI'); | ||
done(); | ||
}); | ||
it('should have "Swagger UI" in title', function () { | ||
return driver.wait(until.titleIs('Swagger UI'), 1000); | ||
}); | ||
@@ -104,5 +101,6 @@ | ||
after(function(){ | ||
after(function(done){ | ||
servers.close(); | ||
done(); | ||
}); | ||
}); | ||
}); |
@@ -55,3 +55,3 @@ { | ||
"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/", | ||
"termsOfServiceUrl": "http://swagger.io/terms/", | ||
"contact": "apiteam@swagger.io", | ||
@@ -58,0 +58,0 @@ "license": "Apache 2.0", |
@@ -7,3 +7,3 @@ { | ||
"title": "Swagger Petstore", | ||
"termsOfService": "http://helloreverb.com/terms/", | ||
"termsOfService": "http://swagger.io/terms/", | ||
"contact": { | ||
@@ -847,3 +847,3 @@ "url": "http://swagger.io", | ||
}, | ||
"$ref": "Category" | ||
"$ref": "#/definitions/Category" | ||
}, | ||
@@ -874,3 +874,3 @@ "name": { | ||
"items": { | ||
"$ref": "Tag" | ||
"$ref": "#/definitions/Tag" | ||
} | ||
@@ -877,0 +877,0 @@ }, |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 4 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 16 instances in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
4060893
190
47744
256
10
34
1
5
7