Commit bbb9f7e9 by Luciano Barletta

terminado

1 parent 031e4964
...@@ -9,7 +9,8 @@ En root se encuentra el controlador que toma el JSON y devuelve la página. El f ...@@ -9,7 +9,8 @@ En root se encuentra el controlador que toma el JSON y devuelve la página. El f
JSON = { JSON = {
'title' : "Título del Formulario", 'title' : "Título del Formulario",
'color' : "Color preferido", 'color' : "Color preferido",
'tabs' : \[Tabs] 'tabs' : \[Tabs],
'send' : "MiUrl.com"
} }
Donde cada Tab es de la forma: Donde cada Tab es de la forma:
...@@ -28,3 +29,14 @@ Campo = { ...@@ -28,3 +29,14 @@ Campo = {
'required' : True|False, 'required' : True|False,
'options' : \["Opción1","Opción2"...] 'options' : \["Opción1","Opción2"...]
} }
Placeholder no es obligatorio. Si required no está será interpretado como False. Options es válido solo en algunos casos pero no causará error.
## <myserver>/login
Formulario especial para login. Se envía solamente la siguiente información.
{
'color' : "Color preferido",
'send' : "MiUrl.com"
}
\ No newline at end of file \ No newline at end of file
...@@ -11,48 +11,27 @@ qwertyuiopasdfghjklzxcvbnm\ ...@@ -11,48 +11,27 @@ qwertyuiopasdfghjklzxcvbnm\
QWERTYUIOPASDFGHJKLZXCVBNM" QWERTYUIOPASDFGHJKLZXCVBNM"
sessions = {} sessions = {}
@app.after_request loginfields = [
def after_request(response): {
# headers permitidos para la conversación "title" : "Usuario",
response.headers.add('Access-Control-Allow-Headers', '\ "type" : "text",
Access-Control-Allow-Methods,\ "required" : True
Access-Control-Allow-Origin,\ },
Content-Type') {
# orígenes permitidos para CORS "title" : "Contraseña",
response.headers.add('Access-Control-Allow-Origin', '*') "type" : "password",
# métodos permitidos "required" : True
response.headers.add('Access-Control-Allow-Methods', 'GET,POST') }
return response ]
def validate(name,psw):
if name == "admin" and psw == "admin":
return True
return False
def token(): @app.route('/datos', methods = ['GET', 'POST'])
result = "" def datos():
i = 0 print(request.json)
while i < TOKEN_LENGHT: return "OK"
char = random.randrange(0,len(TOKEN_STRING))
result += str(TOKEN_STRING[char])
i += 1
return result
@app.route('/login', methods = ['POST']) @app.route('/login', methods = ['GET', 'POST'])
def login(): def login():
data = request.json return render_template("login.html",title="Login",fields=loginfields,color="blue",send="http://192.168.15.119:5000/datos")
if validate(data['name'],data['pass']):
sessions['name'] = token()
return json.dumps({
"error_code" : 0,
"error" : "",
"token" : sessions['name']
})
return json.dumps({
"error_code" : 1,
"error" : "fallo en la validacion",
"token" : None
})
@app.route('/', methods = ['GET', 'POST']) @app.route('/', methods = ['GET', 'POST'])
def main(): def main():
...@@ -68,7 +47,7 @@ def main(): ...@@ -68,7 +47,7 @@ def main():
}, },
{ {
"title" : "mail", "title" : "mail",
"type" : "mail", "type" : "email",
"placeholder" : "ejemplo@gmail.com", "placeholder" : "ejemplo@gmail.com",
} }
] ]
...@@ -79,7 +58,7 @@ def main(): ...@@ -79,7 +58,7 @@ def main():
{ {
"title" : "género", "title" : "género",
"type" : "select", "type" : "select",
"placeholder" : "Gènero", "placeholder" : "Género",
"options" : [ "options" : [
"Hombre", "Hombre",
"Mujer", "Mujer",
...@@ -92,7 +71,6 @@ def main(): ...@@ -92,7 +71,6 @@ def main():
"options" : [ "options" : [
"Hombres", "Hombres",
"Mujeres", "Mujeres",
"#other" "#other"
], ],
"required" : True "required" : True
...@@ -100,11 +78,21 @@ def main(): ...@@ -100,11 +78,21 @@ def main():
] ]
}, },
{ {
"title" : "third", "title" : "Fecha y hora",
"fields" : [] "fields" : [
{
"title" : "Dia",
"type" : "date",
"placeholder" : "2019-12-10"
},
{
"title" : "Hora",
"type" : "time"
}
]
} }
] ]
return render_template("form.html",tabs=data,title="Formulario de Prueba",color="#33aaff") return render_template("form.html",tabs=data,title="Formulario de Prueba",color="#33aaff",send="http://192.168.15.119:5000/datos")
if __name__ == "__main__": if __name__ == "__main__":
app.run("0.0.0.0") app.run("0.0.0.0")
\ No newline at end of file \ No newline at end of file
...@@ -12,17 +12,21 @@ var getDescendantByAttribute = (elem,attr,val) => { ...@@ -12,17 +12,21 @@ var getDescendantByAttribute = (elem,attr,val) => {
}, null); }, null);
} }
function HabilitarTab(bc,tc,n){ function HabilitarTab(tc,n){
if (typeof n != "number") return console.log("El entero es invalido"); if (typeof n != "number") return console.log("El entero es invalido");
for (let it = 0; it < bc.children.length && it < tc.children.length; it++) { for (let it = 0; it < tc.children.length; it++) {
if (it == n) { if (it == n) tc.children[it].style.display = "block";
bc.children[it].classList.add("BotonesActive"); else tc.children[it].style.display = "none";
tc.children[it].style.display = "block";
} else {
bc.children[it].classList.remove("BotonesActive");
tc.children[it].style.display = "none";
} }
}
function HabilitarButton(bc,n){
if (typeof n != "number") return console.log("El entero es invalido");
for (let it = 0; it < bc.children.length; it++) {
if (it == n) bc.children[it].classList.add("BotonesActive");
else bc.children[it].classList.remove("BotonesActive");
} }
} }
...@@ -38,3 +42,90 @@ function Otro(otroselect){ ...@@ -38,3 +42,90 @@ function Otro(otroselect){
else other.style.display = "none"; else other.style.display = "none";
} }
} }
var accessDataContainer = tab => getDescendantByAttribute(tab, "class", "FieldsContainer");
function Boton(tc, url) {
button = document.createElement("button");
button.value = "Enviar";
button.setAttribute("onclick", "LeerYEnviar(document.getElementById('TabsContainer'),'" + url + "')");
button.setAttribute("class","SendButton");
button.innerText = "Enviar";
tc.lastElementChild.children[0].appendChild(button);
}
function NoValido(input,msg){
let tab = getAncestorByAttribute(input,"class","Tabs")
let n = parseInt(tab.id[tab.id.length - 1])
HabilitarTab(document.getElementById('TabsContainer'),n)
HabilitarButton(document.getElementById('BotonesContainer'),n)
input.setCustomValidity(msg)
input.reportValidity()
input.oninput = () => input.setCustomValidity('');
}
function CheckboxValidity(checkboxContainer){
return Array.from(checkboxContainer.children).reduce(
(last,checkbox) => checkbox.className != "Checkbox" ? last : checkbox.lastElementChild.firstElementChild.checked || last,
false
)
}
function GetCheckboxes(field) {
let data = [];
Array.from(field.children).forEach( child => {
if (child.className != "Checkbox") return;
if (child.lastElementChild.firstElementChild.checked) data.push(child.firstElementChild.innerText.replace(/[\n\s\*]*/g,""));
if (data[data.length-1] == "Otro") data[data.length-1] = getAncestorByAttribute(child,"class","FieldInput").lastElementChild.value;
});
return data;
}
function LeerYEnviar(tc,url){
let data = {};
let valid = true;
Array.from(tc.children).forEach( tab =>
Array.from(accessDataContainer(tab).children).forEach( field => {
if (valid == false) return;
if (field.className == "Field") {
let name = getDescendantByAttribute(field,"class","FieldTitle").innerText.replace(/[\n\s\*]*/g,"");
let input = getDescendantByAttribute(field,"class","FieldInput").children[0];
if (input.className == "Checkbox") {
if (CheckboxValidity(input.parentElement) == false) {
valid = false;
NoValido(input.lastElementChild.firstElementChild, "Debe seleccionar al menos una casilla");
}
data[name] = GetCheckboxes(input.parentElement);
}
else if (input.nodeName == "SELECT") {
if (input.checkValidity() == false) {
valid = false;
NoValido(input, "Debe llenar este campo");
}
data[name] = input.selectedOptions[0].value;
if (data[name] == "Otro") data[name] = getAncestorByAttribute(input,"class","FieldInput").lastElementChild.value;
}
else {
if (input.checkValidity() == false) {
valid = false;
if (input.type == "email") NoValido(input, "Mail inválido");
else NoValido(input, "Mail inválido");
}
data[name] = input.value
}
}
})
);
if (valid == false) return;
console.log(data);
http = new XMLHttpRequest();
http.open("POST", url, true);
http.setRequestHeader("Content-Type", "application/json");
http.onload = () => { if (http.status == 200) alert("Enviado con éxito"); };
http.send(JSON.stringify(data));
}
\ No newline at end of file \ No newline at end of file
...@@ -48,7 +48,7 @@ body { ...@@ -48,7 +48,7 @@ body {
} }
.Botones { .Botones {
border-radius: 5px 5px 0px 0px; border-radius: 10px 10px 0px 0px;
background-color: rgb(168, 168, 168); background-color: rgb(168, 168, 168);
border: none; border: none;
border-bottom: 2px solid rgb(120, 120, 120); border-bottom: 2px solid rgb(120, 120, 120);
...@@ -57,7 +57,7 @@ body { ...@@ -57,7 +57,7 @@ body {
.BotonesActive{ .BotonesActive{
background-color: var(--Color); background-color: var(--Color);
height: 105%; height: 110%;
border-bottom: none; border-bottom: none;
} }
...@@ -84,6 +84,7 @@ body { ...@@ -84,6 +84,7 @@ body {
margin-bottom: 2%; margin-bottom: 2%;
min-height: 70%; min-height: 70%;
text-align: center; text-align: center;
position: relative;
} }
.TabTitle { .TabTitle {
...@@ -151,6 +152,13 @@ body { ...@@ -151,6 +152,13 @@ body {
background: rgb(91, 145, 255); background: rgb(91, 145, 255);
} }
.Other {
display: none;
margin-top: 20 !important;
margin-bottom: 20 !important;
margin: auto;
}
.Checkbox { .Checkbox {
width: 46%; width: 46%;
float: left; float: left;
...@@ -178,8 +186,21 @@ body { ...@@ -178,8 +186,21 @@ body {
margin: auto; margin: auto;
} }
.Other { .SendButton {
display: none; position: absolute;
bottom: 5%;
left: 42%;
width: 16%;
height: 30px;
font-size: 15px;
background-color: white;
border-radius: 2px;
border: 2px solid var(--Color);
}
.Required {
font-weight: bold;
color: red;
} }
@media (max-width: 500px) { @media (max-width: 500px) {
......
...@@ -3,8 +3,10 @@ ...@@ -3,8 +3,10 @@
<div class="Field"> <div class="Field">
<div class="FieldTitle"> <div class="FieldTitle">
{{ title|title }} {{ title|title }}
{% if required %} <span class="Required">*</span> {% endif %}
</div> </div>
<div class="FieldInput"> <div class="FieldInput">
{% if type == "select" %} {% if type == "select" %}
<select onchange="Otro(this)" {% if required %} required {% endif %}> <select onchange="Otro(this)" {% if required %} required {% endif %}>
......
...@@ -9,21 +9,20 @@ ...@@ -9,21 +9,20 @@
<title>Generador de Formularios</title> <title>Generador de Formularios</title>
<link rel="icon" href="{{url_for('static',filename='Assets/ICONO ANACSOFT 48 SIN TRASNSF.png')}}" type="image/png"> <link rel="icon" href="{{url_for('static',filename='Assets/ICONO ANACSOFT 48 SIN TRASNSF.png')}}" type="image/png">
</head> </head>
<body onload="HabilitarTab( <body onload="
document.getElementById('BotonesContainer'), HabilitarTab(document.getElementById('TabsContainer'),0),
document.getElementById('TabsContainer'), HabilitarButton(document.getElementById('BotonesContainer'),0),
0 document.documentElement.style.setProperty('--Color','{{ color }}'),
), document.documentElement.style.setProperty('--Color','{{ color }}')"> Boton(document.getElementById('TabsContainer'), '{{ send }}')">
<h1 style="margin: 2% 0% 2% 0; font-size: 5vw;"> {{ title|title }}</h1>
<h1 style="margin: 2% 0% 2% 0; font-size: 5vw;"> {{ title|title }}</h1>
<section id="BotonesContainer" class="BotonesContainer"> <section id="BotonesContainer" class="BotonesContainer">
{% set m = tabs|length %} {% set m = tabs|length %}
{% for i in range(m) %} {% for i in range(m) %}
<button id="Boton{{i}}" class="Botones" style="width: {{ 100/m }}%;" <button id="Boton{{i}}" class="Botones" style="width: {{ 100/m }}%;"
onclick="HabilitarTab( onclick="
document.getElementById('BotonesContainer'), HabilitarTab(document.getElementById('TabsContainer'),parseInt(this.id[this.id.length - 1])),
document.getElementById('TabsContainer'), HabilitarButton(document.getElementById('BotonesContainer'),parseInt(this.id[this.id.length - 1]))">
parseInt(this.id[this.id.length - 1])
)">
{% endfor %} {% endfor %}
</section> </section>
<section id="TabsContainer"> <section id="TabsContainer">
......
<html lang="en">
<head>
<script src="{{url_for('static',filename='Scripts/construct.js')}}"></script>
<script src="{{url_for('static',filename='Scripts/ArmadoDeForm.js')}}"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{url_for('static',filename='Style/Templates.css')}}">
<link rel="stylesheet" href="{{url_for('static',filename='Style/ArmadoDeForm.css')}}">
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
<title>Generador de Formularios</title>
<link rel="icon" href="{{url_for('static',filename='Assets/ICONO ANACSOFT 48 SIN TRASNSF.png')}}" type="image/png">
</head>
<body>
<section id="ArmarFormContainer">
<h1> Generador de Formularios</h1>
<h3>Para comenzar por favor cree un nuevo tab</h3>
<br>
<div id="tabs"></div>
<div style="text-align: center;">
<button class="NewTabButton"
onclick="let t = document.getElementById('tabs'); addTab(t, maxChild(t, accessNumber) + 1)">
+
</button>
</div>
<p id="ErrorMessage" style="font-weight: bold; text-align: center; color: red;"></p>
<h3 id="ContinuarText">Cuando se encuentre conforme con el formulario presione Continuar</h3>
<button id="ContinuarButton" onclick="ArmarForm( generate(document.getElementById('tabs')) )"> Continuar
</button>
</section>
<section id="FormularioResultante" style="display: none;">
<h1 style="margin: 2% 0% 2% 0;"> Su Formulario Ya Esta Listo!</h1>
<section id="BotonesContainer" class="BotonesContainer" >
</section>
<section id="TabsContainer">
</section>
<div class="BotonesContainer BotonResultCont">
<button class="BotonFormResultante"> Editar </button>
<button class="BotonFormResultante" style="background-color: var(--Color);"> Continuar </button>
</div>
</section>
</body>
<!-- templates -->
<template id="tabTemplate">
<div class="TabCards">
<input type="number" class="TabNumber"
onchange="sortChildren(getAncestorByAttribute(this,'name','Tab').parentElement, accessNumber)">
<input class="TabTitle" placeholder="Titulo del Tab" type="text">
<button class="RemoveTabButton" onclick="removeTab(this)">
X
</button>
<br>
<div style="text-align: center;">
<button class="NewInputButton" onclick="addField(this, maxChild(this.parentElement,accessNumber) + 1)">
+
</button>
</div>
</div>
</template>
<template id="fieldTemplate">
<div class="InputContainer">
<input type="number" class="InputNumber"
onchange="sortChildren(getAncestorByAttribute(this,'name','Field').parentElement, accessNumber)">
<input type="text" id="Titulo" class="Input" placeholder="Título">
<select name="input" class="Input">
<option disabled selected value="">Input</option>
<option id="text" value="text">Texto</option>
<option id="number" value="number">Numero</option>
<option id="mail" value="mail">Mail</option>
<option id="password" value="password">Contraseña</option>
<option id="date" value="date">Fecha</option>
<option id="time" value="time">Hora</option>
<option id="textarea" value="textarea">Párrafo</option>
<option id="checkbox" value="checkbox">Selección</option>
</select>
Obligatorio : <input type="checkbox">
<button class="RemoveInputButton"
onclick="let f = getAncestorByAttribute(this,'name','Field'); f.parentElement.removeChild(f)">
-
</button>
</div>
</template>
</html>
\ No newline at end of file \ No newline at end of file
<html lang="en">
<head>
<script src="{{url_for('static',filename='Scripts/ArmadoDeForm.js')}}"></script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{url_for('static',filename='Style/ArmadoDeForm.css')}}">
<link href="https://fonts.googleapis.com/css?family=Montserrat&display=swap" rel="stylesheet">
<title>Generador de Formularios</title>
<link rel="icon" href="{{url_for('static',filename='Assets/ICONO ANACSOFT 48 SIN TRASNSF.png')}}" type="image/png">
</head>
<body onload="
HabilitarTab(document.getElementById('TabsContainer'),0),
document.documentElement.style.setProperty('--Color','{{ color }}'),
Boton(document.getElementById('TabsContainer'), '{{ send }}')">
<section id="TabsContainer">
{% from "tab.html" import tab %}
<div id="Tab0" class="Tabs">
<div class="TabCard">
{{ tab(title=title, fields=fields) }}
</div>
</div>
</section>
</body>
</html>
\ No newline at end of file \ No newline at end of file
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!