UNPKG

api-console-assets

Version:

This repo only exists to publish api console components to npm

433 lines (395 loc) 13.9 kB
<!-- @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="../iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="../paper-input/paper-input-container.html"> <link rel="import" href="../iron-input/iron-input.html"> <link rel="import" href="../paper-icon-button/paper-icon-button.html"> <link rel="import" href="../paper-item/paper-item.html"> <link rel="import" href="../paper-item/paper-item-body.html"> <link rel="import" href="../paper-toast/paper-toast.html"> <link rel="import" href="../arc-icons/arc-icons.html"> <link rel="import" href="../paper-autocomplete/paper-autocomplete.html"> <link rel="import" href="../iron-validatable-behavior/iron-validatable-behavior.html"> <link rel="import" href="../iron-form-element-behavior/iron-form-element-behavior.html"> <link rel="import" href="../iron-behaviors/iron-control-state.html"> <link rel="import" href="../paper-tooltip/paper-tooltip.html"> <!-- A selector for the OAuth scope. It provides an UI to enter a scope for the AOuth settings. ### Example ``` <oauth2-scope-selector></oauth2-scope-selector> ``` Use the `allowed-scopes` attribute to provide a list of predefined scopes supported by the endpoint. When the list is set, autocomplete will be enabled in the selector. Autocomplete is supported by the `paper-autocomplete` element. Setting `prevent-custom-scopes` it will dissallow adding a scope that is not defined in the `allowed-scopes` array. #### Example ``` <oauth2-scope-selector prevent-custom-scopes></oauth2-scope-selector> ``` And in JavaScript ``` var selector = document.querySelector('oauth2-scope-selector'); selector.allowedScopes = ['profile', 'email']; ``` ### Adding scope documentation It is possible to display a documentation alongside the scope. In this case the user will see a description below the scope name in the selected scopes list. For it to work the `allowedScopes` array must contain objects with required keys: `label` and `description`. ``` var scopes = [ {'label': 'user', 'description': 'Grants read/write access to profile info only. Note that this scope includes user:email and user:follow.'}, {'label': 'user:email', 'description': 'Grants read access to a user\'s email addresses.'}, {'label': 'user:follow', 'description': 'Grants access to follow or unfollow other users.'} ]; var selector = document.querySelector('oauth2-scope-selector'); selector.allowedScopes = scopes; ``` The list will be passed to the `paper-autocomplete` (which is not supporting the `description` property yet), and will render different list of selected scopes with the description. See demo for more details. ### Styling `<oauth2-scope-selector>` provides the following custom properties and mixins for styling: Custom property | Description | Default ----------------|-------------|---------- `--oauth2-scope-selector` | Mixin applied to the element | `{}` `--oauth2-scope-selector-label` | Mixin applied to the label element (title of the control) | `{}` `--oauth2-scope-selector-list-item` | Mixin applied to each selected scope item. Consider setting `paper-item` styles for theming. | `{}` ### Theming Use this mixins as a theming option across all ARC elements. Custom property | Description | Default ----------------|-------------|---------- `--icon-button` | Mixin applied to `paper-icon-buttons`. | `{}` `--icon-button-hover` | Mixin applied to `paper-icon-buttons` when hovered. | `{}` `--form-label` | Mixin applied to all labels that are form elements | `{}` @group UI Elements @element oauth2-scope-selector @demo demo/index.html --> <dom-module id="oauth2-scope-selector"> <template> <style> :host { display: block; outline: none; @apply(--oauth2-scope-selector); } .form-label { @apply(--form-label); @apply(--oauth2-scope-selector-label); } .item { /*max-width: calc(100% - 32px);*/ width: calc(100% - 32px); @apply(--oauth2-scope-selector-list-item); } paper-autocomplete { top: 32px; } paper-icon-button { color: var(--hint-trigger-color, rgba(0, 0, 0, 0.54)); transition: color 0.25s linear; @apply(--icon-button); } paper-icon-button:hover { color: var(--hint-trigger-hover-color, rgba(0, 0, 0, 0.78)); @apply(--icon-button-hover); } .scope-item { @apply(--layout-horizontal); @apply(--layout-center); } .scope-display { @apply(--layout-flex); overflow: hidden; @apply(--arc-font-body1); font-size: 16px; } .scope-item[two-line] { margin-bottom: 12px; } .scope-item[two-line] .scope-display { font-weight: 400; } .scope-item-label { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; } .scope-display div[secondary] { font-size: 14px; font-weight: 400; line-height: 20px; color: #737373; } </style> <div class="container"> <label class="form-label">Scopes</label> <paper-input-container no-label-float invalid="[[invalid]]"> <label>Scope value</label> <input is="iron-input" bind-value="{{currentValue}}" on-keydown="_keyDown" id="input" autocomplete="off"/> <paper-icon-button suffix icon="arc:add-circle-outline" on-tap="_appendScope" title="Add scope"></paper-icon-button> <paper-autocomplete target="[[_inputTarget]]" source="[[_normalizeScopes(allowedScopes)]]" on-selected="_suggestionSelected" open-on-focus></paper-input-autocomplete> </paper-input-container> <paper-tooltip for="input" position="bottom">Enter authorization scopes for this API endpoint. Check your provider's documentation for more information about scopes.</paper-tooltip> <section class="scopes-list" role="list"> <template is="dom-repeat" items="[[scopes]]"> <div class="scope-item" two-line$="[[_allowedIsObject]]"> <div class="scope-display"> <div class="scope-item-label">[[item]]</div> <div secondary>[[_computeItemDescription(item)]]</div> </div> <paper-icon-button icon="arc:remove-circle-outline" on-tap="_removeScope"></paper-icon-button> </div> </template> </div> </div> <paper-toast text="Enter scope value to add a scope."></paper-toast> <paper-toast dissalowed text="You can't enter this scope. Use one of the provided scopes."></paper-toast> </template> <script> Polymer({ is: 'oauth2-scope-selector', behaviors: [ Polymer.IronControlState, Polymer.IronFormElementBehavior, Polymer.IronValidatableBehavior ], properties: { /** * List of scopes entered by the user. It can be used it pre-select scopes * by providing an array with scope values. */ scopes: { type: Array, value: function() { return []; }, notify: true }, /** * Current value entered by the user. This is not a scope and it is not * yet in the scopes list. User has to accept the scope before it become * available in the scopes list. */ currentValue: String, // Target for `paper-autocomplete` _inputTarget: { type: HTMLElement, value: function() { return this.$$('input[is="iron-input"]'); } }, /** * List of available scopes. * It can be either list of string or list of object. If this is the * list of object then this expects to each object contain a `label` * and `description` keys. * * ### Example * ``` * { * 'label': 'user', * 'description': 'Grants read/write access to profile info only. ' * } * ``` * When the description is provided it will be displayed below the name * of the scope. */ allowedScopes: Array, // If true then scopes that are in the `allowedScopes` list will be // allowed to be add. preventCustomScopes: Boolean, // Computed value, true if the `allowedScopes` is a list of objects _allowedIsObject: { type: Boolean, value: false, computed: '_computeAllowedInputType(allowedScopes)' }, /** * Set to true to auto-validate the input value when it changes. */ autoValidate: { type: Boolean, value: false }, _oldTabIndex: { type: Number, value: -1 } }, hostAttributes: { 'tabIndex': '-1' }, observers: ['_handleAutoValidate(autoValidate, scopes.*)'], get value() { return this.scopes; }, set value(scopes) { this.scopes = scopes; }, // Add currently entered scope value to the scopes list. _appendScope: function() { var value = this.currentValue; if (!value) { this.$$('paper-toast').opened = true; return; } this.currentValue = ''; this.append(value); }, // Remove scope button click handler _removeScope: function(e) { var item = this.$$('template[is="dom-repeat"]').itemForElement(e.target); if (!item) { return; } var all = this.scopes; var index = all.indexOf(item); if (index === -1) { return; } this.splice('scopes', index, 1); }, // Handler for the `paper-autocomplete` selected event. _suggestionSelected: function(e, detail) { e.preventDefault(); var scope = detail.value; this.append(scope); this.async(function() { this.currentValue = ''; }, 1); }, /** * Adds a scope to the list. The same as pushing item to the `scopes` * array but it will check for duplicates first. */ append: function(scope) { var scopeValue = typeof scope === 'string' ? scope : scope.value; var all = this.scopes; var index = all.indexOf(scopeValue); if (index !== -1) { return; } if (this.preventCustomScopes && this.allowedScopes && this.allowedScopes.length) { index = this._findAllowedScopeIndex(scopeValue); if (index === -1) { this.$$('paper-toast[dissalowed]').opened = true; return; } } this.push('scopes', scopeValue); }, /** * Finds an index if the `scope` in the `allowedScopes` list. * * @param {String} scope A scope value (label) to find. * @return {Number} An index of scope or `-1` if not found. */ _findAllowedScopeIndex: function(scope) { var index = -1; var scopes = this.allowedScopes; if (!scopes || !scopes.length || !scope) { return index; } if (this._allowedIsObject) { for (var i = 0, len = scopes.length; i < len; i++) { if (scopes[i].label === scope) { index = i; break; } } } else { index = this.allowedScopes.indexOf(scope); } return index; }, // A handler for the input's key down event. Handles ENTER press. _keyDown: function(e) { if (e.keyCode !== 13) { return; } if (this.$$('paper-autocomplete').opened) { return; } this._appendScope(); this.async(function() { this.currentValue = ''; this.$$('input[is="iron-input"]').focus(); // this.$$('input[is="iron-input"]').bindValue = ''; }, 10); }, // Normalize scopes to use with autocomplete _normalizeScopes: function(scopes) { if (!scopes || !scopes.length) { return undefined; } return scopes.map(function(item) { if (typeof item === 'string') { return item; } return { 'display': item.label, 'value': item.label, }; }); }, /** * Compute function for the _allowedIsObject. Check first item of the * `allowedScopes` array if it is an object (return `true`) or * string (return `false`); */ _computeAllowedInputType: function(allowedScopes) { if (!allowedScopes || !allowedScopes.length) { return false; } var first = allowedScopes[0]; return typeof first !== 'string'; }, /** * Returns a description for the selected scope. * * @return {String} Description of the scope or `` (empty string) if the * item do not exists. */ _computeItemDescription: function(scope) { var index = this._findAllowedScopeIndex(scope); if (index === -1) { return ''; } return this.allowedScopes[index].description; }, /** * Returns false if the element is required and does not have a selection, * and true otherwise. * * @return {boolean} true if `required` is false, or if `required` is true * and the element has a valid selection. */ _getValidity: function() { return this.disabled || !this.required || (this.required && !!(this.scopes && this.scopes.length)); }, _handleAutoValidate: function(autoValidate) { if (autoValidate) { this.invalid = !this._getValidity(); } } }); </script> </dom-module>