api-console-assets
Version:
This repo only exists to publish api console components to npm
679 lines (608 loc) • 21.9 kB
HTML
<!--
@license
Copyright 2016 The Advanced REST client authors <arc@mulesoft.com>
Licensed under the Apache License, Version 2.0 (the "License"); you may not
use this file except in compliance with the License. You may obtain a copy of
the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations under
the License.
-->
<link rel="import" href="../polymer/polymer.html">
<link rel="import" href="../raml-behaviors/raml-behavior.html">
<link rel="import" href="../iron-flex-layout/iron-flex-layout.html">
<link rel="import" href="../paper-button/paper-button.html">
<link rel="import" href="../docs-parameters-table/docs-parameters-table.html">
<link rel="import" href="../docs-parameters-table/docs-headers-table.html">
<link rel="import" href="../docs-parameters-table/docs-body-parameters-table.html">
<link rel="import" href="../raml-annotations-display/raml-annotations-display.html">
<link rel="import" href="../raml-docs-response-panel/raml-docs-response-panel.html">
<link rel="import" href="../iron-media-query/iron-media-query.html">
<link rel="import" href="../marked-element/marked-element.html">
<link rel="import" href="../markdown-styles/markdown-styles.html">
<link rel="import" href="../iron-collapse/iron-collapse.html">
<link rel="import" href="../iron-icon/iron-icon.html">
<link rel="import" href="../arc-icons/arc-icons.html">
<!--
`<raml-docs-method-viewer>` Documentation view for the method defined in RAML file
This element is meant to work with data structure returned by the
`<raml-js-parser>` and `<raml-path-to-object>`. Regular JSON output from the
RAML JS parser will not work with this element.
### Example
```
<raml-docs-method-viewer
raml="[[methodDefinition]]"
parent-endpoint="[[selectedParent]]"></raml-docs-method-viewer>
```
To properly compute values displayed in the view it needs to know its
`parentEndpoint`. Though, it will work properly if the parent is not passed.
Parent is used to display title of the method.
## Disabling the "try it" button
You can either set the `noTryIt` property to true (or set the `no-try-it` attribute on the element)
or send for the `tryit-toggle` custom event with the `state` property set to the detail object.
The element will listen on `window` object for the event.
### Styling
`<raml-docs-method-viewer>` provides the following custom properties and mixins for styling:
Custom property | Description | Default
----------------|-------------|----------
`--raml-docs-method-viewer` | Mixin applied to the element | `{}`
`--raml-docs-h1` | Mixin applied to H1 | `{}` |
`--raml-docs-h2` | Mixin applied to H2 | `{}` |
`--raml-docs-h3` | Mixin applied to H3 | `{}` |
`--raml-docs-method-viewer-title-method-font-weight` | Font weight of the name if the method | `500` |
`--raml-docs-method-viewer-http-method-font-weight` | Font weight of the HTTP method | `500` |
`--raml-docs-item-description` | Mixin applied to the description field. | `{}` |
`--raml-docs-method-viewer-url-color` | Color of the URL field | `--accent-color` |
`--raml-docs-method-viewer-url-font-style` | font-style of the URL value | `italic` |
`--raml-docs-method-viewer-url` | Mixin applied to the URL field | `{}` |
`--action-button` | Mixin applied to the main action button (Try it) | `{}`
`--action-button-hover` | Mixin applied to the main action button on hover (Try it) | `{}`
`--arc-font-headline` | Mixin applied to the h1 element (API title) | `{}`
`--arc-font-title` | Mixin applied to the h2 elements (section title) | `{}`
`--arc-font-subhead` | Mixin applied to the h3 elements (section sub-titles) | `{}`
`--toggle-button` | Mixin applied to toggling button (show/hide) | `{}`
`--toggle-button-hover` | Mixin applied to toggling button on hover (show/hide) | `{}`
`--raml-docs-method-viewer-title-area-actions` | Mixin applied to toggling actions area | `{}`
`--raml-docs-method-viewer-traits-list` | Mixin applied to the list of traits container | `{}`
`--raml-docs-method-viewer-traits-list-values` | Mixin applied to the list of traits values (names) | `{}`
`--raml-docs-method-viewer-traits-list-label` | Mixin applied to the list of traits list label | `{}`
`--raml-docs-method-viewer-traits-list-color` | Color of the traits list section | `rgba(0,0,0,0.74)`
`--raml-docs-method-viewer-traits-list-values-color` | Color of the traits list values (names) | `rgba(0,0,0,0.94)`
`--raml-docs-method-viewer-traits-list-label-color` | Color of the traits list label | `inherit`
@group RAML Elements
@element raml-docs-method-viewer
@demo demo/index.html
-->
<dom-module id="raml-docs-method-viewer">
<template>
<style include="markdown-styles"></style>
<style>
:host {
display: block;
@apply(--raml-docs-method-viewer);
}
:host([hidden]) {
display: none ;
}
h1 {
@apply(--arc-font-headline);
@apply(--raml-docs-method-viewer-content-section);
@apply(--raml-docs-h1);
}
h2 {
@apply(--arc-font-title);
@apply(--raml-docs-method-viewer-content-section);
@apply(--raml-docs-h2);
}
h3 {
@apply(--arc-font-subhead);
@apply(--raml-docs-method-viewer-content-section);
@apply(--raml-docs-h3);
}
.method-name {
font-weight: var(--raml-docs-method-viewer-title-method-font-weight, 500);
}
.method-value {
text-transform: uppercase;
font-weight: var(--raml-docs-method-viewer-http-method-font-weight, 500);
}
.title-area {
@apply(--layout-horizontal);
@apply(--layout-center);
}
.title {
@apply(--layout-flex);
}
.method-desc {
margin-bottom: 28px;
color: rgba(0,0,0,0.74);
@apply(--arc-font-body1);
@apply(--raml-docs-method-viewer-content-section);
@apply(--raml-docs-item-description);
}
.url-area {
@apply(--layout-horizontal);
@apply(--arc-font-body1);
font-size: 16px;
margin-bottom: 40px;
color: var(--raml-docs-method-viewer-url-color, --accent-color);
@apply(--raml-docs-method-viewer-content-section);
}
.url-value {
font-style: var(--raml-docs-method-viewer-url-font-style, italic);
margin-left: 12px;
word-break: break-all;
@apply(--raml-docs-method-viewer-url);
}
.body-selector {
margin: 0 12px;
}
.action-button {
background-color: var(--primary-color);
color: var(--primary-action-color, #fff);
@apply(--action-button);
}
.action-button:hover {
@apply(--action-button-hover);
}
.bottom.action {
@apply(--layout-horizontal);
@apply(--layout-end-justified);
}
:host([narrow]) .container {
max-width: var(--raml-docs-method-viewer-narrow-container-width, calc(100vw - 32px));
overflow: auto;
}
:host([narrow]) docs-parameters-table,
:host([narrow]) docs-headers-table,
:host([narrow]) docs-body-parameters-table,
:host([narrow]) raml-docs-response-panel {
max-width: var(--raml-docs-method-viewer-narrow-container-width, calc(100vw - 32px));
overflow: auto;
}
:host([narrow]) .title-area {
margin-bottom: 24px;
/*@apply(--layout-start);*/
}
:host([narrow]) h1 {
font-size: 20px;
margin: 0;
}
:host([narrow]) h2 {
font-size: 18px;
}
:host([narrow]) h3 {
font-size: 17px;
}
.section-title-area {
@apply(--layout-horizontal);
@apply(--layout-center);
border-bottom: 1px var(--raml-docs-resource-viewer-title-border-color, #e5e5e5) solid;
}
.section-title-area h3 {
@apply(--layout-flex);
}
.toggle-button {
color: var(--arc-toggle-view-icon-color, rgba(0, 0, 0, 0.54));
transition: color 0.25s linear;
@apply(--toggle-button);
}
.toggle-button:hover {
color: var(--arc-toggle-view-icon-hover-color, rgba(0, 0, 0, 0.78));
@apply(--toggle-button-hover);
}
.toggle-icon {
transform: rotateZ(0deg);
transition: transform 0.3s linear;
}
.toggle-icon.opened {
transform: rotateZ(-180deg);
}
.title-area-actions {
@apply(--raml-docs-method-viewer-title-area-actions);
}
.traits-list {
@apply(--arc-font-body1);
margin-bottom: 8px;
color: var(--raml-docs-method-viewer-traits-list-color, rgba(0,0,0,0.74));
@apply(--raml-docs-method-viewer-traits-list);
}
.trait-value {
color: var(--raml-docs-method-viewer-traits-list-values-color, rgba(0,0,0,0.94));
@apply(--raml-docs-method-viewer-traits-list-values);
}
.trait-label {
color: var(--raml-docs-method-viewer-traits-list-label-color, inherit);
@apply(--raml-docs-method-viewer-traits-list-label);
}
raml-annotations-display {
color: rgba(0,0,0,0.74);
margin-bottom: 12px;
}
</style>
<iron-media-query query="(max-width: [[narrowWidth]])" query-matches="{{narrow}}"></iron-media-query>
<section class="container">
<div class="title-area">
<h1 class="title">
<span>[[parentName]]</span>
<span hidden$="[[!parentName]]">:</span>
<span class="method-name">[[methodName]]</span>
</h1>
<template is="dom-if" if="[[!noTryIt]]">
<div class="action">
<paper-button class="action-button" on-tap="_tryIt">Try it</paper-button>
</div>
</template>
</div>
<template is="dom-if" if="[[hasTraits]]">
<div class="traits-list">
<span class="trait-label">Traits:</span>
<span class="trait-value">[[_computeTraitsList(raml.is)]]</span>
</div>
</template>
<template is="dom-if" if="[[hasValue(raml.annotations)]]">
<raml-annotations-display annotations="[[raml.annotations]]"></raml-annotations-display>
</template>
<div hidden$="[[_computeHideMethodDesc(raml.description)]]" class="method-desc">
<marked-element markdown="[[raml.description]]">
<div class="markdown-html markdown-body"></div>
</marked-element>
</div>
<section class="request-doc">
<h2>Request</h2>
<div class="url-area">
<div class="method-value">[[raml.method]]</div>
<div class="url-value">[[raml.absoluteUri]]</div>
</div>
<section hidden$="[[!hasParameters]]">
<div class="section-title-area">
<h3>Parameters</h3>
<div class="title-area-actions">
<paper-button data-section="parameters" on-tap="_toggleCollapseSection" class="toggle-button" title="Toogle parameters details">
[[_computeToggleActionLabel(parametersOpened)]]
<iron-icon icon="arc:expand-more" class$="[[_computeToggleIconClass(parametersOpened)]]"></iron-icon>
</paper-button>
</div>
</div>
<iron-collapse opened="[[parametersOpened]]">
<docs-parameters-table
uri-parameters="[[raml.allUriParameters]]"
query-parameters="[[raml.queryParameters]]"
has-parameters="{{hasParameters}}"
narrow=[[narrow]] auto-hide></docs-parameters-table>
</iron-collapse>
</section>
<section hidden$="[[!hasHeaders]]">
<div class="section-title-area">
<h3>Headers</h3>
<div class="title-area-actions">
<paper-button data-section="headers" on-tap="_toggleCollapseSection" class="toggle-button" title="Toogle headers details">
[[_computeToggleActionLabel(headersOpened)]]
<iron-icon icon="arc:expand-more" class$="[[_computeToggleIconClass(headersOpened)]]"></iron-icon>
</paper-button>
</div>
</div>
<iron-collapse opened="[[headersOpened]]">
<docs-headers-table
has-headers="{{hasHeaders}}"
headers="[[raml.headers]]"
auto-hide></docs-headers-table>
</iron-collapse>
</section>
<section hidden$="[[!hasBody]]">
<div class="section-title-area">
<h3>Body</h3>
<div class="title-area-actions">
<paper-button data-section="body" on-tap="_toggleCollapseSection" class="toggle-button" title="Toogle body details">
[[_computeToggleActionLabel(bodyOpened)]]
<iron-icon icon="arc:expand-more" class$="[[_computeToggleIconClass(bodyOpened)]]"></iron-icon>
</paper-button>
</div>
</div>
<iron-collapse opened="[[bodyOpened]]">
<docs-body-parameters-table body="[[raml.body]]" narrow=[[narrow]]></docs-body-parameters-table>
</iron-collapse>
</section>
</section>
<section class="response-doc" hidden$="[[!hasResponses]]">
<h2>Response</h2>
<raml-docs-response-panel has-responses="{{hasResponses}}" responses="[[raml.responses]]"></raml-docs-response-panel>
</section>
<template is="dom-if" if="[[!noTryIt]]">
<div class="bottom action">
<paper-button class="action-button" on-tap="_tryIt">Try it</paper-button>
</div>
</template>
</section>
</template>
<script>
Polymer({
is: 'raml-docs-method-viewer',
behaviors: [Polymer.RamlBehavior],
/**
* Fired when the user pressed the `try it` button.
*
* @event tryit-requested
*/
properties: {
// Parent endpoint object
parentEndpoint: {
type: Object,
value: false
},
// True if current endpont has a body
hasBody: {
value: false,
type: Boolean,
computed: '_computeHasBody(raml.body)'
},
// Computed name of the parent resource
parentName: {
type: String,
value: null,
computed: '_computeParentName(parentEndpoint.*)'
},
// Computed name of current method
methodName: {
type: String,
computed: '_computeMethodName(raml.*)'
},
// If true then the query / uri parameters will be displayed.
hasParameters: Boolean,
// Value obtained from the `raml-docs-response-panel`
hasResponses: Boolean,
// If true, the method has traits applied to it.
hasTraits: {
type: Boolean,
readOnly: true
},
/**
* If true then the element will start listen for the
* `raml-is-method-changed`, `raml-selected-object-changed` and
* `raml-selected-path-changed` event and set corresponding properties
* when needed. It's a replacement for the Polymer's data biding
* for apps that are not Polymer powered.
*/
autoHide: {
type: Boolean,
observer: '_autoHideChanged'
},
// If true then the element will be hidden ui the UI.
hidden: {
type: Boolean,
reflectToAttribute: true
},
// If set then the `tryit` button will be hidden.
noTryIt: {
type: Boolean,
value: false
},
/**
* If set it will renders the view in the narrow layout.
*/
narrow: {
type: Boolean,
notify: true,
reflectToAttribute: true
},
// A widith below which the `narrow` property will be set to true.
narrowWidth: {
type: String,
value: '768px'
},
// If true then the parameters docs table is displayed.
parametersOpened: {
type: Boolean,
value: true
},
// If true then the headers docs table is displayed.
headersOpened: {
type: Boolean,
value: true
},
// If true then the body docs table is displayed.
bodyOpened: {
type: Boolean,
value: true
}
},
observers: [
'_objectChanged(raml.*)'
],
attached: function() {
this._eventTarget = Polymer.dom(this).host || document;
if (this.autoHide) {
this._attacheListeners();
}
this.listen(window, 'tryit-toggle', '_toggleTryitHandler');
},
detached: function() {
this.unlisten(window, 'tryit-toggle', '_toggleTryitHandler');
},
_autoHideChanged: function(state) {
if (state === undefined) {
return;
}
if (state) {
this._attacheListeners();
} else {
this._detachListeners();
}
},
_attacheListeners: function() {
if (!this._eventTarget) {
this.hidden = true;
return;
}
this._detachListeners();
this.listen(this._eventTarget, 'raml-is-method-changed',
'_isMethodHandler');
this.listen(this._eventTarget, 'raml-selected-object-changed',
'_selectedChangeHandler');
this.listen(this._eventTarget, 'raml-selected-parent-changed',
'_selectedParentChangeHandler');
},
_detachListeners: function() {
if (!this._eventTarget) {
return;
}
this.unlisten(this._eventTarget, 'raml-is-method-changed',
'_isMethodHandler');
this.unlisten(this._eventTarget, 'raml-selected-object-changed',
'_selectedChangeHandler');
this.unlisten(this._eventTarget, 'raml-selected-parent-changed',
'_selectedParentChangeHandler');
},
_objectChanged: function(record) {
// this.hidden = false;
var raml = record && record.base;
if (!raml) {
this._setHasTraits(false);
return;
}
if (raml.is && raml.is.length) {
this._setHasTraits(true);
} else {
this._setHasTraits(false);
}
},
_computeMethodName: function() {
var m = this.raml;
if (!m) {
return '';
}
return m.displayName || m.method;
},
_computeHideMethodDesc: function(description) {
return !description;
},
_computeHasBody: function(body) {
return !!(body && body.length > 0);
},
_isMethodHandler: function(e, detail) {
var state = detail.state;
this.hidden = !state;
},
_selectedChangeHandler: function(e, detail) {
if (this.hidden) {
this.raml = undefined;
return;
}
this.raml = detail.selectedObject;
},
_selectedParentChangeHandler: function(e, detail) {
if (this.hidden) {
this.parentEndpoint = undefined;
return;
}
this.parentEndpoint = detail.selectedParent;
},
_tryIt: function() {
this.fire('tryit-requested');
},
_computeParentName: function() {
var endpoint = this.parentEndpoint;
if (!endpoint) {
return '';
}
return endpoint.displayName || endpoint.relativeUri;
},
/**
* Toogles collapsable sections.
* The toggle button must have `data-section` property with the name of the
* section to toggle. Variable that controls the state (Boolean value)
* must be called section + 'Opened'.
*/
_toggleCollapseSection: function(e) {
var target = this._getPathElement(e, 'paper-button');
if (!target) {
return console.warn('Toggle element not in path ', e.path);
}
var section = target.dataset.section;
if (!section) {
return console.warn('Toggle section not fond in path ', e.path);
}
var variable = section + 'Opened';
this[variable] = !this[variable];
},
/**
* Extracts an element from the path. It is iterating over the path to find
* an element that matches `nodeName`.
*
* @param {String} nodeName A node to find in the path.
* @return {HTMLElement|dndefined} A first node in the path that matches the
* name or undefiend.
*/
_getPathElement: function(e, nodeName) {
if (!(e instanceof Polymer.DomApi.Event)) {
e = Polymer.dom(e);
}
var path = e.path;
if (!path || !path.length) {
return e.rootTarget;
}
nodeName = nodeName.toUpperCase();
for (var i = 0, len = path.length; i < len; i++) {
if (path[i] && path[i].nodeName && path[i].nodeName === nodeName) {
return path[i];
}
}
},
// Computes class for the toggle's button icon.
_computeToggleIconClass: function(opened) {
var clazz = 'toggle-icon';
if (opened) {
clazz += ' opened';
}
return clazz;
},
// Computes a label for the section toggle buttons.
_computeToggleActionLabel: function(opened) {
return opened ? 'Hide' : 'Show';
},
_toggleTryitHandler: function(e) {
this.noTryIt = !e.detail.state;
},
// Computes list of traits names to display in the view.
_computeTraitsList: function(traits) {
if (!traits || !traits.length) {
return;
}
return traits.map(function(trait) {
if (typeof trait === 'string') {
return trait;
}
if (trait.name) {
return trait.name;
}
try {
var keys = Object.keys(trait);
return keys[0];
} catch (e) {}
}).join(', ');
},
/**
* Check if passed object is set.
* 0 (zero) returns true while empty string returns false.
*
* @return {Boolean} True/False depending if passed object has a value.
*/
hasValue: function(obj) {
var type = typeof obj;
if (type === 'number' && obj === 0) {
return true;
}
if (type === 'boolean') {
return true;
}
if (type === 'string' && obj === '') {
return true;
}
return !!obj;
}
});
</script>
</dom-module>