mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2025-11-03 04:50:14 +08:00
feature (form): form pages
This commit is contained in:
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import { Input, Textarea, Select, Enabler } from './';
|
||||
import { FormObjToJSON, bcrypt_password, format } from '../helpers/';
|
||||
import { FormObjToJSON, bcrypt_password, format, autocomplete } from '../helpers/';
|
||||
|
||||
import "./formbuilder.scss";
|
||||
|
||||
@ -122,7 +122,34 @@ const FormElement = (props) => {
|
||||
}
|
||||
props.onChange(value);
|
||||
};
|
||||
$input = ( <Input onChange={(e) => onTextChange(e.target.value)} {...id} name={struct.label} type="text" value={struct.value || ""} placeholder={struct.placeholder} readOnly={struct.readonly}/> );
|
||||
|
||||
const list_id = struct.datalist ? "list_"+Math.random() : null;
|
||||
$input = ( <Input list={list_id} onChange={(e) => onTextChange(e.target.value)} {...id} name={struct.label} type="text" value={struct.value || ""} placeholder={struct.placeholder} readOnly={struct.readonly}/> );
|
||||
if(list_id != null){
|
||||
const filtered = function(multi, datalist, currentValue){
|
||||
if(multi !== true || currentValue == null) return datalist;
|
||||
|
||||
return autocomplete(
|
||||
currentValue
|
||||
.split(",")
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => t),
|
||||
datalist
|
||||
);
|
||||
};
|
||||
$input = (
|
||||
<span>
|
||||
{ $input }
|
||||
<datalist id={list_id}>
|
||||
{
|
||||
filtered(struct.multi, struct.datalist, struct.value).map((item,i) => {
|
||||
return ( <option key={i} value={item} /> );
|
||||
})
|
||||
}
|
||||
</datalist>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
break;
|
||||
case "number":
|
||||
const onNumberChange = (value) => {
|
||||
|
||||
@ -7,6 +7,7 @@
|
||||
margin-bottom: 10px;
|
||||
opacity: 0.25;
|
||||
font-size: 0.95em;
|
||||
line-height: 0.95em;
|
||||
}
|
||||
|
||||
input::placeholder, textarea::placeholder{
|
||||
|
||||
@ -15,3 +15,13 @@ export function copyToClipboard (str){
|
||||
document.execCommand("copy");
|
||||
$input.remove();
|
||||
}
|
||||
|
||||
export function format(str = ""){
|
||||
if(str.length === 0) return str;
|
||||
return str.split("_")
|
||||
.map((word, index) => {
|
||||
if(index != 0) return word;
|
||||
return word[0].toUpperCase() + word.substring(1);
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
@ -52,3 +52,48 @@ export function createFormBackend(backend_available, backend_data){
|
||||
obj[backend_data.type] = template;
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* return a new list of autocompletion candidates considering the current input
|
||||
*/
|
||||
export function autocomplete(values, list) {
|
||||
if(values.length === 0) return list;
|
||||
let candidates_input = [],
|
||||
candidates_output = [];
|
||||
|
||||
for(let i=0; i<list.length; i++){
|
||||
const last_value = values[values.length - 1];
|
||||
|
||||
if(list[i].indexOf(last_value) === 0){
|
||||
let tmp = JSON.parse(JSON.stringify(values))
|
||||
tmp[values.length - 1] = list[i];
|
||||
if(list[i] === last_value){
|
||||
candidates_input = [tmp];
|
||||
} else {
|
||||
candidates_input.push(tmp)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if(values.indexOf(list[i]) === -1){
|
||||
candidates_output.push(list[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(candidates_input.length === 0){
|
||||
candidates_input = [values]
|
||||
}
|
||||
candidates_output = [""].concat(candidates_output);
|
||||
|
||||
if(candidates_input.length > 1) {
|
||||
return candidates_input.map((candidate) => {
|
||||
return candidate.join(", ");
|
||||
});
|
||||
}
|
||||
return candidates_output.map((candidate, idx) => {
|
||||
return candidates_input[0]
|
||||
.concat(candidate)
|
||||
.join(", ")
|
||||
.replace(/\,\s?$/, "");
|
||||
});
|
||||
}
|
||||
|
||||
@ -11,8 +11,7 @@ export { invalidate, http_get, http_post, http_delete, http_options } from './aj
|
||||
export { prompt, alert, confirm } from './popup';
|
||||
export { notify } from './notify';
|
||||
export { gid, randomString } from './random';
|
||||
export { leftPad, copyToClipboard } from './common';
|
||||
export { leftPad, format, copyToClipboard } from './common';
|
||||
export { getMimeType } from './mimetype';
|
||||
export { settings_get, settings_put } from './settings';
|
||||
export { FormObjToJSON, createFormBackend } from './form';
|
||||
export { format } from './text';
|
||||
export { FormObjToJSON, createFormBackend, autocomplete } from './form';
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
export function format(str = ""){
|
||||
if(str.length === 0) return str;
|
||||
return str.split("_")
|
||||
.map((word, index) => {
|
||||
|
||||
if(index != 0) return word;
|
||||
return word[0].toUpperCase() + word.substring(1);
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
@ -341,6 +341,7 @@ const DateTime = (props) => {
|
||||
|
||||
const FileSize = (props) => {
|
||||
function displaySize(bytes){
|
||||
if(bytes === -1) return "";
|
||||
if(Number.isNaN(bytes) || bytes === undefined){
|
||||
return "";
|
||||
}else if(bytes < 1024){
|
||||
|
||||
@ -7,10 +7,7 @@ export class FormViewer extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {
|
||||
form: {
|
||||
"test": {label: "test", type: "text", "value": null, default: "polo", placeholder: "test"},
|
||||
"something": {label: "test", type: "text", "value": null, default: "polo", placeholder: "test"}
|
||||
}
|
||||
form: {}
|
||||
};
|
||||
}
|
||||
|
||||
@ -23,13 +20,12 @@ export class FormViewer extends React.Component {
|
||||
}
|
||||
|
||||
render(){
|
||||
console.log(this.state.form);
|
||||
return (
|
||||
<div className="component_formviewer">
|
||||
<MenuBar title={this.props.filename} download={this.props.data} />
|
||||
<div className="formviewer_container">
|
||||
<Container>
|
||||
<form className="sticky">
|
||||
<form className="sticky box">
|
||||
<FormBuilder form={this.state.form} onChange={this.onChange.bind(this)} render={ ($input, props, struct, onChange) => {
|
||||
return (
|
||||
<label className={"no-select"}>
|
||||
@ -41,6 +37,12 @@ export class FormViewer extends React.Component {
|
||||
{ $input }
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="nothing"></span>
|
||||
<div style={{width: '100%'}}>
|
||||
{ struct.description ? (<div className="description">{struct.description}</div>) : null }
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
}}/>
|
||||
|
||||
@ -13,18 +13,43 @@
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
|
||||
.formbuilder{
|
||||
label.no-select > div {
|
||||
display: flex;
|
||||
line-height: 30px;
|
||||
.box{
|
||||
padding: 25px 20px;
|
||||
border-radius: 2px;
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
width: 150px;
|
||||
max-width: 150px;
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
color: var(--emphasis);
|
||||
|
||||
.formbuilder{
|
||||
> div {
|
||||
margin-bottom: 10px;
|
||||
@media screen and (max-width: 470px) { margin-bottom: 20px; }
|
||||
|
||||
|
||||
label.no-select > div {
|
||||
display: flex;
|
||||
line-height: 30px;
|
||||
@media screen and (max-width: 470px) {
|
||||
display: block;
|
||||
line-height: inherit;
|
||||
span.nothing{ position: absolute; }
|
||||
}
|
||||
|
||||
> span {
|
||||
display: inline-block;
|
||||
width: 160px;
|
||||
max-width: 160px;
|
||||
text-align: right;
|
||||
padding-right: 15px;
|
||||
color: var(--emphasis);
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
|
||||
@media screen and (max-width: 470px) {
|
||||
text-align: left;
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -42,6 +42,9 @@ type FormElement struct {
|
||||
ReadOnly bool `json:"readonly"`
|
||||
Default interface{} `json:"default"`
|
||||
Value interface{} `json:"value"`
|
||||
MultiValue bool `json:"multi,omitempty"`
|
||||
Datalist []string `json:"datalist,omitempty"`
|
||||
Order int `json:"-"`
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
||||
Reference in New Issue
Block a user