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
JSON = {
'title' : "Título del Formulario",
'color' : "Color preferido",
'tabs' : \[Tabs]
'tabs' : \[Tabs],
'send' : "MiUrl.com"
}
Donde cada Tab es de la forma:
......@@ -27,4 +28,15 @@ Campo = {
'placeholder' : "Texto de ejemplo del input",
'required' : True|False,
'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
......@@ -10,49 +10,28 @@ TOKEN_STRING = "\
qwertyuiopasdfghjklzxcvbnm\
QWERTYUIOPASDFGHJKLZXCVBNM"
sessions = {}
loginfields = [
{
"title" : "Usuario",
"type" : "text",
"required" : True
},
{
"title" : "Contraseña",
"type" : "password",
"required" : True
}
]
@app.after_request
def after_request(response):
# headers permitidos para la conversación
response.headers.add('Access-Control-Allow-Headers', '\
Access-Control-Allow-Methods,\
Access-Control-Allow-Origin,\
Content-Type')
# orígenes permitidos para CORS
response.headers.add('Access-Control-Allow-Origin', '*')
# métodos permitidos
response.headers.add('Access-Control-Allow-Methods', 'GET,POST')
return response
@app.route('/datos', methods = ['GET', 'POST'])
def datos():
print(request.json)
return "OK"
def validate(name,psw):
if name == "admin" and psw == "admin":
return True
return False
def token():
result = ""
i = 0
while i < TOKEN_LENGHT:
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():
data = request.json
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
})
return render_template("login.html",title="Login",fields=loginfields,color="blue",send="http://192.168.15.119:5000/datos")
@app.route('/', methods = ['GET', 'POST'])
def main():
......@@ -68,7 +47,7 @@ def main():
},
{
"title" : "mail",
"type" : "mail",
"type" : "email",
"placeholder" : "ejemplo@gmail.com",
}
]
......@@ -79,7 +58,7 @@ def main():
{
"title" : "género",
"type" : "select",
"placeholder" : "Gènero",
"placeholder" : "Género",
"options" : [
"Hombre",
"Mujer",
......@@ -92,7 +71,6 @@ def main():
"options" : [
"Hombres",
"Mujeres",
"#other"
],
"required" : True
......@@ -100,11 +78,21 @@ def main():
]
},
{
"title" : "third",
"fields" : []
"title" : "Fecha y hora",
"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__":
app.run("0.0.0.0")
\ No newline at end of file
......@@ -12,17 +12,21 @@ var getDescendantByAttribute = (elem,attr,val) => {
}, null);
}
function HabilitarTab(bc,tc,n){
function HabilitarTab(tc,n){
if (typeof n != "number") return console.log("El entero es invalido");
for (let it = 0; it < bc.children.length && it < tc.children.length; it++) {
if (it == n) {
bc.children[it].classList.add("BotonesActive");
tc.children[it].style.display = "block";
} else {
bc.children[it].classList.remove("BotonesActive");
tc.children[it].style.display = "none";
}
for (let it = 0; it < tc.children.length; it++) {
if (it == n) tc.children[it].style.display = "block";
else 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");
}
}
......@@ -37,4 +41,91 @@ function Otro(otroselect){
if (otroselect.checked) other.style.display = "block";
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
......@@ -48,7 +48,7 @@ body {
}
.Botones {
border-radius: 5px 5px 0px 0px;
border-radius: 10px 10px 0px 0px;
background-color: rgb(168, 168, 168);
border: none;
border-bottom: 2px solid rgb(120, 120, 120);
......@@ -57,7 +57,7 @@ body {
.BotonesActive{
background-color: var(--Color);
height: 105%;
height: 110%;
border-bottom: none;
}
......@@ -84,6 +84,7 @@ body {
margin-bottom: 2%;
min-height: 70%;
text-align: center;
position: relative;
}
.TabTitle {
......@@ -151,6 +152,13 @@ body {
background: rgb(91, 145, 255);
}
.Other {
display: none;
margin-top: 20 !important;
margin-bottom: 20 !important;
margin: auto;
}
.Checkbox {
width: 46%;
float: left;
......@@ -178,8 +186,21 @@ body {
margin: auto;
}
.Other {
display: none;
.SendButton {
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) {
......
......@@ -3,8 +3,10 @@
<div class="Field">
<div class="FieldTitle">
{{ title|title }}
{% if required %} <span class="Required">*</span> {% endif %}
</div>
<div class="FieldInput">
{% if type == "select" %}
<select onchange="Otro(this)" {% if required %} required {% endif %}>
......
......@@ -9,21 +9,20 @@
<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('BotonesContainer'),
document.getElementById('TabsContainer'),
0
), document.documentElement.style.setProperty('--Color','{{ color }}')">
<h1 style="margin: 2% 0% 2% 0; font-size: 5vw;"> {{ title|title }}</h1>
<body onload="
HabilitarTab(document.getElementById('TabsContainer'),0),
HabilitarButton(document.getElementById('BotonesContainer'),0),
document.documentElement.style.setProperty('--Color','{{ color }}'),
Boton(document.getElementById('TabsContainer'), '{{ send }}')">
<h1 style="margin: 2% 0% 2% 0; font-size: 5vw;"> {{ title|title }}</h1>
<section id="BotonesContainer" class="BotonesContainer">
{% set m = tabs|length %}
{% for i in range(m) %}
<button id="Boton{{i}}" class="Botones" style="width: {{ 100/m }}%;"
onclick="HabilitarTab(
document.getElementById('BotonesContainer'),
document.getElementById('TabsContainer'),
parseInt(this.id[this.id.length - 1])
)">
<button id="Boton{{i}}" class="Botones" style="width: {{ 100/m }}%;"
onclick="
HabilitarTab(document.getElementById('TabsContainer'),parseInt(this.id[this.id.length - 1])),
HabilitarButton(document.getElementById('BotonesContainer'),parseInt(this.id[this.id.length - 1]))">
{% endfor %}
</section>
<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
<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
Styling with Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!