diff --git a/CHANGES.md b/CHANGES.md index 05e9cd1..fcc7f98 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,13 @@ +2015-01-09, Version 1.6.4 +========================= + + * Prevent double slash in the resource URLs (Miroslav Bajtoš) + + * Allow `uiDirs` to be defined as a String (Simon Ho) + + * Save accessToken in localStorage. Fixes #47 (Samuel Reed) + + 2015-01-06, Version 1.6.3 ========================= @@ -30,12 +40,12 @@ * model-helper: ignore unknown property types (Miroslav Bajtoš) -2014-10-24, Version 1.5.1 +2014-10-24, Version 1.5.0 ========================= -2014-10-24, Version 1.5.0 +2014-10-24, Version 1.5.1 ========================= * Add an option `uiDirs` (Miroslav Bajtoš) diff --git a/index.js b/index.js index 08962c3..6048c3a 100644 --- a/index.js +++ b/index.js @@ -52,9 +52,13 @@ function explorer(loopbackApplication, options) { // In this way one could e.g. make changes to index.html without having // to worry about constantly pulling in JS updates. if (options.uiDirs) { - options.uiDirs.forEach(function(dir) { - app.use(express.static(dir)); - }); + if (typeof options.uiDirs === 'string') { + app.use(express.static(options.uiDirs)); + } else if (Array.isArray(options.uiDirs)) { + options.uiDirs.forEach(function(dir) { + app.use(express.static(dir)); + }); + } } if (options.swaggerDistRoot) { diff --git a/lib/swagger.js b/lib/swagger.js index 3572c81..b25d517 100644 --- a/lib/swagger.js +++ b/lib/swagger.js @@ -156,6 +156,11 @@ function addRoute(app, uri, doc, opts) { var hasBasePath = Object.keys(doc).indexOf('basePath') !== -1; var initialPath = doc.basePath || ''; + // Remove the trailing slash, see + // https://github.com/strongloop/loopback-explorer/issues/48 + if (initialPath[initialPath.length-1] === '/') + initialPath = initialPath.slice(0, -1); + app.get(urlJoin('/', uri), function(req, res) { // There's a few forces at play that require this "hack". The Swagger spec diff --git a/package.json b/package.json index c6b6776..9e71f3e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "loopback-explorer", - "version": "1.6.3", + "version": "1.6.4", "description": "Browse and test your LoopBack app's APIs", "main": "index.js", "scripts": { diff --git a/public/lib/loadSwaggerUI.js b/public/lib/loadSwaggerUI.js index c89917b..327a126 100644 --- a/public/lib/loadSwaggerUI.js +++ b/public/lib/loadSwaggerUI.js @@ -3,9 +3,10 @@ // Refactoring of inline script from index.html. /*global SwaggerUi, log, ApiKeyAuthorization, hljs, window, $ */ $(function() { + var lsKey = 'swagger_accessToken'; $.getJSON('config.json', function(config) { - log(config); - loadSwaggerUi(config); + log(config); + loadSwaggerUi(config); }); var accessToken; @@ -35,6 +36,14 @@ $(function() { $('#api_selector').submit(setAccessToken); $('#input_accessToken').keyup(onInputChange); + // Recover accessToken from localStorage if present. + if (window.localStorage) { + var key = window.localStorage.getItem(lsKey); + if (key) { + $('#input_accessToken').val(key).submit(); + } + } + window.swaggerUi.load(); } @@ -49,6 +58,11 @@ $(function() { accessToken = key; $('.accessTokenDisplay').text('Token Set.').addClass('set'); $('.accessTokenDisplay').attr('data-tooltip', 'Current Token: ' + key); + + // Save this token to localStorage if we can to make it persist on refresh. + if (window.localStorage) { + window.localStorage.setItem(lsKey, key); + } } } diff --git a/test/explorer.test.js b/test/explorer.test.js index ce900aa..c3b4aeb 100644 --- a/test/explorer.test.js +++ b/test/explorer.test.js @@ -4,6 +4,7 @@ var request = require('supertest'); var assert = require('assert'); var path = require('path'); var expect = require('chai').expect; +var urlJoin = require('../lib/url-join'); describe('explorer', function() { @@ -78,6 +79,26 @@ describe('explorer', function() { done(); }); }); + + it('removes trailing slash from baseUrl', function(done) { + // SwaggerUI builds resource URL by concatenating basePath + resourcePath + // Since the resource paths are always startign with a slash, + // if the basePath ends with a slash too, an incorrect URL is produced + var app = loopback(); + app.set('restApiRoot', '/'); + configureRestApiAndExplorer(app); + + request(app) + .get('/explorer/resources/products') + .expect(200) + .end(function(err, res) { + if (err) return done(err); + var baseUrl = res.body.basePath; + var apiPath = res.body.apis[0].path; + expect(baseUrl + apiPath).to.match(/http:\/\/[^\/]+\/products/); + done(); + }); + }); }); describe('with custom front-end files', function() { @@ -106,6 +127,37 @@ describe('explorer', function() { }); }); + describe('when specifying custom static file root directories', function() { + var app; + beforeEach(function() { + app = loopback(); + }); + + it('should allow `uiDirs` to be defined as an Array', function(done) { + app.use('/explorer', explorer(app, { + uiDirs: [ path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') ] + })); + + request(app).get('/explorer/') + .expect(200) + // expect the content of `dummy-swagger-ui/index.html` + .expect('custom index.html\n') + .end(done); + }); + + it('should allow `uiDirs` to be defined as an String', function(done) { + app.use('/explorer', explorer(app, { + uiDirs: path.resolve(__dirname, 'fixtures', 'dummy-swagger-ui') + })); + + request(app).get('/explorer/') + .expect(200) + // expect the content of `dummy-swagger-ui/index.html` + .expect('custom index.html\n') + .end(done); + }); + }); + function givenLoopBackAppWithExplorer(explorerBase) { return function(done) { var app = this.app = loopback(); @@ -115,7 +167,7 @@ describe('explorer', function() { } function configureRestApiAndExplorer(app, explorerBase) { - var Product = loopback.Model.extend('product'); + var Product = loopback.PersistedModel.extend('product'); Product.attachTo(loopback.memory()); app.model(Product);