diff --git a/.gitattributes b/.gitattributes index cbcd3fe9..c4e06cd8 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,6 +1,7 @@ * text eol=lf - +src/**/*.ttf binary dist/**/*.js binary +dist/**/*.ttf binary dist/**/*.map binary dist/**/*.eot binary dist/**/*.svg binary diff --git a/.gitignore b/.gitignore index 0e95196c..28c1c0fd 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,6 @@ swagger-ui.sublime-workspace .idea .project node_modules/* -/nbproject/private/ \ No newline at end of file +/nbproject/private/ +dist/specs/ +test/specs/local/ diff --git a/.travis.yml b/.travis.yml index 37245c73..9d82df84 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,7 @@ sudo: false language: node_js node_js: - - '0.10' - - '0.12' + - '4.2' install: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start diff --git a/README.md b/README.md index 876e5397..f9a30213 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ This will start Swagger UI at `http://localhost:8080`. Once you open the Swagger UI, it will load the [Swagger Petstore](http://petstore.swagger.io/v2/swagger.json) service and show its APIs. You can enter your own server url and click explore to view the API. ### 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: - dist: Contains a distribution which you can deploy on a server or load from your local machine. - dist/lang: The swagger localization @@ -98,6 +98,7 @@ booleanValues | SwaggerUI renders boolean data types as a dropdown. By default i docExpansion | Controls how the API listing is displayed. It can be set to 'none' (default), 'list' (shows operations for each resource), or 'full' (fully expanded: shows operations and their details). apisSorter | Apply a sort to the API/tags list. It can be 'alpha' (sort by name) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. operationsSorter | Apply a sort to the operation list of each API. It can be 'alpha' (sort by paths alphanumerically), 'method' (sort by HTTP method) or a function (see Array.prototype.sort() to know how sort function works). Default is the order returned by the server unchanged. +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. diff --git a/dist/css/print.css b/dist/css/print.css index 7935b285..8329a2cc 100644 --- a/dist/css/print.css +++ b/dist/css/print.css @@ -1136,14 +1136,14 @@ font-size: 24px; padding: 10px 0; } -.swagger-section .api-popup-dialog p.error-msg { +.swagger-section .api-popup-dialog .error-msg { padding-left: 5px; padding-bottom: 5px; } -.swagger-section .api-popup-dialog button.api-popup-authbtn { +.swagger-section .api-popup-dialog .api-popup-authbtn { height: 30px; } -.swagger-section .api-popup-dialog button.api-popup-cancel { +.swagger-section .api-popup-dialog .api-popup-cancel { height: 30px; } .swagger-section .api-popup-scopes { @@ -1153,14 +1153,14 @@ padding: 5px 0; line-height: 20px; } -.swagger-section .api-popup-scopes .api-scope-desc { - padding-left: 20px; - font-style: italic; -} .swagger-section .api-popup-scopes li input { position: relative; top: 2px; } +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} .swagger-section .api-popup-actions { padding-top: 10px; } diff --git a/dist/css/screen.css b/dist/css/screen.css index 905f69be..49b8934e 100644 --- a/dist/css/screen.css +++ b/dist/css/screen.css @@ -1136,14 +1136,14 @@ font-size: 24px; padding: 10px 0; } -.swagger-section .api-popup-dialog p.error-msg { +.swagger-section .api-popup-dialog .error-msg { padding-left: 5px; padding-bottom: 5px; } -.swagger-section .api-popup-dialog button.api-popup-authbtn { +.swagger-section .api-popup-dialog .api-popup-authbtn { height: 30px; } -.swagger-section .api-popup-dialog button.api-popup-cancel { +.swagger-section .api-popup-dialog .api-popup-cancel { height: 30px; } .swagger-section .api-popup-scopes { @@ -1153,14 +1153,14 @@ padding: 5px 0; line-height: 20px; } -.swagger-section .api-popup-scopes .api-scope-desc { - padding-left: 20px; - font-style: italic; -} .swagger-section .api-popup-scopes li input { position: relative; top: 2px; } +.swagger-section .api-popup-scopes .api-scope-desc { + padding-left: 20px; + font-style: italic; +} .swagger-section .api-popup-actions { padding-top: 10px; } @@ -1234,32 +1234,29 @@ background-color: #89bf04; padding: 14px; } -.swagger-section #header a#logo { - font-size: 1.5em; - font-weight: bold; - text-decoration: none; - background: transparent url(../images/logo_small.png) no-repeat left center; - padding: 20px 0 20px 40px; - color: white; +.swagger-section #input_baseUrl { + width: 400px; } -.swagger-section #header form#api_selector { +.swagger-section #api_selector { display: block; clear: none; float: right; } -.swagger-section #header form#api_selector .input { +.swagger-section #api_selector .input { display: block; clear: none; float: left; margin: 0 10px 0 0; } -.swagger-section #header form#api_selector .input input#input_apiKey { +.swagger-section #api_selector input { + font-size: 0.9em; + padding: 3px; + margin: 0; +} +.swagger-section #input_apiKey { width: 200px; } -.swagger-section #header form#api_selector .input input#input_baseUrl { - width: 400px; -} -.swagger-section #header form#api_selector .input a#explore { +.swagger-section #explore { display: block; text-decoration: none; font-weight: bold; @@ -1274,13 +1271,16 @@ -khtml-border-radius: 4px; border-radius: 4px; } -.swagger-section #header form#api_selector .input a#explore:hover { +.swagger-section #explore:hover { background-color: #547f00; } -.swagger-section #header form#api_selector .input input { - font-size: 0.9em; - padding: 3px; - margin: 0; +.swagger-section #header #logo { + font-size: 1.5em; + font-weight: bold; + text-decoration: none; + background: transparent url(../images/logo_small.png) no-repeat left center; + padding: 20px 0 20px 40px; + color: white; } .swagger-section #content_message { margin: 10px 15px; diff --git a/dist/index.html b/dist/index.html index a979eb46..6299f31b 100644 --- a/dist/index.html +++ b/dist/index.html @@ -53,7 +53,8 @@ clientSecret: "your-client-secret-if-required", realm: "your-realms", appName: "your-app-name", - scopeSeparator: "," + scopeSeparator: ",", + additionalQueryStringParams: {} }); } @@ -73,6 +74,7 @@ docExpansion: "none", jsonEditor:true, apisSorter: "alpha", + defaultModelRendering: 'schema', showRequestHeaders: false }); diff --git a/dist/lib/swagger-oauth.js b/dist/lib/swagger-oauth.js index b04a45cb..9ce42427 100644 --- a/dist/lib/swagger-oauth.js +++ b/dist/lib/swagger-oauth.js @@ -7,6 +7,7 @@ var oauth2KeyName; var redirect_uri; var clientSecret; var scopeSeparator; +var additionalQueryStringParams; function handleLogin() { var scopes = []; @@ -156,6 +157,9 @@ function handleLogin() { url += '&client_id=' + encodeURIComponent(clientId); url += '&scope=' + encodeURIComponent(scopes.join(scopeSeparator)); url += '&state=' + encodeURIComponent(state); + for (var key in additionalQueryStringParams) { + url += '&' + key + '=' + encodeURIComponent(additionalQueryStringParams[key]); + } window.open(url); }); @@ -190,6 +194,7 @@ function initOAuth(opts) { clientSecret = (o.clientSecret||null); realm = (o.realm||errors.push('missing realm')); scopeSeparator = (o.scopeSeparator||' '); + additionalQueryStringParams = (o.additionalQueryStringParams||{}); if(errors.length > 0){ log('auth unable initialize oauth: ' + errors); diff --git a/dist/swagger-ui.js b/dist/swagger-ui.js index 75cacd82..0f3b3c77 100644 --- a/dist/swagger-ui.js +++ b/dist/swagger-ui.js @@ -21,10 +21,9 @@ this["Handlebars"]["templates"]["content_type"] = Handlebars.template({"1":funct if (stack1 != null) { buffer += stack1; } return buffer; },"2":function(depth0,helpers,partials,data) { - var stack1, lambda=this.lambda, buffer = " \n"; @@ -150,23 +149,24 @@ window.Docs = { Docs.expandEndpointListForResource(fragments[0]); $("#"+dom_id).slideto({highlight: false}); - // Expand operation - var li_dom_id = fragments.join('_'); - var li_content_dom_id = li_dom_id + "_content"; + // 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; } - }, toggleEndpointListForResource: function(resource) { var elem = $('li#resource_' + Docs.escapeResourceName(resource) + ' ul.endpoints'); if (elem.is(':visible')) { + $.bbq.pushState('#/', 2); Docs.collapseEndpointListForResource(resource); } else { + $.bbq.pushState('#/' + resource, 2); Docs.expandEndpointListForResource(resource); } }, @@ -250,7 +250,8 @@ Handlebars.registerHelper('sanitize', function(html) { Handlebars.registerHelper('renderTextParam', function(param) { var result, type = 'text', idAtt = ''; - var isArray = param.type.toLowerCase() === 'array' || param.allowMultiple; + 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) { @@ -273,6 +274,8 @@ Handlebars.registerHelper('renderTextParam', function(param) { idAtt = ' id=\'' + param.valueId + '\''; } + defaultValue = defaultValue.replace(/'/g,'''); + if(isArray) { result = '\n"; + + "\n
\n"; },"3":function(depth0,helpers,partials,data) { var stack1, buffer = ""; stack1 = helpers['if'].call(depth0, (depth0 != null ? depth0['default'] : depth0), {"name":"if","hash":{},"fn":this.program(4, data),"inverse":this.program(6, data),"data":data}); @@ -770,10 +780,9 @@ this["Handlebars"]["templates"]["parameter_content_type"] = Handlebars.template( if (stack1 != null) { buffer += stack1; } return buffer; },"2":function(depth0,helpers,partials,data) { - var stack1, lambda=this.lambda, buffer = " \n"; @@ -832,10 +841,9 @@ this["Handlebars"]["templates"]["response_content_type"] = Handlebars.template({ if (stack1 != null) { buffer += stack1; } return buffer; },"2":function(depth0,helpers,partials,data) { - var stack1, lambda=this.lambda, buffer = " \n"; @@ -30726,7 +30734,12 @@ window.SwaggerUi = Backbone.Router.extend({ // SwaggerUi accepts all the same options as SwaggerApi initialize: function(options) { options = options || {}; - if(!options.highlightSizeThreshold) { + + if (options.defaultModelRendering !== 'model') { + options.defaultModelRendering = 'schema'; + } + + if (!options.highlightSizeThreshold) { options.highlightSizeThreshold = 100000; } @@ -30899,7 +30912,7 @@ window.SwaggerUi = Backbone.Router.extend({ var $msgbar = $('#message-bar'); $msgbar.removeClass('message-fail'); $msgbar.addClass('message-success'); - $msgbar.html(data); + $msgbar.text(data); if(window.SwaggerTranslator) { window.SwaggerTranslator.translate($msgbar); } @@ -31067,9 +31080,10 @@ SwaggerUi.Views.BasicAuthButton = Backbone.View.extend({ 'click #apply_basic_auth' : 'applyPassword' }, - applyPassword: function(){ - var username = $('.input_username').val(); - var password = $('.input_password').val(); + applyPassword: function(event){ + event.preventDefault(); + var username = $('#input_username').val(); + var password = $('#input_password').val(); var basicAuth = new SwaggerClient.PasswordAuthorization('basic', username, password); this.router.api.clientAuthorizations.add(this.model.type, basicAuth); this.router.load(); @@ -31328,6 +31342,14 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ this.parentId = this.model.parentId; this.nickname = this.model.nickname; 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; }, @@ -31469,6 +31491,7 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ value = successResponse[key]; this.model.successCode = key; if (typeof value === 'object' && typeof value.createJSONSample === 'function') { + this.model.successDescription = value.description; signatureModel = { sampleJSON: JSON.stringify(value.createJSONSample(), void 0, 2), isParam: false, @@ -31483,12 +31506,9 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ signature: this.model.responseClassSignature }; } - var opts = this.options.swaggerOptions; - if (opts.showRequestHeaders) { - this.model.showRequestHeaders = true; - } $(this.el).html(Handlebars.templates.operation(this.model)); if (signatureModel) { + signatureModel.defaultRendering = this.model.defaultRendering; responseSignatureView = new SwaggerUi.Views.SignatureView({ model: signatureModel, router: this.router, @@ -31547,7 +31567,7 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ 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){ @@ -31565,7 +31585,6 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ param.schema.title = ' '; } } - var paramView = new SwaggerUi.Views.ParameterView({ model: param, @@ -31578,6 +31597,7 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ addStatusCode: function(statusCode) { // Render status codes + statusCode.defaultRendering = this.model.defaultRendering; var statusCodeView = new SwaggerUi.Views.StatusCodeView({ model: statusCode, tagName: 'tr', @@ -31982,8 +32002,8 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ $('.response_throbber', $(this.el)).hide(); - //adds curl output - var curlCommand = this.model.asCurl(this.map); + // adds curl output + var curlCommand = this.model.asCurl(this.map, {responseContentType: contentType}); curlCommand = curlCommand.replace('!', '!'); $( 'div.curl', $(this.el)).html('' + curlCommand + ''); @@ -32010,11 +32030,10 @@ SwaggerUi.Views.OperationView = Backbone.View.extend({ toggleOperationContent: function (event) { var elem = $('#' + Docs.escapeResourceName(this.parentId + '_' + this.nickname + '_content')); if (elem.is(':visible')){ - event.preventDefault(); $.bbq.pushState('#/', 2); + event.preventDefault(); Docs.collapseOperation(elem); } else { - event.preventDefault(); Docs.expandOperation(elem); } }, @@ -32116,7 +32135,8 @@ SwaggerUi.Views.ParameterView = Backbone.View.extend({ var signatureModel = { sampleJSON: this.model.sampleJSON, isParam: true, - signature: this.model.signature + signature: this.model.signature, + defaultRendering: this.model.defaultRendering }; if (this.model.sampleJSON) { @@ -32307,8 +32327,12 @@ SwaggerUi.Views.SignatureView = Backbone.View.extend({ $(this.el).html(Handlebars.templates.signature(this.model)); - this.switchToSnippet(); - + if (this.model.defaultRendering === 'model') { + this.switchToDescription(); + } else { + this.switchToSnippet(); + } + this.isParam = this.model.isParam; if (this.isParam) { @@ -32372,6 +32396,7 @@ SwaggerUi.Views.StatusCodeView = Backbone.View.extend({ sampleJSON: JSON.stringify(this.router.api.models[this.model.responseModel].createJSONSample(), null, 2), isParam: false, signature: this.router.api.models[this.model.responseModel].getMockSignature(), + defaultRendering: this.model.defaultRendering }; var responseModelView = new SwaggerUi.Views.SignatureView({model: responseModel, tagName: 'div'}); diff --git a/dist/swagger-ui.min.js b/dist/swagger-ui.min.js index 8f64dadb..77fcd457 100644 --- a/dist/swagger-ui.min.js +++ b/dist/swagger-ui.min.js @@ -1,12 +1,12 @@ -(function(){function e(){e.history=e.history||[],e.history.push(arguments),this.console&&console.log(Array.prototype.slice.call(arguments)[0])}this.Handlebars=this.Handlebars||{},this.Handlebars.templates=this.Handlebars.templates||{},this.Handlebars.templates.apikey_button_view=Handlebars.template({compiler:[6,">= 2.0.0-beta.1"],main:function(e,t,n,r){var i,a="function",o=t.helperMissing,s=this.escapeExpression;return"\n