Merge pull request #1254 from swagger-api/develop_2.0

Merged from develop_2.0
This commit is contained in:
Tony Tam
2015-05-08 15:42:49 -07:00
29 changed files with 746 additions and 262 deletions

View File

@@ -131,7 +131,7 @@ swaggerUi.api.clientAuthorizations.add("key", new SwaggerClient.ApiKeyAuthorizat
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.
The localization files are in the [lang](/lang) directory. Note that language files and translator is not included in SwaggerUI by default. You need to add them manually.
To enable translation you should append next two lines in your Swagger's index.html (or another entry point you use)
```html

3
dist/css/print.css vendored
View File

@@ -274,6 +274,9 @@
font-weight: bold;
font-size: 25px;
}
.swagger-section .swagger-ui-wrap .footer {
margin-top: 20px;
}
.swagger-section .swagger-ui-wrap p.big,
.swagger-section .swagger-ui-wrap div.big p {
font-size: 1em;

3
dist/css/screen.css vendored
View File

@@ -274,6 +274,9 @@
font-weight: bold;
font-size: 25px;
}
.swagger-section .swagger-ui-wrap .footer {
margin-top: 20px;
}
.swagger-section .swagger-ui-wrap p.big,
.swagger-section .swagger-ui-wrap div.big p {
font-size: 1em;

4
dist/index.html vendored
View File

@@ -19,6 +19,7 @@
<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 src='lib/swagger-oauth.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
@@ -34,13 +35,11 @@
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) {
@@ -71,7 +70,6 @@
/*
var apiKey = "myApiKeyXXXX123456789";
$('#input_apiKey').val(apiKey);
addApiKeyAuthorization();
*/
window.swaggerUi.load();

634
dist/swagger-ui.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -15,6 +15,7 @@ var connect = require('gulp-connect');
var header = require('gulp-header');
var pkg = require('./package.json');
var order = require('gulp-order');
var jshint = require('gulp-jshint');
var banner = ['/**',
' * <%= pkg.name %> - <%= pkg.description %>',
' * @version v<%= pkg.version %>',
@@ -48,10 +49,19 @@ function templates() {
.on('error', log);
}
/**
* JShint all *.js files
*/
gulp.task('lint', function () {
return gulp.src('./src/main/javascript/**/*.js')
.pipe(jshint())
.pipe(jshint.reporter('jshint-stylish'));
});
/**
* Build a distribution
*/
gulp.task('dist', ['clean'], function() {
gulp.task('dist', ['clean','lint'], function() {
return es.merge(
gulp.src([

53
lang/en.js Normal file
View File

@@ -0,0 +1,53 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Warning: Deprecated",
"Implementation Notes":"Implementation Notes",
"Response Class":"Response Class",
"Status":"Status",
"Parameters":"Parameters",
"Parameter":"Parameter",
"Value":"Value",
"Description":"Description",
"Parameter Type":"Parameter Type",
"Data Type":"Data Type",
"Response Messages":"Response Messages",
"HTTP Status Code":"HTTP Status Code",
"Reason":"Reason",
"Response Model":"Response Model",
"Request URL":"Request URL",
"Response Body":"Response Body",
"Response Code":"Response Code",
"Response Headers":"Response Headers",
"Hide Response":"Hide Response",
"Try it out!":"Try it out!",
"Show/Hide":"Show/Hide",
"List Operations":"List Operations",
"Expand Operations":"Expand Operations",
"Raw":"Raw",
"can't parse JSON. Raw result":"can't parse JSON. Raw result",
"Model Schema":"Model Schema",
"Model":"Model",
"apply":"apply",
"Username":"Username",
"Password":"Password",
"Terms of service":"Terms of service",
"Created by":"Created by",
"See more at":"See more at",
"Contact the developer":"Contact the developer",
"api version":"api version",
"Response Content Type":"Response Content Type",
"fetching resource":"fetching resource",
"fetching resource list":"fetching resource list",
"Explore":"Explore",
"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.",
"Please specify the protocol for":"Please specify the protocol for",
"Can't read swagger JSON from":"Can't read swagger JSON from",
"Finished Loading Resource Information. Rendering Swagger UI":"Finished Loading Resource Information. Rendering Swagger UI",
"Unable to read api":"Unable to read api",
"from path":"from path",
"server returned":"server returned"
});

53
lang/ru.js Normal file
View File

@@ -0,0 +1,53 @@
'use strict';
/* jshint quotmark: double */
window.SwaggerTranslator.learn({
"Warning: Deprecated":"Ворнинг: Депрекейтед",
"Implementation Notes":"Заметки",
"Response Class":"Пример ответа",
"Status":"Статус",
"Parameters":"Параметры",
"Parameter":"Параметр",
"Value":"Значение",
"Description":"Описание",
"Parameter Type":"Тип параметра",
"Data Type":"Тип данных",
"HTTP Status Code":"HTTP код",
"Reason":"Причина",
"Response Model":"Структура ответа",
"Request URL":"URL запроса",
"Response Body":"Тело ответа",
"Response Code":"HTTP код ответа",
"Response Headers":"Заголовки ответа",
"Hide Response":"Спрятать ответ",
"Response Messages":"Что может прийти в ответ",
"Try it out!":"Попробовать!",
"Show/Hide":"Показать/Скрыть",
"List Operations":"Операции кратко",
"Expand Operations":"Операции подробно",
"Raw":"В сыром виде",
"can't parse JSON. Raw result":"Не удается распарсить ответ:",
"Model Schema":"Структура",
"Model":"Описание",
"apply":"применить",
"Username":"Имя пользователя",
"Password":"Пароль",
"Terms of service":"Условия использования",
"Created by":"Разработано",
"See more at":"Еще тут",
"Contact the developer":"Связаться с разработчиком",
"api version":"Версия API",
"Response Content Type":"Content Type ответа",
"fetching resource":"Получение ресурса",
"fetching resource list":"Получение ресурсов",
"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 swagger JSON from":"Не получается прочитать swagger json из",
"Finished Loading Resource Information. Rendering Swagger UI":"Загрузка информации о ресурсах завершена. Рендерим",
"Unable to read api":"Не удалось прочитать api",
"from path":"по адресу",
"server returned":"сервер сказал"
});

38
lang/translator.js Normal file
View File

@@ -0,0 +1,38 @@
'use strict';
/**
* Translator for documentation pages.
*
* To enable translation you should include one of language-files in your index.html
* after <script src='lang/translator.js' type='text/javascript'></script>.
* For example - <script src='lang/ru.js' type='text/javascript'></script>
*
* If you wish to translate some new texsts 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.
* 2. Mark that text it templates this way <anyHtmlTag data-sw-translate>New Phrase</anyHtmlTag> or <anyHtmlTag data-sw-translate value='New Phrase'/>.
* The main thing here is attribute data-sw-translate. Only inner html, title-attribute and value-attribute are going to translate.
*
*/
window.SwaggerTranslator = {
_words:[],
translate: function() {
var $this = this;
$('[data-sw-translate]').each(function() {
$(this).html($this._tryTranslate($(this).html()));
$(this).val($this._tryTranslate($(this).val()));
$(this).attr('title', $this._tryTranslate($(this).attr('title')));
});
},
_tryTranslate: function(word) {
return this._words[word] !== undefined ? this._words[word] : word;
},
learn: function(wordsMap) {
this._words = wordsMap;
}
};

View File

@@ -1,14 +1,17 @@
{
"name": "swagger-ui",
"author": "Tony Tam <fehguy@gmail.com>",
"contributors": [{
"name": "Mohsen Azimi",
"email": "me@azimi.me"
}],
"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.1-M2",
"version": "2.1.2-M2",
"homepage": "http://swagger.io",
"license": "Apache 2.0",
"main": "dist/swagger-ui.js",
"scripts": {
"build": "gulp",
"serve": "gulp serve",
@@ -35,6 +38,7 @@
"gulp-declare": "^0.3.0",
"gulp-handlebars": "^3.0.1",
"gulp-header": "^1.2.2",
"gulp-jshint": "^1.10.0",
"gulp-less": "^3.0.1",
"gulp-order": "^1.1.1",
"gulp-rename": "^1.2.0",
@@ -42,9 +46,10 @@
"gulp-watch": "^4.1.1",
"gulp-wrap": "^0.11.0",
"http-server": "git+https://github.com/nodeapps/http-server.git",
"jshint-stylish": "^1.0.1",
"less": "^2.4.0",
"mocha": "^2.1.0",
"selenium-webdriver": "^2.45.0",
"swagger-client": "2.1.2-M2"
"swagger-client": "2.1.4-M2"
}
}

View File

@@ -274,6 +274,9 @@
font-weight: bold;
font-size: 25px;
}
.swagger-section .swagger-ui-wrap .footer {
margin-top: 20px;
}
.swagger-section .swagger-ui-wrap p.big,
.swagger-section .swagger-ui-wrap div.big p {
font-size: 1em;

View File

@@ -274,6 +274,9 @@
font-weight: bold;
font-size: 25px;
}
.swagger-section .swagger-ui-wrap .footer {
margin-top: 20px;
}
.swagger-section .swagger-ui-wrap p.big,
.swagger-section .swagger-ui-wrap div.big p {
font-size: 1em;

View File

@@ -19,6 +19,7 @@
<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 src='lib/swagger-oauth.js' type='text/javascript'></script>
<script type="text/javascript">
$(function () {
@@ -34,13 +35,11 @@
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) {
@@ -71,7 +70,6 @@
/*
var apiKey = "myApiKeyXXXX123456789";
$('#input_apiKey').val(apiKey);
addApiKeyAuthorization();
*/
window.swaggerUi.load();

View File

@@ -13,6 +13,9 @@ window.SwaggerUi = Backbone.Router.extend({
// SwaggerUi accepts all the same options as SwaggerApi
initialize: function(options) {
options = options || {};
if(!options.highlightSizeThreshold) {
options.highlightSizeThreshold = 100000;
}
// Allow dom_id to be overridden
if (options.dom_id) {

View File

@@ -5,3 +5,28 @@ Handlebars.registerHelper('sanitize', function(html) {
html = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
return new Handlebars.SafeString(html);
});
Handlebars.registerHelper('renderTextParam', function(param) {
var result, type = 'text';
var isArray = param.type.toLowerCase() === 'array' || param.allowMultiple;
var defaultValue = isArray && Array.isArray(param.default) ? param.default.join('\n') : param.default;
if (typeof defaultValue === 'undefined') {
defaultValue = '';
}
if(param.format && param.format === 'password') {
type = 'password';
}
if(isArray) {
result = '<textarea class=\'body-textarea' + (param.required ? ' required' : '') + '\' name=\'' + param.name + '\'';
result += ' placeholder=\'Provide multiple values in new lines' + (param.required ? ' (at least one required).' : '.') + '\'>';
result += defaultValue + '</textarea>';
} else {
result = '<input class=\'parameter\'' + (param.required ? ' class=\'required\'' : '') + ' minlength=\'' + (param.required ? 1 : 0) + '\'';
result += ' name=\'' + param.name +'\' placeholder=\'' + (param.required ? '(required)' : '') + '\'';
result += ' type=\'' + type + '\' value=\'' + defaultValue + '\'/>';
}
return new Handlebars.SafeString(result);
});

View File

@@ -68,7 +68,9 @@ SwaggerUi.Views.MainView = Backbone.View.extend({
} else {
// Default validator
this.model.validatorUrl = window.location.protocol + '//online.swagger.io/validator';
if(window.location.protocol.startsWith('http')) {
this.model.validatorUrl = window.location.protocol + '//online.swagger.io/validator';
}
}
}
},
@@ -130,7 +132,7 @@ SwaggerUi.Views.MainView = Backbone.View.extend({
auths: auths,
swaggerOptions: this.options.swaggerOptions
});
$('#resources').append(resourceView.render().el);
$('#resources', this.el).append(resourceView.render().el);
},
clear: function(){

View File

@@ -275,11 +275,30 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
error_free = false;
}
});
form.find('select.required').each(function() {
$(this).removeClass('error');
if (this.selectedIndex === -1) {
$(this).addClass('error');
$(this).wiggle({
callback: (function(_this) {
return function() {
$(_this).focus();
};
})(this)
});
error_free = false;
}
});
if (error_free) {
map = {};
opts = {
parent: this
};
if(this.options.swaggerOptions) {
for(var key in this.options.swaggerOptions) {
opts[key] = this.options.swaggerOptions[key];
}
}
isFileUpload = false;
ref1 = form.find('input');
for (l = 0, len = ref1.length; l < len; l++) {
@@ -295,8 +314,9 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
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;
val = this.getTextAreaValue(o);
if ((val !== null) && jQuery.trim(val).length > 0) {
map[o.name] = val;
}
}
ref3 = form.find('select');
@@ -313,7 +333,7 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
if (isFileUpload) {
return this.handleFileUpload(map, form);
} else {
return this.model['do'](map, opts, this.showCompleteStatus, this.showErrorStatus, this);
return this.model.execute(map, opts, this.showCompleteStatus, this.showErrorStatus, this);
}
}
},
@@ -549,6 +569,7 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
url = response.request.url;
}
var headers = response.headers;
content = jQuery.trim(content);
// if server is nice, and sends content-type back, we can use it
var contentType = null;
@@ -608,10 +629,10 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
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/)) {
} 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'])) {
if ('Blob' in window) {
var type = contentType || 'text/html';
@@ -666,5 +687,38 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({
} else {
Docs.expandOperation(elem);
}
},
getTextAreaValue: function(textArea) {
var param, parsed, result, i;
if (textArea.value === null || jQuery.trim(textArea.value).length === 0) {
return null;
}
param = this.getParamByName(textArea.name);
if (param && param.type && param.type.toLowerCase() === 'array') {
parsed = textArea.value.split('\n');
result = [];
for (i = 0; i < parsed.length; i++) {
if (parsed[i] !== null && jQuery.trim(parsed[i]).length > 0) {
result.push(parsed[i]);
}
}
return result.length > 0 ? result : null;
} else {
return textArea.value;
}
},
getParamByName: function(name) {
var i;
if (this.model.parameters) {
for(i = 0; i < this.model.parameters.length; i++) {
if (this.model.parameters[i].name === name) {
return this.model.parameters[i];
}
}
}
return null;
}
});

View File

@@ -4,9 +4,9 @@ SwaggerUi.Views.ParameterView = Backbone.View.extend({
initialize: function(){
Handlebars.registerHelper('isArray', function(param, opts) {
if (param.type.toLowerCase() === 'array' || param.allowMultiple) {
opts.fn(this);
return opts.fn(this);
} else {
opts.inverse(this);
return opts.inverse(this);
}
});
},

View File

@@ -153,6 +153,10 @@
font-size: 25px;
}
.footer {
margin-top: 20px;
}
p.big, div.big p {
font-size: 1em;
margin-bottom: 10px;

View File

@@ -18,8 +18,6 @@
<ul id='resources'></ul>
<div class="footer">
<br>
<br>
<h4 style="color: #999">[ <span style="font-variant: small-caps">base url</span>: {{basePath}}
{{#if info.version}}
, <span style="font-variant: small-caps">api version</span>: {{info.version}}

View File

@@ -85,7 +85,7 @@
{{#if isReadOnly}}
{{else}}
<div class='sandbox_header'>
<input class='submit' name='commit' type='button' value='Try it out!' />
<input class='submit' type='button' value='Try it out!' />
<a href='#' class='response_hider' style='display:none'>Hide Response</a>
<span class='response_throbber' style='display:none'></span>
</div>

View File

@@ -21,11 +21,8 @@
<input type="file" name='{{name}}'/>
<div class="parameter-content-type" />
{{else}}
{{#if default}}
<input class='parameter' minlength='0' name='{{name}}' placeholder='' type='text' value='{{default}}'/>
{{else}}
<input class='parameter' minlength='0' name='{{name}}' placeholder='' type='text' value=''/>
{{/if}}
{{#renderTextParam this}}
{{/renderTextParam}}
{{/if}}
{{/if}}

View File

@@ -1,9 +1,10 @@
{{#if required}}
<td class='code required'>{{name}}</td>
{{/if}}
{{else}}
<td class='code'>{{name}}</td>
{{/if}}
<td>
<select {{#isArray this}} multiple='multiple'{{/isArray}} class='parameter' name='{{name}}'>
<select {{#isArray this}} multiple='multiple'{{/isArray}} class={{#if required}}'parameter required'{{else}}'parameter'{{/if}} name='{{name}}'>
{{#if required}}
{{else}}
{{#if default}}

View File

@@ -1,7 +1,7 @@
<td class='code required'>{{name}}</td>
<td>
{{#if isBody}}
<textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='{{name}}'>{{default}}</textarea>
<textarea class='body-textarea' readonly='readonly' placeholder='(required)' name='{{name}}'>{{default}}</textarea>
{{else}}
{{#if default}}
{{default}}

View File

@@ -18,11 +18,8 @@
{{#if isFile}}
<input class='parameter' class='required' type='file' name='{{name}}'/>
{{else}}
{{#if default}}
<input class='parameter required' minlength='1' name='{{name}}' placeholder='(required)' type='text' value='{{default}}'/>
{{else}}
<input class='parameter required' minlength='1' name='{{name}}' placeholder='(required)' type='text' value=''/>
{{/if}}
{{#renderTextParam this}}
{{/renderTextParam}}
{{/if}}
{{/if}}
</td>

View File

@@ -594,7 +594,8 @@
"name": "password",
"description": "The password for login in clear text",
"required": false,
"type": "string"
"type": "string",
"format": "password"
}
],
"responses": {