KEYCLOAK-2489 - Add support for Script-based AuthenticationExecution definitions.
This is a POC for script based authenticator support. Introduced a ScriptBasedAuthenticator that is bootstraped via a ScriptBasedAuthenticatorFactory can be execute a configured script against a provided execution context. Added an alias property to the AuthFlowExecutionRepresentation in order to be able to differentiate multiple instances of an Authenticator within the same AuthFlow. For convenience editing the AngularJS bindings for the ACE editor were added for fancy script editing - this needs to be cut down a bit wrt to themes and supported scripts - e.g. we probably don't expect users to write authenticator scripts in Cobol... Removed currently not needed ACE sytax highlighting and themes. Scripting is now available to all keycloak components that have access to the KeycloakSession. Introduced new Scripting SPI for configurable scripting providers.
This commit is contained in:
parent
dcb6cedfb7
commit
c8d47926b8
70 changed files with 915 additions and 5 deletions
|
@ -29,6 +29,7 @@ public class AuthenticationExecutionInfoRepresentation implements Serializable {
|
|||
protected String id;
|
||||
protected String requirement;
|
||||
protected String displayName;
|
||||
protected String alias;
|
||||
protected List<String> requirementChoices;
|
||||
protected Boolean configurable;
|
||||
protected Boolean authenticationFlow;
|
||||
|
@ -54,6 +55,14 @@ public class AuthenticationExecutionInfoRepresentation implements Serializable {
|
|||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String getAlias() {
|
||||
return alias;
|
||||
}
|
||||
|
||||
public void setAlias(String alias) {
|
||||
this.alias = alias;
|
||||
}
|
||||
|
||||
public String getRequirement() {
|
||||
return requirement;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.scripting.ScriptingProvider;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -76,4 +77,9 @@ public interface KeycloakSession {
|
|||
* Keycloak user storage. Non-federated, but possibly cache (if it is on) view of users.
|
||||
*/
|
||||
UserProvider userStorage();
|
||||
|
||||
/**
|
||||
* Keycloak scripting support.
|
||||
*/
|
||||
ScriptingProvider scripting();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package org.keycloak.models;
|
||||
|
||||
/**
|
||||
* Denotes an executable Script with metadata.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public interface ScriptModel {
|
||||
|
||||
/**
|
||||
* Returns the unique id of the script. {@literal null} for ad-hoc created scripts.
|
||||
*/
|
||||
String getId();
|
||||
|
||||
/**
|
||||
* Returns the realm id in which the script was defined.
|
||||
*/
|
||||
String getRealmId();
|
||||
|
||||
/**
|
||||
* Returns the name of the script.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Returns the MIME-type if the script code, e.g. for Java Script the MIME-type, {@code text/javascript} is used.
|
||||
*/
|
||||
String getMimeType();
|
||||
|
||||
/**
|
||||
* Returns the actual source code of the script.
|
||||
*/
|
||||
String getCode();
|
||||
|
||||
/**
|
||||
* Returns the description of the script.
|
||||
*/
|
||||
String getDescription();
|
||||
}
|
|
@ -24,6 +24,7 @@ package org.keycloak.provider;
|
|||
public class ProviderConfigProperty {
|
||||
public static final String BOOLEAN_TYPE="boolean";
|
||||
public static final String STRING_TYPE="String";
|
||||
public static final String SCRIPT_TYPE="Script";
|
||||
public static final String ROLE_TYPE="Role";
|
||||
public static final String LIST_TYPE="List";
|
||||
public static final String CLIENT_LIST_TYPE="ClientList";
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.models.ScriptModel;
|
||||
|
||||
import javax.script.Invocable;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class InvocableScript implements Invocable {
|
||||
|
||||
/**
|
||||
* Holds the script metadata as well as the actual script.
|
||||
*/
|
||||
private final ScriptModel script;
|
||||
|
||||
/**
|
||||
* Holds the {@link ScriptEngine} instance initialized with the script code.
|
||||
*/
|
||||
private final ScriptEngine scriptEngine;
|
||||
|
||||
public InvocableScript(ScriptModel script, ScriptEngine scriptEngine) {
|
||||
this.script = script;
|
||||
this.scriptEngine = scriptEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeMethod(Object thiz, String name, Object... args) throws ScriptException, NoSuchMethodException {
|
||||
return getInvocableEngine().invokeMethod(thiz, name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invokeFunction(String name, Object... args) throws ScriptException, NoSuchMethodException {
|
||||
return getInvocableEngine().invokeFunction(name, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(Class<T> clazz) {
|
||||
return getInvocableEngine().getInterface(clazz);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getInterface(Object thiz, Class<T> clazz) {
|
||||
return getInvocableEngine().getInterface(thiz, clazz);
|
||||
}
|
||||
|
||||
private Invocable getInvocableEngine() {
|
||||
return (Invocable) scriptEngine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@literal true} iif the {@link ScriptEngine} has a function with the given {@code functionName}.
|
||||
* @param functionName
|
||||
* @return
|
||||
*/
|
||||
public boolean hasFunction(String functionName){
|
||||
|
||||
Object candidate = scriptEngine.getContext().getAttribute(functionName);
|
||||
|
||||
return candidate != null;
|
||||
}
|
||||
}
|
97
server-spi/src/main/java/org/keycloak/scripting/Script.java
Normal file
97
server-spi/src/main/java/org/keycloak/scripting/Script.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.models.ScriptModel;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class Script implements ScriptModel {
|
||||
|
||||
private String id;
|
||||
|
||||
private String realmId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String mimeType;
|
||||
|
||||
private String code;
|
||||
|
||||
private String description;
|
||||
|
||||
public Script(String id, String realmId, String name, String mimeType, String code, String description) {
|
||||
|
||||
this.id = id;
|
||||
this.realmId = realmId;
|
||||
this.name = name;
|
||||
this.mimeType = mimeType;
|
||||
this.code = code;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRealmId() {
|
||||
return realmId;
|
||||
}
|
||||
|
||||
public void setRealmId(String realmId) {
|
||||
this.realmId = realmId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
public void setMimeType(String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Script{" +
|
||||
"id='" + id + '\'' +
|
||||
", realmId='" + realmId + '\'' +
|
||||
", name='" + name + '\'' +
|
||||
", type='" + mimeType + '\'' +
|
||||
", code='" + code + '\'' +
|
||||
", description='" + description + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import javax.script.Bindings;
|
||||
|
||||
/**
|
||||
* Callback interface for customization of {@link Bindings} for a {@link javax.script.ScriptEngine}.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface ScriptBindingsConfigurer {
|
||||
|
||||
/**
|
||||
* A default {@link ScriptBindingsConfigurer} leaves the Bindings empty.
|
||||
*/
|
||||
ScriptBindingsConfigurer EMPTY = new ScriptBindingsConfigurer() {
|
||||
|
||||
@Override
|
||||
public void configureBindings(Bindings bindings) {
|
||||
//NOOP
|
||||
}
|
||||
};
|
||||
|
||||
void configureBindings(Bindings bindings);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.models.ScriptModel;
|
||||
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* Augments a {@link ScriptException} and adds additional metadata.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class ScriptExecutionException extends RuntimeException {
|
||||
|
||||
public ScriptExecutionException(ScriptModel script, ScriptException se) {
|
||||
super("Error executing script '" + script.getName() + "'", se);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.models.ScriptModel;
|
||||
import org.keycloak.provider.Provider;
|
||||
|
||||
import javax.script.ScriptEngine;
|
||||
|
||||
/**
|
||||
* A {@link Provider} than provides Scripting capabilities.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public interface ScriptingProvider extends Provider {
|
||||
|
||||
/**
|
||||
* Returns an {@link InvocableScript} based on the given {@link ScriptModel}.
|
||||
* <p>The {@code InvocableScript} wraps a dedicated {@link ScriptEngine} that was populated with the provided {@link ScriptBindingsConfigurer}</p>
|
||||
*
|
||||
* @param script the script to wrap
|
||||
* @param bindingsConfigurer populates the {@link javax.script.Bindings}
|
||||
* @return
|
||||
*/
|
||||
InvocableScript prepareScript(ScriptModel script, ScriptBindingsConfigurer bindingsConfigurer);
|
||||
|
||||
/**
|
||||
* Returns an {@link InvocableScript} based on the given {@link ScriptModel} with an {@link ScriptBindingsConfigurer#EMPTY} {@code ScriptBindingsConfigurer}.
|
||||
* @see #prepareScript(ScriptModel, ScriptBindingsConfigurer)
|
||||
* @param script
|
||||
* @return
|
||||
*/
|
||||
InvocableScript prepareScript(ScriptModel script);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public interface ScriptingProviderFactory extends ProviderFactory<ScriptingProvider> {
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.provider.Spi;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class ScriptingSpi implements Spi {
|
||||
|
||||
@Override
|
||||
public boolean isInternal() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "scripting";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends Provider> getProviderClass() {
|
||||
return ScriptingProvider.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends ProviderFactory> getProviderFactoryClass() {
|
||||
return ScriptingProviderFactory.class;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,7 @@ org.keycloak.events.EventStoreSpi
|
|||
org.keycloak.exportimport.ExportSpi
|
||||
org.keycloak.exportimport.ImportSpi
|
||||
org.keycloak.timer.TimerSpi
|
||||
org.keycloak.scripting.ScriptingSpi
|
||||
org.keycloak.services.managers.BruteForceProtectorSpi
|
||||
org.keycloak.services.resource.RealmResourceSPI
|
||||
org.keycloak.protocol.ClientInstallationSpi
|
||||
|
@ -53,4 +54,3 @@ org.keycloak.authentication.FormAuthenticatorSpi
|
|||
org.keycloak.authentication.FormActionSpi
|
||||
org.keycloak.cluster.ClusterSpi
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,115 @@
|
|||
package org.keycloak.authentication.authenticators.browser;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
import org.keycloak.authentication.AuthenticationFlowContext;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.RealmModel;
|
||||
import org.keycloak.models.UserModel;
|
||||
import org.keycloak.scripting.InvocableScript;
|
||||
import org.keycloak.scripting.Script;
|
||||
import org.keycloak.scripting.ScriptBindingsConfigurer;
|
||||
import org.keycloak.scripting.ScriptingProvider;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptException;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An {@link Authenticator} that can execute a configured script during authentication flow.
|
||||
* <p>scripts must provide </p>
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class ScriptBasedAuthenticator implements Authenticator {
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(ScriptBasedAuthenticator.class);
|
||||
|
||||
static final String SCRIPT_CODE = "scriptCode";
|
||||
static final String SCRIPT_NAME = "scriptName";
|
||||
static final String SCRIPT_DESCRIPTION = "scriptDescription";
|
||||
|
||||
static final String ACTION = "action";
|
||||
static final String AUTHENTICATE = "authenticate";
|
||||
static final String TEXT_JAVASCRIPT = "text/javascript";
|
||||
|
||||
@Override
|
||||
public void authenticate(AuthenticationFlowContext context) {
|
||||
tryInvoke(AUTHENTICATE, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void action(AuthenticationFlowContext context) {
|
||||
tryInvoke(ACTION, context);
|
||||
}
|
||||
|
||||
private void tryInvoke(String functionName, AuthenticationFlowContext context) {
|
||||
|
||||
InvocableScript script = getInvocableScript(context);
|
||||
|
||||
if (!script.hasFunction(functionName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
//should context be wrapped in a readonly wrapper?
|
||||
script.invokeFunction(functionName, context);
|
||||
} catch (ScriptException | NoSuchMethodException e) {
|
||||
LOGGER.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
private InvocableScript getInvocableScript(final AuthenticationFlowContext context) {
|
||||
|
||||
final Script script = createAdhocScriptFromContext(context);
|
||||
|
||||
ScriptBindingsConfigurer bindingsConfigurer = new ScriptBindingsConfigurer() {
|
||||
|
||||
@Override
|
||||
public void configureBindings(Bindings bindings) {
|
||||
|
||||
bindings.put("script", script);
|
||||
bindings.put("LOG", LOGGER);
|
||||
}
|
||||
};
|
||||
|
||||
ScriptingProvider scripting = context.getSession().scripting();
|
||||
|
||||
//how to deal with long running scripts -> timeout?
|
||||
|
||||
return scripting.prepareScript(script, bindingsConfigurer);
|
||||
}
|
||||
|
||||
private Script createAdhocScriptFromContext(AuthenticationFlowContext context) {
|
||||
|
||||
Map<String, String> config = context.getAuthenticatorConfig().getConfig();
|
||||
|
||||
String scriptName = config.get(SCRIPT_NAME);
|
||||
String scriptCode = config.get(SCRIPT_CODE);
|
||||
String scriptDescription = config.get(SCRIPT_DESCRIPTION);
|
||||
|
||||
RealmModel realm = context.getRealm();
|
||||
|
||||
return new Script(null /* scriptId */, realm.getId(), scriptName, TEXT_JAVASCRIPT, scriptCode, scriptDescription);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresUser() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean configuredFor(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequiredActions(KeycloakSession session, RealmModel realm, UserModel user) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//NOOP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
package org.keycloak.authentication.authenticators.browser;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.authentication.Authenticator;
|
||||
import org.keycloak.authentication.AuthenticatorFactory;
|
||||
import org.keycloak.models.AuthenticationExecutionModel;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
import org.keycloak.provider.ProviderConfigProperty;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_CODE;
|
||||
import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_DESCRIPTION;
|
||||
import static org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticator.SCRIPT_NAME;
|
||||
import static org.keycloak.provider.ProviderConfigProperty.SCRIPT_TYPE;
|
||||
import static org.keycloak.provider.ProviderConfigProperty.STRING_TYPE;
|
||||
|
||||
/**
|
||||
* An {@link AuthenticatorFactory} for {@link ScriptBasedAuthenticator}s.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class ScriptBasedAuthenticatorFactory implements AuthenticatorFactory {
|
||||
|
||||
static final String PROVIDER_ID = "auth-script-based";
|
||||
|
||||
static final AuthenticationExecutionModel.Requirement[] REQUIREMENT_CHOICES = {
|
||||
AuthenticationExecutionModel.Requirement.REQUIRED,
|
||||
AuthenticationExecutionModel.Requirement.OPTIONAL,
|
||||
AuthenticationExecutionModel.Requirement.DISABLED};
|
||||
|
||||
static final ScriptBasedAuthenticator SINGLETON = new ScriptBasedAuthenticator();
|
||||
|
||||
@Override
|
||||
public Authenticator create(KeycloakSession session) {
|
||||
|
||||
/*
|
||||
would be great to have the actual authenticatorId here in order to initialize the authenticator in the ctor with
|
||||
the appropriate config from session.getContext().getRealm().getAuthenticatorConfigById(authenticatorId);
|
||||
|
||||
This would help to avoid potentially re-evaluating the provide script multiple times per authenticator execution.
|
||||
*/
|
||||
return SINGLETON;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return PROVIDER_ID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getReferenceCategory() {
|
||||
return "script";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConfigurable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUserSetupAllowed() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AuthenticationExecutionModel.Requirement[] getRequirementChoices() {
|
||||
return REQUIREMENT_CHOICES;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisplayType() {
|
||||
return "Script-based Authentication";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getHelpText() {
|
||||
return "Script based authentication.";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ProviderConfigProperty> getConfigProperties() {
|
||||
|
||||
ProviderConfigProperty name = new ProviderConfigProperty();
|
||||
name.setType(STRING_TYPE);
|
||||
name.setName(SCRIPT_NAME);
|
||||
name.setLabel("Script Name");
|
||||
name.setHelpText("The name of the script used to authenticate.");
|
||||
|
||||
ProviderConfigProperty description = new ProviderConfigProperty();
|
||||
description.setType(STRING_TYPE);
|
||||
description.setName(SCRIPT_DESCRIPTION);
|
||||
description.setLabel("Script Description");
|
||||
description.setHelpText("The description of the script used to authenticate.");
|
||||
|
||||
ProviderConfigProperty script = new ProviderConfigProperty();
|
||||
script.setType(SCRIPT_TYPE);
|
||||
script.setName(SCRIPT_CODE);
|
||||
script.setLabel("Script Source");
|
||||
script.setDefaultValue("//enter your script here");
|
||||
script.setHelpText("The script used to authenticate. Scripts must at least define a function with the name 'authenticate' that accepts a context (AuthenticationFlowContext) parameter." +
|
||||
"This authenticator exposes the following additional variables: 'script', 'LOG'");
|
||||
|
||||
return asList(name, description, script);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.models.ScriptModel;
|
||||
|
||||
import javax.script.Bindings;
|
||||
import javax.script.ScriptContext;
|
||||
import javax.script.ScriptEngine;
|
||||
import javax.script.ScriptEngineManager;
|
||||
import javax.script.ScriptException;
|
||||
|
||||
/**
|
||||
* A {@link ScriptingProvider} that uses a {@link ScriptEngineManager} to evaluate scripts with a {@link ScriptEngine}.
|
||||
*
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class DefaultScriptingProvider implements ScriptingProvider {
|
||||
|
||||
private final ScriptEngineManager scriptEngineManager;
|
||||
|
||||
public DefaultScriptingProvider(ScriptEngineManager scriptEngineManager) {
|
||||
this.scriptEngineManager = scriptEngineManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocableScript prepareScript(ScriptModel script) {
|
||||
return prepareScript(script, ScriptBindingsConfigurer.EMPTY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InvocableScript prepareScript(ScriptModel script, ScriptBindingsConfigurer bindingsConfigurer) {
|
||||
|
||||
if (script == null) {
|
||||
throw new NullPointerException("script must not be null");
|
||||
}
|
||||
|
||||
if (script.getCode() == null || script.getCode().trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("script must not be null or empty");
|
||||
}
|
||||
|
||||
if (bindingsConfigurer == null) {
|
||||
throw new NullPointerException("bindingsConfigurer must not be null");
|
||||
}
|
||||
|
||||
ScriptEngine engine = lookupScriptEngineFor(script);
|
||||
|
||||
if (engine == null) {
|
||||
throw new IllegalStateException("Could not find ScriptEngine for script: " + script);
|
||||
}
|
||||
|
||||
configureBindings(bindingsConfigurer, engine);
|
||||
|
||||
loadScriptIntoEngine(script, engine);
|
||||
|
||||
return new InvocableScript(script, engine);
|
||||
}
|
||||
|
||||
private void configureBindings(ScriptBindingsConfigurer bindingsConfigurer, ScriptEngine engine) {
|
||||
|
||||
Bindings bindings = engine.createBindings();
|
||||
bindingsConfigurer.configureBindings(bindings);
|
||||
engine.setBindings(bindings, ScriptContext.ENGINE_SCOPE);
|
||||
}
|
||||
|
||||
private void loadScriptIntoEngine(ScriptModel script, ScriptEngine engine) {
|
||||
|
||||
try {
|
||||
engine.eval(script.getCode());
|
||||
} catch (ScriptException se) {
|
||||
throw new ScriptExecutionException(script, se);
|
||||
}
|
||||
}
|
||||
|
||||
private ScriptEngine lookupScriptEngineFor(ScriptModel script) {
|
||||
return scriptEngineManager.getEngineByMimeType(script.getMimeType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//NOOP
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package org.keycloak.scripting;
|
||||
|
||||
import org.keycloak.Config;
|
||||
import org.keycloak.models.KeycloakSession;
|
||||
import org.keycloak.models.KeycloakSessionFactory;
|
||||
|
||||
import javax.script.ScriptEngineManager;
|
||||
|
||||
/**
|
||||
* @author <a href="mailto:thomas.darimont@gmail.com">Thomas Darimont</a>
|
||||
*/
|
||||
public class DefaultScriptingProviderFactory implements ScriptingProviderFactory {
|
||||
|
||||
static final String ID = "script-based-auth";
|
||||
|
||||
private final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
|
||||
|
||||
@Override
|
||||
public ScriptingProvider create(KeycloakSession session) {
|
||||
return new DefaultScriptingProvider(scriptEngineManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Config.Scope config) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postInit(KeycloakSessionFactory factory) {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return ID;
|
||||
}
|
||||
}
|
|
@ -21,6 +21,7 @@ import org.keycloak.models.cache.CacheRealmProvider;
|
|||
import org.keycloak.models.cache.CacheUserProvider;
|
||||
import org.keycloak.provider.Provider;
|
||||
import org.keycloak.provider.ProviderFactory;
|
||||
import org.keycloak.scripting.ScriptingProvider;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
|
@ -35,6 +36,7 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
private final DefaultKeycloakTransactionManager transactionManager;
|
||||
private RealmProvider model;
|
||||
private UserProvider userModel;
|
||||
private ScriptingProvider scriptingProvider;
|
||||
private UserSessionProvider sessionProvider;
|
||||
private UserFederationManager federationManager;
|
||||
private KeycloakContext context;
|
||||
|
@ -168,4 +170,13 @@ public class DefaultKeycloakSession implements KeycloakSession {
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ScriptingProvider scripting() {
|
||||
|
||||
if (scriptingProvider == null) {
|
||||
scriptingProvider = getProvider(ScriptingProvider.class);
|
||||
}
|
||||
|
||||
return scriptingProvider;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -483,6 +483,15 @@ public class AuthenticationManagementResource {
|
|||
rep.getRequirementChoices().add(choice.name());
|
||||
}
|
||||
rep.setId(execution.getId());
|
||||
|
||||
if (factory.isConfigurable()) {
|
||||
AuthenticatorConfigModel authenticatorConfig = realm.getAuthenticatorConfigById(execution.getAuthenticatorConfig());
|
||||
|
||||
if (authenticatorConfig != null) {
|
||||
rep.setAlias(authenticatorConfig.getAlias());
|
||||
}
|
||||
}
|
||||
|
||||
rep.setRequirement(execution.getRequirement().name());
|
||||
rep.setProviderId(execution.getAuthenticator());
|
||||
rep.setAuthenticationConfig(execution.getAuthenticatorConfig());
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
org.keycloak.authentication.authenticators.browser.CookieAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.browser.UsernamePasswordFormFactory
|
||||
org.keycloak.authentication.authenticators.browser.OTPFormAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.browser.ScriptBasedAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.browser.SpnegoAuthenticatorFactory
|
||||
org.keycloak.authentication.authenticators.directgrant.ValidateOTP
|
||||
org.keycloak.authentication.authenticators.directgrant.ValidatePassword
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
org.keycloak.scripting.DefaultScriptingProviderFactory
|
|
@ -94,6 +94,7 @@ public class ProvidersTest extends AbstractAuthenticationTest {
|
|||
"Validates a OTP on a separate OTP form. Only shown if required based on the configured conditions.");
|
||||
addProviderInfo(result, "auth-cookie", "Cookie", "Validates the SSO cookie set by the auth server.");
|
||||
addProviderInfo(result, "auth-otp-form", "OTP Form", "Validates a OTP on a separate OTP form.");
|
||||
addProviderInfo(result, "auth-script-based", "Script-based Authentication", "Script based authentication.");
|
||||
addProviderInfo(result, "auth-spnego", "Kerberos", "Initiates the SPNEGO protocol. Most often used with Kerberos.");
|
||||
addProviderInfo(result, "auth-username-password-form", "Username Password Form",
|
||||
"Validates a username and password from login form.");
|
||||
|
|
|
@ -90,5 +90,8 @@
|
|||
"async": "${keycloak.connectionsInfinispan.async:false}",
|
||||
"sessionsOwners": "${keycloak.connectionsInfinispan.sessionsOwners:2}"
|
||||
}
|
||||
},
|
||||
|
||||
"scripting": {
|
||||
}
|
||||
}
|
|
@ -36,6 +36,10 @@
|
|||
<script src="${resourceUrl}/lib/angular/select2.js" type="text/javascript"></script>
|
||||
<script src="${resourceUrl}/lib/fileupload/angular-file-upload.min.js"></script>
|
||||
<script src="${resourceUrl}/lib/filesaver/FileSaver.js"></script>
|
||||
<script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/ace.js"></script>
|
||||
<script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/theme-github.js"></script>
|
||||
<script src="${resourceUrl}/lib/ui-ace/src-min-noconflict/mode-javascript.js"></script>
|
||||
<script src="${resourceUrl}/lib/ui-ace/ui-ace.min.js"></script>
|
||||
|
||||
<script src="${authUrl}/js/${resourceVersion}/keycloak.js" type="text/javascript"></script>
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ var auth = {};
|
|||
var resourceBundle;
|
||||
var locale = 'en';
|
||||
|
||||
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'angularTreeview', 'pascalprecht.translate', 'ngCookies', 'ngSanitize']);
|
||||
var module = angular.module('keycloak', [ 'keycloak.services', 'keycloak.loaders', 'ui.bootstrap', 'ui.select2', 'angularFileUpload', 'angularTreeview', 'pascalprecht.translate', 'ngCookies', 'ngSanitize', 'ui.ace']);
|
||||
var resourceRequests = 0;
|
||||
var loadingTimer = -1;
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
<td class="kc-sorter">
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$first" class="btn btn-default btn-sm" data-ng-click="raisePriority(execution)"><i class="fa fa-angle-up"></i></button>
|
||||
<button data-ng-hide="flow.builtIn" data-ng-disabled="$last" class="btn btn-default btn-sm" data-ng-click="lowerPriority(execution)"><i class="fa fa-angle-down"></i></button>
|
||||
<span>{{execution.displayName|capitalize}}</span>
|
||||
<span>{{execution.displayName|capitalize}}<span ng-if="execution.alias">({{execution.alias}})</span></span>
|
||||
</td>
|
||||
<td ng-repeat="lev in execution.postLevels"></td>
|
||||
<td ng-repeat="choice in execution.requirementChoices">
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<div data-ng-repeat="option in properties" class="form-group" data-ng-controller="ProviderConfigCtrl">
|
||||
<label class="col-md-2 control-label">{{:: option.label | translate}}</label>
|
||||
|
||||
<div class="col-md-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role' || option.type == 'ClientList' || option.type == 'Password'">
|
||||
<div class="col-md-6" data-ng-hide="option.type == 'boolean' || option.type == 'List' || option.type == 'Role' || option.type == 'ClientList' || option.type == 'Password' || option.type=='Script'">
|
||||
<input class="form-control" type="text" data-ng-model="config[ option.name ]" >
|
||||
</div>
|
||||
<div class="col-md-6" data-ng-show="option.type == 'Password'">
|
||||
|
@ -32,6 +32,12 @@
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6" data-ng-show="option.type == 'Script'">
|
||||
<div ng-model="config[option.name]" placeholder="Enter your script..." ui-ace="{ useWrapMode: true, showGutter: true, theme:'github', mode: 'javascript'}">
|
||||
{{config[option.name]}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<kc-tooltip>{{:: option.helpText | translate}}</kc-tooltip>
|
||||
</div>
|
||||
</div>
|
|
@ -375,3 +375,8 @@ h1 i {
|
|||
margin-left: 0;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.ace_editor {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2010, Ajax.org B.V.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Ajax.org B.V. nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,21 @@
|
|||
Ace (Ajax.org Cloud9 Editor)
|
||||
============================
|
||||
|
||||
Ace is a code editor written in JavaScript.
|
||||
|
||||
This repository has only generated files.
|
||||
If you want to work on ace please go to https://github.com/ajaxorg/ace instead.
|
||||
|
||||
|
||||
here you can find pre-built files for convenience of embedding.
|
||||
it contains 4 versions
|
||||
* [src](https://github.com/ajaxorg/ace-builds/tree/master/src) concatenated but not minified
|
||||
* [src-min](https://github.com/ajaxorg/ace-builds/tree/master/src-min) concatenated and minified with uglify.js
|
||||
* [src-noconflict](https://github.com/ajaxorg/ace-builds/tree/master/src-noconflict) uses ace.require instead of require
|
||||
* [src-min-noconflict](https://github.com/ajaxorg/ace-builds/tree/master/src-min-noconflict) -
|
||||
|
||||
|
||||
For a simple way of embedding ace into webpage see [editor.html](https://github.com/ajaxorg/ace-builds/blob/master/editor.html) or list of other [simple examples](https://github.com/ajaxorg/ace-builds/tree/master/demo)
|
||||
To see ace in action go to [kitchen-sink-demo](http://ajaxorg.github.com/ace-builds/kitchen-sink.html), [scrollable-page-demo](http://ajaxorg.github.com/ace-builds/demo/scrollable-page.html) or [minimal demo](http://ajaxorg.github.com/ace-builds/editor.html),
|
||||
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/beautify/php_rules",["require","exports","module","ace/token_iterator"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator;t.newLines=[{type:"support.php_tag",value:"<?php"},{type:"support.php_tag",value:"<?"},{type:"support.php_tag",value:"?>"},{type:"paren.lparen",value:"{",indent:!0},{type:"paren.rparen",breakBefore:!0,value:"}",indent:!1},{type:"paren.rparen",breakBefore:!0,value:"})",indent:!1,dontBreak:!0},{type:"comment"},{type:"text",value:";"},{type:"text",value:":",context:"php"},{type:"keyword",value:"case",indent:!0,dontBreak:!0},{type:"keyword",value:"default",indent:!0,dontBreak:!0},{type:"keyword",value:"break",indent:!1,dontBreak:!0},{type:"punctuation.doctype.end",value:">"},{type:"meta.tag.punctuation.end",value:">"},{type:"meta.tag.punctuation.begin",value:"<",blockTag:!0,indent:!0,dontBreak:!0},{type:"meta.tag.punctuation.begin",value:"</",indent:!1,breakBefore:!0,dontBreak:!0},{type:"punctuation.operator",value:";"}],t.spaces=[{type:"xml-pe",prepend:!0},{type:"entity.other.attribute-name",prepend:!0},{type:"storage.type",value:"var",append:!0},{type:"storage.type",value:"function",append:!0},{type:"keyword.operator",value:"="},{type:"keyword",value:"as",prepend:!0,append:!0},{type:"keyword",value:"function",append:!0},{type:"support.function",next:/[^\(]/,append:!0},{type:"keyword",value:"or",append:!0,prepend:!0},{type:"keyword",value:"and",append:!0,prepend:!0},{type:"keyword",value:"case",append:!0},{type:"keyword.operator",value:"||",append:!0,prepend:!0},{type:"keyword.operator",value:"&&",append:!0,prepend:!0}],t.singleTags=["!doctype","area","base","br","hr","input","img","link","meta"],t.transform=function(e,n,r){var i=e.getCurrentToken(),s=t.newLines,o=t.spaces,u=t.singleTags,a="",f=0,l=!1,c,h,p={},d,v={},m=!1,g="";while(i!==null){console.log(i);if(!i){i=e.stepForward();continue}i.type=="support.php_tag"&&i.value!="?>"?r="php":i.type=="support.php_tag"&&i.value=="?>"?r="html":i.type=="meta.tag.name.style"&&r!="css"?r="css":i.type=="meta.tag.name.style"&&r=="css"?r="html":i.type=="meta.tag.name.script"&&r!="js"?r="js":i.type=="meta.tag.name.script"&&r=="js"&&(r="html"),v=e.stepForward(),v&&v.type.indexOf("meta.tag.name")==0&&(d=v.value),p.type=="support.php_tag"&&p.value=="<?="&&(l=!0),i.type=="meta.tag.name"&&(i.value=i.value.toLowerCase()),i.type=="text"&&(i.value=i.value.trim());if(!i.value){i=v;continue}g=i.value;for(var y in o)i.type==o[y].type&&(!o[y].value||i.value==o[y].value)&&v&&(!o[y].next||o[y].next.test(v.value))&&(o[y].prepend&&(g=" "+i.value),o[y].append&&(g+=" "));i.type.indexOf("meta.tag.name")==0&&(c=i.value),m=!1;for(y in s)if(i.type==s[y].type&&(!s[y].value||i.value==s[y].value)&&(!s[y].blockTag||u.indexOf(d)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!1&&f--;if(s[y].breakBefore&&(!s[y].prev||s[y].prev.test(p.value))){a+="\n",m=!0;for(y=0;y<f;y++)a+=" "}break}if(l===!1)for(y in s)if(p.type==s[y].type&&(!s[y].value||p.value==s[y].value)&&(!s[y].blockTag||u.indexOf(c)===-1)&&(!s[y].context||s[y].context===r)){s[y].indent===!0&&f++;if(!s[y].dontBreak&&!m){a+="\n";for(y=0;y<f;y++)a+=" "}break}a+=g,p.type=="support.php_tag"&&p.value=="?>"&&(l=!1),h=c,p=i,i=v;if(i===null)break}return a}}),ace.define("ace/ext/beautify",["require","exports","module","ace/token_iterator","ace/ext/beautify/php_rules"],function(e,t,n){"use strict";var r=e("ace/token_iterator").TokenIterator,i=e("./beautify/php_rules").transform;t.beautify=function(e){var t=new r(e,0,0),n=t.getCurrentToken(),s=e.$modeId.split("/").pop(),o=i(t,s);e.doc.setValue(o)},t.commands=[{name:"beautify",exec:function(e){t.beautify(e.session)},bindKey:"Ctrl-Shift-B"}]});
|
||||
(function() {
|
||||
ace.require(["ace/ext/beautify"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/elastic_tabstops_lite",["require","exports","module","ace/editor","ace/config"],function(e,t,n){"use strict";var r=function(e){this.$editor=e;var t=this,n=[],r=!1;this.onAfterExec=function(){r=!1,t.processRows(n),n=[]},this.onExec=function(){r=!0},this.onChange=function(e){r&&(n.indexOf(e.start.row)==-1&&n.push(e.start.row),e.end.row!=e.start.row&&n.push(e.end.row))}};(function(){this.processRows=function(e){this.$inChange=!0;var t=[];for(var n=0,r=e.length;n<r;n++){var i=e[n];if(t.indexOf(i)>-1)continue;var s=this.$findCellWidthsForBlock(i),o=this.$setBlockCellWidthsToMax(s.cellWidths),u=s.firstRow;for(var a=0,f=o.length;a<f;a++){var l=o[a];t.push(u),this.$adjustRow(u,l),u++}}this.$inChange=!1},this.$findCellWidthsForBlock=function(e){var t=[],n,r=e;while(r>=0){n=this.$cellWidthsForRow(r);if(n.length==0)break;t.unshift(n),r--}var i=r+1;r=e;var s=this.$editor.session.getLength();while(r<s-1){r++,n=this.$cellWidthsForRow(r);if(n.length==0)break;t.push(n)}return{cellWidths:t,firstRow:i}},this.$cellWidthsForRow=function(e){var t=this.$selectionColumnsForRow(e),n=[-1].concat(this.$tabsForRow(e)),r=n.map(function(e){return 0}).slice(1),i=this.$editor.session.getLine(e);for(var s=0,o=n.length-1;s<o;s++){var u=n[s]+1,a=n[s+1],f=this.$rightmostSelectionInCell(t,a),l=i.substring(u,a);r[s]=Math.max(l.replace(/\s+$/g,"").length,f-u)}return r},this.$selectionColumnsForRow=function(e){var t=[],n=this.$editor.getCursorPosition();return this.$editor.session.getSelection().isEmpty()&&e==n.row&&t.push(n.column),t},this.$setBlockCellWidthsToMax=function(e){var t=!0,n,r,i,s=this.$izip_longest(e);for(var o=0,u=s.length;o<u;o++){var a=s[o];if(!a.push){console.error(a);continue}a.push(NaN);for(var f=0,l=a.length;f<l;f++){var c=a[f];t&&(n=f,i=0,t=!1);if(isNaN(c)){r=f;for(var h=n;h<r;h++)e[h][o]=i;t=!0}i=Math.max(i,c)}}return e},this.$rightmostSelectionInCell=function(e,t){var n=0;if(e.length){var r=[];for(var i=0,s=e.length;i<s;i++)e[i]<=t?r.push(i):r.push(0);n=Math.max.apply(Math,r)}return n},this.$tabsForRow=function(e){var t=[],n=this.$editor.session.getLine(e),r=/\t/g,i;while((i=r.exec(n))!=null)t.push(i.index);return t},this.$adjustRow=function(e,t){var n=this.$tabsForRow(e);if(n.length==0)return;var r=0,i=-1,s=this.$izip(t,n);for(var o=0,u=s.length;o<u;o++){var a=s[o][0],f=s[o][1];i+=1+a,f+=r;var l=i-f;if(l==0)continue;var c=this.$editor.session.getLine(e).substr(0,f),h=c.replace(/\s*$/g,""),p=c.length-h.length;l>0&&(this.$editor.session.getDocument().insertInLine({row:e,column:f+1},Array(l+1).join(" ")+" "),this.$editor.session.getDocument().removeInLine(e,f,f+1),r+=l),l<0&&p>=-l&&(this.$editor.session.getDocument().removeInLine(e,f+l,f),r+=l)}},this.$izip_longest=function(e){if(!e[0])return[];var t=e[0].length,n=e.length;for(var r=1;r<n;r++){var i=e[r].length;i>t&&(t=i)}var s=[];for(var o=0;o<t;o++){var u=[];for(var r=0;r<n;r++)e[r][o]===""?u.push(NaN):u.push(e[r][o]);s.push(u)}return s},this.$izip=function(e,t){var n=e.length>=t.length?t.length:e.length,r=[];for(var i=0;i<n;i++){var s=[e[i],t[i]];r.push(s)}return r}}).call(r.prototype),t.ElasticTabstopsLite=r;var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{useElasticTabstops:{set:function(e){e?(this.elasticTabstops||(this.elasticTabstops=new r(this)),this.commands.on("afterExec",this.elasticTabstops.onAfterExec),this.commands.on("exec",this.elasticTabstops.onExec),this.on("change",this.elasticTabstops.onChange)):this.elasticTabstops&&(this.commands.removeListener("afterExec",this.elasticTabstops.onAfterExec),this.commands.removeListener("exec",this.elasticTabstops.onExec),this.removeListener("change",this.elasticTabstops.onChange))}}})});
|
||||
(function() {
|
||||
ace.require(["ace/ext/elastic_tabstops_lite"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
;
|
||||
(function() {
|
||||
ace.require(["ace/ext/error_marker"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/menu_tools/overlay_page",["require","exports","module","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../../lib/dom"),i="#ace_settingsmenu, #kbshortcutmenu {background-color: #F7F7F7;color: black;box-shadow: -5px 4px 5px rgba(126, 126, 126, 0.55);padding: 1em 0.5em 2em 1em;overflow: auto;position: absolute;margin: 0;bottom: 0;right: 0;top: 0;z-index: 9991;cursor: default;}.ace_dark #ace_settingsmenu, .ace_dark #kbshortcutmenu {box-shadow: -20px 10px 25px rgba(126, 126, 126, 0.25);background-color: rgba(255, 255, 255, 0.6);color: black;}.ace_optionsMenuEntry:hover {background-color: rgba(100, 100, 100, 0.1);-webkit-transition: all 0.5s;transition: all 0.3s}.ace_closeButton {background: rgba(245, 146, 146, 0.5);border: 1px solid #F48A8A;border-radius: 50%;padding: 7px;position: absolute;right: -8px;top: -8px;z-index: 1000;}.ace_closeButton{background: rgba(245, 146, 146, 0.9);}.ace_optionsMenuKey {color: darkslateblue;font-weight: bold;}.ace_optionsMenuCommand {color: darkcyan;font-weight: normal;}";r.importCssString(i),n.exports.overlayPage=function(t,n,i,s,o,u){function l(e){e.keyCode===27&&a.click()}i=i?"top: "+i+";":"",o=o?"bottom: "+o+";":"",s=s?"right: "+s+";":"",u=u?"left: "+u+";":"";var a=document.createElement("div"),f=document.createElement("div");a.style.cssText="margin: 0; padding: 0; position: fixed; top:0; bottom:0; left:0; right:0;z-index: 9990; background-color: rgba(0, 0, 0, 0.3);",a.addEventListener("click",function(){document.removeEventListener("keydown",l),a.parentNode.removeChild(a),t.focus(),a=null}),document.addEventListener("keydown",l),f.style.cssText=i+s+o+u,f.addEventListener("click",function(e){e.stopPropagation()});var c=r.createElement("div");c.style.position="relative";var h=r.createElement("div");h.className="ace_closeButton",h.addEventListener("click",function(){a.click()}),c.appendChild(h),f.appendChild(c),f.appendChild(n),a.appendChild(f),document.body.appendChild(a),t.blur()}}),ace.define("ace/ext/menu_tools/get_editor_keyboard_shortcuts",["require","exports","module","ace/lib/keys"],function(e,t,n){"use strict";var r=e("../../lib/keys");n.exports.getEditorKeybordShortcuts=function(e){var t=r.KEY_MODS,n=[],i={};return e.keyBinding.$handlers.forEach(function(e){var t=e.commandKeyBinding;for(var r in t){var s=r.replace(/(^|-)\w/g,function(e){return e.toUpperCase()}),o=t[r];Array.isArray(o)||(o=[o]),o.forEach(function(e){typeof e!="string"&&(e=e.name),i[e]?i[e].key+="|"+s:(i[e]={key:s,command:e},n.push(i[e]))})}}),n}}),ace.define("ace/ext/keybinding_menu",["require","exports","module","ace/editor","ace/ext/menu_tools/overlay_page","ace/ext/menu_tools/get_editor_keyboard_shortcuts"],function(e,t,n){"use strict";function i(t){if(!document.getElementById("kbshortcutmenu")){var n=e("./menu_tools/overlay_page").overlayPage,r=e("./menu_tools/get_editor_keyboard_shortcuts").getEditorKeybordShortcuts,i=r(t),s=document.createElement("div"),o=i.reduce(function(e,t){return e+'<div class="ace_optionsMenuEntry"><span class="ace_optionsMenuCommand">'+t.command+"</span> : "+'<span class="ace_optionsMenuKey">'+t.key+"</span></div>"},"");s.id="kbshortcutmenu",s.innerHTML="<h1>Keyboard Shortcuts</h1>"+o+"</div>",n(t,s,"0","0","0",null)}}var r=e("ace/editor").Editor;n.exports.init=function(e){r.prototype.showKeyboardShortcuts=function(){i(this)},e.commands.addCommands([{name:"showKeyboardShortcuts",bindKey:{win:"Ctrl-Alt-h",mac:"Command-Alt-h"},exec:function(e,t){e.showKeyboardShortcuts()}}])}});
|
||||
(function() {
|
||||
ace.require(["ace/ext/keybinding_menu"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/linking",["require","exports","module","ace/editor","ace/config"],function(e,t,n){function i(e){var t=e.editor,n=e.getAccelKey();if(n){var t=e.editor,r=e.getDocumentPosition(),i=t.session,s=i.getTokenAt(r.row,r.column);t._emit("linkHover",{position:r,token:s})}}function s(e){var t=e.getAccelKey(),n=e.getButton();if(n==0&&t){var r=e.editor,i=e.getDocumentPosition(),s=r.session,o=s.getTokenAt(i.row,i.column);r._emit("linkClick",{position:i,token:o})}}var r=e("ace/editor").Editor;e("../config").defineOptions(r.prototype,"editor",{enableLinking:{set:function(e){e?(this.on("click",s),this.on("mousemove",i)):(this.off("click",s),this.off("mousemove",i))},value:!1}})});
|
||||
(function() {
|
||||
ace.require(["ace/ext/linking"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/modelist",["require","exports","module"],function(e,t,n){"use strict";function i(e){var t=a.text,n=e.split(/[\/\\]/).pop();for(var i=0;i<r.length;i++)if(r[i].supportsFile(n)){t=r[i];break}return t}var r=[],s=function(e,t,n){this.name=e,this.caption=t,this.mode="ace/mode/"+e,this.extensions=n;var r;/\^/.test(n)?r=n.replace(/\|(\^)?/g,function(e,t){return"$|"+(t?"^":"^.*\\.")})+"$":r="^.*\\.("+n+")$",this.extRe=new RegExp(r,"gi")};s.prototype.supportsFile=function(e){return e.match(this.extRe)};var o={ABAP:["abap"],ABC:["abc"],ActionScript:["as"],ADA:["ada|adb"],Apache_Conf:["^htaccess|^htgroups|^htpasswd|^conf|htaccess|htgroups|htpasswd"],AsciiDoc:["asciidoc|adoc"],Assembly_x86:["asm|a"],AutoHotKey:["ahk"],BatchFile:["bat|cmd"],C_Cpp:["cpp|c|cc|cxx|h|hh|hpp|ino"],C9Search:["c9search_results"],Cirru:["cirru|cr"],Clojure:["clj|cljs"],Cobol:["CBL|COB"],coffee:["coffee|cf|cson|^Cakefile"],ColdFusion:["cfm"],CSharp:["cs"],CSS:["css"],Curly:["curly"],D:["d|di"],Dart:["dart"],Diff:["diff|patch"],Dockerfile:["^Dockerfile"],Dot:["dot"],Dummy:["dummy"],DummySyntax:["dummy"],Eiffel:["e|ge"],EJS:["ejs"],Elixir:["ex|exs"],Elm:["elm"],Erlang:["erl|hrl"],Forth:["frt|fs|ldr"],FTL:["ftl"],Gcode:["gcode"],Gherkin:["feature"],Gitignore:["^.gitignore"],Glsl:["glsl|frag|vert"],Gobstones:["gbs"],golang:["go"],Groovy:["groovy"],HAML:["haml"],Handlebars:["hbs|handlebars|tpl|mustache"],Haskell:["hs"],haXe:["hx"],HTML:["html|htm|xhtml"],HTML_Elixir:["eex|html.eex"],HTML_Ruby:["erb|rhtml|html.erb"],INI:["ini|conf|cfg|prefs"],Io:["io"],Jack:["jack"],Jade:["jade"],Java:["java"],JavaScript:["js|jsm|jsx"],JSON:["json"],JSONiq:["jq"],JSP:["jsp"],JSX:["jsx"],Julia:["jl"],LaTeX:["tex|latex|ltx|bib"],Lean:["lean|hlean"],LESS:["less"],Liquid:["liquid"],Lisp:["lisp"],LiveScript:["ls"],LogiQL:["logic|lql"],LSL:["lsl"],Lua:["lua"],LuaPage:["lp"],Lucene:["lucene"],Makefile:["^Makefile|^GNUmakefile|^makefile|^OCamlMakefile|make"],Markdown:["md|markdown"],Mask:["mask"],MATLAB:["matlab"],Maze:["mz"],MEL:["mel"],MUSHCode:["mc|mush"],MySQL:["mysql"],Nix:["nix"],NSIS:["nsi|nsh"],ObjectiveC:["m|mm"],OCaml:["ml|mli"],Pascal:["pas|p"],Perl:["pl|pm"],pgSQL:["pgsql"],PHP:["php|phtml|shtml|php3|php4|php5|phps|phpt|aw|ctp|module"],Powershell:["ps1"],Praat:["praat|praatscript|psc|proc"],Prolog:["plg|prolog"],Properties:["properties"],Protobuf:["proto"],Python:["py"],R:["r"],Razor:["cshtml"],RDoc:["Rd"],RHTML:["Rhtml"],RST:["rst"],Ruby:["rb|ru|gemspec|rake|^Guardfile|^Rakefile|^Gemfile"],Rust:["rs"],SASS:["sass"],SCAD:["scad"],Scala:["scala"],Scheme:["scm|sm|rkt|oak|scheme"],SCSS:["scss"],SH:["sh|bash|^.bashrc"],SJS:["sjs"],Smarty:["smarty|tpl"],snippets:["snippets"],Soy_Template:["soy"],Space:["space"],SQL:["sql"],SQLServer:["sqlserver"],Stylus:["styl|stylus"],SVG:["svg"],Swift:["swift"],Tcl:["tcl"],Tex:["tex"],Text:["txt"],Textile:["textile"],Toml:["toml"],Twig:["twig|swig"],Typescript:["ts|typescript|str"],Vala:["vala"],VBScript:["vbs|vb"],Velocity:["vm"],Verilog:["v|vh|sv|svh"],VHDL:["vhd|vhdl"],Wollok:["wlk|wpgm|wtest"],XML:["xml|rdf|rss|wsdl|xslt|atom|mathml|mml|xul|xbl|xaml"],XQuery:["xq"],YAML:["yaml|yml"],Django:["html"]},u={ObjectiveC:"Objective-C",CSharp:"C#",golang:"Go",C_Cpp:"C and C++",coffee:"CoffeeScript",HTML_Ruby:"HTML (Ruby)",HTML_Elixir:"HTML (Elixir)",FTL:"FreeMarker"},a={};for(var f in o){var l=o[f],c=(u[f]||f).replace(/_/g," "),h=f.toLowerCase(),p=new s(h,c,l[0]);a[h]=p,r.push(p)}n.exports={getModeForPath:i,modes:r,modesByName:a}});
|
||||
(function() {
|
||||
ace.require(["ace/ext/modelist"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/spellcheck",["require","exports","module","ace/lib/event","ace/editor","ace/config"],function(e,t,n){"use strict";var r=e("../lib/event");t.contextMenuHandler=function(e){var t=e.target,n=t.textInput.getElement();if(!t.selection.isEmpty())return;var i=t.getCursorPosition(),s=t.session.getWordRange(i.row,i.column),o=t.session.getTextRange(s);t.session.tokenRe.lastIndex=0;if(!t.session.tokenRe.test(o))return;var u="",a=o+" "+u;n.value=a,n.setSelectionRange(o.length,o.length+1),n.setSelectionRange(0,0),n.setSelectionRange(0,o.length);var f=!1;r.addListener(n,"keydown",function l(){r.removeListener(n,"keydown",l),f=!0}),t.textInput.setInputHandler(function(e){console.log(e,a,n.selectionStart,n.selectionEnd);if(e==a)return"";if(e.lastIndexOf(a,0)===0)return e.slice(a.length);if(e.substr(n.selectionEnd)==a)return e.slice(0,-a.length);if(e.slice(-2)==u){var r=e.slice(0,-2);if(r.slice(-1)==" ")return f?r.substring(0,n.selectionEnd):(r=r.slice(0,-1),t.session.replace(s,r),"")}return e})};var i=e("../editor").Editor;e("../config").defineOptions(i.prototype,"editor",{spellcheck:{set:function(e){var n=this.textInput.getElement();n.spellcheck=!!e,e?this.on("nativecontextmenu",t.contextMenuHandler):this.removeListener("nativecontextmenu",t.contextMenuHandler)},value:!0}})});
|
||||
(function() {
|
||||
ace.require(["ace/ext/spellcheck"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/split",["require","exports","module","ace/lib/oop","ace/lib/lang","ace/lib/event_emitter","ace/editor","ace/virtual_renderer","ace/edit_session"],function(e,t,n){"use strict";function l(e,t){this.$u=e,this.$doc=t}var r=e("./lib/oop"),i=e("./lib/lang"),s=e("./lib/event_emitter").EventEmitter,o=e("./editor").Editor,u=e("./virtual_renderer").VirtualRenderer,a=e("./edit_session").EditSession,f=function(e,t,n){this.BELOW=1,this.BESIDE=0,this.$container=e,this.$theme=t,this.$splits=0,this.$editorCSS="",this.$editors=[],this.$orientation=this.BESIDE,this.setSplits(n||1),this.$cEditor=this.$editors[0],this.on("focus",function(e){this.$cEditor=e}.bind(this))};(function(){r.implement(this,s),this.$createEditor=function(){var e=document.createElement("div");e.className=this.$editorCSS,e.style.cssText="position: absolute; top:0px; bottom:0px",this.$container.appendChild(e);var t=new o(new u(e,this.$theme));return t.on("focus",function(){this._emit("focus",t)}.bind(this)),this.$editors.push(t),t.setFontSize(this.$fontSize),t},this.setSplits=function(e){var t;if(e<1)throw"The number of splits have to be > 0!";if(e==this.$splits)return;if(e>this.$splits){while(this.$splits<this.$editors.length&&this.$splits<e)t=this.$editors[this.$splits],this.$container.appendChild(t.container),t.setFontSize(this.$fontSize),this.$splits++;while(this.$splits<e)this.$createEditor(),this.$splits++}else while(this.$splits>e)t=this.$editors[this.$splits-1],this.$container.removeChild(t.container),this.$splits--;this.resize()},this.getSplits=function(){return this.$splits},this.getEditor=function(e){return this.$editors[e]},this.getCurrentEditor=function(){return this.$cEditor},this.focus=function(){this.$cEditor.focus()},this.blur=function(){this.$cEditor.blur()},this.setTheme=function(e){this.$editors.forEach(function(t){t.setTheme(e)})},this.setKeyboardHandler=function(e){this.$editors.forEach(function(t){t.setKeyboardHandler(e)})},this.forEach=function(e,t){this.$editors.forEach(e,t)},this.$fontSize="",this.setFontSize=function(e){this.$fontSize=e,this.forEach(function(t){t.setFontSize(e)})},this.$cloneSession=function(e){var t=new a(e.getDocument(),e.getMode()),n=e.getUndoManager();if(n){var r=new l(n,t);t.setUndoManager(r)}return t.$informUndoManager=i.delayedCall(function(){t.$deltas=[]}),t.setTabSize(e.getTabSize()),t.setUseSoftTabs(e.getUseSoftTabs()),t.setOverwrite(e.getOverwrite()),t.setBreakpoints(e.getBreakpoints()),t.setUseWrapMode(e.getUseWrapMode()),t.setUseWorker(e.getUseWorker()),t.setWrapLimitRange(e.$wrapLimitRange.min,e.$wrapLimitRange.max),t.$foldData=e.$cloneFoldData(),t},this.setSession=function(e,t){var n;t==null?n=this.$cEditor:n=this.$editors[t];var r=this.$editors.some(function(t){return t.session===e});return r&&(e=this.$cloneSession(e)),n.setSession(e),e},this.getOrientation=function(){return this.$orientation},this.setOrientation=function(e){if(this.$orientation==e)return;this.$orientation=e,this.resize()},this.resize=function(){var e=this.$container.clientWidth,t=this.$container.clientHeight,n;if(this.$orientation==this.BESIDE){var r=e/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=r+"px",n.container.style.top="0px",n.container.style.left=i*r+"px",n.container.style.height=t+"px",n.resize()}else{var s=t/this.$splits;for(var i=0;i<this.$splits;i++)n=this.$editors[i],n.container.style.width=e+"px",n.container.style.top=i*s+"px",n.container.style.left="0px",n.container.style.height=s+"px",n.resize()}}}).call(f.prototype),function(){this.execute=function(e){this.$u.execute(e)},this.undo=function(){var e=this.$u.undo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.redo=function(){var e=this.$u.redo(!0);e&&this.$doc.selection.setSelectionRange(e)},this.reset=function(){this.$u.reset()},this.hasUndo=function(){return this.$u.hasUndo()},this.hasRedo=function(){return this.$u.hasRedo()}}.call(l.prototype),t.Split=f}),ace.define("ace/ext/split",["require","exports","module","ace/split"],function(e,t,n){"use strict";n.exports=e("../split")});
|
||||
(function() {
|
||||
ace.require(["ace/ext/split"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/static_highlight",["require","exports","module","ace/edit_session","ace/layer/text","ace/config","ace/lib/dom"],function(e,t,n){"use strict";var r=e("../edit_session").EditSession,i=e("../layer/text").Text,s=".ace_static_highlight {font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'Droid Sans Mono', monospace;font-size: 12px;white-space: pre-wrap}.ace_static_highlight .ace_gutter {width: 2em;text-align: right;padding: 0 3px 0 0;margin-right: 3px;}.ace_static_highlight.ace_show_gutter .ace_line {padding-left: 2.6em;}.ace_static_highlight .ace_line { position: relative; }.ace_static_highlight .ace_gutter-cell {-moz-user-select: -moz-none;-khtml-user-select: none;-webkit-user-select: none;user-select: none;top: 0;bottom: 0;left: 0;position: absolute;}.ace_static_highlight .ace_gutter-cell:before {content: counter(ace_line, decimal);counter-increment: ace_line;}.ace_static_highlight {counter-reset: ace_line;}",o=e("../config"),u=e("../lib/dom"),a=function(){this.config={}};a.prototype=i.prototype;var f=function(e,t,n){var r=e.className.match(/lang-(\w+)/),i=t.mode||r&&"ace/mode/"+r[1];if(!i)return!1;var s=t.theme||"ace/theme/textmate",o="",a=[];if(e.firstElementChild){var l=0;for(var c=0;c<e.childNodes.length;c++){var h=e.childNodes[c];h.nodeType==3?(l+=h.data.length,o+=h.data):a.push(l,h)}}else o=u.getInnerText(e),t.trim&&(o=o.trim());f.render(o,i,s,t.firstLineNumber,!t.showGutter,function(t){u.importCssString(t.css,"ace_highlight"),e.innerHTML=t.html;var r=e.firstChild.firstChild;for(var i=0;i<a.length;i+=2){var s=t.session.doc.indexToPosition(a[i]),o=a[i+1],f=r.children[s.row];f&&f.appendChild(o)}n&&n()})};f.render=function(e,t,n,i,s,u){function h(){var r=f.renderSync(e,t,n,i,s);return u?u(r):r}var a=1,l=r.prototype.$modes;typeof n=="string"&&(a++,o.loadModule(["theme",n],function(e){n=e,--a||h()}));var c;return t&&typeof t=="object"&&!t.getTokenizer&&(c=t,t=c.path),typeof t=="string"&&(a++,o.loadModule(["mode",t],function(e){if(!l[t]||c)l[t]=new e.Mode(c);t=l[t],--a||h()})),--a||h()},f.renderSync=function(e,t,n,i,o){i=parseInt(i||1,10);var u=new r("");u.setUseWorker(!1),u.setMode(t);var f=new a;f.setSession(u),u.setValue(e);var l=[],c=u.getLength();for(var h=0;h<c;h++)l.push("<div class='ace_line'>"),o||l.push("<span class='ace_gutter ace_gutter-cell' unselectable='on'></span>"),f.$renderLine(l,h,!0,!1),l.push("\n</div>");var p="<div class='"+n.cssClass+"'>"+"<div class='ace_static_highlight"+(o?"":" ace_show_gutter")+"' style='counter-reset:ace_line "+(i-1)+"'>"+l.join("")+"</div>"+"</div>";return f.destroy(),{css:s+n.cssText,html:p,session:u}},n.exports=f,n.exports.highlight=f});
|
||||
(function() {
|
||||
ace.require(["ace/ext/static_highlight"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/statusbar",["require","exports","module","ace/lib/dom","ace/lib/lang"],function(e,t,n){"use strict";var r=e("ace/lib/dom"),i=e("ace/lib/lang"),s=function(e,t){this.element=r.createElement("div"),this.element.className="ace_status-indicator",this.element.style.cssText="display: inline-block;",t.appendChild(this.element);var n=i.delayedCall(function(){this.updateStatus(e)}.bind(this)).schedule.bind(null,100);e.on("changeStatus",n),e.on("changeSelection",n),e.on("keyboardActivity",n)};(function(){this.updateStatus=function(e){function n(e,n){e&&t.push(e,n||"|")}var t=[];n(e.keyBinding.getStatusText(e)),e.commands.recording&&n("REC");var r=e.selection,i=r.lead;if(!r.isEmpty()){var s=e.getSelectionRange();n("("+(s.end.row-s.start.row)+":"+(s.end.column-s.start.column)+")"," ")}n(i.row+":"+i.column," "),r.rangeCount&&n("["+r.rangeCount+"]"," "),t.pop(),this.element.textContent=t.join("")}}).call(s.prototype),t.StatusBar=s});
|
||||
(function() {
|
||||
ace.require(["ace/ext/statusbar"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/themelist",["require","exports","module","ace/lib/fixoldbrowsers"],function(e,t,n){"use strict";e("ace/lib/fixoldbrowsers");var r=[["Chrome"],["Clouds"],["Crimson Editor"],["Dawn"],["Dreamweaver"],["Eclipse"],["GitHub"],["IPlastic"],["Solarized Light"],["TextMate"],["Tomorrow"],["XCode"],["Kuroir"],["KatzenMilch"],["SQL Server","sqlserver","light"],["Ambiance","ambiance","dark"],["Chaos","chaos","dark"],["Clouds Midnight","clouds_midnight","dark"],["Cobalt","cobalt","dark"],["idle Fingers","idle_fingers","dark"],["krTheme","kr_theme","dark"],["Merbivore","merbivore","dark"],["Merbivore Soft","merbivore_soft","dark"],["Mono Industrial","mono_industrial","dark"],["Monokai","monokai","dark"],["Pastel on dark","pastel_on_dark","dark"],["Solarized Dark","solarized_dark","dark"],["Terminal","terminal","dark"],["Tomorrow Night","tomorrow_night","dark"],["Tomorrow Night Blue","tomorrow_night_blue","dark"],["Tomorrow Night Bright","tomorrow_night_bright","dark"],["Tomorrow Night 80s","tomorrow_night_eighties","dark"],["Twilight","twilight","dark"],["Vibrant Ink","vibrant_ink","dark"]];t.themesByName={},t.themes=r.map(function(e){var n=e[1]||e[0].replace(/ /g,"_").toLowerCase(),r={caption:e[0],theme:"ace/theme/"+n,isDark:e[2]=="dark",name:n};return t.themesByName[n]=r,r})});
|
||||
(function() {
|
||||
ace.require(["ace/ext/themelist"], function() {});
|
||||
})();
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
ace.define("ace/ext/whitespace",["require","exports","module","ace/lib/lang"],function(e,t,n){"use strict";var r=e("../lib/lang");t.$detectIndentation=function(e,t){function c(e){var t=0;for(var r=e;r<n.length;r+=e)t+=n[r]||0;return t}var n=[],r=[],i=0,s=0,o=Math.min(e.length,1e3);for(var u=0;u<o;u++){var a=e[u];if(!/^\s*[^*+\-\s]/.test(a))continue;if(a[0]==" ")i++,s=-Number.MAX_VALUE;else{var f=a.match(/^ */)[0].length;if(f&&a[f]!=" "){var l=f-s;l>0&&!(s%l)&&!(f%l)&&(r[l]=(r[l]||0)+1),n[f]=(n[f]||0)+1}s=f}while(u<o&&a[a.length-1]=="\\")a=e[u++]}var h=r.reduce(function(e,t){return e+t},0),p={score:0,length:0},d=0;for(var u=1;u<12;u++){var v=c(u);u==1?(d=v,v=n[1]?.9:.8,n.length||(v=0)):v/=d,r[u]&&(v+=r[u]/h),v>p.score&&(p={score:v,length:u})}if(p.score&&p.score>1.4)var m=p.length;if(i>d+1){if(m==1||d<i/4||p.score<1.8)m=undefined;return{ch:" ",length:m}}if(d>i+1)return{ch:" ",length:m}},t.detectIndentation=function(e){var n=e.getLines(0,1e3),r=t.$detectIndentation(n)||{};return r.ch&&e.setUseSoftTabs(r.ch==" "),r.length&&e.setTabSize(r.length),r},t.trimTrailingSpace=function(e,t){var n=e.getDocument(),r=n.getAllLines(),i=t?-1:0;for(var s=0,o=r.length;s<o;s++){var u=r[s],a=u.search(/\s+$/);a>i&&n.removeInLine(s,a,u.length)}},t.convertIndentation=function(e,t,n){var i=e.getTabString()[0],s=e.getTabSize();n||(n=s),t||(t=i);var o=t==" "?t:r.stringRepeat(t,n),u=e.doc,a=u.getAllLines(),f={},l={};for(var c=0,h=a.length;c<h;c++){var p=a[c],d=p.match(/^\s*/)[0];if(d){var v=e.$getStringScreenWidth(d)[0],m=Math.floor(v/s),g=v%s,y=f[m]||(f[m]=r.stringRepeat(o,m));y+=l[g]||(l[g]=r.stringRepeat(" ",g)),y!=d&&(u.removeInLine(c,0,d.length),u.insertInLine({row:c,column:0},y))}}e.setTabSize(n),e.setUseSoftTabs(t==" ")},t.$parseStringArg=function(e){var t={};/t/.test(e)?t.ch=" ":/s/.test(e)&&(t.ch=" ");var n=e.match(/\d+/);return n&&(t.length=parseInt(n[0],10)),t},t.$parseArg=function(e){return e?typeof e=="string"?t.$parseStringArg(e):typeof e.text=="string"?t.$parseStringArg(e.text):e:{}},t.commands=[{name:"detectIndentation",exec:function(e){t.detectIndentation(e.session)}},{name:"trimTrailingSpace",exec:function(e){t.trimTrailingSpace(e.session)}},{name:"convertIndentation",exec:function(e,n){var r=t.$parseArg(n);t.convertIndentation(e.session,r.ch,r.length)}},{name:"setIndentation",exec:function(e,n){var r=t.$parseArg(n);r.length&&e.session.setTabSize(r.length),r.ch&&e.session.setUseSoftTabs(r.ch==" ")}}]});
|
||||
(function() {
|
||||
ace.require(["ace/ext/whitespace"], function() {});
|
||||
})();
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
ace.define("ace/mode/plain_text",["require","exports","module","ace/lib/oop","ace/mode/text","ace/mode/text_highlight_rules","ace/mode/behaviour"],function(e,t,n){"use strict";var r=e("../lib/oop"),i=e("./text").Mode,s=e("./text_highlight_rules").TextHighlightRules,o=e("./behaviour").Behaviour,u=function(){this.HighlightRules=s,this.$behaviour=new o};r.inherits(u,i),function(){this.type="text",this.getNextLineIndent=function(e,t,n){return""},this.$id="ace/mode/plain_text"}.call(u.prototype),t.Mode=u})
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
ace.define("ace/snippets/javascript",["require","exports","module"],function(e,t,n){"use strict";t.snippetText='# Prototype\nsnippet proto\n ${1:class_name}.prototype.${2:method_name} = function(${3:first_argument}) {\n ${4:// body...}\n };\n# Function\nsnippet fun\n function ${1?:function_name}(${2:argument}) {\n ${3:// body...}\n }\n# Anonymous Function\nregex /((=)\\s*|(:)\\s*|(\\()|\\b)/f/(\\))?/\nsnippet f\n function${M1?: ${1:functionName}}($2) {\n ${0:$TM_SELECTED_TEXT}\n }${M2?;}${M3?,}${M4?)}\n# Immediate function\ntrigger \\(?f\\(\nendTrigger \\)?\nsnippet f(\n (function(${1}) {\n ${0:${TM_SELECTED_TEXT:/* code */}}\n }(${1}));\n# if\nsnippet if\n if (${1:true}) {\n ${0}\n }\n# if ... else\nsnippet ife\n if (${1:true}) {\n ${2}\n } else {\n ${0}\n }\n# tertiary conditional\nsnippet ter\n ${1:/* condition */} ? ${2:a} : ${3:b}\n# switch\nsnippet switch\n switch (${1:expression}) {\n case \'${3:case}\':\n ${4:// code}\n break;\n ${5}\n default:\n ${2:// code}\n }\n# case\nsnippet case\n case \'${1:case}\':\n ${2:// code}\n break;\n ${3}\n\n# while (...) {...}\nsnippet wh\n while (${1:/* condition */}) {\n ${0:/* code */}\n }\n# try\nsnippet try\n try {\n ${0:/* code */}\n } catch (e) {}\n# do...while\nsnippet do\n do {\n ${2:/* code */}\n } while (${1:/* condition */});\n# Object Method\nsnippet :f\nregex /([,{[])|^\\s*/:f/\n ${1:method_name}: function(${2:attribute}) {\n ${0}\n }${3:,}\n# setTimeout function\nsnippet setTimeout\nregex /\\b/st|timeout|setTimeo?u?t?/\n setTimeout(function() {${3:$TM_SELECTED_TEXT}}, ${1:10});\n# Get Elements\nsnippet gett\n getElementsBy${1:TagName}(\'${2}\')${3}\n# Get Element\nsnippet get\n getElementBy${1:Id}(\'${2}\')${3}\n# console.log (Firebug)\nsnippet cl\n console.log(${1});\n# return\nsnippet ret\n return ${1:result}\n# for (property in object ) { ... }\nsnippet fori\n for (var ${1:prop} in ${2:Things}) {\n ${0:$2[$1]}\n }\n# hasOwnProperty\nsnippet has\n hasOwnProperty(${1})\n# docstring\nsnippet /**\n /**\n * ${1:description}\n *\n */\nsnippet @par\nregex /^\\s*\\*\\s*/@(para?m?)?/\n @param {${1:type}} ${2:name} ${3:description}\nsnippet @ret\n @return {${1:type}} ${2:description}\n# JSON.parse\nsnippet jsonp\n JSON.parse(${1:jstr});\n# JSON.stringify\nsnippet jsons\n JSON.stringify(${1:object});\n# self-defining function\nsnippet sdf\n var ${1:function_name} = function(${2:argument}) {\n ${3:// initial code ...}\n\n $1 = function($2) {\n ${4:// main code}\n };\n }\n# singleton\nsnippet sing\n function ${1:Singleton} (${2:argument}) {\n // the cached instance\n var instance;\n\n // rewrite the constructor\n $1 = function $1($2) {\n return instance;\n };\n \n // carry over the prototype properties\n $1.prototype = this;\n\n // the instance\n instance = new $1();\n\n // reset the constructor pointer\n instance.constructor = $1;\n\n ${3:// code ...}\n\n return instance;\n }\n# class\nsnippet class\nregex /^\\s*/clas{0,2}/\n var ${1:class} = function(${20}) {\n $40$0\n };\n \n (function() {\n ${60:this.prop = ""}\n }).call(${1:class}.prototype);\n \n exports.${1:class} = ${1:class};\n# \nsnippet for-\n for (var ${1:i} = ${2:Things}.length; ${1:i}--; ) {\n ${0:${2:Things}[${1:i}];}\n }\n# for (...) {...}\nsnippet for\n for (var ${1:i} = 0; $1 < ${2:Things}.length; $1++) {\n ${3:$2[$1]}$0\n }\n# for (...) {...} (Improved Native For-Loop)\nsnippet forr\n for (var ${1:i} = ${2:Things}.length - 1; $1 >= 0; $1--) {\n ${3:$2[$1]}$0\n }\n\n\n#modules\nsnippet def\n define(function(require, exports, module) {\n "use strict";\n var ${1/.*\\///} = require("${1}");\n \n $TM_SELECTED_TEXT\n });\nsnippet req\nguard ^\\s*\n var ${1/.*\\///} = require("${1}");\n $0\nsnippet requ\nguard ^\\s*\n var ${1/.*\\/(.)/\\u$1/} = require("${1}").${1/.*\\/(.)/\\u$1/};\n $0\n',t.scope="javascript"})
|
|
@ -0,0 +1 @@
|
|||
ace.define("ace/snippets/json",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="json"})
|
|
@ -0,0 +1 @@
|
|||
ace.define("ace/snippets/plain_text",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="plain_text"})
|
|
@ -0,0 +1 @@
|
|||
ace.define("ace/snippets/xml",["require","exports","module"],function(e,t,n){"use strict";t.snippetText=undefined,t.scope="xml"})
|
|
@ -0,0 +1 @@
|
|||
ace.define("ace/theme/github",["require","exports","module","ace/lib/dom"],function(e,t,n){t.isDark=!1,t.cssClass="ace-github",t.cssText='.ace-github .ace_gutter {background: #e8e8e8;color: #AAA;}.ace-github {background: #fff;color: #000;}.ace-github .ace_keyword {font-weight: bold;}.ace-github .ace_string {color: #D14;}.ace-github .ace_variable.ace_class {color: teal;}.ace-github .ace_constant.ace_numeric {color: #099;}.ace-github .ace_constant.ace_buildin {color: #0086B3;}.ace-github .ace_support.ace_function {color: #0086B3;}.ace-github .ace_comment {color: #998;font-style: italic;}.ace-github .ace_variable.ace_language {color: #0086B3;}.ace-github .ace_paren {font-weight: bold;}.ace-github .ace_boolean {font-weight: bold;}.ace-github .ace_string.ace_regexp {color: #009926;font-weight: normal;}.ace-github .ace_variable.ace_instance {color: teal;}.ace-github .ace_constant.ace_language {font-weight: bold;}.ace-github .ace_cursor {color: black;}.ace-github.ace_focus .ace_marker-layer .ace_active-line {background: rgb(255, 255, 204);}.ace-github .ace_marker-layer .ace_active-line {background: rgb(245, 245, 245);}.ace-github .ace_marker-layer .ace_selection {background: rgb(181, 213, 255);}.ace-github.ace_multiselect .ace_selection.ace_start {box-shadow: 0 0 3px 0px white;}.ace-github.ace_nobold .ace_line > span {font-weight: normal !important;}.ace-github .ace_marker-layer .ace_step {background: rgb(252, 255, 0);}.ace-github .ace_marker-layer .ace_stack {background: rgb(164, 229, 101);}.ace-github .ace_marker-layer .ace_bracket {margin: -1px 0 0 -1px;border: 1px solid rgb(192, 192, 192);}.ace-github .ace_gutter-active-line {background-color : rgba(0, 0, 0, 0.07);}.ace-github .ace_marker-layer .ace_selected-word {background: rgb(250, 250, 255);border: 1px solid rgb(200, 200, 250);}.ace-github .ace_invisible {color: #BFBFBF}.ace-github .ace_print-margin {width: 1px;background: #e8e8e8;}.ace-github .ace_indent-guide {background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y;}';var r=e("../lib/dom");r.importCssString(t.cssText,t.cssClass)})
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
7
themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/ui-ace.min.js
vendored
Normal file
7
themes/src/main/resources/theme/keycloak/common/resources/lib/ui-ace/ui-ace.min.js
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
/**
|
||||
* angular-ui-ace - This directive allows you to add ACE editor elements.
|
||||
* @version v0.2.3 - 2016-02-09
|
||||
* @link http://angular-ui.github.com
|
||||
* @license MIT
|
||||
*/
|
||||
"use strict";angular.module("ui.ace",[]).constant("uiAceConfig",{}).directive("uiAce",["uiAceConfig",function(a){if(angular.isUndefined(window.ace))throw new Error("ui-ace need ace to work... (o rly?)");var b=function(a,b,c){if(angular.isDefined(c.workerPath)){var d=window.ace.require("ace/config");d.set("workerPath",c.workerPath)}angular.isDefined(c.require)&&c.require.forEach(function(a){window.ace.require(a)}),angular.isDefined(c.showGutter)&&a.renderer.setShowGutter(c.showGutter),angular.isDefined(c.useWrapMode)&&b.setUseWrapMode(c.useWrapMode),angular.isDefined(c.showInvisibles)&&a.renderer.setShowInvisibles(c.showInvisibles),angular.isDefined(c.showIndentGuides)&&a.renderer.setDisplayIndentGuides(c.showIndentGuides),angular.isDefined(c.useSoftTabs)&&b.setUseSoftTabs(c.useSoftTabs),angular.isDefined(c.showPrintMargin)&&a.setShowPrintMargin(c.showPrintMargin),angular.isDefined(c.disableSearch)&&c.disableSearch&&a.commands.addCommands([{name:"unfind",bindKey:{win:"Ctrl-F",mac:"Command-F"},exec:function(){return!1},readOnly:!0}]),angular.isString(c.theme)&&a.setTheme("ace/theme/"+c.theme),angular.isString(c.mode)&&b.setMode("ace/mode/"+c.mode),angular.isDefined(c.firstLineNumber)&&(angular.isNumber(c.firstLineNumber)?b.setOption("firstLineNumber",c.firstLineNumber):angular.isFunction(c.firstLineNumber)&&b.setOption("firstLineNumber",c.firstLineNumber()));var e,f;if(angular.isDefined(c.advanced))for(e in c.advanced)f={name:e,value:c.advanced[e]},a.setOption(f.name,f.value);if(angular.isDefined(c.rendererOptions))for(e in c.rendererOptions)f={name:e,value:c.rendererOptions[e]},a.renderer.setOption(f.name,f.value);angular.forEach(c.callbacks,function(b){angular.isFunction(b)&&b(a)})};return{restrict:"EA",require:"?ngModel",link:function(c,d,e,f){var g,h,i=a.ace||{},j=angular.extend({},i,c.$eval(e.uiAce)),k=window.ace.edit(d[0]),l=k.getSession(),m=function(){var a=arguments[0],b=Array.prototype.slice.call(arguments,1);angular.isDefined(a)&&c.$evalAsync(function(){if(!angular.isFunction(a))throw new Error("ui-ace use a function as callback.");a(b)})},n={onChange:function(a){return function(b){var d=l.getValue();!f||d===f.$viewValue||c.$$phase||c.$root.$$phase||c.$evalAsync(function(){f.$setViewValue(d)}),m(a,b,k)}},onBlur:function(a){return function(){m(a,k)}}};e.$observe("readonly",function(a){k.setReadOnly(!!a||""===a)}),f&&(f.$formatters.push(function(a){if(angular.isUndefined(a)||null===a)return"";if(angular.isObject(a)||angular.isArray(a))throw new Error("ui-ace cannot use an object or an array as a model");return a}),f.$render=function(){l.setValue(f.$viewValue)});var o=function(a,d){a!==d&&(j=angular.extend({},i,c.$eval(e.uiAce)),j.callbacks=[j.onLoad],j.onLoad!==i.onLoad&&j.callbacks.unshift(i.onLoad),l.removeListener("change",g),g=n.onChange(j.onChange),l.on("change",g),k.removeListener("blur",h),h=n.onBlur(j.onBlur),k.on("blur",h),b(k,l,j))};c.$watch(e.uiAce,o,!0),o(i),d.on("$destroy",function(){k.session.$stopWorker(),k.destroy()}),c.$watch(function(){return[d[0].offsetWidth,d[0].offsetHeight]},function(){k.resize(),k.renderer.updateFull()},!0)}}}]);
|
Loading…
Reference in a new issue