Revert "⌨️Add autocomplete widget with command line completion"
This commit is contained in:
@@ -10,8 +10,6 @@
|
|||||||
--bg-dark-color: #000000;
|
--bg-dark-color: #000000;
|
||||||
// Background color
|
// Background color
|
||||||
--bg-color: #121212;
|
--bg-color: #121212;
|
||||||
// Auto-complete color
|
|
||||||
--atc-color: #212121;
|
|
||||||
// Text color
|
// Text color
|
||||||
--fg-color: #FFF;
|
--fg-color: #FFF;
|
||||||
|
|
||||||
@@ -28,8 +26,6 @@
|
|||||||
--bg-dark-color: #ffffff;
|
--bg-dark-color: #ffffff;
|
||||||
// Background color
|
// Background color
|
||||||
--bg-color: #F6F8FA;
|
--bg-color: #F6F8FA;
|
||||||
// Auto-complete color
|
|
||||||
--atc-color: #F1F1F1;
|
|
||||||
// Text color
|
// Text color
|
||||||
--fg-color: #121212;
|
--fg-color: #121212;
|
||||||
|
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="autocomplete-wrapper">
|
|
||||||
<label>
|
|
||||||
<slot />
|
|
||||||
<input type="text"
|
|
||||||
:placeholder="placeholder"
|
|
||||||
v-model="value"
|
|
||||||
@input="updateSuggestions"
|
|
||||||
@keyup="updateSuggestions"
|
|
||||||
@click="updateSuggestions"
|
|
||||||
@keydown="handleKeystroke"
|
|
||||||
ref="acInput"
|
|
||||||
:spellcheck="spellcheck"
|
|
||||||
:autocapitalize="spellcheck"
|
|
||||||
:autocorrect="spellcheck">
|
|
||||||
|
|
||||||
<ul class="suggestions" v-if="suggestions.length > 0 && suggestionsVisible" :style="{ transform: `translate(${suggestionsOffsetLeft}px, 0)` }">
|
|
||||||
<li v-for="(suggestion, index) in suggestions" @click.prevent="forceSuggestion(suggestion)" :class="{ active: currentSuggestionIndex === index }">{{ suggestion }}</li>
|
|
||||||
</ul>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
.autocomplete-wrapper {
|
|
||||||
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
input:focus + ul.suggestions, ul.suggestions:hover {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.suggestions {
|
|
||||||
display: none;
|
|
||||||
background-color: var(--atc-color);
|
|
||||||
position: absolute;
|
|
||||||
top: 90%;
|
|
||||||
margin: 0 4px;
|
|
||||||
left: 0;
|
|
||||||
|
|
||||||
padding: 0;
|
|
||||||
border-radius: 0 0 4px 4px;
|
|
||||||
z-index: 9999;
|
|
||||||
transition: transform 200ms ease-out;
|
|
||||||
|
|
||||||
li {
|
|
||||||
width: 100%;
|
|
||||||
display: block;
|
|
||||||
margin: 5px 0;
|
|
||||||
padding: 10px 10px;
|
|
||||||
font-weight: 700;
|
|
||||||
font-size: 18px;
|
|
||||||
font-family: monospace;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
|
|
||||||
&:hover, &.active {
|
|
||||||
background-color: var(--ac-color);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
const KEY_TAB = 9;
|
|
||||||
const KEY_ESC = 27;
|
|
||||||
|
|
||||||
const KEY_ARROW_UP = 38;
|
|
||||||
const KEY_ARROW_DOWN = 40;
|
|
||||||
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
spellcheck: {
|
|
||||||
type: Boolean,
|
|
||||||
default: true,
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
|
|
||||||
placeholder: {
|
|
||||||
type: String,
|
|
||||||
default: 'Start typing...',
|
|
||||||
required: false
|
|
||||||
},
|
|
||||||
|
|
||||||
source: {
|
|
||||||
type: Array,
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
|
|
||||||
value: {}
|
|
||||||
},
|
|
||||||
|
|
||||||
watch: {
|
|
||||||
value () {
|
|
||||||
this.$emit('input', this.value);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
value: "",
|
|
||||||
|
|
||||||
selectionStart: 0,
|
|
||||||
suggestionsOffsetLeft: 0,
|
|
||||||
currentSuggestionIndex: -1,
|
|
||||||
suggestionsVisible: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
|
||||||
updateSuggestions (event) {
|
|
||||||
// Hide suggestions if ESC pressed.
|
|
||||||
if(event.which && event.which === KEY_ESC){
|
|
||||||
event.preventDefault();
|
|
||||||
this.suggestionsVisible = false;
|
|
||||||
this.currentSuggestionIndex = -1;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// As suggestions is a reactive property, this implicitly
|
|
||||||
// causes suggestions to update.
|
|
||||||
this.selectionStart = this.$refs.acInput.selectionStart;
|
|
||||||
this.suggestionsOffsetLeft = (12 * this.selectionStart);
|
|
||||||
this.suggestionsVisible = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
forceSuggestion (text) {
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
this.value = input + text;
|
|
||||||
|
|
||||||
this.selectionStart = this.value.length;
|
|
||||||
this.suggestionsVisible = true;
|
|
||||||
this.currentSuggestionIndex = -1;
|
|
||||||
},
|
|
||||||
|
|
||||||
handleKeystroke (event) {
|
|
||||||
if(event.which === KEY_ARROW_UP){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.currentSuggestionIndex = this.currentSuggestionIndex - 1 >= 0
|
|
||||||
? this.currentSuggestionIndex - 1
|
|
||||||
: 0;
|
|
||||||
}else if(event.which === KEY_ARROW_DOWN){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
this.currentSuggestionIndex = this.currentSuggestionIndex < this.suggestions.length - 1
|
|
||||||
? this.currentSuggestionIndex + 1
|
|
||||||
: this.suggestions.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(event.which === KEY_TAB){
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
let activeSuggestion = this.suggestions[this.currentSuggestionIndex >= 0 ? this.currentSuggestionIndex : 0];
|
|
||||||
if(activeSuggestion){
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
this.value = input + activeSuggestion;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
computed: {
|
|
||||||
/**
|
|
||||||
* Gets the suggestions list to be displayed under the input box.
|
|
||||||
*
|
|
||||||
* @returns {default.props.source|{type, required}}
|
|
||||||
*/
|
|
||||||
suggestions () {
|
|
||||||
let input = this.value.substring(0, this.selectionStart);
|
|
||||||
|
|
||||||
return this.source.filter((entry) => {
|
|
||||||
return entry.toLowerCase().startsWith(input.toLowerCase())
|
|
||||||
&& input.toLowerCase() !== entry.toLowerCase();
|
|
||||||
})
|
|
||||||
// Cut off the part that's already been typed.
|
|
||||||
.map((entry) => entry.substring(this.selectionStart))
|
|
||||||
// We only want the top 3 suggestions.
|
|
||||||
.slice(0, 3);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
mounted () {
|
|
||||||
this.updateSuggestions({
|
|
||||||
target: this.$refs.acInput
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
7
package-lock.json
generated
7
package-lock.json
generated
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "postwoman",
|
"name": "postwoman",
|
||||||
"version": "0.1.0",
|
"version": "1.0.0",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -10128,11 +10128,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/vue-virtual-scroll-list/-/vue-virtual-scroll-list-1.4.2.tgz",
|
||||||
"integrity": "sha512-jcXl1cYDxGZX+aF9vsUauXWnUkXm8oQxnvLTJ8UMTmMxwzbmlHX7vs0xGDdEej91vJpBNrdNNseWPxboTvI+UA=="
|
"integrity": "sha512-jcXl1cYDxGZX+aF9vsUauXWnUkXm8oQxnvLTJ8UMTmMxwzbmlHX7vs0xGDdEej91vJpBNrdNNseWPxboTvI+UA=="
|
||||||
},
|
},
|
||||||
"vuejs-auto-complete": {
|
|
||||||
"version": "0.9.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/vuejs-auto-complete/-/vuejs-auto-complete-0.9.0.tgz",
|
|
||||||
"integrity": "sha512-7UV3s9bXdnsbGARhHcOuDAszGUsz7JpsFKBfHQuQvo4rfH0yQIru2Rb/x2bWU+m+VW4fS9DKDSYi6tY511QSIA=="
|
|
||||||
},
|
|
||||||
"vuex": {
|
"vuex": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.1.1.tgz",
|
||||||
|
|||||||
@@ -7,9 +7,11 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"predev": "node build.js --dev",
|
"predev": "node build.js --dev",
|
||||||
"dev": "nuxt",
|
"dev": "nuxt",
|
||||||
|
|
||||||
"prebuild": "node build.js",
|
"prebuild": "node build.js",
|
||||||
"build": "nuxt build",
|
"build": "nuxt build",
|
||||||
"start": "nuxt start",
|
"start": "nuxt start",
|
||||||
|
|
||||||
"pregenerate": "node build.js",
|
"pregenerate": "node build.js",
|
||||||
"generate": "nuxt generate"
|
"generate": "nuxt generate"
|
||||||
},
|
},
|
||||||
@@ -18,7 +20,6 @@
|
|||||||
"@nuxtjs/pwa": "^3.0.0-0",
|
"@nuxtjs/pwa": "^3.0.0-0",
|
||||||
"nuxt": "^2.9.2",
|
"nuxt": "^2.9.2",
|
||||||
"vue-virtual-scroll-list": "^1.4.2",
|
"vue-virtual-scroll-list": "^1.4.2",
|
||||||
"vuejs-auto-complete": "^0.9.0",
|
|
||||||
"vuex-persist": "^2.1.0"
|
"vuex-persist": "^2.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -31,12 +31,14 @@
|
|||||||
<pw-section class="blue-dark" label="Request Body" v-if="method === 'POST' || method === 'PUT' || method === 'PATCH'">
|
<pw-section class="blue-dark" label="Request Body" v-if="method === 'POST' || method === 'PUT' || method === 'PATCH'">
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<autocomplete v-model="contentType" :source="validContentTypes" :spellcheck="false">Content Type</autocomplete>
|
<label>Content Type</label>
|
||||||
|
<select v-model="contentType">
|
||||||
|
<option>application/json</option>
|
||||||
|
<option>www-form/urlencoded</option>
|
||||||
|
</select>
|
||||||
<span>
|
<span>
|
||||||
<pw-toggle :on="rawInput" @change="rawInput = !rawInput">
|
<input v-model="rawInput" style="cursor: pointer;" type="checkbox" id="rawInput">
|
||||||
Raw input {{ rawInput ? "enabled" : "disabled" }}
|
<label for="rawInput" style="cursor: pointer;">Raw Input</label>
|
||||||
</pw-toggle>
|
|
||||||
</span>
|
</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@@ -190,11 +192,9 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import autocomplete from '../components/autocomplete';
|
|
||||||
import history from "../components/history";
|
import history from "../components/history";
|
||||||
import section from "../components/section";
|
import section from "../components/section";
|
||||||
import textareaAutoHeight from "../directives/textareaAutoHeight";
|
import textareaAutoHeight from "../directives/textareaAutoHeight";
|
||||||
import toggle from "../components/toggle";
|
|
||||||
|
|
||||||
const statusCategories = [{
|
const statusCategories = [{
|
||||||
name: 'informational',
|
name: 'informational',
|
||||||
@@ -248,13 +248,10 @@
|
|||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
'pw-section': section,
|
'pw-section': section,
|
||||||
'pw-toggle': toggle,
|
history
|
||||||
history,
|
|
||||||
autocomplete
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
url: 'https://reqres.in',
|
url: 'https://reqres.in',
|
||||||
auth: 'None',
|
auth: 'None',
|
||||||
@@ -273,33 +270,7 @@
|
|||||||
headers: '',
|
headers: '',
|
||||||
body: ''
|
body: ''
|
||||||
},
|
},
|
||||||
previewEnabled: false,
|
previewEnabled: false
|
||||||
|
|
||||||
/**
|
|
||||||
* These are content types that can be automatically
|
|
||||||
* serialized by postwoman.
|
|
||||||
*/
|
|
||||||
knownContentTypes: [
|
|
||||||
'application/json',
|
|
||||||
'application/x-www-form-urlencoded'
|
|
||||||
],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* These are a list of Content Types known to Postwoman.
|
|
||||||
*/
|
|
||||||
validContentTypes: [
|
|
||||||
'application/json',
|
|
||||||
'application/hal+json',
|
|
||||||
'application/xml',
|
|
||||||
'application/x-www-form-urlencoded',
|
|
||||||
'text/html',
|
|
||||||
'text/plain'
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
contentType(val) {
|
|
||||||
this.rawInput = !this.knownContentTypes.includes(val);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
@@ -321,7 +292,7 @@
|
|||||||
} = this
|
} = this
|
||||||
if (this.contentType === 'application/json') {
|
if (this.contentType === 'application/json') {
|
||||||
try {
|
try {
|
||||||
const obj = JSON.parse(`{${bodyParams.filter(({key}) => !!key).map(({key, value}) => `
|
const obj = JSON.parse(`{${bodyParams.filter(({ key }) => !!key).map(({ key, value }) => `
|
||||||
"${key}": "${value}"
|
"${key}": "${value}"
|
||||||
`).join()}}`)
|
`).join()}}`)
|
||||||
return JSON.stringify(obj)
|
return JSON.stringify(obj)
|
||||||
@@ -412,7 +383,7 @@
|
|||||||
requestBody = this.rawInput ? this.rawParams : this.rawRequestBody;
|
requestBody = this.rawInput ? this.rawParams : this.rawRequestBody;
|
||||||
|
|
||||||
Object.assign(headers, {
|
Object.assign(headers, {
|
||||||
//'Content-Length': requestBody.length,
|
'Content-Length': requestBody.length,
|
||||||
'Content-Type': `${this.contentType}; charset=utf-8`
|
'Content-Type': `${this.contentType}; charset=utf-8`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -437,7 +408,7 @@
|
|||||||
url: this.url + this.path + this.queryString,
|
url: this.url + this.path + this.queryString,
|
||||||
auth,
|
auth,
|
||||||
headers,
|
headers,
|
||||||
data: requestBody.toString()
|
data: requestBody
|
||||||
});
|
});
|
||||||
|
|
||||||
(() => {
|
(() => {
|
||||||
@@ -561,23 +532,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setRouteQueryState() {
|
setRouteQueryState () {
|
||||||
const flat = key => this[key] !== '' ? `${key}=${this[key]}&` : ''
|
const flat = key => this[key] !== '' ? `${key}=${this[key]}&` : ''
|
||||||
const deep = key => {
|
const deep = key => {
|
||||||
const haveItems = [...this[key]].length
|
const haveItems = [...this[key]].length
|
||||||
if (haveItems && this[key]['value'] !== '') {
|
if(haveItems && this[key]['value'] !== '') {
|
||||||
return `${key}=${JSON.stringify(this[key])}&`
|
return `${key}=${JSON.stringify(this[key])}&`
|
||||||
} else return ''
|
|
||||||
}
|
}
|
||||||
let flats = ['method', 'url', 'path', 'auth', 'httpUser', 'httpPassword', 'bearerToken', 'contentType'].map(item => flat(item))
|
else return ''
|
||||||
|
}
|
||||||
|
let flats = [ 'method', 'url', 'path', 'auth', 'httpUser', 'httpPassword', 'bearerToken','contentType'].map(item => flat(item))
|
||||||
let deeps = ['headers', 'params', 'bodyParams'].map(item => deep(item))
|
let deeps = ['headers', 'params', 'bodyParams'].map(item => deep(item))
|
||||||
this.$router.replace('/?' + flats.concat(deeps).join('').slice(0, -1))
|
this.$router.replace('/?'+ flats.concat(deeps).join('').slice(0,-1))
|
||||||
},
|
},
|
||||||
setRouteQueries(queries) {
|
setRouteQueries(queries) {
|
||||||
if (typeof (queries) !== 'object') throw new Error('Route query parameters must be a Object')
|
if(typeof(queries) !== 'object') throw new Error('Route query parameters must be a Object')
|
||||||
for (const key in queries) {
|
for (const key in queries) {
|
||||||
if (key === 'headers' || key === 'params' || key === 'bodyParams') this[key] = JSON.parse(queries[key])
|
if(key === 'headers' || key === 'params' || key ==='bodyParams') this[key] = JSON.parse(queries[key])
|
||||||
else if (typeof (this[key]) === 'string') this[key] = queries[key];
|
else if (typeof(this[key]) === 'string') this[key] = queries[key];
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
observeRequestButton() {
|
observeRequestButton() {
|
||||||
@@ -587,7 +559,7 @@
|
|||||||
entries.forEach(entry => {
|
entries.forEach(entry => {
|
||||||
sendButtonElement.classList.toggle('show');
|
sendButtonElement.classList.toggle('show');
|
||||||
});
|
});
|
||||||
}, {threshold: 1});
|
}, { threshold: 1 });
|
||||||
|
|
||||||
observer.observe(requestElement);
|
observer.observe(requestElement);
|
||||||
}
|
}
|
||||||
@@ -612,7 +584,6 @@
|
|||||||
], val => {
|
], val => {
|
||||||
this.setRouteQueryState()
|
this.setRouteQueryState()
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user