Fixed tabindex and add support for input suggestion to Connector Wizard
This commit is contained in:
@@ -489,6 +489,20 @@ body {
|
||||
color: #e9a;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field.highlight > input[type="text"],
|
||||
.form1 > fieldset .field.highlight > input[type="file"],
|
||||
.form1 > fieldset .field.highlight > input[type="email"],
|
||||
.form1 > fieldset .field.highlight > input[type="number"],
|
||||
.form1 > fieldset .field.highlight > input[type="search"],
|
||||
.form1 > fieldset .field.highlight > input[type="tel"],
|
||||
.form1 > fieldset .field.highlight > input[type="url"],
|
||||
.form1 > fieldset .field.highlight > input[type="password"],
|
||||
.form1 > fieldset .field.highlight > select,
|
||||
.form1 > fieldset .field.highlight > textarea {
|
||||
background: #666;
|
||||
border-bottom: 2px solid #ccc;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field.error > input[type="text"],
|
||||
.form1 > fieldset .field.error > input[type="file"],
|
||||
.form1 > fieldset .field.error > input[type="email"],
|
||||
@@ -552,6 +566,7 @@ body {
|
||||
border-style: solid;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > button:focus,
|
||||
.form1 > fieldset .field > button:hover {
|
||||
border-color: #a56;
|
||||
background: #c78;
|
||||
@@ -562,10 +577,6 @@ body {
|
||||
border-color: #a56;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > button:focus {
|
||||
outline: 1px dotted #eee;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > button.secondary {
|
||||
float: right;
|
||||
background: transparent;
|
||||
@@ -573,6 +584,7 @@ body {
|
||||
border-color: #eee;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > button.secondary:focus,
|
||||
.form1 > fieldset .field > button.secondary:hover {
|
||||
border-color: #ddd;
|
||||
color: #ddd;
|
||||
@@ -582,3 +594,79 @@ body {
|
||||
border-color: #666;
|
||||
color: #666;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions {
|
||||
background: #262626;
|
||||
box-shadow: 0 0 3px #0006;
|
||||
border: 1px solid #666;
|
||||
position: relative;
|
||||
margin: 3px;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions::before,
|
||||
.form1 > fieldset .field > ul.input-suggestions::after {
|
||||
top: -5px;
|
||||
left: 5px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
content: " ";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #262626;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions::after {
|
||||
top: -6px;
|
||||
z-index: 0;
|
||||
background: #666;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
border-bottom: 1px solid #222;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li:hover,
|
||||
.form1 > fieldset .field > ul.input-suggestions > li.current {
|
||||
background: #555;
|
||||
border-bottom: 1px solid #555;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li:first-child:hover::before,
|
||||
.form1
|
||||
> fieldset
|
||||
.field
|
||||
> ul.input-suggestions
|
||||
> li.current:first-child::before {
|
||||
top: -6px;
|
||||
position: absolute;
|
||||
z-index: 0;
|
||||
left: 5px;
|
||||
display: block;
|
||||
content: " ";
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
background: #555;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li > .sugt-title {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.form1 > fieldset .field > ul.input-suggestions > li > .sugt-value {
|
||||
color: #fdd;
|
||||
font-size: 0.9em;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
v-for="(field, key) in current.fields"
|
||||
:key="key"
|
||||
class="field"
|
||||
:class="{ error: field.error.length > 0 }"
|
||||
:class="{ error: field.error.length > 0, highlight: field.highlighted }"
|
||||
>
|
||||
{{ field.field.name }}
|
||||
|
||||
@@ -74,8 +74,13 @@
|
||||
:name="field.field.name"
|
||||
:placeholder="field.field.example"
|
||||
:autofocus="field.autofocus"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@keydown="keydown($event, key, field)"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
/>
|
||||
|
||||
<input
|
||||
@@ -87,18 +92,28 @@
|
||||
:name="field.field.name"
|
||||
:placeholder="field.field.example"
|
||||
:autofocus="field.autofocus"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
/>
|
||||
|
||||
<input
|
||||
v-if="field.field.type === 'checkbox'"
|
||||
v-model="field.field.value"
|
||||
v-focus="field.autofocus"
|
||||
type="checkbox"
|
||||
autocomplete="off"
|
||||
:name="field.field.name"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
:autofocus="field.autofocus"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
/>
|
||||
|
||||
<textarea
|
||||
@@ -109,42 +124,56 @@
|
||||
:placeholder="field.field.example"
|
||||
:name="field.field.name"
|
||||
:autofocus="field.autofocus"
|
||||
@input="verify(key, field, false)"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@keydown="keydown(key, field)"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@keyup="expandTextarea"
|
||||
@change="verify(key, field, true)"
|
||||
@change="changed(key, field, true)"
|
||||
></textarea>
|
||||
|
||||
<input
|
||||
v-if="field.field.type === 'textfile'"
|
||||
v-focus="field.autofocus"
|
||||
type="file"
|
||||
autocomplete="off"
|
||||
:placeholder="field.field.example"
|
||||
:name="field.field.name + '-file'"
|
||||
:autofocus="field.autofocus"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@change="importFile($event.target, field)"
|
||||
/>
|
||||
<input
|
||||
v-if="field.field.type === 'textfile'"
|
||||
v-model="field.field.value"
|
||||
v-focus="field.autofocus"
|
||||
type="text"
|
||||
autocomplete="off"
|
||||
:name="field.field.name"
|
||||
:placeholder="field.field.example"
|
||||
:autofocus="field.autofocus"
|
||||
style="display: none"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
/>
|
||||
|
||||
<select
|
||||
v-if="field.field.type === 'select'"
|
||||
v-model="field.field.value"
|
||||
v-focus="field.autofocus"
|
||||
autocomplete="off"
|
||||
:name="field.field.name"
|
||||
:autofocus="field.autofocus"
|
||||
:value="field.field.value"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
:tabindex="field.tabIndex"
|
||||
:disabled="field.field.readonly"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
>
|
||||
<option
|
||||
v-for="(option, oKey) in field.field.example.split(',')"
|
||||
@@ -169,19 +198,46 @@
|
||||
>
|
||||
<input
|
||||
v-model="field.field.value"
|
||||
v-focus="field.autofocus && oKey === 0"
|
||||
type="radio"
|
||||
autocomplete="off"
|
||||
:name="field.field.name"
|
||||
:autofocus="field.autofocus && oKey === 0"
|
||||
:value="option"
|
||||
:checked="field.field.value === option"
|
||||
:aria-checked="field.field.value === option"
|
||||
@input="verify(key, field, false)"
|
||||
@change="verify(key, field, true)"
|
||||
:tabindex="field.nextSubTabIndex(oKey)"
|
||||
:disabled="field.field.readonly"
|
||||
@focus="focus(key, field, true)"
|
||||
@blur="focus(key, field, false)"
|
||||
@input="changed(key, field, false)"
|
||||
@change="changed(key, field, true)"
|
||||
/>
|
||||
{{ option }}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<ul
|
||||
v-if="field.suggestion.suggestions.length > 0"
|
||||
class="input-suggestions lst-nostyle"
|
||||
@mouseenter="field.holdSuggestions(true)"
|
||||
@mouseleave="field.holdSuggestions(false)"
|
||||
>
|
||||
<li
|
||||
v-for="(suggestion, sKey) in field.suggestion.suggestions"
|
||||
:key="sKey"
|
||||
:class="{ current: sKey === field.suggestion.selected }"
|
||||
@click="clickInputSuggestion(key, field, sKey)"
|
||||
>
|
||||
<div class="sugt-title">
|
||||
{{ suggestion.title }}
|
||||
</div>
|
||||
<div class="sugt-value">
|
||||
{{ suggestion.value }}
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div v-if="field.error.length > 0" class="error">{{ field.error }}</div>
|
||||
<div v-else-if="field.message.length > 0" class="message">
|
||||
{{ field.message }}
|
||||
@@ -196,8 +252,11 @@
|
||||
<div class="field">
|
||||
<button
|
||||
v-if="current.submittable"
|
||||
v-focus="submitterTabIndex === 1"
|
||||
type="submit"
|
||||
:disabled="current.submitting || disabled"
|
||||
:tabindex="submitterTabIndex"
|
||||
:autofocus="submitterTabIndex === 1"
|
||||
@click="submitAndGetNext"
|
||||
>
|
||||
{{ current.actionText }}
|
||||
@@ -205,6 +264,7 @@
|
||||
<button
|
||||
v-if="current.cancellable"
|
||||
:disabled="current.submitting || disabled"
|
||||
:tabindex="submitterTabIndex + 1"
|
||||
class="secondary"
|
||||
@click="cancelAndGetNext"
|
||||
>
|
||||
@@ -227,24 +287,16 @@
|
||||
<script>
|
||||
import "./connector.css";
|
||||
import * as command from "../commands/commands.js";
|
||||
import * as fieldBuilder from "./connector_field_builder.js";
|
||||
|
||||
const preloaderIDPrefix = "connector-resource-preload-control-";
|
||||
|
||||
function buildField(i, field) {
|
||||
return {
|
||||
verified: false,
|
||||
inputted: false,
|
||||
error: "",
|
||||
message: "",
|
||||
field: field,
|
||||
autofocus: i == 0
|
||||
};
|
||||
}
|
||||
const hightlightClearTimeout = 1000;
|
||||
|
||||
function buildEmptyCurrent() {
|
||||
return {
|
||||
data: null,
|
||||
alert: false,
|
||||
clearHightlightTimeout: null,
|
||||
title: "",
|
||||
message: "",
|
||||
fields: [],
|
||||
@@ -279,6 +331,8 @@ export default {
|
||||
currentConnectorCloseWait: null,
|
||||
current: buildEmptyCurrent(),
|
||||
preloaderIDName: "",
|
||||
fieldValueBackup: [],
|
||||
submitterTabIndex: 1,
|
||||
working: false,
|
||||
disabled: false,
|
||||
cancelled: false
|
||||
@@ -335,14 +389,21 @@ export default {
|
||||
this.current.type = next.type();
|
||||
this.current.data = next.data();
|
||||
|
||||
let fields = null,
|
||||
tabIndex = 1;
|
||||
|
||||
switch (this.current.type) {
|
||||
case command.NEXT_PROMPT:
|
||||
let fields = this.current.data.inputs();
|
||||
fields = this.current.data.inputs();
|
||||
|
||||
for (let i in fields) {
|
||||
this.current.fields.push(buildField(i, fields[i]));
|
||||
for (let i = 0; i < fields.length; i++) {
|
||||
const f = fieldBuilder.build(tabIndex, i, fields[i]);
|
||||
|
||||
this.current.fields.push(f);
|
||||
tabIndex = f.nextTabIndex();
|
||||
}
|
||||
|
||||
this.submitterTabIndex = tabIndex > 0 ? tabIndex : 1;
|
||||
this.current.actionText = this.current.data.actionText();
|
||||
this.current.submittable = true;
|
||||
this.current.alert = true;
|
||||
@@ -404,7 +465,11 @@ export default {
|
||||
|
||||
this.getConnector().wizard.close();
|
||||
|
||||
try {
|
||||
await waiter;
|
||||
} catch (e) {
|
||||
// Do nothing
|
||||
}
|
||||
},
|
||||
runWizard() {
|
||||
if (this.currentConnectorCloseWait !== null) {
|
||||
@@ -438,7 +503,7 @@ export default {
|
||||
getFieldValues() {
|
||||
let mod = {};
|
||||
|
||||
for (let i in this.current.fields) {
|
||||
for (let i = 0; i < this.current.fields.length; i++) {
|
||||
mod[this.current.fields[i].field.name] = this.current.fields[
|
||||
i
|
||||
].field.value;
|
||||
@@ -446,6 +511,45 @@ export default {
|
||||
|
||||
return mod;
|
||||
},
|
||||
createFieldValueBackup() {
|
||||
let backup = [];
|
||||
|
||||
for (let i = 0; i < this.current.fields.length; i++) {
|
||||
backup.push(this.current.fields[i].field.value);
|
||||
}
|
||||
|
||||
this.fieldValueBackup = backup;
|
||||
},
|
||||
clearFieldValueBackup() {
|
||||
this.fieldValueBackup = [];
|
||||
},
|
||||
clearFieldHighlights() {
|
||||
for (let i = 0; i < this.current.fields.length; i++) {
|
||||
this.current.fields[i].highlighted = false;
|
||||
}
|
||||
},
|
||||
delayedClearFieldHighlights(timeout) {
|
||||
const self = this;
|
||||
|
||||
if (self.clearHightlightTimeout === null) {
|
||||
clearTimeout(self.clearHightlightTimeout);
|
||||
self.clearHightlightTimeout = null;
|
||||
}
|
||||
|
||||
self.clearHightlightTimeout = setTimeout(() => {
|
||||
self.clearHightlightTimeout = null;
|
||||
self.clearFieldHighlights();
|
||||
}, timeout);
|
||||
},
|
||||
restoreFieldValuesFromBackup(except) {
|
||||
for (let i = 0; i < this.fieldValueBackup.length; i++) {
|
||||
if (except === i) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.current.fields[i].field.value = this.fieldValueBackup[i];
|
||||
}
|
||||
},
|
||||
expandTextarea(event) {
|
||||
event.target.style.overflowY = "hidden";
|
||||
event.target.style.height = "";
|
||||
@@ -484,7 +588,7 @@ export default {
|
||||
verify(key, field, force) {
|
||||
try {
|
||||
field.message = "" + field.field.verify(field.field.value);
|
||||
field.inputted = true;
|
||||
field.modified = true;
|
||||
field.verified = true;
|
||||
field.error = "";
|
||||
} catch (e) {
|
||||
@@ -492,27 +596,27 @@ export default {
|
||||
field.message = "";
|
||||
field.verified = false;
|
||||
|
||||
if (field.inputted || force) {
|
||||
if (field.modified || force) {
|
||||
field.error = "" + e;
|
||||
}
|
||||
}
|
||||
|
||||
field.highlighted = false;
|
||||
|
||||
if (
|
||||
!field.verified &&
|
||||
(field.inputted || force) &&
|
||||
(field.modified || force) &&
|
||||
field.error.length <= 0
|
||||
) {
|
||||
field.error = "Invalid";
|
||||
}
|
||||
|
||||
this.current.fields[key] = field;
|
||||
|
||||
return field.verified;
|
||||
},
|
||||
verifyAll() {
|
||||
let verified = true;
|
||||
|
||||
for (let i in this.current.fields) {
|
||||
for (let i = 0; i < this.current.fields.length; i++) {
|
||||
if (this.verify(i, this.current.fields[i], true)) {
|
||||
continue;
|
||||
}
|
||||
@@ -522,6 +626,157 @@ export default {
|
||||
|
||||
return verified;
|
||||
},
|
||||
focus(key, field, focused) {
|
||||
field.highlighted = false;
|
||||
|
||||
if (!focused) {
|
||||
// Don't reset a holding field
|
||||
if (!field.inputted) {
|
||||
field.resetSuggestions(false);
|
||||
} else if (field.resetSuggestions(false)) {
|
||||
this.clickInputSuggestion(
|
||||
key,
|
||||
field,
|
||||
field.selectedSuggestionIndex()
|
||||
);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.createFieldValueBackup();
|
||||
field.reloadSuggestions();
|
||||
},
|
||||
applySuggestion(key, field, suggestion) {
|
||||
this.restoreFieldValuesFromBackup(-1);
|
||||
|
||||
field.field.value = suggestion.value;
|
||||
|
||||
for (let i = 0; i < this.current.fields.length; i++) {
|
||||
this.current.fields[i].highlighted = false;
|
||||
|
||||
if (
|
||||
i === key ||
|
||||
this.current.fields[i].inputted ||
|
||||
this.current.fields[i].field.readonly
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof suggestion.fields[this.current.fields[i].field.name] ===
|
||||
"undefined"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.current.fields[i].field.value =
|
||||
suggestion.fields[this.current.fields[i].field.name];
|
||||
|
||||
if (!this.verify(i, this.current.fields[i], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
this.current.fields[i].highlighted = true;
|
||||
}
|
||||
},
|
||||
applySuggestionAndVerify(key, field, force, suggestion) {
|
||||
field.inputted = true;
|
||||
|
||||
this.applySuggestion(key, field, suggestion);
|
||||
|
||||
return this.verify(key, field, force);
|
||||
},
|
||||
changed(key, field, force) {
|
||||
this.createFieldValueBackup();
|
||||
|
||||
field.highlighted = false;
|
||||
field.inputted = true;
|
||||
field.enableInputSuggestionsOnAllInput();
|
||||
field.reloadSuggestions();
|
||||
|
||||
this.verify(key, field, force);
|
||||
},
|
||||
keydown(event, key, field) {
|
||||
switch (event.key) {
|
||||
case "ArrowUp":
|
||||
event.preventDefault();
|
||||
field.moveSuggestionsCursor(true);
|
||||
|
||||
this.applySuggestionAndVerify(
|
||||
key,
|
||||
field,
|
||||
true,
|
||||
field.curentSuggestion()
|
||||
);
|
||||
break;
|
||||
|
||||
case "ArrowDown":
|
||||
event.preventDefault();
|
||||
field.moveSuggestionsCursor(false);
|
||||
|
||||
this.applySuggestionAndVerify(
|
||||
key,
|
||||
field,
|
||||
true,
|
||||
field.curentSuggestion()
|
||||
);
|
||||
break;
|
||||
|
||||
case "Escape":
|
||||
if (!field.suggestionsPending()) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.restoreFieldValuesFromBackup(key);
|
||||
this.clearFieldValueBackup();
|
||||
this.clearFieldHighlights();
|
||||
this.verify(key, field, true);
|
||||
|
||||
field.disableSuggestionsForInput(field.field.value);
|
||||
field.resetSuggestions(true);
|
||||
break;
|
||||
|
||||
case "Enter":
|
||||
if (!field.suggestionsPending()) {
|
||||
return;
|
||||
}
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
this.clickInputSuggestion(
|
||||
key,
|
||||
field,
|
||||
field.selectedSuggestionIndex()
|
||||
);
|
||||
break;
|
||||
}
|
||||
},
|
||||
clickInputSuggestion(key, field, index) {
|
||||
const self = this;
|
||||
|
||||
field.selectSuggestion(index);
|
||||
|
||||
if (
|
||||
self.applySuggestionAndVerify(
|
||||
key,
|
||||
field,
|
||||
true,
|
||||
field.curentSuggestion()
|
||||
)
|
||||
) {
|
||||
field.disableSuggestionsForInput(field.field.value);
|
||||
} else {
|
||||
field.enableInputSuggestionsOnAllInput();
|
||||
}
|
||||
|
||||
field.resetSuggestions(true);
|
||||
|
||||
self.clearFieldValueBackup();
|
||||
self.delayedClearFieldHighlights(hightlightClearTimeout);
|
||||
},
|
||||
async submitAndGetNext() {
|
||||
if (this.current.submitting || this.disabled) {
|
||||
return;
|
||||
|
||||
213
ui/widgets/connector_field_builder.js
Normal file
213
ui/widgets/connector_field_builder.js
Normal file
@@ -0,0 +1,213 @@
|
||||
// Sshwifty - A Web SSH client
|
||||
//
|
||||
// Copyright (C) 2019-2020 Rui NI <nirui@gmx.com>
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as
|
||||
// published by the Free Software Foundation, either version 3 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
function getTabIndex(tabIndex, field) {
|
||||
if (field.readonly) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (field.type) {
|
||||
case "text":
|
||||
case "password":
|
||||
case "checkbox":
|
||||
case "textarea":
|
||||
case "textfile":
|
||||
case "select":
|
||||
case "radio":
|
||||
return tabIndex;
|
||||
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function build(tabIndex, i, field) {
|
||||
return {
|
||||
verified: false,
|
||||
modified: false,
|
||||
inputted: false,
|
||||
highlighted: false,
|
||||
error: "",
|
||||
message: "",
|
||||
field: field,
|
||||
autofocus: tabIndex === 1 && !field.readonly,
|
||||
tabIndex: getTabIndex(tabIndex, field),
|
||||
blockedSuggestionValue: "",
|
||||
blockingSuggestion: false,
|
||||
nextTabIndex() {
|
||||
if (this.field.readonly) {
|
||||
return this.tabIndex;
|
||||
}
|
||||
|
||||
switch (this.field.type) {
|
||||
case "radio":
|
||||
return this.tabIndex + this.field.example.split(",").length;
|
||||
|
||||
default:
|
||||
return this.tabIndex + 1;
|
||||
}
|
||||
},
|
||||
nextSubTabIndex(subIndex) {
|
||||
if (this.field.readonly) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.tabIndex + subIndex;
|
||||
},
|
||||
suggestion: {
|
||||
selected: -1,
|
||||
suggestions: [],
|
||||
orignalValue: "",
|
||||
orignalValueStored: false,
|
||||
holding: false,
|
||||
needsReset: false,
|
||||
reset() {
|
||||
this.selected = -1;
|
||||
this.suggestions = [];
|
||||
this.holding = false;
|
||||
this.needsReset = false;
|
||||
this.clearStored();
|
||||
|
||||
return true;
|
||||
},
|
||||
softReset() {
|
||||
if (this.holding) {
|
||||
this.needsReset = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.reset();
|
||||
},
|
||||
hold(toHold) {
|
||||
this.holding = toHold;
|
||||
|
||||
if (this.holding || !this.needsReset) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.reset();
|
||||
},
|
||||
storeOrignal(val) {
|
||||
if (this.orignalValueStored) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.orignalValue = val;
|
||||
this.orignalValueStored = true;
|
||||
},
|
||||
loadStored(defaultValue) {
|
||||
return this.orignalValueStored ? this.orignalValue : defaultValue;
|
||||
},
|
||||
clearStored() {
|
||||
this.orignalValue = "";
|
||||
this.orignalValueStored = false;
|
||||
},
|
||||
select(index, fieldValue) {
|
||||
if (this.selected < 0) {
|
||||
this.storeOrignal(fieldValue);
|
||||
}
|
||||
|
||||
if (index < -1 || index >= this.suggestions.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.selected = index;
|
||||
},
|
||||
cursorUp(fieldValue) {
|
||||
this.select(this.selected - 1, fieldValue);
|
||||
},
|
||||
cursorDown(fieldValue) {
|
||||
this.select(this.selected + 1, fieldValue);
|
||||
},
|
||||
cursorMove(toUp, fieldValue) {
|
||||
toUp ? this.cursorUp(fieldValue) : this.cursorDown(fieldValue);
|
||||
},
|
||||
reload(fieldValue, suggestions) {
|
||||
this.selected = -1;
|
||||
this.suggestions = [];
|
||||
|
||||
this.clearStored();
|
||||
|
||||
if (suggestions.length === 1 && suggestions[0].value === fieldValue) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let v in suggestions) {
|
||||
this.suggestions.push({
|
||||
title: suggestions[v].title,
|
||||
value: suggestions[v].value,
|
||||
fields: suggestions[v].meta
|
||||
});
|
||||
}
|
||||
},
|
||||
current(defaultValue) {
|
||||
if (this.selected < 0) {
|
||||
return {
|
||||
title: "Input",
|
||||
value: this.loadStored(defaultValue),
|
||||
fields: {}
|
||||
};
|
||||
}
|
||||
|
||||
return this.suggestions[this.selected];
|
||||
}
|
||||
},
|
||||
disableSuggestionsForInput(val) {
|
||||
this.blockedSuggestionValue = val;
|
||||
this.blockingSuggestion = true;
|
||||
},
|
||||
enableInputSuggestionsOnAllInput() {
|
||||
this.blockedSuggestionValue = "";
|
||||
this.blockingSuggestion = false;
|
||||
},
|
||||
suggestionsPending() {
|
||||
return this.suggestion.suggestions.length > 0;
|
||||
},
|
||||
reloadSuggestions() {
|
||||
if (
|
||||
this.blockingSuggestion &&
|
||||
this.field.value === this.blockedSuggestionValue
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.suggestion.reload(
|
||||
this.field.value,
|
||||
this.field.suggestions(this.field.value)
|
||||
);
|
||||
},
|
||||
resetSuggestions(force) {
|
||||
return force ? this.suggestion.reset() : this.suggestion.softReset();
|
||||
},
|
||||
holdSuggestions(toHold) {
|
||||
this.suggestion.hold(toHold);
|
||||
},
|
||||
moveSuggestionsCursor(toUp) {
|
||||
this.suggestion.cursorMove(toUp, this.field.value);
|
||||
},
|
||||
selectSuggestion(index) {
|
||||
this.suggestion.select(index, this.field.value);
|
||||
},
|
||||
curentSuggestion() {
|
||||
return this.suggestion.current(this.field.value);
|
||||
},
|
||||
selectedSuggestionIndex() {
|
||||
return this.suggestion.selected;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user