diff --git a/build/prepare_deploy.sh b/build/prepare_deploy.sh
index 1854e62c..c544aa4b 100755
--- a/build/prepare_deploy.sh
+++ b/build/prepare_deploy.sh
@@ -12,7 +12,7 @@ git checkout @{-1}
cd -
# build
-gulp build
+npm run build-dist
cd demo
cp -R ../dist/* ./dist/
mkdir -p releases
diff --git a/build/tasks/build.js b/build/tasks/build.js
index 5361d12c..5dfdf2cb 100644
--- a/build/tasks/build.js
+++ b/build/tasks/build.js
@@ -11,25 +11,29 @@ var gulp = require('gulp');
var sass = require('gulp-sass');
var replace = require('gulp-replace');
var rename = require('gulp-rename');
+var argv = require('yargs').argv;
gulp.task('build', function (callback) {
+ if (argv.skipRebuild) {
+ console.log('>>> Rebuild skipped')
+ return callback();
+ }
return runSequence(
'clean',
- 'bundleProd',
- callback
- );
-});
-
-gulp.task('buildDev', function (callback) {
- return runSequence(
- 'clean',
+ 'concatPrism',
'bundle',
+ 'concatDeps',
callback
);
});
-gulp.task('bundle', ['concatPrism', 'buildStatic', 'concatDeps']);
-gulp.task('bundleProd', ['bundle', 'buildStaticMin', 'concatDepsMin']);
+gulp.task('rebuild', function(done) {
+ return runSequence(
+ 'bundle',
+ 'concatDeps',
+ callback
+ );
+});
gulp.task('inlineTemplates', ['sass'], function() {
return gulp.src(paths.source, { base: './' })
@@ -38,20 +42,20 @@ gulp.task('inlineTemplates', ['sass'], function() {
.pipe(gulp.dest(paths.tmp));
});
-var JS_DEV_DEPS = [
+var JS_DEPS = argv.prod ? [
'lib/utils/browser-update.js',
'node_modules/zone.js/dist/zone.js',
'node_modules/zone.js/dist/long-stack-trace-zone.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/babel-polyfill/dist/polyfill.js'
-];
-
-var JS_DEV_DEPS_MIN = [
+] : [
'lib/utils/browser-update.js',
'node_modules/zone.js/dist/zone.min.js',
'node_modules/reflect-metadata/Reflect.js',
'node_modules/babel-polyfill/dist/polyfill.min.js'
-]
+];
+
+var outputFileName = paths.redocBuilt + (argv.prod ? '.min.js' : '.js');
gulp.task('sass', function () {
return gulp.src(paths.scss, { base: './' })
@@ -60,38 +64,22 @@ gulp.task('sass', function () {
});
// concatenate angular2 deps
-gulp.task('concatDeps', ['buildStatic'], function() {
- return concatDeps(JS_DEV_DEPS, paths.redocBuilt + '.js');
+gulp.task('concatDeps', function() {
+ return gulp.src(JS_DEPS.concat([outputFileName]))
+ .pipe(sourcemaps.init({loadMaps: true}))
+ .pipe(concat(outputFileName))
+ .pipe(sourcemaps.write('.'))
+ .pipe(gulp.dest('.'))
});
-gulp.task('concatDepsMin', ['buildStatic'], function() {
- return concatDeps(JS_DEV_DEPS_MIN, paths.redocBuilt + '.min.js');
-});
-
-gulp.task('buildStatic', ['inlineTemplates'], function(cb) {
- bundle(paths.redocBuilt + '.js', false, cb);
-});
-
-gulp.task('buildStaticMin', ['inlineTemplates'], function(cb) {
- bundle(paths.redocBuilt + '.min.js', true, cb);
-});
-
-function concatDeps(deps, file) {
- return gulp.src(deps.concat([file]))
- .pipe(sourcemaps.init({loadMaps: true}))
- .pipe(concat(file))
- .pipe(sourcemaps.write('.'))
- .pipe(gulp.dest('.'))
-}
-
-function bundle(outputFile, minify, cb) {
+gulp.task('bundle', ['inlineTemplates'], function bundle(cb) {
fs.existsSync('dist') || fs.mkdirSync('dist');
var builder = new Builder('./', 'system.config.js');
builder
.buildStatic(path.join(paths.tmp, paths.sourceEntryPoint),
- outputFile,
- { format:'umd', sourceMaps: true, lowResSourceMaps: true, minify: minify }
+ outputFileName,
+ { format:'umd', sourceMaps: !argv.prod, lowResSourceMaps: true, minify: argv.prod }
)
.then(function() {
// wait some time to allow flush
@@ -100,7 +88,7 @@ function bundle(outputFile, minify, cb) {
.catch(function(err) {
cb(new Error(err));
});
-}
+});
gulp.task('concatPrism', function() {
require('../../system.config.js');
@@ -129,7 +117,7 @@ gulp.task('concatPrism', function() {
'components/prism-scala.js'
].map(file => path.join(prismFolder, file));
- gulp.src(prismFiles)
- .pipe(concat(path.join(paths.tmp, 'prismjs-bundle.js')))
- .pipe(gulp.dest('.'))
+ return gulp.src(prismFiles)
+ .pipe(concat(path.join(paths.tmp, 'prismjs-bundle.js')))
+ .pipe(gulp.dest('.'))
});
diff --git a/build/tasks/e2e.js b/build/tasks/e2e.js
index c2828e83..ad09d558 100644
--- a/build/tasks/e2e.js
+++ b/build/tasks/e2e.js
@@ -19,7 +19,7 @@ gulp.task('test-server', function (done) {
});
-gulp.task('e2e', ['bundleProd', 'test-server'], function(done) {
+gulp.task('e2e', ['build', 'test-server'], function(done) {
gulp.src(['tests/e2e/**/*.js'], { read:false })
.pipe(gp.protractor({
configFile: './protractor.conf.js'
diff --git a/build/tasks/watch.js b/build/tasks/watch.js
index 77eec19d..bf2fc0bf 100644
--- a/build/tasks/watch.js
+++ b/build/tasks/watch.js
@@ -6,9 +6,9 @@ function changed(event) {
console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
}
-gulp.task('watch', ['buildDev'], function () {
- gulp.watch([ paths.source ], [ 'bundle', browserSync.reload ]).on('change', changed);
- gulp.watch([ paths.html ], [ 'bundle', browserSync.reload]).on('change', changed);
- gulp.watch([ paths.scss ], [ 'bundle', browserSync.reload]).on('change', changed);
+gulp.task('watch', ['build'], function () {
+ gulp.watch([ paths.source ], [ 'rebuild', browserSync.reload ]).on('change', changed);
+ gulp.watch([ paths.html ], [ 'rebuild', browserSync.reload]).on('change', changed);
+ gulp.watch([ paths.scss ], [ 'rebuild', browserSync.reload]).on('change', changed);
gulp.watch([ paths.demo ], [ '', browserSync.reload ]).on('change', changed);
});
diff --git a/lib/components/JsonSchema/json-schema.html b/lib/components/JsonSchema/json-schema.html
index b0d735e8..3a0e67cd 100644
--- a/lib/components/JsonSchema/json-schema.html
+++ b/lib/components/JsonSchema/json-schema.html
@@ -35,6 +35,7 @@
{{prop._range}}
Required
+
Default: {{prop.default | json}}
{{enumItem.val | json}}
diff --git a/lib/components/JsonSchema/json-schema.js b/lib/components/JsonSchema/json-schema.js
index 2b399a10..c313c350 100644
--- a/lib/components/JsonSchema/json-schema.js
+++ b/lib/components/JsonSchema/json-schema.js
@@ -11,7 +11,8 @@ import JsonPointer from '../../utils/JsonPointer';
templateUrl: './lib/components/JsonSchema/json-schema.html',
styleUrls: ['./lib/components/JsonSchema/json-schema.css'],
directives: [JsonSchema, DropDown],
- inputs: ['isArray', 'final', 'nestOdd', 'childFor', 'isRequestSchema']
+ inputs: ['isArray', 'final', 'nestOdd', 'childFor', 'isRequestSchema'],
+ detect: true
})
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef]])
export class JsonSchema extends BaseComponent {
diff --git a/lib/components/Method/method.js b/lib/components/Method/method.js
index 0070788c..9b2ce7fa 100644
--- a/lib/components/Method/method.js
+++ b/lib/components/Method/method.js
@@ -14,7 +14,8 @@ import { RequestSamples } from '../RequestSamples/request-samples';
templateUrl: './lib/components/Method/method.html',
styleUrls: ['./lib/components/Method/method.css'],
directives: [ ParamsList, ResponsesList, ResponsesSamples, SchemaSample, RequestSamples ],
- inputs: ['tag']
+ inputs: ['tag'],
+ detect: true
})
export class Method extends BaseComponent {
constructor(schemaMgr) {
diff --git a/lib/components/Method/method.scss b/lib/components/Method/method.scss
index ea625f20..1ddca717 100644
--- a/lib/components/Method/method.scss
+++ b/lib/components/Method/method.scss
@@ -22,6 +22,8 @@ responses-list, params-list {
background-color: darken($black, 2%);
display: block;
font-weight: $light;
+ white-space: nowrap;
+ overflow-x: auto;
}
.method-endpoint > h5 {
diff --git a/lib/components/MethodsList/methods-list.js b/lib/components/MethodsList/methods-list.js
index c9a55f3f..3c036b99 100644
--- a/lib/components/MethodsList/methods-list.js
+++ b/lib/components/MethodsList/methods-list.js
@@ -10,7 +10,8 @@ import { EncodeURIComponentPipe } from '../../utils/pipes';
templateUrl: './lib/components/MethodsList/methods-list.html',
styleUrls: ['./lib/components/MethodsList/methods-list.css'],
directives: [ forwardRef(() => Method) ],
- pipes: [ EncodeURIComponentPipe ]
+ pipes: [ EncodeURIComponentPipe ],
+ detect: true
})
export class MethodsList extends BaseComponent {
diff --git a/lib/components/ParamsList/params-list.html b/lib/components/ParamsList/params-list.html
index 62117c4c..b07078d5 100644
--- a/lib/components/ParamsList/params-list.html
+++ b/lib/components/ParamsList/params-list.html
@@ -15,6 +15,7 @@
{{param._displayType}} {{param._displayFormat}}
Required
+ Default: {{param.default | json}}
{{enumItem.val | json}}
diff --git a/lib/components/Redoc/redoc.js b/lib/components/Redoc/redoc.js
index 76669ded..b7c43cb4 100644
--- a/lib/components/Redoc/redoc.js
+++ b/lib/components/Redoc/redoc.js
@@ -29,7 +29,9 @@ var _modeLocked = false;
],
templateUrl: './lib/components/Redoc/redoc.html',
styleUrls: ['./lib/components/Redoc/redoc.css'],
- directives: [ ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar ]
+ directives: [ ApiInfo, ApiLogo, MethodsList, SideMenu, StickySidebar ],
+ detect: true,
+ onPushOnly: false
})
@Reflect.metadata('parameters', [
[SchemaManager], [OptionsService], [ElementRef], [RedocEventsService]])
diff --git a/lib/components/RequestSamples/request-samples.html b/lib/components/RequestSamples/request-samples.html
index a11d9b1f..d1175c8c 100644
--- a/lib/components/RequestSamples/request-samples.html
+++ b/lib/components/RequestSamples/request-samples.html
@@ -1,6 +1,6 @@
-
+
diff --git a/lib/components/RequestSamples/request-samples.js b/lib/components/RequestSamples/request-samples.js
index 96168c0e..f31de1ac 100644
--- a/lib/components/RequestSamples/request-samples.js
+++ b/lib/components/RequestSamples/request-samples.js
@@ -15,7 +15,9 @@ import { RedocEventsService } from '../../services/index';
styleUrls: ['./lib/components/RequestSamples/request-samples.css'],
directives: [SchemaSample, Tabs, Tab],
inputs: ['schemaPointer'],
- pipes: [PrismPipe]
+ pipes: [PrismPipe],
+ detect: true,
+ onPushOnly: false
})
@Reflect.metadata('parameters', [[SchemaManager], [RedocEventsService], [new ViewChildren(Tabs), QueryList]])
export class RequestSamples extends BaseComponent {
@@ -25,23 +27,14 @@ export class RequestSamples extends BaseComponent {
this.childTabs = childQuery.first;
});
this.events = events;
+ this.selectedLang = this.events.samplesLanguageChanged;
}
- init() {
- this.subscribeForEvents();
- }
changeLangNotify(lang) {
this.events.samplesLanguageChanged.next(lang);
}
- subscribeForEvents() {
- this.events.samplesLanguageChanged.subscribe((sampleLang) => {
- if (!this.childTabs) return;
- this.childTabs.selectyByTitle(sampleLang);
- });
- }
-
prepareModel() {
this.data = {};
this.data.schemaPointer = JsonPointer.join(this.schemaPointer, 'schema');
diff --git a/lib/components/ResponsesList/responses-list.html b/lib/components/ResponsesList/responses-list.html
index 15d643ca..39746643 100644
--- a/lib/components/ResponsesList/responses-list.html
+++ b/lib/components/ResponsesList/responses-list.html
@@ -8,9 +8,13 @@
+
diff --git a/lib/components/ResponsesList/responses-list.js b/lib/components/ResponsesList/responses-list.js
index 3830845c..473fae84 100644
--- a/lib/components/ResponsesList/responses-list.js
+++ b/lib/components/ResponsesList/responses-list.js
@@ -16,7 +16,8 @@ function isNumeric(n) {
selector: 'responses-list',
templateUrl: './lib/components/ResponsesList/responses-list.html',
styleUrls: ['./lib/components/ResponsesList/responses-list.css'],
- directives: [JsonSchema, Zippy, JsonSchemaLazy]
+ directives: [JsonSchema, Zippy, JsonSchemaLazy],
+ detect: true
})
@Reflect.metadata('parameters', [[SchemaManager], [OptionsService]])
export class ResponsesList extends BaseComponent {
diff --git a/lib/components/ResponsesList/responses-list.scss b/lib/components/ResponsesList/responses-list.scss
index c63354c9..49cab871 100644
--- a/lib/components/ResponsesList/responses-list.scss
+++ b/lib/components/ResponsesList/responses-list.scss
@@ -28,6 +28,11 @@ header {
font-weight: bold;
text-transform: uppercase;
margin-bottom: 15px;
+
+ &:not(:first-child) {
+ margin-top: 15px;
+ margin-bottom: 0;
+ }
}
.header {
diff --git a/lib/components/SideMenu/side-menu.js b/lib/components/SideMenu/side-menu.js
index 5f6de191..9834f61b 100644
--- a/lib/components/SideMenu/side-menu.js
+++ b/lib/components/SideMenu/side-menu.js
@@ -11,7 +11,9 @@ import { ScrollService, Hash, MenuService, OptionsService } from '../../services
selector: 'side-menu',
templateUrl: './lib/components/SideMenu/side-menu.html',
providers: [ScrollService, MenuService, Hash],
- styleUrls: ['./lib/components/SideMenu/side-menu.css']
+ styleUrls: ['./lib/components/SideMenu/side-menu.css'],
+ detect: true,
+ onPushOnly: false
})
@Reflect.metadata('parameters', [[SchemaManager], [ElementRef], [BrowserDomAdapter],
[ScrollService], [MenuService], [Hash], [OptionsService], [ChangeDetectorRef]])
@@ -31,10 +33,10 @@ export class SideMenu extends BaseComponent {
this.options = optionsService.options;
this.detectorRef = detectorRef;
- this.menuService.changed.subscribe((cat, item) => this.changed(cat, item));
+ this.menuService.changed.subscribe((evt) => this.changed(evt));
}
- changed(cat, item) {
+ changed({cat, item}) {
this.activeCatCaption = cat.name || '';
this.activeItemCaption = item && item.summary || '';
@@ -54,11 +56,10 @@ export class SideMenu extends BaseComponent {
this.$mobileNav = this.dom.querySelector(this.$element, '.mobile-nav');
this.$resourcesNav = this.dom.querySelector(this.$element, '#resources-nav');
- //decorate option.scrollYOffset to account mobile nav
- var origOffset = this.options.scrollYOffset;
- this.options.scrollYOffset = () => {
+ //decorate scrollYOffset to account mobile nav
+ this.scrollService.scrollYOffset = () => {
let mobileNavOffset = this.$mobileNav.clientHeight;
- return origOffset() + mobileNavOffset;
+ return this.options.scrollYOffset() + mobileNavOffset;
};
}
@@ -73,12 +74,14 @@ export class SideMenu extends BaseComponent {
toggleMobileNav() {
let dom = this.dom;
- let $overflowParent = (this.$scrollParent === global) ? dom.defaultDoc().body : this.$scrollParent;
+ let $overflowParent = (this.options.$scrollParent === global) ? dom.defaultDoc().body
+ : this.$scrollParent.$scrollParent;
if (dom.hasStyle(this.$resourcesNav, 'height')) {
dom.removeStyle(this.$resourcesNav, 'height');
dom.removeStyle($overflowParent, 'overflow-y');
} else {
- let viewportHeight = this.$scrollParent.innerHeight || this.$scrollParent.clientHeight;
+ let viewportHeight = this.options.$scrollParent.innerHeight
+ || this.options.$scrollParent.clientHeight;
let height = viewportHeight - this.$mobileNav.getBoundingClientRect().bottom;
dom.setStyle($overflowParent, 'overflow-y', 'hidden');
dom.setStyle(this.$resourcesNav, 'height', height + 'px');
diff --git a/lib/components/base.js b/lib/components/base.js
index 97a1e77c..30d8246d 100644
--- a/lib/components/base.js
+++ b/lib/components/base.js
@@ -67,6 +67,7 @@ export function RedocComponent(options) {
let inputs = safeConcat(options.inputs, commonInputs);
let directives = safeConcat(options.directives, CORE_DIRECTIVES);
let pipes = safeConcat(options.pipes, [JsonPointerEscapePipe, MarkedPipe, JsonPipe, AsyncPipe]);
+ if (options.onPushOnly === undefined) options.onPushOnly = true;
return function decorator(target) {
@@ -75,7 +76,9 @@ export function RedocComponent(options) {
inputs: inputs,
outputs: options.outputs,
providers: options.providers,
- changeDetection: options.changeDetection || ChangeDetectionStrategy.Default,
+ changeDetection: options.detect ?
+ (options.onPushOnly ? ChangeDetectionStrategy.OnPush : ChangeDetectionStrategy.Default) :
+ ChangeDetectionStrategy.Detached,
templateUrl: options.templateUrl,
template: options.template,
styles: options.styles,
@@ -83,6 +86,9 @@ export function RedocComponent(options) {
pipes: pipes
});
+ console.log(options.selector, options.detect ?
+ (options.onPushOnly ? 'OnPush' : 'Default') : 'Detached');
+
return componentDecorator(target) || target;
};
}
diff --git a/lib/services/menu.service.js b/lib/services/menu.service.js
index 175efd61..5c2ea128 100644
--- a/lib/services/menu.service.js
+++ b/lib/services/menu.service.js
@@ -90,7 +90,7 @@ export class MenuService {
this.activeMethodPtr = currentItem.pointer;
}
- this.changed.next(menu[catIdx], currentItem);
+ this.changed.next({cat: menu[catIdx], item: currentItem});
}
_calcActiveIndexes(offset) {
diff --git a/lib/shared/components/Tabs/tabs.js b/lib/shared/components/Tabs/tabs.js
index ed6094de..5cf174ec 100644
--- a/lib/shared/components/Tabs/tabs.js
+++ b/lib/shared/components/Tabs/tabs.js
@@ -1,11 +1,13 @@
'use strict';
-import {Component, EventEmitter} from '@angular/core';
-import {CORE_DIRECTIVES} from '@angular/common';
+import { Component, EventEmitter } from '@angular/core';
+import { CORE_DIRECTIVES } from '@angular/common';
+import { ChangeDetectorRef, ChangeDetectionStrategy } from '@angular/core';
@Component({
selector: 'tabs',
events: ['change'],
+ inputs: ['selected'],
template: `
-
`,
directives: [CORE_DIRECTIVES],
- styleUrls: ['./lib/shared/components/Tabs/tabs.css']
+ styleUrls: ['./lib/shared/components/Tabs/tabs.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush
})
+@Reflect.metadata('parameters', [[ChangeDetectorRef]])
export class Tabs {
- constructor() {
+ constructor(changeDetector) {
this.tabs = [];
this.change = new EventEmitter();
+ this.changeDetector = changeDetector;
}
selectTab(tab, notify = true) {
@@ -47,6 +52,7 @@ export class Tabs {
prevActive.active = true;
}
notify && this.change.next(tabTitle);
+ this.changeDetector.markForCheck();
}
addTab(tab) {
@@ -55,6 +61,10 @@ export class Tabs {
}
this.tabs.push(tab);
}
+
+ ngOnInit() {
+ if (this.selected) this.selected.subscribe(title => this.selectyByTitle(title));
+ }
}
@Component({
diff --git a/package.json b/package.json
index 51f333c6..a5678844 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "redoc",
"description": "Swagger-generated API Reference Documentation",
- "version": "0.10.0",
+ "version": "0.11.0",
"repository": {
"type": "git",
"url": "git://github.com/Rebilly/ReDoc"
@@ -11,10 +11,10 @@
"test": "gulp lint && ./build/run_tests.sh",
"jspm-install": "jspm install",
"start": "gulp serve",
- "build-dist": "gulp build",
+ "build-dist": "gulp build --prod",
"branch-release": "git reset --hard && branch-release",
"unit": "gulp test",
- "e2e": "gulp e2e",
+ "e2e": "gulp e2e --prod",
"deploy": "build/prepare_deploy.sh && deploy-to-gh-pages demo"
},
"keywords": [
@@ -114,6 +114,7 @@
"sinon": "^1.17.2",
"systemjs-builder": "^0.15.16",
"vinyl-paths": "^2.0.0",
+ "yargs": "^4.7.1",
"zone.js": "^0.6.12"
}
}
diff --git a/tests/e2e/redoc.spec.js b/tests/e2e/redoc.spec.js
index ace018ca..50608752 100644
--- a/tests/e2e/redoc.spec.js
+++ b/tests/e2e/redoc.spec.js
@@ -43,12 +43,39 @@ describe('Scroll sync', () => {
fixFFTest(done);
});
- it('should update active menu entries on page scroll', () => {
- scrollToEl('[tag="store"]').then(function() {
+ it('should update active menu entries on page scroll forwards', () => {
+ scrollToEl('[tag="store"]').then(() => {
expect($('.menu-cat-header.active').getInnerHtml()).toContain('store');
expect($('.selected-tag').getInnerHtml()).toContain('store');
});
});
+
+ it('should update active menu entries on page scroll backwards', () => {
+ scrollToEl('[operation-id="getPetById"]').then(() => {
+ expect($('.menu-cat-header.active').getInnerHtml()).toContain('pet');
+ expect($('.selected-tag').getInnerHtml()).toContain('pet');
+ expect($('.menu-cat li.active').getInnerHtml()).toContain('Find pet by ID');
+ expect($('.selected-endpoint').getInnerHtml()).toContain('Find pet by ID');
+ });
+ });
+});
+
+describe('Language tabs sync', () => {
+ let specUrl = URL;
+
+ beforeEach((done) => {
+ browser.get(specUrl);
+ fixFFTest(done);
+ });
+
+ it('should sync language tabs', () => {
+ var $item = $$('[operation-id="addPet"] tabs > ul > li').last();
+ // check if correct item
+ expect($item.getText()).toContain('PHP');
+ $item.click().then(() => {
+ expect($('[operation-id="updatePet"] li.active').getText()).toContain('PHP');
+ });
+ });
});
if (process.env.JOB === 'e2e-guru') {