Reworked the field duplication code to be more robust and allow for fields with multiple elements like radio fields
This commit is contained in:
parent
e209810b8c
commit
008b4af741
@ -229,7 +229,7 @@ mhelperMulti field@Field {..} fs@FieldSettings {..} wrapperClass defs minVals Mu
|
|||||||
cfs = FieldSettings "" Nothing (Just cid) (Just cName) [("hidden", "true")]
|
cfs = FieldSettings "" Nothing (Just cid) (Just cName) [("hidden", "true")]
|
||||||
mkName i = name `T.append` (T.pack $ '-' : show i)
|
mkName i = name `T.append` (T.pack $ '-' : show i)
|
||||||
mkId i = theId `T.append` (T.pack $ '-' : show i)
|
mkId i = theId `T.append` (T.pack $ '-' : show i)
|
||||||
mkNames c = [(mkName i, mkId i) | i <- [0 .. c]]
|
mkNames c = [(i, (mkName i, mkId i)) | i <- [0 .. c]]
|
||||||
onMissingSucc _ _ = FormSuccess Nothing
|
onMissingSucc _ _ = FormSuccess Nothing
|
||||||
onMissingFail m l = FormFailure [renderMessage m l MsgValueRequired]
|
onMissingFail m l = FormFailure [renderMessage m l MsgValueRequired]
|
||||||
isSuccNothing r = case r of
|
isSuccNothing r = case r of
|
||||||
@ -256,7 +256,9 @@ mhelperMulti field@Field {..} fs@FieldSettings {..} wrapperClass defs minVals Mu
|
|||||||
if cDef == 0
|
if cDef == 0
|
||||||
then [(FormMissing, Left "")]
|
then [(FormMissing, Left "")]
|
||||||
else [(FormMissing, Right d) | d <- defs]
|
else [(FormMissing, Right d) | d <- defs]
|
||||||
Just p -> mapM (\n -> mkRes field fs p mfs n onMissingSucc (FormSuccess . Just)) (map fst $ mkNames counter)
|
Just p -> mapM
|
||||||
|
(\n -> mkRes field fs p mfs n onMissingSucc (FormSuccess . Just))
|
||||||
|
(map (fst . snd) $ mkNames counter)
|
||||||
|
|
||||||
-- delete button
|
-- delete button
|
||||||
|
|
||||||
@ -264,17 +266,33 @@ mhelperMulti field@Field {..} fs@FieldSettings {..} wrapperClass defs minVals Mu
|
|||||||
-- each delete button to ensure that the function only gets included once.
|
-- each delete button to ensure that the function only gets included once.
|
||||||
let delFunction = toWidget
|
let delFunction = toWidget
|
||||||
[julius|
|
[julius|
|
||||||
function deleteField(field) {
|
function deleteField(wrapper) {
|
||||||
var numFields = $("." + #{wrapperClass}).length;
|
var numFields = $("." + #{wrapperClass}).length;
|
||||||
|
|
||||||
if (numFields == 1)
|
if (numFields == 1)
|
||||||
field.val("");
|
{
|
||||||
|
wrapper.find("*").each(function() {
|
||||||
|
removeVals($(this));
|
||||||
|
});
|
||||||
|
}
|
||||||
else
|
else
|
||||||
field.parent().parent().remove();
|
wrapper.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// input types where we don't want to reset the value
|
||||||
|
const keepValueTypes = ["radio", "checkbox", "button"];
|
||||||
|
|
||||||
|
function removeVals(e) {
|
||||||
|
// uncheck any checkboxes or radio fields and empty any text boxes
|
||||||
|
if(e.prop('checked') == true)
|
||||||
|
e.prop('checked', false);
|
||||||
|
|
||||||
|
if(!keepValueTypes.includes(e.prop('type')))
|
||||||
|
e.val("");
|
||||||
}
|
}
|
||||||
|]
|
|]
|
||||||
|
|
||||||
mkDelBtn fieldId = do
|
mkDelBtn fieldId wrapperClass = do
|
||||||
let delBtnId = delBtnPrefix <> fieldId
|
let delBtnId = delBtnPrefix <> fieldId
|
||||||
[whamlet|
|
[whamlet|
|
||||||
<button ##{delBtnId} .#{msDelClass} style="margin-left: 0.75rem" type="button">
|
<button ##{delBtnId} .#{msDelClass} style="margin-left: 0.75rem" type="button">
|
||||||
@ -287,20 +305,20 @@ mhelperMulti field@Field {..} fs@FieldSettings {..} wrapperClass defs minVals Mu
|
|||||||
[julius|
|
[julius|
|
||||||
$("#" + #{delBtnId}).click(function() {
|
$("#" + #{delBtnId}).click(function() {
|
||||||
var field = $("#" + #{fieldId});
|
var field = $("#" + #{fieldId});
|
||||||
deleteField(field);
|
deleteField(field.parents("." + #{wrapperClass}));
|
||||||
});
|
});
|
||||||
|]
|
|]
|
||||||
|
|
||||||
-- generate field views
|
-- generate field views
|
||||||
(rs, fvs) <- do
|
(rs, fvs) <- do
|
||||||
let mkView' ((n,i), r@(res, _)) = do
|
let mkView' ((c, (n,i)), r@(res, _)) = do
|
||||||
let del = Just (mkDelBtn i, wrapperClass)
|
let del = Just (mkDelBtn i wrapperClass, wrapperClass, c)
|
||||||
fv <- mkView field fs r del msErrWidget msWrapperErrClass i n False
|
fv <- mkView field fs r del msErrWidget msWrapperErrClass i n False
|
||||||
return (res, fv)
|
return (res, fv)
|
||||||
xs = zip (mkNames counter) results
|
xs = zip (mkNames counter) results
|
||||||
notSuccNothing (_, (r,_)) = not $ isSuccNothing r
|
notSuccNothing (_, (r,_)) = not $ isSuccNothing r
|
||||||
ys = case filter notSuccNothing xs of
|
ys = case filter notSuccNothing xs of
|
||||||
[] -> [((mkName 0, mkId 0), (FormSuccess Nothing, Left ""))] -- always need at least one value to generate a field
|
[] -> [((0, (mkName 0, mkId 0)), (FormSuccess Nothing, Left ""))] -- always need at least one value to generate a field
|
||||||
zs -> zs
|
zs -> zs
|
||||||
rvs <- mapM mkView' ys
|
rvs <- mapM mkView' ys
|
||||||
return $ unzip rvs
|
return $ unzip rvs
|
||||||
@ -349,15 +367,46 @@ mhelperMulti field@Field {..} fs@FieldSettings {..} wrapperClass defs minVals Mu
|
|||||||
var newId = #{theId} + "-" + newNumber;
|
var newId = #{theId} + "-" + newNumber;
|
||||||
var newDelId = #{delBtnPrefix} + newId;
|
var newDelId = #{delBtnPrefix} + newId;
|
||||||
|
|
||||||
|
// get new wrapper and remove old error messages
|
||||||
var newWrapper = $("." + #{wrapperClass}).first().clone();
|
var newWrapper = $("." + #{wrapperClass}).first().clone();
|
||||||
newWrapper.children( ":not(." + #{wrapperClass} + "-inner)" ).remove(); // remove error messages
|
newWrapper.children( ":not(." + #{wrapperClass} + "-inner)" ).remove();
|
||||||
|
|
||||||
var newField = newWrapper.find("[id^=" + #{theId} + "]");
|
// get counter from wrapper
|
||||||
newField.val("").attr('name', newName).attr('id', newId);
|
var oldCount = newWrapper.data("counter");
|
||||||
|
var oldName = #{name} + "-" + oldCount;
|
||||||
|
var oldId = #{theId} + "-" + oldCount;
|
||||||
|
var oldDelBtn = #{delBtnPrefix} + oldId;
|
||||||
|
|
||||||
|
// replace any id, name or for attributes that began with
|
||||||
|
// the old values and replace them with the new values
|
||||||
|
var idRegex = new RegExp("^" + oldId);
|
||||||
|
var nameRegex = new RegExp("^" + oldName);
|
||||||
|
|
||||||
|
var els = newWrapper.find("*");
|
||||||
|
els.each(function() {
|
||||||
|
var e = $(this);
|
||||||
|
|
||||||
|
if(e.prop('id') != undefined)
|
||||||
|
e.prop('id', e.prop('id').replace(idRegex, newId));
|
||||||
|
|
||||||
|
if(e.prop('name') != undefined)
|
||||||
|
e.prop('name', e.prop('name').replace(nameRegex, newName));
|
||||||
|
|
||||||
|
if(e.prop('for') != undefined)
|
||||||
|
e.prop('for', e.prop('for').replace(idRegex, newId)); // radio fields use id in for attribute
|
||||||
|
|
||||||
|
removeVals(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
// set new counter on wrapper
|
||||||
|
newWrapper.data("counter", newNumber);
|
||||||
|
|
||||||
|
//var newField = newWrapper.find("[id^=" + #{theId} + "]");
|
||||||
|
//newField.val("").attr('name', newName).attr('id', newId);
|
||||||
|
|
||||||
var newDelBtn = newWrapper.find("[id^=" + #{delBtnPrefix} + "]");
|
var newDelBtn = newWrapper.find("[id^=" + #{delBtnPrefix} + "]");
|
||||||
newDelBtn.attr('id', newDelId);
|
newDelBtn.prop('id', newDelId);
|
||||||
newDelBtn.click(() => deleteField(newField));
|
newDelBtn.click(() => deleteField(newWrapper));
|
||||||
|
|
||||||
newWrapper.insertBefore("#" + #{addBtnId});
|
newWrapper.insertBefore("#" + #{addBtnId});
|
||||||
});
|
});
|
||||||
@ -403,7 +452,9 @@ mkView :: (site ~ HandlerSite m, MonadHandler m)
|
|||||||
=> Field m a
|
=> Field m a
|
||||||
-> FieldSettings site
|
-> FieldSettings site
|
||||||
-> (FormResult b, Either Text a)
|
-> (FormResult b, Either Text a)
|
||||||
-> Maybe (WidgetFor site (), Text) -- Delete button widget and class for div wrapping each field with it's delete button.
|
-- Delete button widget, class for div wrapping each field with it's delete button and counter value for that field.
|
||||||
|
-- Nothing if the field passed doesn't need a delete button e.g. if it is the counter field.
|
||||||
|
-> Maybe (WidgetFor site (), Text, Int)
|
||||||
-> Maybe (Html -> WidgetFor site ()) -- Function to display error messages.
|
-> Maybe (Html -> WidgetFor site ()) -- Function to display error messages.
|
||||||
-> Text
|
-> Text
|
||||||
-> Text
|
-> Text
|
||||||
@ -419,8 +470,8 @@ mkView Field {..} FieldSettings {..} (res, val) mdel merrW errClass theId name i
|
|||||||
fv' = fieldView theId name fsAttrs val isReq
|
fv' = fieldView theId name fsAttrs val isReq
|
||||||
fv = do
|
fv = do
|
||||||
[whamlet|
|
[whamlet|
|
||||||
$maybe (delBtn, wrapperClass) <- mdel
|
$maybe (delBtn, wrapperClass, counter) <- mdel
|
||||||
<div .#{wrapperClass} :isJust merr:.#{errClass}>
|
<div .#{wrapperClass} :isJust merr:.#{errClass} data-counter=#{counter}>
|
||||||
<div .#{wrapperClass}-inner>
|
<div .#{wrapperClass}-inner>
|
||||||
^{fv'}
|
^{fv'}
|
||||||
^{delBtn}
|
^{delBtn}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user