Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ public interface LoginFormsProvider extends Provider {
*/
void addScript(String scriptUrl);

default void addScript(String scriptUrl, boolean async, boolean defer) {
addScript(scriptUrl);
}

Response createResponse(UserModel.RequiredAction action);

Response createForm(String form);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.keycloak.forms.login.freemarker.model.RegisterBean;
import org.keycloak.forms.login.freemarker.model.RequiredActionUrlFormatterMethod;
import org.keycloak.forms.login.freemarker.model.SAMLPostFormBean;
import org.keycloak.forms.login.freemarker.model.ScriptBean;
import org.keycloak.forms.login.freemarker.model.TotpBean;
import org.keycloak.forms.login.freemarker.model.TotpLoginBean;
import org.keycloak.forms.login.freemarker.model.UrlBean;
Expand Down Expand Up @@ -136,11 +137,16 @@ public FreeMarkerLoginFormsProvider(KeycloakSession session, FreeMarkerUtil free
this.uriInfo = session.getContext().getUri();
}

@SuppressWarnings("unchecked")
@Override
public void addScript(String scriptUrl) {
List<String> scripts = (List<String>) this.attributes.get("scripts");
scripts.add(scriptUrl);
addScript(scriptUrl, false, false);
}

@SuppressWarnings("unchecked")
@Override
public void addScript(final String scriptUrl, final boolean async, final boolean defer) {
List<ScriptBean> scripts = (List<ScriptBean>) this.attributes.get("scripts");
scripts.add(new ScriptBean(scriptUrl, async, defer));
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.keycloak.forms.login.freemarker.model;

public class ScriptBean {

private final String url;
private final boolean async;
private final boolean defer;

public ScriptBean(String url, boolean async, boolean defer) {
this.url = url;
this.async = async;
this.defer = defer;
}

public String getUrl() {
return url;
}

public boolean isAsync() {
return async;
}

public boolean isDefer() {
return defer;
}

/*
* This is a workaround: When an old theme template copies the mechanism of loading these scripts:
* <script src="${script}" type="text/javascript"></script>
* They assume the "script" is the URL. By returning URL in toString, Freemarker will call toString on the object and
* return the url. This way, we don't break backwards compatibility
*/
@Override
public String toString() {
return url;
}
}
12 changes: 11 additions & 1 deletion themes/src/main/resources/theme/base/login/template.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,19 @@
<script src="${url.resourcesPath}/${script}" type="text/javascript"></script>
</#list>
</#if>
<#if properties.asyncScripts?has_content>
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This allows a theme extending base (or another theme that extends base) to add scripts that should be loaded with the async or defer parameters

<#list properties.asyncScripts?split(' ') as script>
<script src="${url.resourcesPath}/${script}" type="text/javascript" async></script>
</#list>
</#if>
<#if properties.deferScripts?has_content>
<#list properties.deferScripts?split(' ') as script>
<script src="${url.resourcesPath}/${script}" type="text/javascript" defer></script>
</#list>
</#if>
<#if scripts??>
<#list scripts as script>
<script src="${script}" type="text/javascript"></script>
<script src="${script.url}" type="text/javascript" ${script.async?then('async', '')} ${script.defer?then('defer', '')}></script>
</#list>
</#if>
</head>
Expand Down