diff --git a/.jshintignore b/.jshintignore new file mode 100644 index 00000000..93e99231 --- /dev/null +++ b/.jshintignore @@ -0,0 +1,4 @@ +node_modules +src/main/javascript/doc.js +dist +lib \ No newline at end of file diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 00000000..e5afedf9 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,35 @@ +{ + "node": true, + "browser": true, + "esnext": true, + "bitwise": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": false, + "newcap": true, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": true, + "trailing": true, + "smarttabs": true, + "globals": { + "Backbone": false, + "_": false, + "$": false, + "jQuery": false, + "marked": false, + "Docs": false, + "SwaggerClient": false, + "Handlebars": false, + "ApiKeyAuthorization": false, + "PasswordAuthorization": false, + "hljs": false, + "SwaggerUi": false, + "swaggerUi": false // TODO: remove me + } +} \ No newline at end of file diff --git a/.travis.yml b/.travis.yml index 854331e8..d2d38fd1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,4 +5,9 @@ node_js: install: - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - - npm install \ No newline at end of file + - npm i -g jshint + - npm install + +script: + - jshint . + - npm test \ No newline at end of file diff --git a/dist/swagger-ui.js b/dist/swagger-ui.js index 9e510605..e8002ac9 100644 --- a/dist/swagger-ui.js +++ b/dist/swagger-ui.js @@ -4,6 +4,203 @@ * @link http://swagger.io * @license Apache 2.0 */ +'use strict'; + +window.SwaggerUi = Backbone.Router.extend({ + + dom_id: 'swagger_ui', + + // Attributes + options: null, + api: null, + headerView: null, + mainView: null, + + // SwaggerUi accepts all the same options as SwaggerApi + initialize: function(options) { + options = options || {}; + + // Allow dom_id to be overridden + if (options.dom_id) { + this.dom_id = options.dom_id; + delete options.dom_id; + } + + if (!options.supportedSubmitMethods){ + options.supportedSubmitMethods = [ + 'get', + 'put', + 'post', + 'delete', + 'head', + 'options', + 'patch' + ]; + } + + // Create an empty div which contains the dom_id + if (! $('#' + this.dom_id)){ + $('body').append('
') ; + } + + this.options = options; + + // set marked options + marked.setOptions({gfm: true}); + + // Set the callbacks + var that = this; + this.options.success = function() { return that.render(); }; + this.options.progress = function(d) { return that.showMessage(d); }; + this.options.failure = function(d) { return that.onLoadFailure(d); }; + + // Create view to handle the header inputs + this.headerView = new SwaggerUi.Views.HeaderView({el: $('#header')}); + + // Event handler for when the baseUrl/apiKey is entered by user + this.headerView.on('update-swagger-ui', function(data) { + return this.updateSwaggerUi(data); + }); + }, + + // Set an option after initializing + setOption: function(option, value) { + this.options[option] = value; + }, + + // Get the value of a previously set option + getOption: function(option) { + return this.options[option]; + }, + + // Event handler for when url/key is received from user + updateSwaggerUi: function(data){ + this.options.url = data.url; + this.load(); + }, + + // Create an api and render + load: function(){ + // Initialize the API object + if (this.mainView) { + this.mainView.clear(); + } + var url = this.options.url; + if (url && url.indexOf('http') !== 0) { + url = this.buildUrl(window.location.href.toString(), url); + } + + this.options.url = url; + this.headerView.update(url); + + this.api = new SwaggerClient(this.options); + }, + + // collapse all sections + collapseAll: function(){ + Docs.collapseEndpointListForResource(''); + }, + + // list operations for all sections + listAll: function(){ + Docs.collapseOperationsForResource(''); + }, + + // expand operations for all sections + expandAll: function(){ + Docs.expandOperationsForResource(''); + }, + + // This is bound to success handler for SwaggerApi + // so it gets called when SwaggerApi completes loading + render: function(){ + this.showMessage('Finished Loading Resource Information. Rendering Swagger UI...'); + this.mainView = new SwaggerUi.Views.MainView({ + model: this.api, + el: $('#' + this.dom_id), + swaggerOptions: this.options + }).render(); + this.showMessage(); + switch (this.options.docExpansion) { + case 'full': + this.expandAll(); break; + case 'list': + this.listAll(); break; + default: + break; + } + this.renderGFM(); + + if (this.options.onComplete){ + this.options.onComplete(this.api, this); + } + + setTimeout(Docs.shebang.bind(this), 100); + }, + + buildUrl: function(base, url){ + if (url.indexOf('/') === 0) { + var parts = base.split('/'); + base = parts[0] + '//' + parts[2]; + return base + url; + } else { + var endOfPath = base.length; + + if (base.indexOf('?') > -1){ + endOfPath = Math.min(endOfPath, base.indexOf('?')); + } + + if (base.indexOf('#') > -1){ + endOfPath = Math.min(endOfPath, base.indexOf('#')); + } + + base = base.substring(0, endOfPath); + + if (base.indexOf('/', base.length - 1 ) !== -1){ + return base + url; + } + + return base + '/' + url; + } + }, + + // Shows message on topbar of the ui + showMessage: function(data){ + if (data === undefined) { + data = ''; + } + $('#message-bar').removeClass('message-fail'); + $('#message-bar').addClass('message-success'); + $('#message-bar').html(data); + }, + + // shows message in red + onLoadFailure: function(data){ + if (data === undefined) { + data = ''; + } + $('#message-bar').removeClass('message-success'); + $('#message-bar').addClass('message-fail'); + + var val = $('#message-bar').html(data); + + if (this.options.onFailure) { + this.options.onFailure(data); + } + + return val; + }, + + // Renders GFM for elements with 'markdown' class + renderGFM: function(){ + $('.markdown').each(function(){ + $(this).html(marked($(this).html())); + }); + } + +}); + +window.SwaggerUi.Views = {}; 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(depth0,helpers,partials,data) { @@ -36,25 +233,28 @@ this["Handlebars"]["templates"]["content_type"] = Handlebars.template({"1":funct if (stack1 != null) { buffer += stack1; } return buffer + "\n"; },"useData":true}); +'use strict'; + + $(function() { // Helper function for vertically aligning DOM elements // http://www.seodenver.com/simple-vertical-align-plugin-for-jquery/ $.fn.vAlign = function() { - return this.each(function(i){ - var ah = $(this).height(); - var ph = $(this).parent().height(); - var mh = (ph - ah) / 2; - $(this).css('margin-top', mh); + return this.each(function(){ + var ah = $(this).height(); + var ph = $(this).parent().height(); + var mh = (ph - ah) / 2; + $(this).css('margin-top', mh); }); }; $.fn.stretchFormtasticInputWidthToParent = function() { - return this.each(function(i){ - var p_width = $(this).closest("form").innerWidth(); - var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest("form").css('padding-right'), 10); - var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10); - $(this).css('width', p_width - p_padding - this_padding); + return this.each(function(){ + var p_width = $(this).closest("form").innerWidth(); + var p_padding = parseInt($(this).closest("form").css('padding-left') ,10) + parseInt($(this).closest('form').css('padding-right'), 10); + var this_padding = parseInt($(this).css('padding-left'), 10) + parseInt($(this).css('padding-right'), 10); + $(this).css('width', p_width - p_padding - this_padding); }); }; @@ -76,7 +276,7 @@ $(function() { $(this).removeClass('error'); // Tack the error style on if the input is empty.. - if ($(this).val() == '') { + if ($(this).val() === '') { $(this).addClass('error'); $(this).wiggle(); error_free = false; @@ -89,7 +289,7 @@ $(function() { }); -function clippyCopiedCallback(a) { +function clippyCopiedCallback() { $('#api_key_copied').fadeIn().delay(1000).fadeOut(); // var b = $("#clippy_tooltip_" + a); @@ -100,16 +300,16 @@ function clippyCopiedCallback(a) { } // Logging function that accounts for browsers that don't have window.console -log = function(){ +function log(){ log.history = log.history || []; log.history.push(arguments); if(this.console){ console.log( Array.prototype.slice.call(arguments)[0] ); } -}; +} // Handle browsers that do console incorrectly (IE9 and below, see http://stackoverflow.com/a/5539378/7913) -if (Function.prototype.bind && console && typeof console.log == "object") { +if (Function.prototype.bind && console && typeof console.log === "object") { [ "log","info","warn","error","assert","dir","clear","profile","profileEnd" ].forEach(function (method) { @@ -231,11 +431,13 @@ var Docs = { } }; -Handlebars.registerHelper('sanitize', function(html) { - html = html.replace(/