Merge pull request #635 from sgmap/form_add_champs

Form add champs
This commit is contained in:
LeSim 2017-07-27 14:38:53 +02:00 committed by Mathieu Magnin
commit a3c0404302
35 changed files with 460 additions and 15 deletions

View file

@ -0,0 +1 @@
<svg width="1792" height="1792" viewBox="0 0 1792 1792" xmlns="http://www.w3.org/2000/svg"><path d="M1683 808l-742 741q-19 19-45 19t-45-19L109 808q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"/></svg>

After

Width:  |  Height:  |  Size: 270 B

View file

@ -17,4 +17,6 @@
//= require leaflet.1.1.0
//= require highcharts
//= require chartkick
//= require select2
//= require typeahead.bundle
//= require_tree .

View file

@ -0,0 +1,27 @@
(function () {
var display = 'label';
var bloodhound = new Bloodhound({
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(display),
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: '/ban/search?request=%QUERY',
wildcard: '%QUERY'
}
});
bloodhound.initialize();
var bindTypeahead = function() {
$("input[data-address='true']").typeahead({
minLength: 1
}, {
display: display,
source: bloodhound,
limit: 5
});
};
document.addEventListener('turbolinks:load', bindTypeahead);
})();

View file

@ -0,0 +1,36 @@
(function() {
var showNotFound = function() {
$('.dossier-link .text-info').hide();
$('.dossier-link .text-warning').show();
};
var showData = function(data) {
$('.dossier-link .dossier-text-summary').text(data.textSummary);
$('.dossier-link .text-info').show();
$('.dossier-link .text-warning').hide();
};
var hideEverything = function() {
$('.dossier-link .text-info').hide();
$('.dossier-link .text-warning').hide();
};
var fetchProcedureLibelle = function(e) {
var dossierId = $(e.target).val();
if(dossierId) {
$.get('/users/dossiers/' + dossierId + '/text_summary')
.done(showData)
.fail(showNotFound);
} else {
hideEverything();
}
};
var timeOut = null;
var debounceFetchProcedureLibelle = function(e) {
if(timeOut){ clearTimeout(timeOut); }
timeOut = setTimeout(function() { fetchProcedureLibelle(e); }, 300);
};
$(document).on('input', '[data-type=dossier-link]', debounceFetchProcedureLibelle);
})();

View file

@ -0,0 +1,3 @@
document.addEventListener('turbolinks:load', function() {
$('select.select2').select2();
});

View file

@ -0,0 +1,8 @@
$(document).on('blur keydown', 'input, textarea', function() {
$(this).addClass('touched');
});
$(document).on('click', 'input[type="submit"]:not([formnovalidate])', function() {
var $form = $(this).closest('form');
$('input, textarea', $form).addClass('touched');
});

View file

@ -6,7 +6,8 @@
body,
input,
textarea {
textarea,
select {
@extend %new-type;
font-size: 16px;
line-height: 1.42857143;

View file

@ -0,0 +1,17 @@
@import "constants";
@import "colors";
.dossier-link {
.help-block > p {
margin-top: - $default-padding;
margin-bottom: 2 * $default-padding;
}
.text-info {
color: $blue;
}
.text-warning {
color: $dark-red;
}
}

View file

@ -2,8 +2,6 @@
@import "colors";
.form {
overflow: hidden;
h1 {
text-align: center;
margin-bottom: 20px;
@ -14,15 +12,18 @@
display: inline-block;
}
input[type=text],
input[type=text]:not([data-address='true']),
input[type=email],
input[type=password],
textarea {
input[type=date],
input[type=number],
input[type=tel],
textarea,
select {
display: block;
width: 100%;
border-radius: 4px;
border: solid 1px $border-grey;
margin-bottom: 4 * $default-spacer;
margin-bottom: 2 * $default-padding;
padding: $default-padding;
&:disabled {
@ -30,8 +31,140 @@
}
}
.send {
float: right;
input[type=text],
input[type=email],
input[type=password],
input[type=date],
input[type=number],
input[type=tel],
textarea {
width: 100%;
}
input[type=email],
input[type=number],
input[type=tel], {
max-width: 500px;
}
input[type=checkbox],
input[type=radio] {
margin-bottom: 2 * $default-padding;
}
input[type=date] {
max-width: 180px;
}
input:invalid,
textarea:invalid {
box-shadow: none;
}
input.touched:invalid,
textarea.touched:invalid {
border-color: $dark-red;
box-shadow: 0px 0px 5px $dark-red;
}
select,
.select2-selection {
// hack found here: https://stackoverflow.com/questions/1895476/how-to-style-a-select-dropdown-with-css-only-without-javascript
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: image-url("icons/chevron-down.svg") no-repeat;
background-size: 14px;
background-position: right 10px center;
padding-right: 3 * $default-spacer;
// CAUTION: IE hackery ahead
&::-ms-expand {
display: none; // remove default arrow in IE 10 and 11 */
}
// target Internet Explorer 9 to undo the custom arrow */
@media screen and (min-width:0\0) {
select {
background: none\9;
}
}
}
.select2 {
min-width: 50%;
}
.select2-container {
display: block;
margin-bottom: 2 * $default-padding;
&.select2-container--focus {
.select2-selection {
border-color: $border-grey;
}
}
// scss-lint:disable SelectorFormat
.select2-selection__rendered {
padding: $default-padding;
}
.select2-selection__choice {
background-color: #FFFFFF;
}
// scss-lint:enable
}
.twitter-typeahead {
margin-bottom: 2 * $default-padding;
}
input.tt-input,
input.tt-hint {
border-radius: 4px;
border: solid 1px $border-grey;
padding: $default-padding;
}
input.tt-hint {
color: $grey;
}
.datetime {
input[type=date] {
display: inline-block;
}
select {
display: inline-block;
}
}
.header-section {
color: #4393F3;
font-weight: bold;
font-size: 20px;
margin-bottom: 2 * $default-padding;
}
.explication-libelle {
font-weight: bold;
font-size: 20px;
margin-bottom: $default-padding;
}
.explication {
background-color: $light-grey;
padding: $default-padding;
margin-bottom: 2 * $default-padding;
}
.send-wrapper {
text-align: right;
.send {
margin-bottom: $default-padding;
}
}
}

View file

@ -4,4 +4,6 @@
// = require ./utils
// = require ./fonts
// = require leaflet.1.1.0
// = require select2
// = require typeahead
// = require_tree .

View file

@ -32,5 +32,41 @@ class RootController < ApplicationController
end
def patron
@all_champs = TypeDeChamp.type_champs
.map { |name, _| TypeDeChamp.new(type_champ: name, libelle: name, mandatory: true) }
.map { |type_de_champ| Champ.new(type_de_champ: type_de_champ) }
.map.with_index do |champ, i|
champ.id = i
champ
end
@all_champs
.select { |champ| champ.type_champ == 'header_section' }
.each { |champ| champ.type_de_champ.libelle = 'un super titre de section' }
@all_champs
.select { |champ| %w(drop_down_list multiple_drop_down_list).include?(champ.type_champ) }
.each do |champ|
champ.type_de_champ.drop_down_list = DropDownList.new(type_de_champ: champ.type_de_champ)
champ.drop_down_list.value =
"option A
option B
-- avant l'option C --
option C"
champ.value = '["option B", "option C"]'
end
type_champ_values = {
'date': '2016-07-26',
'datetime': '26/07/2016 07:35',
'textarea': 'Une description de mon projet',
'explication': 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In erat mauris, faucibus quis pharetra sit amet, pretium ac libero. Etiam vehicula eleifend bibendum. Morbi gravida metus ut sapien condimentum sodales mollis augue sodales. Vestibulum quis quam at sem placerat aliquet',
}
type_champ_values.each do |(type_champ, value)|
@all_champs
.select { |champ| champ.type_champ == type_champ.to_s }
.each { |champ| champ.value = value }
end
end
end

View file

@ -14,6 +14,10 @@ class DropDownList < ActiveRecord::Base
champ.object.value.blank? ? [] : multiple ? JSON.parse(champ.object.value) : [champ.object.value]
end
def selected_options_without_decorator(champ)
champ.value.blank? ? [] : multiple ? JSON.parse(champ.value) : [champ.value]
end
def multiple
type_de_champ.type_champ == 'multiple_drop_down_list'
end

View file

@ -0,0 +1,9 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'text',
'data-address': 'true',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle,
value: champ.value,
required: champ.mandatory }

View file

@ -0,0 +1 @@
%label{ for: :"champs_#{champ.id}" }> #{champ.libelle} #{champ.mandatory ? '*' : nil}

View file

@ -0,0 +1,9 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'checkbox',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
checked: ('checked' if champ.value == 'on'),
required: champ.mandatory }
%br

View file

@ -0,0 +1,10 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%div
%label
= radio_button_tag "champs['#{champ.id}']", "M.", champ.value == 'Mme' ? false : true
Monsieur
%label
= radio_button_tag "champs['#{champ.id}']", "Mme", champ.value == 'Mme'
Madame

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ name: "champs['#{champ.id}']",
placeholder: "JJ/MM/AAAA",
id: "champs_#{champ.id}",
value: champ.value,
type: "date",
required: champ.mandatory }

View file

@ -0,0 +1,22 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
.datetime
%input{ name: "champs['#{champ.id}']",
placeholder: champ.libelle,
id: "champs_#{champ.id}",
value: (champ.value.split(/[ ][0-9]*:[0-9]*/).first unless champ.value.nil?),
type: 'date',
required: champ.mandatory }
%select{ name: "time_hour['#{champ.id}']", id: "time_hour_#{champ.id}", required: champ.mandatory }
- (0..23).each do |num|
- num = "%.2i" %num
%option{ value: num, selected: (:selected if champ.same_hour?(num)) }
= num
h
%select{ name: "time_minute['#{champ.id}']", id: "time_minute_#{champ.id}", required: champ.mandatory }
- (0..55).step(5) do |num|
- num = "%.2i" %num
%option{ value: num, selected: (:selected if champ.same_minute?(num)) }
= num
min

View file

@ -0,0 +1,4 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
= select_tag("champs['#{champ.id}']",
options_for_select(Champ.departements, selected: champ.value))

View file

@ -0,0 +1,23 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
- dossier = Dossier.find_by(id: champ.value)
- show_text_summary = dossier.present?
- show_warning = !show_text_summary && champ.value.present?
- text_summary = dossier.try(:text_summary)
.dossier-link
%input{ name: "champs['#{ champ.id }']",
placeholder: "Numéro de dossier",
id: "champs_#{ champ.id }",
value: champ.value,
type: 'number',
'autocomplete' => 'off',
'data-type' => 'dossier-link',
required: champ.mandatory }
.help-block
%p.text-info{ style: show_text_summary ? nil : 'display: none;' }
%span.dossier-text-summary= text_summary
%p.text-warning{ style: show_warning ? nil : 'display: none;' }
Ce dossier est inconnu

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
- if champ.drop_down_list && champ.drop_down_list.options.any?
= select_tag("champs['#{champ.id}']",
options_for_select(champ.drop_down_list.options,
selected: champ.drop_down_list.selected_options_without_decorator(champ),
disabled: champ.drop_down_list.disabled_options),
multiple: false)

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'email',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle,
value: champ.value,
required: champ.mandatory }

View file

@ -0,0 +1,9 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'checkbox',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
checked: ('checked' if champ.value == 'on'),
required: champ.mandatory }
%br

View file

@ -0,0 +1,2 @@
%h2.explication-libelle= champ.libelle
%p.explication= champ.value

View file

@ -0,0 +1,2 @@
%h2.header-section
= champ.libelle

View file

@ -0,0 +1,9 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
- if champ.drop_down_list && champ.drop_down_list.options.any?
= select_tag("champs['#{champ.id}']",
options_for_select(champ.drop_down_list.options,
selected: champ.drop_down_list.selected_options_without_decorator(champ),
disabled: champ.drop_down_list.disabled_options),
multiple: true,
class: 'select2')

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'number',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle,
value: champ.value,
required: champ.mandatory }

View file

@ -0,0 +1,4 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
= select_tag("champs['#{champ.id}']",
options_for_select(Champ.pays, selected: champ.value))

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'tel',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle,
value: champ.value,
required: champ.mandatory }

View file

@ -0,0 +1,4 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
= select_tag("champs['#{champ.id}']",
options_for_select(Champ.regions, selected: champ.value))

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%input{ type: 'text',
name: "champs['#{champ.id}']",
id: "champs_#{champ.id}",
placeholder: champ.libelle,
value: champ.value,
required: champ.mandatory }

View file

@ -0,0 +1,8 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%textarea{ name: "champs['#{champ.id}']",
placeholder: champ.description,
id: "champs_#{champ.id}",
row: '6',
required: champ.mandatory }
= sanitize(champ.value)

View file

@ -0,0 +1,10 @@
= render partial: 'new_gestionnaire/dossiers/champs/champ_label', locals: { champ: champ }
%div
%label
= radio_button_tag "champs['#{champ.id}']", "true", champ.value == 'true'
Oui
%label
= radio_button_tag "champs['#{champ.id}']", "false", champ.value == 'false'
Non

View file

@ -17,4 +17,5 @@
= form_for(Commentaire.new, url: commentaire_dossier_path(@dossier.procedure, @dossier), html: { class: 'form' }) do |f|
= f.text_area :body, rows: 5, placeholder: 'Répondre ici', required: true
= f.submit 'Envoyer', class: 'button send'
.send-wrapper
= f.submit 'Envoyer', class: 'button send'

View file

@ -3,12 +3,12 @@
%h1 Formulaires
%form.form
%label Nom
%input{ type: "text" }
%textarea{ placeholder: "Description de votre projet" }
%label Mot de passe
- @all_champs.each do |champ|
= render partial: "new_gestionnaire/dossiers/champs/#{champ.type_champ}", locals: { champ: champ }
%input{ type: "password", value: "12345678" }
%input.button.send{ type: "submit", value: "Envoyer" }
.send-wrapper
%input.button.send{ type: "submit", value: "Enregistrer un brouillon (formnovalidate)", formnovalidate: true }
%input.button.send{ type: "submit", value: "Envoyer" }
%h1 Boutons