Merge branch 'async-form-responses' into 'master'
Async form responses See merge request !161
This commit is contained in:
commit
84237c4484
@ -2,7 +2,7 @@ SystemMessage
|
|||||||
from UTCTime Maybe
|
from UTCTime Maybe
|
||||||
to UTCTime Maybe
|
to UTCTime Maybe
|
||||||
authenticatedOnly Bool
|
authenticatedOnly Bool
|
||||||
severity MessageClass
|
severity MessageStatus
|
||||||
defaultLanguage Lang
|
defaultLanguage Lang
|
||||||
content Html
|
content Html
|
||||||
summary Html Maybe
|
summary Html Maybe
|
||||||
|
|||||||
@ -220,7 +220,7 @@ instance RenderMessage UniWorX MsgLanguage where
|
|||||||
instance RenderMessage UniWorX (UnsupportedAuthPredicate (Route UniWorX)) where
|
instance RenderMessage UniWorX (UnsupportedAuthPredicate (Route UniWorX)) where
|
||||||
renderMessage f ls (UnsupportedAuthPredicate tag route) = renderMessage f ls $ MsgUnsupportedAuthPredicate tag (show route)
|
renderMessage f ls (UnsupportedAuthPredicate tag route) = renderMessage f ls $ MsgUnsupportedAuthPredicate tag (show route)
|
||||||
|
|
||||||
embedRenderMessage ''UniWorX ''MessageClass ("Message" <>)
|
embedRenderMessage ''UniWorX ''MessageStatus ("Message" <>)
|
||||||
embedRenderMessage ''UniWorX ''NotificationTrigger $ ("NotificationTrigger" <>) . concat . drop 1 . splitCamel
|
embedRenderMessage ''UniWorX ''NotificationTrigger $ ("NotificationTrigger" <>) . concat . drop 1 . splitCamel
|
||||||
embedRenderMessage ''UniWorX ''StudyFieldType id
|
embedRenderMessage ''UniWorX ''StudyFieldType id
|
||||||
embedRenderMessage ''UniWorX ''SheetFileType id
|
embedRenderMessage ''UniWorX ''SheetFileType id
|
||||||
|
|||||||
@ -20,6 +20,8 @@ import Database.Persist.Sql (fromSqlKey)
|
|||||||
|
|
||||||
-- import qualified Data.UUID.Cryptographic as UUID
|
-- import qualified Data.UUID.Cryptographic as UUID
|
||||||
|
|
||||||
|
import Control.Monad.Trans.Writer (mapWriterT)
|
||||||
|
|
||||||
-- BEGIN - Buttons needed only here
|
-- BEGIN - Buttons needed only here
|
||||||
data ButtonCreate = CreateMath | CreateInf -- Dummy for Example
|
data ButtonCreate = CreateMath | CreateInf -- Dummy for Example
|
||||||
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
deriving (Enum, Eq, Ord, Bounded, Read, Show, Generic, Typeable)
|
||||||
@ -84,15 +86,12 @@ postAdminTestR = do
|
|||||||
_other -> addMessage Warning "KEIN Knopf erkannt"
|
_other -> addMessage Warning "KEIN Knopf erkannt"
|
||||||
|
|
||||||
((emailResult, emailWidget), emailEnctype) <- runFormPost . identifyForm "email" $ renderAForm FormStandard emailTestForm
|
((emailResult, emailWidget), emailEnctype) <- runFormPost . identifyForm "email" $ renderAForm FormStandard emailTestForm
|
||||||
case emailResult of
|
formResultModal emailResult AdminTestR $ \(email, ls) -> do
|
||||||
(FormSuccess (email, ls)) -> do
|
jId <- mapWriterT runDB $ do
|
||||||
jId <- runDB $ do
|
jId <- queueJob $ JobSendTestEmail email ls
|
||||||
jId <- queueJob $ JobSendTestEmail email ls
|
tell . pure $ Message Success [shamlet|Email-test gestartet (Job ##{tshow (fromSqlKey jId)})|]
|
||||||
addMessage Success [shamlet|Email-test gestartet (Job ##{tshow (fromSqlKey jId)})|]
|
return jId
|
||||||
return jId
|
writeJobCtl $ JobCtlPerform jId
|
||||||
writeJobCtl $ JobCtlPerform jId
|
|
||||||
FormMissing -> return ()
|
|
||||||
(FormFailure errs) -> forM_ errs $ addMessage Error . toHtml
|
|
||||||
|
|
||||||
let emailWidget' = [whamlet|
|
let emailWidget' = [whamlet|
|
||||||
<form method=post action=@{AdminTestR} enctype=#{emailEnctype} data-ajax-submit>
|
<form method=post action=@{AdminTestR} enctype=#{emailEnctype} data-ajax-submit>
|
||||||
|
|||||||
@ -654,5 +654,5 @@ formResultModal res finalDest handler = maybeT_ $ do
|
|||||||
if
|
if
|
||||||
| isModal -> sendResponse $ toJSON messages
|
| isModal -> sendResponse $ toJSON messages
|
||||||
| otherwise -> do
|
| otherwise -> do
|
||||||
forM_ messages $ \Message{..} -> addMessage messageClass messageContent
|
forM_ messages $ \Message{..} -> addMessage messageStatus messageContent
|
||||||
redirect finalDest
|
redirect finalDest
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import Data.Aeson (Value)
|
|||||||
import Data.CaseInsensitive (CI)
|
import Data.CaseInsensitive (CI)
|
||||||
import Data.CaseInsensitive.Instances ()
|
import Data.CaseInsensitive.Instances ()
|
||||||
|
|
||||||
import Utils.Message (MessageClass)
|
import Utils.Message (MessageStatus)
|
||||||
import Settings.Cluster (ClusterSettingsKey)
|
import Settings.Cluster (ClusterSettingsKey)
|
||||||
|
|
||||||
import Data.Binary (Binary)
|
import Data.Binary (Binary)
|
||||||
|
|||||||
@ -39,7 +39,7 @@ import qualified Data.Text.Encoding as Text
|
|||||||
|
|
||||||
import qualified Ldap.Client as Ldap
|
import qualified Ldap.Client as Ldap
|
||||||
|
|
||||||
import Utils hiding (MessageClass(..))
|
import Utils hiding (MessageStatus(..))
|
||||||
import Control.Lens
|
import Control.Lens
|
||||||
|
|
||||||
import Data.Maybe (fromJust)
|
import Data.Maybe (fromJust)
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
module Utils.Message
|
module Utils.Message
|
||||||
( MessageClass(..)
|
( MessageStatus(..)
|
||||||
, UnknownMessageClass(..)
|
, UnknownMessageStatus(..)
|
||||||
, addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget
|
, addMessage, addMessageI, addMessageIHamlet, addMessageFile, addMessageWidget
|
||||||
, Message(..)
|
, Message(..)
|
||||||
, messageI, messageIHamlet, messageFile, messageWidget
|
, messageI, messageIHamlet, messageFile, messageWidget
|
||||||
@ -25,64 +25,64 @@ import Text.Blaze.Html.Renderer.Text (renderHtml)
|
|||||||
import Text.HTML.SanitizeXSS (sanitizeBalance)
|
import Text.HTML.SanitizeXSS (sanitizeBalance)
|
||||||
|
|
||||||
|
|
||||||
data MessageClass = Error | Warning | Info | Success
|
data MessageStatus = Error | Warning | Info | Success
|
||||||
deriving (Eq, Ord, Enum, Bounded, Show, Read, Lift)
|
deriving (Eq, Ord, Enum, Bounded, Show, Read, Lift)
|
||||||
|
|
||||||
instance Universe MessageClass
|
instance Universe MessageStatus
|
||||||
instance Finite MessageClass
|
instance Finite MessageStatus
|
||||||
|
|
||||||
deriveJSON defaultOptions
|
deriveJSON defaultOptions
|
||||||
{ constructorTagModifier = camelToPathPiece
|
{ constructorTagModifier = camelToPathPiece
|
||||||
} ''MessageClass
|
} ''MessageStatus
|
||||||
|
|
||||||
nullaryPathPiece ''MessageClass camelToPathPiece
|
nullaryPathPiece ''MessageStatus camelToPathPiece
|
||||||
derivePersistField "MessageClass"
|
derivePersistField "MessageStatus"
|
||||||
|
|
||||||
newtype UnknownMessageClass = UnknownMessageClass Text
|
newtype UnknownMessageStatus = UnknownMessageStatus Text
|
||||||
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
deriving (Eq, Ord, Read, Show, Generic, Typeable)
|
||||||
|
|
||||||
instance Exception UnknownMessageClass
|
instance Exception UnknownMessageStatus
|
||||||
|
|
||||||
|
|
||||||
data Message = Message
|
data Message = Message
|
||||||
{ messageClass :: MessageClass
|
{ messageStatus :: MessageStatus
|
||||||
, messageContent :: Html
|
, messageContent :: Html
|
||||||
}
|
}
|
||||||
|
|
||||||
instance Eq Message where
|
instance Eq Message where
|
||||||
a == b = ((==) `on` messageClass) a b && ((==) `on` renderHtml . messageContent) a b
|
a == b = ((==) `on` messageStatus) a b && ((==) `on` renderHtml . messageContent) a b
|
||||||
|
|
||||||
instance Ord Message where
|
instance Ord Message where
|
||||||
a `compare` b = (compare `on` messageClass) a b `mappend` (compare `on` renderHtml . messageContent) a b
|
a `compare` b = (compare `on` messageStatus) a b `mappend` (compare `on` renderHtml . messageContent) a b
|
||||||
|
|
||||||
instance ToJSON Message where
|
instance ToJSON Message where
|
||||||
toJSON Message{..} = object
|
toJSON Message{..} = object
|
||||||
[ "class" .= messageClass
|
[ "status" .= messageStatus
|
||||||
, "content" .= renderHtml messageContent
|
, "content" .= renderHtml messageContent
|
||||||
]
|
]
|
||||||
|
|
||||||
instance FromJSON Message where
|
instance FromJSON Message where
|
||||||
parseJSON = withObject "Message" $ \o -> do
|
parseJSON = withObject "Message" $ \o -> do
|
||||||
messageClass <- o .: "class"
|
messageStatus <- o .: "status"
|
||||||
messageContent <- preEscapedText . sanitizeBalance <$> o .: "content"
|
messageContent <- preEscapedText . sanitizeBalance <$> o .: "content"
|
||||||
return Message{..}
|
return Message{..}
|
||||||
|
|
||||||
|
|
||||||
addMessage :: MonadHandler m => MessageClass -> Html -> m ()
|
addMessage :: MonadHandler m => MessageStatus -> Html -> m ()
|
||||||
addMessage mc = ClassyPrelude.Yesod.addMessage (toPathPiece mc)
|
addMessage mc = ClassyPrelude.Yesod.addMessage (toPathPiece mc)
|
||||||
|
|
||||||
addMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageClass -> msg -> m ()
|
addMessageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageStatus -> msg -> m ()
|
||||||
addMessageI mc = ClassyPrelude.Yesod.addMessageI (toPathPiece mc)
|
addMessageI mc = ClassyPrelude.Yesod.addMessageI (toPathPiece mc)
|
||||||
|
|
||||||
messageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageClass -> msg -> m Message
|
messageI :: (MonadHandler m, RenderMessage (HandlerSite m) msg) => MessageStatus -> msg -> m Message
|
||||||
messageI messageClass msg = do
|
messageI messageStatus msg = do
|
||||||
messageContent <- toHtml . ($ msg) <$> getMessageRender
|
messageContent <- toHtml . ($ msg) <$> getMessageRender
|
||||||
return Message{..}
|
return Message{..}
|
||||||
|
|
||||||
addMessageIHamlet :: ( MonadHandler m
|
addMessageIHamlet :: ( MonadHandler m
|
||||||
, RenderMessage (HandlerSite m) msg
|
, RenderMessage (HandlerSite m) msg
|
||||||
, HandlerSite m ~ site
|
, HandlerSite m ~ site
|
||||||
) => MessageClass -> HtmlUrlI18n msg (Route site) -> m ()
|
) => MessageStatus -> HtmlUrlI18n msg (Route site) -> m ()
|
||||||
addMessageIHamlet mc iHamlet = do
|
addMessageIHamlet mc iHamlet = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
ClassyPrelude.Yesod.addMessage (toPathPiece mc) =<< withUrlRenderer (iHamlet $ toHtml . mr)
|
ClassyPrelude.Yesod.addMessage (toPathPiece mc) =<< withUrlRenderer (iHamlet $ toHtml . mr)
|
||||||
@ -90,22 +90,22 @@ addMessageIHamlet mc iHamlet = do
|
|||||||
messageIHamlet :: ( MonadHandler m
|
messageIHamlet :: ( MonadHandler m
|
||||||
, RenderMessage (HandlerSite m) msg
|
, RenderMessage (HandlerSite m) msg
|
||||||
, HandlerSite m ~ site
|
, HandlerSite m ~ site
|
||||||
) => MessageClass -> HtmlUrlI18n msg (Route site) -> m Message
|
) => MessageStatus -> HtmlUrlI18n msg (Route site) -> m Message
|
||||||
messageIHamlet mc iHamlet = do
|
messageIHamlet mc iHamlet = do
|
||||||
mr <- getMessageRender
|
mr <- getMessageRender
|
||||||
Message mc <$> withUrlRenderer (iHamlet $ toHtml . mr)
|
Message mc <$> withUrlRenderer (iHamlet $ toHtml . mr)
|
||||||
|
|
||||||
addMessageFile :: MessageClass -> FilePath -> ExpQ
|
addMessageFile :: MessageStatus -> FilePath -> ExpQ
|
||||||
addMessageFile mc tPath = [e|addMessageIHamlet mc $(ihamletFile tPath)|]
|
addMessageFile mc tPath = [e|addMessageIHamlet mc $(ihamletFile tPath)|]
|
||||||
|
|
||||||
messageFile :: MessageClass -> FilePath -> ExpQ
|
messageFile :: MessageStatus -> FilePath -> ExpQ
|
||||||
messageFile mc tPath = [e|messageIHamlet mc $(ihamletFile tPath)|]
|
messageFile mc tPath = [e|messageIHamlet mc $(ihamletFile tPath)|]
|
||||||
|
|
||||||
addMessageWidget :: forall m site.
|
addMessageWidget :: forall m site.
|
||||||
( MonadHandler m
|
( MonadHandler m
|
||||||
, HandlerSite m ~ site
|
, HandlerSite m ~ site
|
||||||
, Yesod site
|
, Yesod site
|
||||||
) => MessageClass -> WidgetT site IO () -> m ()
|
) => MessageStatus -> WidgetT site IO () -> m ()
|
||||||
-- ^ _Note_: `addMessageWidget` ignores `pageTitle` and `pageHead`
|
-- ^ _Note_: `addMessageWidget` ignores `pageTitle` and `pageHead`
|
||||||
addMessageWidget mc wgt = do
|
addMessageWidget mc wgt = do
|
||||||
PageContent{pageBody} <- liftHandlerT $ widgetToPageContent wgt
|
PageContent{pageBody} <- liftHandlerT $ widgetToPageContent wgt
|
||||||
@ -115,7 +115,7 @@ messageWidget :: forall m site.
|
|||||||
( MonadHandler m
|
( MonadHandler m
|
||||||
, HandlerSite m ~ site
|
, HandlerSite m ~ site
|
||||||
, Yesod site
|
, Yesod site
|
||||||
) => MessageClass -> WidgetT site IO () -> m Message
|
) => MessageStatus -> WidgetT site IO () -> m Message
|
||||||
messageWidget mc wgt = do
|
messageWidget mc wgt = do
|
||||||
PageContent{pageBody} <- liftHandlerT $ widgetToPageContent wgt
|
PageContent{pageBody} <- liftHandlerT $ widgetToPageContent wgt
|
||||||
messageIHamlet mc (const pageBody :: HtmlUrlI18n (SomeMessage site) (Route site))
|
messageIHamlet mc (const pageBody :: HtmlUrlI18n (SomeMessage site) (Route site))
|
||||||
|
|||||||
@ -1,5 +1,74 @@
|
|||||||
.async-form-response {
|
.async-form-response {
|
||||||
margin: 20px 0;
|
margin: 20px 0;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 18px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.async-form-response::before,
|
||||||
|
.async-form-response::after {
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
left: 50%;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.async-form-response--success::before {
|
||||||
|
content: '';
|
||||||
|
width: 17px;
|
||||||
|
height: 28px;
|
||||||
|
border: solid #069e04;
|
||||||
|
border-width: 0 5px 5px 0;
|
||||||
|
transform: translateX(-50%) rotate(45deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.async-form-response--info::before {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 30px;
|
||||||
|
top: 10px;
|
||||||
|
background-color: #777;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
.async-form-response--info::after {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
background-color: #777;
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.async-form-response--warning::before {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 30px;
|
||||||
|
background-color: rgb(255, 187, 0);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
.async-form-response--warning::after {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 5px;
|
||||||
|
top: 35px;
|
||||||
|
background-color: rgb(255, 187, 0);
|
||||||
|
transform: translateX(-50%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.async-form-response--error::before {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #940d0d;
|
||||||
|
transform: translateX(-50%) rotate(-45deg);
|
||||||
|
}
|
||||||
|
.async-form-response--error::after {
|
||||||
|
content: '';
|
||||||
|
width: 5px;
|
||||||
|
height: 40px;
|
||||||
|
background-color: #940d0d;
|
||||||
|
transform: translateX(-50%) rotate(45deg);
|
||||||
}
|
}
|
||||||
|
|
||||||
.async-form-loading {
|
.async-form-loading {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
transform: translate(-50%, -50%) scale(0.8, 0.8);
|
transform: translate(-50%, -50%) scale(0.8, 0.8);
|
||||||
display: block;
|
display: flex;
|
||||||
background-color: rgba(255, 255, 255, 1);
|
background-color: rgba(255, 255, 255, 1);
|
||||||
min-width: 60vw;
|
min-width: 60vw;
|
||||||
min-height: 100px;
|
min-height: 100px;
|
||||||
@ -26,10 +26,6 @@
|
|||||||
z-index: 200;
|
z-index: 200;
|
||||||
transform: translate(-50%, -50%) scale(1, 1);
|
transform: translate(-50%, -50%) scale(1, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.modal__content {
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (max-width: 1024px) {
|
@media (max-width: 1024px) {
|
||||||
@ -96,3 +92,8 @@
|
|||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.modal__content {
|
||||||
|
margin: 20px 0;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|||||||
@ -89,6 +89,7 @@
|
|||||||
alertElements.forEach(initAlert);
|
alertElements.forEach(initAlert);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: alertsEl,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -57,6 +57,7 @@
|
|||||||
initAsidenavSubmenus();
|
initAsidenavSubmenus();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: asideEl,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -6,9 +6,12 @@
|
|||||||
var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response';
|
var ASYNC_FORM_RESPONSE_CLASS = 'async-form-response';
|
||||||
var ASYNC_FORM_LOADING_CLASS = 'async-form-loading';
|
var ASYNC_FORM_LOADING_CLASS = 'async-form-loading';
|
||||||
var ASYNC_FORM_MIN_DELAY = 600;
|
var ASYNC_FORM_MIN_DELAY = 600;
|
||||||
|
var DEFAULT_FAILURE_MESSAGE = 'The response we received from the server did not match what we expected. Please let us know this happened via the help widget in the top navigation.';
|
||||||
|
|
||||||
window.utils.asyncForm = function(formElement, options) {
|
window.utils.asyncForm = function(formElement, options) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
var lastRequestTimestamp = 0;
|
var lastRequestTimestamp = 0;
|
||||||
|
|
||||||
function setup() {
|
function setup() {
|
||||||
@ -16,19 +19,27 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function processResponse(response) {
|
function processResponse(response) {
|
||||||
var responseElement = document.createElement('div');
|
var responseElement = makeResponseElement(response.content, response.status);
|
||||||
responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS);
|
|
||||||
responseElement.innerHTML = response.content;
|
|
||||||
var parentElement = formElement.parentElement;
|
var parentElement = formElement.parentElement;
|
||||||
|
|
||||||
// make sure there is a delay between click and response
|
// make sure there is a delay between click and response
|
||||||
var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());
|
var delay = Math.max(0, ASYNC_FORM_MIN_DELAY + lastRequestTimestamp - Date.now());
|
||||||
|
|
||||||
setTimeout(function() {
|
setTimeout(function() {
|
||||||
parentElement.insertBefore(responseElement, formElement);
|
parentElement.insertBefore(responseElement, formElement);
|
||||||
formElement.remove();
|
formElement.remove();
|
||||||
}, delay);
|
}, delay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makeResponseElement(content, status) {
|
||||||
|
var responseElement = document.createElement('div');
|
||||||
|
status = status || 'info';
|
||||||
|
responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS);
|
||||||
|
responseElement.classList.add(ASYNC_FORM_RESPONSE_CLASS + '--' + status);
|
||||||
|
responseElement.innerHTML = content;
|
||||||
|
return responseElement;
|
||||||
|
}
|
||||||
|
|
||||||
function submitHandler(event) {
|
function submitHandler(event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
@ -47,17 +58,28 @@
|
|||||||
|
|
||||||
window.utils.httpClient.post(url, headers, body)
|
window.utils.httpClient.post(url, headers, body)
|
||||||
.then(function(response) {
|
.then(function(response) {
|
||||||
return response.json();
|
if (response.headers.get("content-type").indexOf("application/json") !== -1) {// checking response header
|
||||||
|
return response.json();
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Unexpected Content-Type. Expected Content-Type: "application/json". Requested URL:' + url + '"');
|
||||||
|
}
|
||||||
}).then(function(response) {
|
}).then(function(response) {
|
||||||
processResponse(response[0])
|
processResponse(response[0]);
|
||||||
}).catch(function(error) {
|
}).catch(function(error) {
|
||||||
console.error('could not fetch or process response from ' + url, { error });
|
var failureMessage = DEFAULT_FAILURE_MESSAGE;
|
||||||
|
if (options.i18n && options.i18n.asyncFormFailure) {
|
||||||
|
failureMessage = options.i18n.asyncFormFailure;
|
||||||
|
}
|
||||||
|
processResponse({ content: failureMessage });
|
||||||
|
|
||||||
|
formElement.classList.remove(ASYNC_FORM_LOADING_CLASS);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: formElement,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -225,6 +225,7 @@
|
|||||||
init();
|
init();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: wrapper,
|
||||||
destroy: destroyUtils,
|
destroy: destroyUtils,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -159,6 +159,7 @@
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: formElement,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -124,6 +124,7 @@
|
|||||||
init();
|
init();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: wrapper,
|
||||||
destroy: destroy,
|
destroy: destroy,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -54,6 +54,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: form,
|
||||||
destroy: destroyUtils,
|
destroy: destroyUtils,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -97,6 +98,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: form,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -138,6 +140,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: form,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -149,6 +152,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: form,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -44,6 +44,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: wrapper,
|
||||||
destroy: destroyUtils,
|
destroy: destroyUtils,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -135,6 +136,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: input,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -169,6 +171,7 @@
|
|||||||
setup();
|
setup();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: input,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -195,6 +198,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: input,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -218,6 +222,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: input,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -146,6 +146,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: modalElement,
|
||||||
destroy: destroyUtils,
|
destroy: destroyUtils,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
window.utils = window.utils || {};
|
window.utils = window.utils || {};
|
||||||
|
|
||||||
var registeredSetupListeners = {};
|
var registeredSetupListeners = {};
|
||||||
|
var activeInstances = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* setup function to initiate a util (utilName) on a scope (sope) with options (options).
|
* setup function to initiate a util (utilName) on a scope (sope) with options (options).
|
||||||
@ -13,57 +14,98 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
window.utils.setup = function(utilName, scope, options) {
|
window.utils.setup = function(utilName, scope, options) {
|
||||||
|
|
||||||
var utilInstance;
|
|
||||||
|
|
||||||
if (!utilName || !scope) {
|
if (!utilName || !scope) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var listener = function(event) {
|
var utilInstance;
|
||||||
|
|
||||||
if (event.detail.targetUtil !== utilName) {
|
// i18n
|
||||||
return false;
|
if (window.I18N) {
|
||||||
}
|
options.i18n = window.I18N;
|
||||||
|
|
||||||
if (options.setupFunction) {
|
|
||||||
utilInstance = options.setupFunction(scope, options);
|
|
||||||
} else {
|
|
||||||
var util = window.utils[utilName];
|
|
||||||
if (!util) {
|
|
||||||
throw new Error('"' + utilName + '" is not a known js util');
|
|
||||||
}
|
|
||||||
|
|
||||||
utilInstance = util(scope, options);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.utils.teardown(utilName);
|
|
||||||
if (registeredSetupListeners[utilName] && !options.singleton) {
|
|
||||||
registeredSetupListeners[utilName].push(listener);
|
|
||||||
} else {
|
|
||||||
registeredSetupListeners[utilName] = [ listener ];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('setup', listener);
|
if (activeInstances[utilName]) {
|
||||||
|
var instanceWithSameScope = activeInstances[utilName]
|
||||||
|
.filter(function(instance) { return !!instance; })
|
||||||
|
.find(function(instance) {
|
||||||
|
return instance.scope === scope;
|
||||||
|
});
|
||||||
|
var isAlreadySetup = !!instanceWithSameScope;
|
||||||
|
|
||||||
document.dispatchEvent(new CustomEvent('setup', {
|
if (isAlreadySetup) {
|
||||||
detail: { targetUtil: utilName, module: 'none' },
|
console.warn('Trying to setup a JS utility that\'s already been set up', { utility: utilName, scope, options });
|
||||||
bubbles: true,
|
}
|
||||||
cancelable: true,
|
}
|
||||||
}));
|
|
||||||
|
function setup() {
|
||||||
|
var listener = function(event) {
|
||||||
|
if (event.detail.targetUtil !== utilName) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.setupFunction) {
|
||||||
|
utilInstance = options.setupFunction(scope, options);
|
||||||
|
} else {
|
||||||
|
var util = window.utils[utilName];
|
||||||
|
if (!util) {
|
||||||
|
throw new Error('"' + utilName + '" is not a known js util');
|
||||||
|
}
|
||||||
|
|
||||||
|
utilInstance = util(scope, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utilInstance) {
|
||||||
|
if (activeInstances[utilName] && Array.isArray(activeInstances[utilName])) {
|
||||||
|
activeInstances[utilName].push(utilInstance);
|
||||||
|
} else {
|
||||||
|
activeInstances[utilName] = [ utilInstance ];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (registeredSetupListeners[utilName] && Array.isArray(registeredSetupListeners[utilName])) {
|
||||||
|
window.utils.teardown(utilName);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!registeredSetupListeners[utilName] || Array.isArray(registeredSetupListeners[utilName])) {
|
||||||
|
registeredSetupListeners[utilName] = [];
|
||||||
|
}
|
||||||
|
registeredSetupListeners[utilName].push(listener);
|
||||||
|
|
||||||
|
document.addEventListener('setup', listener);
|
||||||
|
|
||||||
|
document.dispatchEvent(new CustomEvent('setup', {
|
||||||
|
detail: { targetUtil: utilName, module: 'none' },
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
setup();
|
||||||
|
|
||||||
return utilInstance;
|
return utilInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
window.utils.teardown = function(utilName) {
|
window.utils.teardown = function(utilName, destroy) {
|
||||||
if (registeredSetupListeners[utilName]) {
|
if (registeredSetupListeners[utilName]) {
|
||||||
registeredSetupListeners[utilName].forEach(function(listener) {
|
registeredSetupListeners[utilName]
|
||||||
document.removeEventListener('setup', listener);
|
.filter(function(listener) { return !!listener })
|
||||||
});
|
.forEach(function(listener) {
|
||||||
|
document.removeEventListener('setup', listener);
|
||||||
|
});
|
||||||
delete registeredSetupListeners[utilName];
|
delete registeredSetupListeners[utilName];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (destroy === true && activeInstances[utilName]) {
|
||||||
|
activeInstances[utilName]
|
||||||
|
.filter(function(instance) { return !!instance })
|
||||||
|
.forEach(function(instance) {
|
||||||
|
instance.destroy();
|
||||||
|
});
|
||||||
|
delete activeInstances[utilName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
|
|||||||
@ -70,6 +70,7 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
scope: wrapper,
|
||||||
destroy: function() {},
|
destroy: function() {},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@ -86,9 +86,5 @@
|
|||||||
$(t).tabgroup();
|
$(t).tabgroup();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
|
||||||
destroy: function() {},
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
})($);
|
})($);
|
||||||
|
|||||||
@ -35,14 +35,16 @@ function setupDatepicker(wrapper) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
// this global I18N object will be picked up automatically by the setup util
|
||||||
var I18N = {
|
window.I18N = {
|
||||||
filesSelected: 'Dateien ausgewählt', // TODO: interpolate these to be translated
|
filesSelected: 'Dateien ausgewählt', // TODO: interpolate these to be translated
|
||||||
selectFile: 'Datei auswählen',
|
selectFile: 'Datei auswählen',
|
||||||
selectFiles: 'Datei(en) auswählen',
|
selectFiles: 'Datei(en) auswählen',
|
||||||
};
|
asyncFormFailure: 'Da ist etwas schief gelaufen, das tut uns Leid.<br>Falls das erneut passiert schicke uns gerne eine kurze Beschreibung dieses Ereignisses über das Hilfe-Widget rechts oben.<br><br>Vielen Dank für deine Hilfe',
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
window.utils.setup('flatpickr', document.body, { setupFunction: setupDatepicker });
|
window.utils.setup('flatpickr', document.body, { setupFunction: setupDatepicker });
|
||||||
window.utils.setup('showHide', document.body);
|
window.utils.setup('showHide', document.body);
|
||||||
window.utils.setup('inputs', document.body, { i18n: I18N });
|
window.utils.setup('inputs', document.body);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user