Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Bill Burke 2015-07-15 14:17:54 -04:00
commit b3eadcc990
546 changed files with 102225 additions and 32722 deletions

View file

@ -46,8 +46,8 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
private static final String CHANGELOG = "META-INF/jpa-changelog-master.xml";
@Override
public String getCurrentVersionSql() {
return "SELECT ID from DATABASECHANGELOG ORDER BY DATEEXECUTED DESC LIMIT 1";
public String getCurrentVersionSql(String defaultSchema) {
return "SELECT ID from " + getTable("DATABASECHANGELOG", defaultSchema) + " ORDER BY DATEEXECUTED DESC LIMIT 1";
}
@Override
@ -65,7 +65,7 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
if (changeSets.get(0).getId().equals(FIRST_VERSION)) {
Statement statement = connection.createStatement();
try {
statement.executeQuery("SELECT id FROM REALM");
statement.executeQuery("SELECT id FROM " + getTable("REALM", defaultSchema));
logger.infov("Updating database from {0} to {1}", FIRST_VERSION, changeSets.get(changeSets.size() - 1).getId());
liquibase.markNextChangeSetRan(null);
@ -231,4 +231,8 @@ public class LiquibaseJpaUpdaterProvider implements JpaUpdaterProvider {
}
private String getTable(String table, String defaultSchema) {
return defaultSchema != null ? defaultSchema + "." + table : table;
}
}

View file

@ -133,7 +133,7 @@ public class DefaultJpaConnectionProviderFactory implements JpaConnectionProvide
if (databaseSchema.equals("update")) {
String currentVersion = null;
try {
ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql());
ResultSet resultSet = connection.createStatement().executeQuery(updater.getCurrentVersionSql(schema));
if (resultSet.next()) {
currentVersion = resultSet.getString(1);
}

View file

@ -14,7 +14,7 @@ public interface JpaUpdaterProvider extends Provider {
public String LAST_VERSION = "1.4.0";
public String getCurrentVersionSql();
public String getCurrentVersionSql(String defaultSchema);
public void update(KeycloakSession session, Connection connection, String defaultSchema);

View file

@ -14,18 +14,6 @@
<artifactId>keycloak-adapters-distribution-parent</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>as7-eap6-adapter</module>
<module>jetty81-adapter-zip</module>

View file

@ -1,25 +0,0 @@
Keycloak Feature Pack Builds
============================
The feature pack builds rely on WildFly Feature packs to create different combinations
of Keycloak server/adapter and WildFly web/full.
Types of Builds Created
--------------------
The three directories under feature-pack-builds are _adapter-only_, _server-only_, and _server-and-adapter_.
* **adapter-only** - A WildFly server with the Keycloak adapter subsystem added. This build is based on the WildFly Web Feature Pack. **keycloak-adapter-feature-pack** contains all the modules needed to run the Keycloak WildFly Adapter. Therefore, the build is _org.wildfly:wildfly-web-feature-pack_ + _org.keycloak:keycloak-adapter-feature-pack_.
* **server-only** - A WildFly server with the Keycloak adapter subsystem added. This build is based on the WildFly Full Feature Pack. **keycloak-server-feature-pack** contains all the modules needed to run the Keycloak Server without those already provided by the full WildFly Server. Therefore, the build is _org.wildfly:wildfly-feature-pack_ + _org.keycloak:keycloak-server-feature-pack_.
* **server-and-adapter** is the same thing as **server-only** except it also includes **keycloak-adapter-feature-pack**. Therefore, the build is _org.wildfly:wildfly-feature-pack_ + _org.keycloak:keycloak-server-feature-pack_ + _org.keycloak:keycloak-adapter-feature-pack_.
Building
--------
Each of the three types of builds in turn creates a build version and a dist version.
The build version is a server that uses the new WildFly 9 feature whereby maven artifacts are not bundled with the server. Instead, they are looked up in a repository.
For the dist version, these artifacts are copied into the server itself and no maven repo is required.
By default, the dist version does not get built. To build it, specify the jboss-release profile:
_mvn install -Pjboss-release_

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>thin-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,88 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>adapter-only-builds</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-only-build</artifactId>
<name>Keycloak WildFly Build: Adapter Only</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,25 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
<feature-packs>
<!-- uncomment wildfly-feature-pack to build against wildfly full instead of wildfly web -->
<!--<feature-pack groupId="org.wildfly" artifactId="wildfly-feature-pack" version="${wildfly.version}"/>-->
<feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>thin-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,92 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>adapter-only-builds</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-only-dist</artifactId>
<name>Keycloak WildFly Dist: Adapter Only</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jboss-release</id>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View file

@ -1,25 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
<feature-packs>
<!-- uncomment wildfly-feature-pack to build against wildfly full instead of wildfly web -->
<!--<feature-pack groupId="org.wildfly" artifactId="wildfly-feature-pack" version="${wildfly.version}"/>-->
<feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -1,21 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>feature-pack-builds</artifactId>
<groupId>org.keycloak</groupId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Adapter Only Builds</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>adapter-only-builds</artifactId>
<packaging>pom</packaging>
<modules>
<module>adapter-feature-pack</module>
<module>adapter-only-build</module>
<module>adapter-only-dist</module>
</modules>
</project>

View file

@ -1,21 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>distribution-pom</artifactId>
<groupId>org.keycloak</groupId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Feature Pack Builds</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>feature-pack-builds</artifactId>
<packaging>pom</packaging>
<modules>
<module>adapter-only</module>
<module>server-only</module>
<module>server-and-adapter</module>
</modules>
</project>

View file

@ -1,20 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>feature-pack-builds</artifactId>
<groupId>org.keycloak</groupId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Builds with both server and adapter</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>server-and-adapter</artifactId>
<packaging>pom</packaging>
<modules>
<module>server-and-adapter-build</module>
<module>server-and-adapter-dist</module>
</modules>
</project>

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>thin-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,93 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>server-and-adapter</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-and-adapter-build</artifactId>
<name>Keycloak WildFly Build: Server and Adapter</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,23 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
<feature-packs>
<feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
<feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>thin-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,98 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>server-and-adapter</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-and-adapter-dist</artifactId>
<name>Keycloak WildFly Dist: Server and Adapter</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-adapter-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jboss-release</id>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View file

@ -1,23 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
<feature-packs>
<feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
<feature-pack groupId="org.keycloak" artifactId="keycloak-adapter-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -1,21 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<artifactId>feature-pack-builds</artifactId>
<groupId>org.keycloak</groupId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<name>Server Only Builds</name>
<description/>
<modelVersion>4.0.0</modelVersion>
<artifactId>server-only-builds</artifactId>
<packaging>pom</packaging>
<modules>
<module>server-feature-pack</module>
<module>server-only-build</module>
<module>server-only-dist</module>
</modules>
</project>

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>thin-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,87 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>server-only-builds</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-only-build</artifactId>
<name>Keycloak WildFly Build: Server Only</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View file

@ -1,22 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0">
<feature-packs>
<feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -1,36 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2014 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>full-server</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory/>
<includes>
<include>${project.build.finalName}/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View file

@ -1,92 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.keycloak</groupId>
<artifactId>server-only-builds</artifactId>
<version>1.3.0.Final-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-only-dist</artifactId>
<name>Keycloak WildFly Dist: Server Only</name>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-feature-pack</artifactId>
<version>${project.version}</version>
<type>zip</type>
</dependency>
</dependencies>
<profiles>
<profile>
<id>jboss-release</id>
<build>
<plugins>
<plugin>
<groupId>org.wildfly.build</groupId>
<artifactId>wildfly-server-provisioning-maven-plugin</artifactId>
<executions>
<execution>
<id>server-provisioning</id>
<goals>
<goal>build</goal>
</goals>
<phase>compile</phase>
<configuration>
<config-file>server-provisioning.xml</config-file>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemble</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
<recompressZippedFiles>true</recompressZippedFiles>
<finalName>${project.build.finalName}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>${project.build.directory}</outputDirectory>
<workDirectory>${project.build.directory}/assembly/work</workDirectory>
<tarLongFileMode>gnu</tarLongFileMode>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View file

@ -1,22 +0,0 @@
<!--
~ JBoss, Home of Professional Open Source.
~ Copyright 2015 Red Hat, Inc., and individual contributors
~ as indicated by the @author tags.
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<server-provisioning xmlns="urn:wildfly:server-provisioning:1.0" extract-schemas="true" copy-module-artifacts="true">
<feature-packs>
<feature-pack groupId="org.keycloak" artifactId="keycloak-server-feature-pack" version="${project.version}"/>
</feature-packs>
</server-provisioning>

View file

@ -8,6 +8,7 @@
</resources>
<dependencies>
<module name="javax.api"/>
<module name="org.bouncycastle"/>
</dependencies>
</module>

View file

@ -14,18 +14,6 @@
<artifactId>distribution-pom</artifactId>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
<modules>
<module>adapters</module>
<module>demo-dist</module>

View file

@ -30,13 +30,6 @@
<build>
<finalName>auth-server</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.jboss.as.plugins</groupId>
<artifactId>jboss-as-maven-plugin</artifactId>

View file

@ -103,11 +103,11 @@
</para>
</simplesect>
<simplesect>
<title>WildFly 9.0.0.CR2</title>
<title>WildFly 9.0.0.Final</title>
<para>
Following on from the distribution changes that was done in the last release the standalone download
of Keycloak is now based on WildFly 9.0.0.CR2. This als affects the overlay which can only be deployed
to WildFly 9.0.0.CR2 or JBoss EAP 6.4.0.GA. WildFly 8.2.0.Final is no longer supported for the server.
of Keycloak is now based on WildFly 9.0.0.Final. This als affects the overlay which can only be deployed
to WildFly 9.0.0.Final or JBoss EAP 6.4.0.GA. WildFly 8.2.0.Final is no longer supported for the server.
</para>
</simplesect>
<simplesect>

View file

@ -199,7 +199,7 @@ public class CustomerService {
<title>Securing WARs via Keycloak Subsystem</title>
<para>
You do not have to crack open a WAR to secure it with Keycloak. Alternatively, you can externally secure
it via the Keycloak Subsystem. While you don't have to specify KEYCLOAK as an <literal>auth-method</literal>,
it via the Keycloak Adapter Subsystem. While you don't have to specify KEYCLOAK as an <literal>auth-method</literal>,
you still have to define the <literal>security-constraints</literal> in <literal>web.xml</literal>. You do
not, however, have to create a <literal>WEB-INF/keycloak.json</literal> file. This metadata is instead defined
within XML in your server's <literal>domain.xml</literal> or <literal>standalone.xml</literal> subsystem
@ -207,10 +207,12 @@ public class CustomerService {
</para>
<para>
<programlisting><![CDATA[
<server xmlns="urn:jboss:domain:1.4">
<extensions>
<extension module="org.keycloak.keycloak-adapter-subsystem"/>
</extensions>
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak:1.0">
<profile>
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
<secure-deployment name="WAR MODULE NAME.war">
<realm>demo</realm>
<realm-public-key>MIGfMA0GCSqGSIb3DQEBAQUAA</realm-public-key>
@ -220,7 +222,7 @@ public class CustomerService {
<credential name="secret">password</credential>
</secure-deployment>
</subsystem>
</profile>
</profile>
]]>
</programlisting>
</para>
@ -242,7 +244,7 @@ public class CustomerService {
</para>
<para>
<programlisting><![CDATA[
<subsystem xmlns="urn:jboss:domain:keycloak:1.0">
<subsystem xmlns="urn:jboss:domain:keycloak:1.1">
<realm name="demo">
<realm-public-key>MIGfMA0GCSqGSIb3DQEBA</realm-public-key>
<auth-server-url>http://localhost:8080/auth</auth-server-url>

View file

@ -43,9 +43,9 @@
<section id="overlay_install">
<title>Install on existing WildFly 9.0.0.CR2</title>
<title>Install on existing WildFly 9.0.0.Final</title>
<para>
Keycloak can be installed into an existing WildFly 9.0.0.CR2 server. To do this download
Keycloak can be installed into an existing WildFly 9.0.0.Final server. To do this download
<literal>keycloak-overlay-&project.version;.zip</literal> or <literal>keycloak-overlay-&project.version;.tar.gz</literal>.
Once downloaded extract into the root directory of your WildFly installation. To start WildFly with Keycloak
run:
@ -65,16 +65,16 @@
to, for example <literal>standalone/configuration/standalone.xml</literal>. From <literal>standalone-keycloak.xml</literal>
you need to copy 3 elements:
<itemizedlist>
<listitem><literal>&lt;extension module="org.keycloak.keycloak-subsystem"/&gt;</literal></listitem>
<listitem><literal>&lt;extension module="org.keycloak.keycloak-server-subsystem"/&gt;</literal></listitem>
<listitem><literal>&lt;datasource jndi-name="java:jboss/datasources/KeycloakDS" ...&gt;</literal></listitem>
<listitem><literal>&lt;subsystem xmlns="urn:jboss:domain:keycloak:1.0" ...&gt;</literal></listitem>
<listitem><literal>&lt;subsystem xmlns="urn:jboss:domain:keycloak-server:1.1" ...&gt;</literal></listitem>
</itemizedlist>
</para>
</section>
<section>
<title>Install on existing JBoss EAP 6.4.0.GA</title>
<para>
Same procedure as JBoss EAP 6.4.0.GA, but download <literal>keycloak-overlay-eap6-&project.version;.zip</literal> or <literal>keycloak-overlay-eap6-&project.version;.tar.gz</literal>.
Same procedure as WildFly 9.0.0.Final, but download <literal>keycloak-overlay-eap6-&project.version;.zip</literal> or <literal>keycloak-overlay-eap6-&project.version;.tar.gz</literal>.
</para>
</section>
<section>
@ -84,7 +84,7 @@
To install it first download <literal>keycloak-demo-&project.version;.zip</literal> or
<literal>keycloak-demo-&project.version;.tar.gz</literal>. Once downloaded extract it inside
<literal>keycloak-demo-&project.version;</literal> you'll find <literal>keycloak</literal> which contains
a full WildFly 9.0.0.CR2 server with Keycloak Server and Adapters included. You'll also find <literal>docs</literal>
a full WildFly 9.0.0.Final server with Keycloak Server and Adapters included. You'll also find <literal>docs</literal>
and <literal>examples</literal> which contains everything you need to get started developing applications that use Keycloak.
</para>
<para>
@ -196,7 +196,7 @@
<term>schema</term>
<listitem>
<para>
Specify the default database schema to use
Specify the database schema to use
</para>
</listitem>
</varlistentry>

View file

@ -884,21 +884,22 @@ module.factory('ClientOrigins', function($resource) {
});
module.factory('Current', function(Realm, $route, $rootScope) {
var current = {};
current.realms = {};
current.realm = null;
var current = {
realms: {},
realm: null
};
$rootScope.$on('$routeChangeStart', function() {
current.realm = null;
current.realms = Realm.query(null, function(realms) {
var currentRealm = null;
if ($route.current.params.realm) {
for (var i = 0; i < realms.length; i++) {
if (realms[i].realm == $route.current.params.realm) {
current.realm = realms[i];
currentRealm = realms[i];
}
}
}
current.realm = currentRealm;
});
});

View file

@ -47,9 +47,9 @@
<tr>
<th class="kc-table-actions" colspan="3" data-ng-show="access.manageClients">
<div class="pull-right">
<a class="btn btn-primary" tooltip="Manually register cluster node. This is usually not needed as cluster node should be registered automatically by adapter"
<a class="btn btn-default" tooltip="Manually register cluster node. This is usually not needed as cluster node should be registered automatically by adapter"
tooltip-placement="bottom" href="#/register-node/realms/{{realm.realm}}/clients/{{client.id}}/clustering">Register node manually</a>
<a class="btn btn-primary" data-ng-click="testNodesAvailable()" data-ng-show="nodeRegistrations && nodeRegistrations.length > 0">Test cluster availability</a>
<a class="btn btn-default" data-ng-click="testNodesAvailable()" data-ng-show="nodeRegistrations && nodeRegistrations.length > 0">Test cluster availability</a>
</div>
</th>
</tr>

View file

@ -19,8 +19,8 @@
</div>
<div class="pull-right" data-ng-show="access.manageRealm">
<a class="btn btn-primary" href="#/create/client/{{realm.realm}}">Create</a>
<a class="btn btn-primary" href="#/import/client/{{realm.realm}}" data-ng-show="importButton">Import</a>
<a class="btn btn-default" href="#/create/client/{{realm.realm}}">Create</a>
<a class="btn btn-default" href="#/import/client/{{realm.realm}}" data-ng-show="importButton">Import</a>
</div>
</div>
</th>

View file

@ -24,8 +24,8 @@
</div>
<div class="pull-right" data-ng-show="access.manageRealm">
<a class="btn btn-primary" href="#/create/client/{{realm.realm}}/{{client.id}}/mappers">Create</a>
<a class="btn btn-primary" href="#/realms/{{realm.realm}}/clients/{{client.id}}/add-mappers">Add Builtin</a>
<a class="btn btn-default" href="#/create/client/{{realm.realm}}/{{client.id}}/mappers">Create</a>
<a class="btn btn-default" href="#/realms/{{realm.realm}}/clients/{{client.id}}/add-mappers">Add Builtin</a>
</div>
</div>
</th>

View file

@ -14,7 +14,7 @@
<tr>
<th class="kc-table-actions" colspan="3" data-ng-show="access.manageClients">
<div class="pull-right">
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}/clients/{{client.id}}">Add Role</a>
<a class="btn btn-default" href="#/create/role/{{realm.realm}}/clients/{{client.id}}">Add Role</a>
</div>
</th>
</tr>

View file

@ -25,7 +25,7 @@
<tr>
<th class="kc-table-actions" colspan="3">
<div class="pull-right">
<a class="btn btn-primary" ng-click="loadUsers()" tooltip-placement="left" tooltip="Warning, this is a potentially expensive operation depending on number of active sessions.">Show Sessions</a>
<a class="btn btn-default" ng-click="loadUsers()" tooltip-placement="left" tooltip="Warning, this is a potentially expensive operation depending on number of active sessions.">Show Sessions</a>
</div>
</th>
</tr>

View file

@ -22,34 +22,4 @@
</ul>
</li>
</ul>
<ul class="nav navbar-nav navbar-primary" data-ng-controller="RealmDropdownCtrl">
<li class="dropdown" data-ng-show="current.realm.realm">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
{{current.realm.realm|capitalize}}
<b class="caret" data-ng-show="current.realms.length > 1"></b>
</a>
<ul class="dropdown-menu" data-ng-show="current.realms.length > 1">
<li data-ng-repeat="realm in current.realms" data-ng-if="realm.realm != current.realm.realm">
<a href="" ng-click="changeRealm(realm.realm)">{{realm.realm|capitalize}}</a>
</li>
</ul>
</li>
<li class="dropdown" data-ng-show="!current.realm.realm">
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
Select realm...
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li data-ng-repeat="realm in current.realms">
<a href="" ng-click="changeRealm(realm.realm)">{{realm.realm}}</a>
</li>
</ul>
</li>
<li class="pull-right" data-ng-show="auth.user && access.createRealm">
<a class="button primary" href="#/create/realm" data-ng-class="path[0] == 'create' && path[1] == 'realm' && 'active'"
data-ng-show="auth.user">Add Realm</a>
</li>
</ul>
</div>

View file

@ -1,4 +1,4 @@
<div class="col-md-12">
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<h1>Add Realm</h1>
@ -49,3 +49,5 @@
</div>
</form>
</div>
<kc-menu></kc-menu>

View file

@ -28,8 +28,8 @@
<span class="glyphicon glyphicon-minus" data-ng-show="filter"></span>
Filter
</button>
<button class="btn btn-default btn-primary" data-ng-click="update()">Update</button>
<button class="btn btn-default btn-primary" data-ng-click="reset()">Reset</button>
<button class="btn btn-default btn-default" data-ng-click="update()">Update</button>
<button class="btn btn-default btn-default" data-ng-click="reset()">Reset</button>
</div>
<form class="form-horizontal" data-ng-show="filter">
<div class="form-group">

View file

@ -26,8 +26,8 @@
<span class="glyphicon glyphicon-minus" data-ng-show="filter"></span>
Filter
</button>
<button class="btn btn-default btn-primary" data-ng-click="update()">Update</button>
<button class="btn btn-default btn-primary" data-ng-click="reset()">Reset</button>
<button class="btn btn-default btn-default" data-ng-click="update()">Update</button>
<button class="btn btn-default btn-default" data-ng-click="reset()">Reset</button>
</div>
<form class="form-horizontal">
<div class="form-group" data-ng-show="filter">

View file

@ -1,4 +1,5 @@
<div class="col-md-12">
<div class="col-sm-9 col-md-10 col-sm-push-3 col-md-push-2">
<h1>Realms</h1>
<table class="datatable table table-striped table-bordered">
@ -14,3 +15,6 @@
</tbody>
</table>
</div>
<kc-menu></kc-menu>

View file

@ -21,7 +21,7 @@
</div>
<div class="pull-right" data-ng-show="access.manageRealm">
<a class="btn btn-primary" href="#/create/role/{{realm.realm}}">Add Role</a>
<a class="btn btn-default" href="#/create/role/{{realm.realm}}">Add Role</a>
</div>
</div>
</th>

View file

@ -11,7 +11,7 @@
<tr>
<th class="kc-table-actions" colspan="3">
<div class="pull-right">
<a class="btn btn-primary" ng-click="logoutAll()">Logout All</a>
<a class="btn btn-default" ng-click="logoutAll()">Logout All</a>
</div>
</th>
</tr>

View file

@ -15,10 +15,10 @@
</div>
</div>
</div>
<button class="btn btn-primary" ng-click="query.search = null; firstPage()">View all users</button>
<button class="btn btn-default" ng-click="query.search = null; firstPage()">View all users</button>
<div class="pull-right" data-ng-show="access.manageUsers">
<a class="btn btn-primary" href="#/create/user/{{realm.realm}}">Add User</a>
<a class="btn btn-default" href="#/create/user/{{realm.realm}}">Add User</a>
</div>
</div>
</th>

View file

@ -13,7 +13,7 @@
<tr data-ng-show="access.manageUsers">
<th class="kc-table-actions" colspan="6">
<div class="pull-right" data-ng-show="access.manageUsers">
<a class="btn btn-primary" ng-click="logoutAll()">Logout All Sessions</a>
<a class="btn btn-default" ng-click="logoutAll()">Logout All Sessions</a>
</div>
</th>
</tr>

View file

@ -1,5 +1,22 @@
<div kc-sidebar-resize class="col-sm-3 col-md-2 col-sm-pull-9 col-md-pull-10 sidebar-pf sidebar-pf-left">
<div class="nav-category">
<div kc-sidebar-resize class="col-sm-3 col-md-2 col-sm-pull-9 col-md-pull-10 sidebar-pf sidebar-pf-left" data-ng-controller="RealmDropdownCtrl">
<div class="realm-selector">
<h2 data-ng-show="current.realm">{{current.realm.realm|capitalize}} <i class="fa fa-angle-down"></i></h2>
<h2 data-ng-hide="current.realm">Select realm <i class="fa fa-angle-down"></i></h2>
<div class="realm-dropmenu">
<!-- if it has more than 5 it generates a scroll bar -->
<ul>
<li data-ng-repeat="realm in current.realms | orderBy:'realm'" data-ng-if="realm.realm != current.realm.realm">
<a href="" ng-click="changeRealm(realm.realm)">{{realm.realm|capitalize}}</a>
</li>
</ul>
<div class="realm-add" data-ng-show="auth.user && access.createRealm">
<a href="#/create/realm" class="btn btn-sm btn-block btn-primary">Add Realm</a>
</div>
</div>
</div>
<div class="nav-category" data-ng-show="current.realm">
<h2>Configure</h2>
<ul class="nav nav-pills nav-stacked">
<li data-ng-show="access.viewRealm" data-ng-class="((!path[2]
@ -10,27 +27,22 @@
|| path[2] == 'cache-settings'
|| path[2] == 'defense'
|| path[2] == 'keys-settings' || path[2] == 'smtp-settings' || path[2] == 'ldap-settings' || path[2] == 'auth-settings') && path[3] != 'clients') && 'active'">
<a href="#/realms/{{realm.realm}}">Settings</a>
<a href="#/realms/{{realm.realm}}"><span class="pficon pficon-settings"></span> Settings</a>
</li>
<li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'clients' || path[1] == 'client' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients">Clients</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || path[2] == 'default-roles' || (path[1] == 'role' && path[3] != 'clients')) && 'active'"><a href="#/realms/{{realm.realm}}/roles">Roles</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings">Identity Providers</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'user-federation' || path[2] == 'user-federation') && 'active'"><a href="#/realms/{{realm.realm}}/user-federation">User Federation</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'authentication' || path[2] == 'authentication') && 'active'"><a href="#/realms/{{realm.realm}}/authentication/flows">Authentication</a></li>
<li data-ng-show="access.viewClients" data-ng-class="(path[2] == 'clients' || path[1] == 'client' || path[3] == 'clients') && 'active'"><a href="#/realms/{{realm.realm}}/clients"><i class="fa fa-cubes"></i> Clients</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'roles' || path[2] == 'default-roles' || (path[1] == 'role' && path[3] != 'clients')) && 'active'"><a href="#/realms/{{realm.realm}}/roles"><i class="fa fa-tasks"></i> Roles</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'identity-provider-settings' || path[2] == 'identity-provider-mappers') && 'active'"><a href="#/realms/{{realm.realm}}/identity-provider-settings"><i class="fa fa-exchange"></i> Identity Providers</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'user-federation' || path[2] == 'user-federation') && 'active'"><a href="#/realms/{{realm.realm}}/user-federation"><i class="fa fa-database"></i> User Federation</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[1] == 'authentication' || path[2] == 'authentication') && 'active'"><a href="#/realms/{{realm.realm}}/authentication/flows"><i class="fa fa-lock"></i> Authentication</a></li>
</ul>
</div>
<div class="nav-category">
<div class="nav-category" data-ng-show="current.realm">
<h2>Manage</h2>
<ul class="nav nav-pills nav-stacked">
<li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users">Users</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm">Sessions</a></li>
<li data-ng-show="access.viewEvents" data-ng-class="(path[2] == 'events' || path[2] == 'events-settings') && 'active'"><a href="#/realms/{{realm.realm}}/events">Events</a></li>
</ul>
</div>
<div class="nav-category" data-ng-hide="createRealm">
<ul class="nav nav-pills nav-stacked">
<li data-ng-show="access.viewUsers" data-ng-class="(path[2] == 'users' || path[1] == 'user') && 'active'"><a href="#/realms/{{realm.realm}}/users"><span class="pficon pficon-users"></span> Users</a></li>
<li data-ng-show="access.viewRealm" data-ng-class="(path[2] == 'sessions') && 'active'"><a href="#/realms/{{realm.realm}}/sessions/realm"><i class="fa fa-clock-o"></i> Sessions</a></li>
<li data-ng-show="access.viewEvents" data-ng-class="(path[2] == 'events' || path[2] == 'events-settings') && 'active'"><a href="#/realms/{{realm.realm}}/events"><i class="fa fa-calendar"></i> Events</a></li>
</ul>
</div>
</div>

View file

@ -2,12 +2,14 @@ html,body {
height: 100%;
}
/**
.navbar-pf .navbar-brand {
background: url('../img/brand.svg') no-repeat 0px 5px;
display: block;
height: 25px;
width: 200px;
}
**/
form {
margin-top: 20px;
@ -152,3 +154,138 @@ table {
.select2-container-multi .select2-choices .select2-search-field {
height: 26px;
}
/*********** New Menu ***********/
.sidebar-pf-left{
background: #292e34;
}
.sidebar-pf .nav-pills > li a i, .sidebar-pf .nav-pills > li a span{
color: #72767b;
display: inline-block;
margin-right: 10px;
}
.sidebar-pf .nav-pills > li > a{
color: #dbdada;
padding: 0px 20px 0 30px!important;
line-height: 30px;
border-left-width: 12px;
border-left-style: solid;
border-left-color: #292e34;
margin-left: -6px;
}
.sidebar-pf .nav-pills > li > a:hover{
background: #393f44;
border-color:#292e34;
border-left-color: #393f44;
color: #fff;
}
.sidebar-pf .nav-pills > li > a:after{
display: none!important;
}
.sidebar-pf .nav-pills > li.active > a {
color: #fff;
background: #393f44!important;
border-bottom: 1px solid #000!important;
border-top: 1px solid #000!important;
border-left-color: #39a5dc!important;
}
.sidebar-pf .nav-pills > li.active a i, .sidebar-pf .nav-pills > li.active a span{
color: #39a5dc;
}
/*********** Realm selector ***********/
.realm-selector{
color: #fff;
margin: 0 -20px;
position: relative;
}
.realm-dropmenu{
display: none;
cursor: pointer;
position: absolute;
top: 60px;
left: 0;
right: 0;
z-index: 999;
background: #fff;
}
.realm-selector:hover .realm-dropmenu{
display: block;
}
.realm-add{
padding: 10px;
}
.realm-selector h2{
font-size: 16px;
line-height: 60px;
padding: 0 20px;
margin: 0;
border-bottom: 1px solid #d5d5d6;
}
.realm-selector h2 i{
display: inline-block;
float: right;
line-height: 60px;
}
.realm-selector ul{
padding-left: 0;
margin: 0;
list-style: none;
max-height: 200px;
overflow-y:auto;
}
.realm-selector ul li a{
line-height: 60px;
padding: 0 20px;
border-bottom: 1px solid #d5d5d6;
line-height: 39px;
display: block;
font-size: 14px;
}
/*********** Overwrites header defaults ***********/
.navbar-pf{
border-top: none!important;
}
.navbar-brand{
padding: 0!important;
height: 56px!important;
line-height: 56px;
background-position: center center!important;
background-image: url('../img/keyclok-logo.svg')!important;
background-size: 148px 36px !important;
background-repeat: no-repeat;
width: 148px!important;
}
.navbar-pf .navbar-utility > li > a{
padding: 22px 30px 23px 40px!important;
}
/* @media (min-width: 768px) */
.navbar-pf .navbar-utility li.dropdown > .dropdown-toggle .pficon-user {
top: 22px;
left:20px;
}

View file

@ -0,0 +1,194 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-145.2 359 325.4 77.2" enable-background="new -145.2 359 325.4 77.2" xml:space="preserve">
<g>
<g>
<path fill="none" stroke="#FFFFFF" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M-79.1,393.1c-7.2,5-14.7,3.7-23.2-3.4c-4.9-4.1-11.2-2.8-15.4-1.5c-2.6,0.8-6.3,0.7-9.5,0.1c-14-2.9-10.9,6-8.3,14
c4.8,14.6-3.2,18-6,12.8c-1.8,6.6,7.1,8.6,10.9,7.7c6-1.4,14.1-2.2,19-0.6c9.5,2.9,13.1,0.5,11.5-2.6c-0.5-1-0.2-2.4,0.6-3.1
c2.8-2.4,5.3-0.4,8-1.9c2.1-1.2,2.1-3.9-1.2-5.5c-1.7-0.8-1.6-2.9,0.2-3.8c3.7-2,8.8-1,10-5.1C-81.9,398.7-80.7,395-79.1,393.1z"
/>
<path fill="none" stroke="#FFFFFF" stroke-width="7" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M-112.4,367.4c-1.1-0.6-4.3-2.6-5.1-3.1c-0.8-0.5-2.7-1.9-4.8-1.9s-4,1.4-4.8,1.9c-0.8,0.5-4,2.5-5.1,3.1c-0.8,0.5-3.7,2-3.7,6.3
c0,1.3,0,3.6,0,4.5c0,2.8,1.6,5,4.5,6.4c1,0.5,1.8,1.3,1.8,3.5c0,0.9,0.4,1.2,0.9,1.2h0.7c0.6,0,1,0.2,1,1.3c0,0.6,0,2.1,0,2.1
v37.2l2.7,2.8h1.2l5.7-5.8v-34.2c0,0,0-1.5,0-2.1c0-1,0.3-1.3,1-1.3h0.7c0.6,0,0.9-0.2,0.9-1.2c0-2.1,0.8-3,1.8-3.5
c2.9-1.5,4.5-3.6,4.5-6.4c0-1,0-3.2,0-4.5C-108.7,369.5-111.6,367.9-112.4,367.4z"/>
</g>
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="-227.7191" y1="2220.7964" x2="-165.056" y2="2220.7964" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FDFDFD"/>
<stop offset="0.1452" style="stop-color:#F4F5F5"/>
<stop offset="0.6844" style="stop-color:#D9DBDB"/>
<stop offset="1" style="stop-color:#CFD1D1"/>
</linearGradient>
<path fill="url(#SVGID_1_)" d="M-79.1,393.1c-7.2,5-14.7,3.7-23.2-3.4c-4.9-4.1-11.2-2.8-15.4-1.5c-2.6,0.8-6.3,0.7-9.5,0.1
c-14-2.9-10.9,6-8.3,14c4.8,14.6-3.2,18-6,12.8c-1.8,6.6,7.1,8.6,10.9,7.7c6-1.4,14.1-2.2,19-0.6c9.5,2.9,13.1,0.5,11.5-2.6
c-0.5-1-0.2-2.4,0.6-3.1c2.8-2.4,5.3-0.4,8-1.9c2.1-1.2,2.1-3.9-1.2-5.5c-1.7-0.8-1.6-2.9,0.2-3.8c3.7-2,8.8-1,10-5.1
C-81.9,398.7-80.7,395-79.1,393.1z"/>
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="192.3203" y1="1507.8835" x2="184.0467" y2="1507.8835" gradientTransform="matrix(1 0 0 1 -302 -1102)">
<stop offset="0" style="stop-color:#E6E6E6"/>
<stop offset="1" style="stop-color:#B2B3B3"/>
</linearGradient>
<path fill="url(#SVGID_2_)" d="M-115,391.3c0,5,0.7,22.8,4.5,30.4l-8.7-0.2v-31.5L-115,391.3z"/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="-200.8627" y1="2227.3811" x2="-193.8624" y2="2207.8804" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#F6F6F6"/>
<stop offset="1" style="stop-color:#B2B3B3"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M-134.6,403.1c-2.8-7.5-6.5-16.6,7.5-13.7c3.2,0.7,6.9,0.7,9.5-0.1c4.3-1.3,10-2.4,14.5,1.5
c8.9,7.7,16.9,8.3,24.1,3.3c-1.6,1.9-3.1,5.6-3.3,7.1c-0.2,1.3-1.1,1.9-2.4,2.4c-18.5,7.5-15.4-5.3-21.4-9.5
c-3.2-2.2-7.7-2.1-11.2-0.8c-3.2,1.2-6.4,0.9-9.8-0.4C-132.9,390.8-136.7,391.9-134.6,403.1z"/>
<line fill="none" stroke="#FFFFFF" stroke-width="3.5" stroke-miterlimit="10" x1="-117.4" y1="421.8" x2="-117.4" y2="390.6"/>
<g opacity="0.75">
<path fill="#FFFFFF" d="M-110.3,389c2.7,0,4.9,0.7,6.8,2.3c5.5,4.6,10.6,6.8,15.6,6.8c1.5,0,2.9-0.2,4.4-0.6
c-0.3,0.9-0.6,1.6-0.7,2.1c-0.4,1.4-1.6,1.8-4.4,2.4c-1.5,0.3-3.1,0.7-4.7,1.5c-1.6,0.8-2.5,2.3-2.5,3.9c0,1.5,0.9,2.8,2.4,3.5
c1.2,0.5,1.5,1.1,1.5,1.4c0,0.3-0.3,0.5-0.5,0.6c-0.6,0.3-1.2,0.4-2.1,0.4c-0.2,0-0.3,0-0.5,0c-0.2,0-0.4,0-0.5,0
c-1.6,0-3.4,0.2-5.2,1.7c-1.5,1.3-2,3.7-1.1,5.6c0.1,0.3,0.1,0.4,0.1,0.4c-0.1,0.1-0.8,0.6-2.6,0.6c-1.8,0-4.1-0.4-6.7-1.2
c-2-0.6-4.5-0.9-7.5-0.9c-3.8,0-8.4,0.6-12.6,1.5c-0.4,0.1-0.9,0.1-1.5,0.1c-1.9,0-4.2-0.5-5.7-1.6c1.7,0,3.3-0.9,4.4-2.4
c1.3-1.8,3.2-6.3,0.2-15.3l-0.1-0.2c-1.3-3.9-2.9-8.8-1.5-10.7c0.5-0.7,1.6-1.1,3.4-1.1c1.2,0,2.6,0.2,4.3,0.5
c1.8,0.4,3.6,0.6,5.4,0.6c1.9,0,3.7-0.2,5.1-0.7C-115.4,389.7-112.9,389-110.3,389 M-110.3,387c-2.7,0-5.2,0.6-7.3,1.3
c-1.3,0.4-2.9,0.6-4.6,0.6c-1.6,0-3.4-0.2-5-0.5c-1.9-0.4-3.4-0.6-4.7-0.6c-8.5,0-5.9,7.7-3.6,14.6c3.4,10.4,0.3,15.1-2.7,15.1
c-1.2,0-2.5-0.8-3.3-2.3c-1.5,5.6,4.8,7.9,9,7.9c0.7,0,1.4-0.1,2-0.2c3.7-0.8,8.1-1.5,12.2-1.5c2.5,0,4.9,0.2,6.9,0.8
c3,0.9,5.5,1.3,7.3,1.3c4,0,5.3-1.8,4.2-3.9c-0.5-1-0.2-2.4,0.6-3.1c1.4-1.2,2.7-1.3,3.9-1.3c0.3,0,0.7,0,1,0c1,0,2-0.1,3.1-0.7
c2.1-1.2,2.1-3.9-1.2-5.5c-1.7-0.8-1.6-2.9,0.2-3.8c3.7-2,8.8-1,10-5.1c0.4-1.5,1.7-5.2,3.3-7.1c-2.9,2-5.9,3-8.9,3
c-4.5,0-9.2-2.2-14.3-6.4C-104.7,387.7-107.6,387-110.3,387L-110.3,387z M-79.1,393.1L-79.1,393.1L-79.1,393.1z"/>
</g>
<path fill="none" stroke="#034672" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" d="
M-79.1,393.1c-7.2,5-14.7,3.7-23.2-3.4c-4.9-4.1-11.2-2.8-15.4-1.5c-2.6,0.8-6.3,0.7-9.5,0.1c-14-2.9-10.9,6-8.3,14
c4.8,14.6-3.2,18-6,12.8c-1.8,6.6,7.1,8.6,10.9,7.7c6-1.4,14.1-2.2,19-0.6c9.5,2.9,13.1,0.5,11.5-2.6c-0.5-1-0.2-2.4,0.6-3.1
c2.8-2.4,5.3-0.4,8-1.9c2.1-1.2,2.1-3.9-1.2-5.5c-1.7-0.8-1.6-2.9,0.2-3.8c3.7-2,8.8-1,10-5.1C-81.9,398.7-80.7,395-79.1,393.1z"/>
<path fill="#034672" d="M-134.6,402.1c-2.8-7.5-6.5-16.6,7.5-13.7c3.2,0.7,6.9,0.7,9.5-0.1c4.3-1.3,10-2.4,14.5,1.5
c8.9,7.7,16.9,8.3,24.1,3.3c-1.6,1.9-3.1,5.6-3.3,7.1c-0.2,1.3-1.1,1.9-2.4,2.4c-13.1,4.8-14.1-5.5-20.1-9.7
c-3.2-2.2-9-1.9-12.5-0.6c-3.2,1.2-6.4,0.9-9.8-0.4C-132.9,389.8-136.7,390.9-134.6,402.1z"/>
<path fill="#FFFFFF" d="M-112.4,367.4c-1.1-0.6-4.3-2.6-5.1-3.1c-0.8-0.5-2.7-1.9-4.8-1.9s-4,1.4-4.8,1.9c-0.8,0.5-4,2.5-5.1,3.1
c-0.8,0.5-3.7,2-3.7,6.3c0,1.3,0,3.6,0,4.5c0,2.8,1.6,5,4.5,6.4c1,0.5,1.8,1.3,1.8,3.5c0,0.9,0.4,1.2,0.9,1.2h0.7
c0.6,0,1,0.2,1,1.3c0,0.6,0,2.1,0,2.1v37.2l2.7,2.8h1.2l5.7-5.8v-34.2c0,0,0-1.5,0-2.1c0-1,0.3-1.3,1-1.3h0.7
c0.6,0,0.9-0.2,0.9-1.2c0-2.1,0.8-3,1.8-3.5c2.9-1.5,4.5-3.6,4.5-6.4c0-1,0-3.2,0-4.5C-108.7,369.5-111.6,367.9-112.4,367.4z"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="-217.9037" y1="2215.0122" x2="-187.068" y2="2207.345" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#B8D7E9"/>
<stop offset="0.3324" style="stop-color:#CCE3F1"/>
<stop offset="0.6937" style="stop-color:#DAEBF7"/>
<stop offset="1" style="stop-color:#DFEEF9"/>
</linearGradient>
<path fill="url(#SVGID_4_)" d="M-112.4,367.4c-1.1-0.6-4.3-2.6-5.1-3.1c-0.8-0.5-2.7-1.9-4.8-1.9v69.3l4.8-4.9v-34.2
c0,0,0-1.5,0-2.1c0-1,0.3-1.3,1-1.3h0.7c0.6,0,0.9-0.2,0.9-1.2c0-2.1,0.8-3,1.8-3.5c2.9-1.5,4.5-3.6,4.5-6.4c0-1,0-3.2,0-4.5
C-108.7,369.5-111.6,367.9-112.4,367.4z"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="-214.9444" y1="2190.8406" x2="-206.3191" y2="2233.0925" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#F1F9FE"/>
<stop offset="0.4254" style="stop-color:#E9F5FD"/>
<stop offset="1" style="stop-color:#E4F3FD"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M-122.3,362.5c-2.1,0-4,1.4-4.8,1.9c-0.8,0.5-4,2.5-5.1,3.1c-0.8,0.5-3.7,2-3.7,6.3
c0,1.3,0,3.6,0,4.5c0,2.8,1.6,5,4.5,6.4c1,0.5,1.8,1.3,1.8,3.5c0,0.9,0.4,1.2,0.9,1.2h0.7c0.6,0,1,0.2,1,1.3c0,0.6,0,2.1,0,2.1
v37.2l2.7,2.8h1.2l0.9-0.9L-122.3,362.5L-122.3,362.5z"/>
<path fill="none" stroke="#FFFFFF" stroke-width="2" stroke-miterlimit="10" d="M-122.6,362.5c1.9,0.9,3.4,2,4.2,2.4
c0.8,0.5,4,2.5,5.1,3.1c0.8,0.5,3.7,2,3.7,6.3c0,1.3,0,2.8,0,3.8c0,2.8-1.6,5-4.5,6.4c-1,0.5-1.8,1.4-1.8,3.6v1.2"/>
<path fill="none" stroke="#034672" stroke-width="2" stroke-miterlimit="10" d="M-112.4,367.4c-1.1-0.6-4.3-2.6-5.1-3.1
c-0.8-0.5-2.7-1.9-4.8-1.9s-4,1.4-4.8,1.9c-0.8,0.5-4,2.5-5.1,3.1c-0.8,0.5-3.7,2-3.7,6.3c0,1.3,0,3.6,0,4.5c0,2.8,1.6,5,4.5,6.4
c1,0.5,1.8,1.3,1.8,3.5c0,0.9,0.4,1.2,0.9,1.2h0.7c0.6,0,1,0.2,1,1.3c0,0.6,0,2.1,0,2.1v37.2l2.7,2.8h1.2l5.7-5.8v-34.2
c0,0,0-1.5,0-2.1c0-1,0.3-1.3,1-1.3h0.7c0.6,0,0.9-0.2,0.9-1.2c0-2.1,0.8-3,1.8-3.5c2.9-1.5,4.5-3.6,4.5-6.4c0-1,0-3.2,0-4.5
C-108.7,369.5-111.6,367.9-112.4,367.4z"/>
<path fill="#E9F6FE" stroke="#034672" stroke-width="2" stroke-miterlimit="10" d="M-107.5,392.7"/>
<g>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="-106.4885" y1="2203.667" x2="-106.4885" y2="2254.552" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_6_)" d="M-14.5,407.6h-11.6c0.3,2.3,1,3.9,2.1,4.7s2.9,1.2,5.5,1.2c3.4,0,7.4-0.2,12-0.7l0.9,6
c-3.3,1.6-8,2.4-14,2.4c-6,0-10.3-1.3-12.9-3.9c-2.6-2.6-3.8-6.9-3.8-12.9c0-6.3,1.2-10.7,3.7-13.2c2.5-2.5,6.7-3.8,12.6-3.8
c5.3,0,9.2,0.9,11.6,2.8c2.4,1.8,3.6,4.7,3.6,8.4c0,3-0.8,5.2-2.3,6.7C-8.5,406.8-11,407.6-14.5,407.6z M-26.3,401.8h9.1
c1.2,0,2-0.3,2.4-0.8c0.4-0.6,0.6-1.4,0.6-2.5c0-1.5-0.4-2.6-1.2-3.2c-0.8-0.6-2.2-0.9-4.3-0.9c-2.5,0-4.2,0.5-5.1,1.5
C-25.6,396.9-26.1,398.8-26.3,401.8z"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="-72.864" y1="2203.667" x2="-72.864" y2="2254.5503" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_7_)" d="M31,388.3l-11.4,32.6c-0.6,1.7-1.4,3.3-2.2,4.8c-0.9,1.5-2,2.9-3.4,4.3c-1.4,1.4-3.1,2.4-5.2,3
c-2.1,0.7-4.4,0.8-6.9,0.5L1,427.8c2.6-0.7,4.6-1.6,6.1-2.7c1.5-1.1,2.6-2.6,3.5-4.5l0.1-0.3H8.9c-1.6,0-2.6-0.8-3.1-2.3
l-10.5-29.8H5.6l6,20.8c0.4,1.5,0.7,3.1,1,4.8h0.8c0.1-0.5,0.3-1.3,0.7-2.4s0.5-1.9,0.7-2.4l5.9-20.8L31,388.3L31,388.3z"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="-41.775" y1="2203.667" x2="-41.775" y2="2254.552" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_8_)" d="M57.6,412.8l0.9,6.3c-3.3,1.4-7.5,2.1-12.4,2.1c-5.9,0-10.1-1.3-12.5-3.8
c-2.4-2.5-3.6-6.9-3.6-13.1c0-6.2,1.2-10.6,3.6-13.1c2.4-2.5,6.6-3.8,12.6-3.8c4.9,0,8.8,0.7,11.9,2l-1,6
c-4.7-0.1-7.8-0.1-9.2-0.1c-3,0-5,0.6-6.1,1.9c-1.1,1.3-1.7,3.6-1.7,7.2c0,3.5,0.6,5.9,1.7,7.2c1.1,1.3,3.1,1.9,6.1,1.9
C51.6,413.4,54.9,413.2,57.6,412.8z"/>
<linearGradient id="SVGID_9_" gradientUnits="userSpaceOnUse" x1="8.9715" y1="2203.667" x2="8.9715" y2="2254.553" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_9_)" d="M95,387.4c6,0,10.2,1.3,12.7,3.9c2.5,2.6,3.7,7,3.7,13.1c0,6.2-1.2,10.5-3.7,13.1
c-2.5,2.5-6.7,3.8-12.7,3.8c-6,0-10.3-1.3-12.8-3.8c-2.5-2.5-3.7-6.9-3.7-13.1c0-6.2,1.2-10.6,3.7-13.2
C84.7,388.7,89,387.4,95,387.4z M95,394.6c-2.6,0-4.3,0.6-5.1,2c-0.9,1.3-1.3,3.9-1.3,7.8c0,3.8,0.4,6.4,1.3,7.7
c0.9,1.3,2.6,2,5.1,2c2.5,0,4.2-0.7,5.1-2c0.9-1.3,1.3-3.9,1.3-7.7c0-3.9-0.4-6.5-1.3-7.8C99.2,395.3,97.5,394.6,95,394.6z"/>
<linearGradient id="SVGID_10_" gradientUnits="userSpaceOnUse" x1="42.879" y1="2203.667" x2="42.879" y2="2254.552" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_10_)" d="M115.9,395.5l-0.9-6.5c5.8-1,11.4-1.6,16.7-1.6c4.3,0,7.5,0.9,9.6,2.6c2,1.8,3.1,4.8,3.1,9.2v21.2
h-7.6l-1-4.9c-3.2,3.8-7.2,5.7-11.9,5.7c-3.1,0-5.6-0.8-7.6-2.4s-2.9-3.9-2.9-6.8v-3.3c0-2.6,0.9-4.6,2.6-6
c1.7-1.4,4.1-2.1,7.2-2.1h11.5v-1.4c0-1.6-0.4-2.8-1.1-3.3c-0.7-0.6-2.1-0.8-4.1-0.8C125.9,394.9,121.4,395.1,115.9,395.5z
M122.9,409.4v1.2c0,2.2,1.3,3.3,3.8,3.3c2.6,0,5.3-1,8-3.1v-4.5H126C124,406.4,122.9,407.4,122.9,409.4z"/>
<linearGradient id="SVGID_11_" gradientUnits="userSpaceOnUse" x1="-136.063" y1="2203.667" x2="-136.063" y2="2254.5491" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_11_)" d="M-43.5,406.1c-0.9-1.6-1.9-2.7-3-3.5v-0.1c1.3-0.9,2.3-1.9,3-3.1l8.3-11.1H-46l-7.9,11.2h-3
c0.3-1.8,0.5-3.7,0.5-5.9v-18.8h-3l-6.7,9.5v36.1h9.6v-10.1c0-1.3-0.2-2.9-0.5-4.8h3.1l9,14.9H-34L-43.5,406.1z"/>
<linearGradient id="SVGID_12_" gradientUnits="userSpaceOnUse" x1="-16.68" y1="2203.667" x2="-16.68" y2="2254.551" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_12_)" d="M76.7,413.2h-2.6c-2.4,0-3.6-1.1-3.6-3.3v-35.1h-3l-6.6,9.4v28.2c0,2.8,0.8,5,2.5,6.5
c1.6,1.5,3.9,2.3,6.8,2.3c3.5,0,6-0.4,7.7-1.3L76.7,413.2z"/>
<linearGradient id="SVGID_13_" gradientUnits="userSpaceOnUse" x1="78.107" y1="2203.667" x2="78.107" y2="2254.5491" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#FFFFFE"/>
<stop offset="0.4815" style="stop-color:#F2F1F1"/>
<stop offset="1" style="stop-color:#E9E7E8"/>
</linearGradient>
<path fill="url(#SVGID_13_)" d="M170.7,406.1c-0.9-1.6-1.9-2.7-3-3.5v-0.1c1.3-0.9,2.3-1.9,3-3.1l8.3-11.1h-10.8l-7.9,11.2h-3
c0.3-1.8,0.5-3.7,0.5-5.9v-18.8h-3l-6.7,9.5v36.1h9.6v-10.1c0-1.3-0.2-2.9-0.5-4.8h3.1l9,14.9h10.8L170.7,406.1z"/>
</g>
<linearGradient id="SVGID_14_" gradientUnits="userSpaceOnUse" x1="-208.281" y1="2186.001" x2="-208.281" y2="2196.1689" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#00639A"/>
<stop offset="0.2355" style="stop-color:#00578A"/>
<stop offset="0.507" style="stop-color:#004D7B"/>
<stop offset="0.7167" style="stop-color:#004773"/>
<stop offset="1" style="stop-color:#00446E"/>
</linearGradient>
<polygon fill="url(#SVGID_14_)" points="-122.3,372.4 -131.3,370.4 -132.3,374.1 -122.3,379.2 -112.2,374.1 -113.2,370.4 "/>
<polyline opacity="0.2" enable-background="new " points="-122.3,379.2 -112.2,374.1 -113.2,370.4 -122.3,372.4 "/>
<path fill="#034672" d="M-127.2,391.9c3.4,1.3,6.7,1.5,9.8,0.4l-0.3-2.2c-2.6,0.8-6.3,0.7-9.5,0.1L-127.2,391.9z"/>
<path fill="#034672" d="M-122.6,391.5c-0.4,2.8,1.9,4.7,1.9,7.6C-116.8,394.8-121.7,393.3-122.6,391.5z"/>
<path fill="#034672" d="M-122.6,391.7c-0.1,3.2-0.4,5.6-1.7,7.2C-126.8,394.2-123.7,392.6-122.6,391.7z"/>
<circle fill="#034672" cx="-122.6" cy="391.7" r="1.6"/>
<linearGradient id="SVGID_15_" gradientUnits="userSpaceOnUse" x1="-197.511" y1="2237.772" x2="-197.511" y2="2237.772" gradientTransform="matrix(1 0 0 1 86 -1815.5)">
<stop offset="0" style="stop-color:#F6F6F6"/>
<stop offset="0.5386" style="stop-color:#E4E4E4"/>
<stop offset="1" style="stop-color:#DADADA"/>
</linearGradient>
<path fill="url(#SVGID_15_)" d="M-111.5,422.3"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -1,3 +1,3 @@
parent=base
import=common/keycloak
styles=css/styles.css lib/patternfly/css/patternfly.css lib/select2-3.4.1/select2.css css/styles.css
styles=lib/patternfly/css/patternfly.css lib/select2-3.4.1/select2.css css/styles.css

View file

@ -0,0 +1,59 @@
# Bootstrap Combobox
We had need of a combobox at work and after looking around at the available options I was not happy with any of them. The project had all it's styling based on Twitter's Bootstrap, so building on that made sense.
## How to use it
The dependencies are the Bootstrap stylesheet(CSS or LESS). Include it and then the stylesheet(CSS or LESS) and javascript.
Then just activate the plugin on a normal select box(suggest having a blank option first):
<select class="combobox">
<option></option>
<option value="PA">Pennsylvania</option>
<option value="CT">Connecticut</option>
<option value="NY">New York</option>
<option value="MD">Maryland</option>
<option value="VA">Virginia</option>
</select>
<script type="text/javascript">
$(document).ready(function(){
$('.combobox').combobox();
});
</script>
### Options
When activating the plugin, you may include an object containing options for the combobox
$('.combobox').combobox({bsVersion: '2'});
`menu`: Custom markup for the dropdown menu list element.
`item`: Custom markup for the dropdown menu list items.
`matcher`: Custom function with one `item` argument that compares the item to the input. Defaults to matching on the query being a substring of the item, case insenstive
`sorter`: Custom function that sorts a list `items` for display in the dropdown
`highlighter`: Custom function for highlighting an `item`. Defaults to bolding the query within a matched item
`template`: Custom function that returns markup for the combobox.
`bsVersion`: Version of bootstrap being used. This is used by the default `template` function to generate markup correctly. Defaults to '3'. Set to '2' for compatibility with Bootstrap 2
## Dependencies
Uses the latest 1.X version of jQuery and the latest 2.X or 3.X of bootstrap.
## Live Example
### Bootstrap 2.0 Version
http://dl.dropbox.com/u/21368/bootstrap-combobox/index.html
### Bootstrap 3.0 Version
http://bootstrap-combobox-test.herokuapp.com/
## License
Licensed under the Apache License, Version 2.0

View file

@ -0,0 +1,42 @@
.form-search .combobox-container,
.form-inline .combobox-container {
display: inline-block;
margin-bottom: 0;
vertical-align: top;
}
.form-search .combobox-container .input-group-addon,
.form-inline .combobox-container .input-group-addon {
width: auto;
}
.combobox-selected .caret {
display: none;
}
/* :not doesn't work in IE8 */
.combobox-container:not(.combobox-selected) .glyphicon-remove {
display: none;
}
.typeahead-long {
max-height: 300px;
overflow-y: auto;
}
.control-group.error .combobox-container .add-on {
color: #B94A48;
border-color: #B94A48;
}
.control-group.error .combobox-container .caret {
border-top-color: #B94A48;
}
.control-group.warning .combobox-container .add-on {
color: #C09853;
border-color: #C09853;
}
.control-group.warning .combobox-container .caret {
border-top-color: #C09853;
}
.control-group.success .combobox-container .add-on {
color: #468847;
border-color: #468847;
}
.control-group.success .combobox-container .caret {
border-top-color: #468847;
}

View file

@ -0,0 +1,438 @@
/* =============================================================
* bootstrap-combobox.js v1.1.6
* =============================================================
* Copyright 2012 Daniel Farrell
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ============================================================ */
!function( $ ) {
"use strict";
/* COMBOBOX PUBLIC CLASS DEFINITION
* ================================ */
var Combobox = function ( element, options ) {
this.options = $.extend({}, $.fn.combobox.defaults, options);
this.$source = $(element);
this.$container = this.setup();
this.$element = this.$container.find('input[type=text]');
this.$target = this.$container.find('input[type=hidden]');
this.$button = this.$container.find('.dropdown-toggle');
this.$menu = $(this.options.menu).appendTo('body');
this.template = this.options.template || this.template
this.matcher = this.options.matcher || this.matcher;
this.sorter = this.options.sorter || this.sorter;
this.highlighter = this.options.highlighter || this.highlighter;
this.shown = false;
this.selected = false;
this.refresh();
this.transferAttributes();
this.listen();
};
Combobox.prototype = {
constructor: Combobox
, setup: function () {
var combobox = $(this.template());
this.$source.before(combobox);
this.$source.hide();
return combobox;
}
, disable: function() {
this.$element.prop('disabled', true);
this.$button.attr('disabled', true);
this.disabled = true;
this.$container.addClass('combobox-disabled');
}
, enable: function() {
this.$element.prop('disabled', false);
this.$button.attr('disabled', false);
this.disabled = false;
this.$container.removeClass('combobox-disabled');
}
, parse: function () {
var that = this
, map = {}
, source = []
, selected = false
, selectedValue = '';
this.$source.find('option').each(function() {
var option = $(this);
if (option.val() === '') {
that.options.placeholder = option.text();
return;
}
map[option.text()] = option.val();
source.push(option.text());
if (option.prop('selected')) {
selected = option.text();
selectedValue = option.val();
}
})
this.map = map;
if (selected) {
this.$element.val(selected);
this.$target.val(selectedValue);
this.$container.addClass('combobox-selected');
this.selected = true;
}
return source;
}
, transferAttributes: function() {
this.options.placeholder = this.$source.attr('data-placeholder') || this.options.placeholder
this.$element.attr('placeholder', this.options.placeholder)
this.$target.prop('name', this.$source.prop('name'))
this.$target.val(this.$source.val())
this.$source.removeAttr('name') // Remove from source otherwise form will pass parameter twice.
this.$element.attr('required', this.$source.attr('required'))
this.$element.attr('rel', this.$source.attr('rel'))
this.$element.attr('title', this.$source.attr('title'))
this.$element.attr('class', this.$source.attr('class'))
this.$element.attr('tabindex', this.$source.attr('tabindex'))
this.$source.removeAttr('tabindex')
if (this.$source.attr('disabled')!==undefined)
this.disable();
}
, select: function () {
var val = this.$menu.find('.active').attr('data-value');
this.$element.val(this.updater(val)).trigger('change');
this.$target.val(this.map[val]).trigger('change');
this.$source.val(this.map[val]).trigger('change');
this.$container.addClass('combobox-selected');
this.selected = true;
return this.hide();
}
, updater: function (item) {
return item;
}
, show: function () {
var pos = $.extend({}, this.$element.position(), {
height: this.$element[0].offsetHeight
});
this.$menu
.insertAfter(this.$element)
.css({
top: pos.top + pos.height
, left: pos.left
})
.show();
$('.dropdown-menu').on('mousedown', $.proxy(this.scrollSafety, this));
this.shown = true;
return this;
}
, hide: function () {
this.$menu.hide();
$('.dropdown-menu').off('mousedown', $.proxy(this.scrollSafety, this));
this.$element.on('blur', $.proxy(this.blur, this));
this.shown = false;
return this;
}
, lookup: function (event) {
this.query = this.$element.val();
return this.process(this.source);
}
, process: function (items) {
var that = this;
items = $.grep(items, function (item) {
return that.matcher(item);
})
items = this.sorter(items);
if (!items.length) {
return this.shown ? this.hide() : this;
}
return this.render(items.slice(0, this.options.items)).show();
}
, template: function() {
if (this.options.bsVersion == '2') {
return '<div class="combobox-container"><input type="hidden" /> <div class="input-append"> <input type="text" autocomplete="off" /> <span class="add-on dropdown-toggle" data-dropdown="dropdown"> <span class="caret"/> <i class="icon-remove"/> </span> </div> </div>'
} else {
return '<div class="combobox-container"> <input type="hidden" /> <div class="input-group"> <input type="text" autocomplete="off" /> <span class="input-group-addon dropdown-toggle" data-dropdown="dropdown"> <span class="caret" /> <span class="glyphicon glyphicon-remove" /> </span> </div> </div>'
}
}
, matcher: function (item) {
return ~item.toLowerCase().indexOf(this.query.toLowerCase());
}
, sorter: function (items) {
var beginswith = []
, caseSensitive = []
, caseInsensitive = []
, item;
while (item = items.shift()) {
if (!item.toLowerCase().indexOf(this.query.toLowerCase())) {beginswith.push(item);}
else if (~item.indexOf(this.query)) {caseSensitive.push(item);}
else {caseInsensitive.push(item);}
}
return beginswith.concat(caseSensitive, caseInsensitive);
}
, highlighter: function (item) {
var query = this.query.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
return item.replace(new RegExp('(' + query + ')', 'ig'), function ($1, match) {
return '<strong>' + match + '</strong>';
})
}
, render: function (items) {
var that = this;
items = $(items).map(function (i, item) {
i = $(that.options.item).attr('data-value', item);
i.find('a').html(that.highlighter(item));
return i[0];
})
items.first().addClass('active');
this.$menu.html(items);
return this;
}
, next: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, next = active.next();
if (!next.length) {
next = $(this.$menu.find('li')[0]);
}
next.addClass('active');
}
, prev: function (event) {
var active = this.$menu.find('.active').removeClass('active')
, prev = active.prev();
if (!prev.length) {
prev = this.$menu.find('li').last();
}
prev.addClass('active');
}
, toggle: function () {
if (!this.disabled) {
if (this.$container.hasClass('combobox-selected')) {
this.clearTarget();
this.triggerChange();
this.clearElement();
} else {
if (this.shown) {
this.hide();
} else {
this.clearElement();
this.lookup();
}
}
}
}
, scrollSafety: function(e) {
if (e.target.tagName == 'UL') {
this.$element.off('blur');
}
}
, clearElement: function () {
this.$element.val('').focus();
}
, clearTarget: function () {
this.$source.val('');
this.$target.val('');
this.$container.removeClass('combobox-selected');
this.selected = false;
}
, triggerChange: function () {
this.$source.trigger('change');
}
, refresh: function () {
this.source = this.parse();
this.options.items = this.source.length;
}
, listen: function () {
this.$element
.on('focus', $.proxy(this.focus, this))
.on('blur', $.proxy(this.blur, this))
.on('keypress', $.proxy(this.keypress, this))
.on('keyup', $.proxy(this.keyup, this));
if (this.eventSupported('keydown')) {
this.$element.on('keydown', $.proxy(this.keydown, this));
}
this.$menu
.on('click', $.proxy(this.click, this))
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
.on('mouseleave', 'li', $.proxy(this.mouseleave, this));
this.$button
.on('click', $.proxy(this.toggle, this));
}
, eventSupported: function(eventName) {
var isSupported = eventName in this.$element;
if (!isSupported) {
this.$element.setAttribute(eventName, 'return;');
isSupported = typeof this.$element[eventName] === 'function';
}
return isSupported;
}
, move: function (e) {
if (!this.shown) {return;}
switch(e.keyCode) {
case 9: // tab
case 13: // enter
case 27: // escape
e.preventDefault();
break;
case 38: // up arrow
e.preventDefault();
this.prev();
break;
case 40: // down arrow
e.preventDefault();
this.next();
break;
}
e.stopPropagation();
}
, keydown: function (e) {
this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
this.move(e);
}
, keypress: function (e) {
if (this.suppressKeyPressRepeat) {return;}
this.move(e);
}
, keyup: function (e) {
switch(e.keyCode) {
case 40: // down arrow
case 39: // right arrow
case 38: // up arrow
case 37: // left arrow
case 36: // home
case 35: // end
case 16: // shift
case 17: // ctrl
case 18: // alt
break;
case 9: // tab
case 13: // enter
if (!this.shown) {return;}
this.select();
break;
case 27: // escape
if (!this.shown) {return;}
this.hide();
break;
default:
this.clearTarget();
this.lookup();
}
e.stopPropagation();
e.preventDefault();
}
, focus: function (e) {
this.focused = true;
}
, blur: function (e) {
var that = this;
this.focused = false;
var val = this.$element.val();
if (!this.selected && val !== '' ) {
this.$element.val('');
this.$source.val('').trigger('change');
this.$target.val('').trigger('change');
}
if (!this.mousedover && this.shown) {setTimeout(function () { that.hide(); }, 200);}
}
, click: function (e) {
e.stopPropagation();
e.preventDefault();
this.select();
this.$element.focus();
}
, mouseenter: function (e) {
this.mousedover = true;
this.$menu.find('.active').removeClass('active');
$(e.currentTarget).addClass('active');
}
, mouseleave: function (e) {
this.mousedover = false;
}
};
/* COMBOBOX PLUGIN DEFINITION
* =========================== */
$.fn.combobox = function ( option ) {
return this.each(function () {
var $this = $(this)
, data = $this.data('combobox')
, options = typeof option == 'object' && option;
if(!data) {$this.data('combobox', (data = new Combobox(this, options)));}
if (typeof option == 'string') {data[option]();}
});
};
$.fn.combobox.defaults = {
bsVersion: '3'
, menu: '<ul class="typeahead typeahead-long dropdown-menu"></ul>'
, item: '<li><a href="#"></a></li>'
};
$.fn.combobox.Constructor = Combobox;
}( window.jQuery );

View file

@ -0,0 +1,54 @@
.form-search, .form-inline {
.combobox-container {
display: inline-block;
margin-bottom: 0;
vertical-align: top;
.input-group-addon{
width: auto;
}
}
}
.combobox-selected .caret {
display: none;
}
/* :not doesn't work in IE8 */
.combobox-container:not(.combobox-selected) .glyphicon-remove {
display: none;
}
.typeahead-long {
max-height: 300px;
overflow-y: auto;
}
.control-group.error .combobox-container{
.add-on {
color: #B94A48;
border-color: #B94A48;
}
.caret {
border-top-color: #B94A48;
}
}
.control-group.warning .combobox-container {
.add-on {
color: #C09853;
border-color: #C09853;
}
.caret {
border-top-color: #C09853;
}
}
.control-group.success .combobox-container{
.add-on {
color: #468847;
border-color: #468847;
}
.caret {
border-top-color: #468847;
}
}

View file

@ -0,0 +1,87 @@
# Contributing to this project
Please take a moment to review this document in order to make the contribution
process easy and effective for everyone involved.
Following these guidelines helps to communicate that you respect the time of
the developers managing and developing this open source project. In return,
they should reciprocate that respect in addressing your issue or assessing
patches and features.
## Using the issue tracker
The issue tracker is the preferred channel for [bug reports](#bugs),
[features requests](#features) and submitting pull
requests, but please respect the following restrictions:
* Please **do not** use the issue tracker for personal support requests (use
[Stack Overflow](http://stackoverflow.com) or IRC).
* Please **do not** derail or troll issues. Keep the discussion on topic and
respect the opinions of others.
<a name="bugs"></a>
## Bug reports
A bug is a _demonstrable problem_ that is caused by the code in the repository.
Good bug reports are extremely helpful - thank you!
Guidelines for bug reports:
1. **Use the GitHub issue search.** Check if the issue has already been
reported.
2. **Check if the issue has been fixed.** Try to reproduce it using the
latest `master` or development branch in the repository.
3. **Provide environment details.** Provide your operating system, browser(s), jQuery version, Bootstrap version, and bootstrap-select version.
4. **Create an isolated and reproducible test case.** Create a [reduced test
case](http://css-tricks.com/6263-reduced-test-cases/).
5. **Include a live example.** Make use of jsFiddle or jsBin to share your isolated test cases.
A good bug report shouldn't leave others needing to chase you up for more
information. Please try to be as detailed as possible in your report. What is
your environment? What steps will reproduce the issue? What browser(s) and OS
experience the problem? What would you expect to be the outcome? All these
details will help people to fix any potential bugs.
Example:
> Short and descriptive example bug report title
>
> A summary of the issue and the browser/OS environment in which it occurs. If
> suitable, include the steps required to reproduce the bug.
>
> 1. This is the first step
> 2. This is the second step
> 3. Further steps, etc.
>
> `<url>` - a link to the reduced test case
>
> Any other information you want to share that is relevant to the issue being
> reported. This might include the lines of code that you have identified as
> causing the bug, and potential solutions (and your opinions on their
> merits).
<a name="features"></a>
## Feature requests
Feature requests are welcome. But take a moment to find out whether your idea
fits with the scope and aims of the project. It's up to *you* to make a strong
case to convince the project's developers of the merits of this feature. Please
provide as much detail and context as possible.
## Pull Request Guidelines
* To instantiate a context or use it, use the variable **that** instead of **_this**.
* Submit your CLA, if you haven't.
* Please check to make sure that there aren't existing pull requests attempting to address the issue mentioned. We also recommend checking for issues related to the issue on the tracker, as a team member may be working on the issue in a branch or fork.
* Non-trivial changes should be discussed in an issue first
* If possible, use JSlint or JSHint to validate it
* If possible, add relevant tests to cover the change
* Write a convincing description of your PR and why we should land it

View file

@ -0,0 +1,61 @@
bootstrap-select
================
A custom select / multiselect for Bootstrap using button dropdown, designed to behave like regular Bootstrap selects;
## Demo and Documentation
See a Bootstrap 2.3.2 example [here](http://silviomoreto.github.com/bootstrap-select/). <br/>
See a Bootstrap 3.0.2 example [here](http://silviomoreto.github.com/bootstrap-select/3) (work-in-progress).
## Authors
[Silvio Moreto](http://github.com/silviomoreto),
[Ana Carolina](http://github.com/anacarolinats),
[caseyjhol](https://github.com/caseyjhol), and
[Matt Bryson](https://github.com/mattbryson).
## Usage
Create your `<select>` with the `.selectpicker` class.
<select class="selectpicker">
<option>Mustard</option>
<option>Ketchup</option>
<option>Barbecue</option>
</select>
Enable Bootstrap-Select via JavaScript:
$('.selectpicker').selectpicker();
Or just
$('select').selectpicker();
Checkout the [documentation](http://silviomoreto.github.com/bootstrap-select/) for further information.
## CDN
* https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.3.5/bootstrap-select.min.js
* https://cdnjs.cloudflare.com/ajax/libs/bootstrap-select/1.3.5/bootstrap-select.min.css
## Bugs and feature requests
Anyone and everyone is welcome to contribute. Please take a moment to
review the [guidelines for contributing](CONTRIBUTING.md). Make sure you're using the latest version of bootstrap-select before submitting an issue.
* [Bug reports](CONTRIBUTING.md#bugs)
* [Feature requests](CONTRIBUTING.md#features)
## Copyright and license
Copyright (C) 2013 bootstrap-select
Licensed under the MIT license.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View file

@ -0,0 +1,309 @@
/*!
* bootstrap-select v1.5.4
* http://silviomoreto.github.io/bootstrap-select/
*
* Copyright 2013 bootstrap-select
* Licensed under the MIT license
*/
.bootstrap-select.btn-group:not(.input-group-btn),
.bootstrap-select.btn-group[class*="span"] {
float: none;
display: inline-block;
margin-bottom: 10px;
margin-left: 0;
}
.form-search .bootstrap-select.btn-group,
.form-inline .bootstrap-select.btn-group,
.form-horizontal .bootstrap-select.btn-group {
margin-bottom: 0;
}
.bootstrap-select.form-control {
margin-bottom: 0;
padding: 0;
border: none;
}
.bootstrap-select.btn-group.pull-right,
.bootstrap-select.btn-group[class*="span"].pull-right,
.row-fluid .bootstrap-select.btn-group[class*="span"].pull-right {
float: right;
}
.input-append .bootstrap-select.btn-group {
margin-left: -1px;
}
.input-prepend .bootstrap-select.btn-group {
margin-right: -1px;
}
.bootstrap-select:not([class*="span"]):not([class*="col-"]):not([class*="form-control"]):not(.input-group-btn) {
width: 220px;
}
.bootstrap-select {
/*width: 220px\9; IE8 and below*/
width: 220px\0; /*IE9 and below*/
}
.bootstrap-select.form-control:not([class*="span"]) {
width: 100%;
}
.bootstrap-select > .btn {
width: 100%;
padding-right: 25px;
}
.error .bootstrap-select .btn {
border: 1px solid #b94a48;
}
.bootstrap-select.show-menu-arrow.open > .btn {
z-index: 2051;
}
.bootstrap-select .btn:focus {
outline: thin dotted #333333 !important;
outline: 5px auto -webkit-focus-ring-color !important;
outline-offset: -2px;
}
.bootstrap-select.btn-group .btn .filter-option {
display: inline-block;
overflow: hidden;
width: 100%;
float: left;
text-align: left;
}
.bootstrap-select.btn-group .btn .caret {
position: absolute;
top: 50%;
right: 12px;
margin-top: -2px;
vertical-align: middle;
}
.bootstrap-select.btn-group > .disabled,
.bootstrap-select.btn-group .dropdown-menu li.disabled > a {
cursor: not-allowed;
}
.bootstrap-select.btn-group > .disabled:focus {
outline: none !important;
}
.bootstrap-select.btn-group[class*="span"] .btn {
width: 100%;
}
.bootstrap-select.btn-group .dropdown-menu {
min-width: 100%;
z-index: 2000;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bootstrap-select.btn-group .dropdown-menu.inner {
position: static;
border: 0;
padding: 0;
margin: 0;
-webkit-border-radius: 0;
-moz-border-radius: 0;
border-radius: 0;
-webkit-box-shadow: none;
-moz-box-shadow: none;
box-shadow: none;
}
.bootstrap-select.btn-group .dropdown-menu dt {
display: block;
padding: 3px 20px;
cursor: default;
}
.bootstrap-select.btn-group .div-contain {
overflow: hidden;
}
.bootstrap-select.btn-group .dropdown-menu li {
position: relative;
}
.bootstrap-select.btn-group .dropdown-menu li > a.opt {
position: relative;
padding-left: 35px;
}
.bootstrap-select.btn-group .dropdown-menu li > a {
cursor: pointer;
}
.bootstrap-select.btn-group .dropdown-menu li > dt small {
font-weight: normal;
}
.bootstrap-select.btn-group.show-tick .dropdown-menu li.selected a i.check-mark {
position: absolute;
display: inline-block;
right: 15px;
margin-top: 2.5px;
}
.bootstrap-select.btn-group .dropdown-menu li a i.check-mark {
display: none;
}
.bootstrap-select.btn-group.show-tick .dropdown-menu li a span.text {
margin-right: 34px;
}
.bootstrap-select.btn-group .dropdown-menu li small {
padding-left: 0.5em;
}
.bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:hover small,
.bootstrap-select.btn-group .dropdown-menu li:not(.disabled) > a:focus small,
.bootstrap-select.btn-group .dropdown-menu li.active:not(.disabled) > a small {
color: #64b1d8;
color: rgba(255,255,255,0.4);
}
.bootstrap-select.btn-group .dropdown-menu li > dt small {
font-weight: normal;
}
.bootstrap-select.show-menu-arrow .dropdown-toggle:before {
content: '';
display: inline-block;
border-left: 7px solid transparent;
border-right: 7px solid transparent;
border-bottom: 7px solid #CCC;
border-bottom-color: rgba(0, 0, 0, 0.2);
position: absolute;
bottom: -4px;
left: 9px;
display: none;
}
.bootstrap-select.show-menu-arrow .dropdown-toggle:after {
content: '';
display: inline-block;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-bottom: 6px solid white;
position: absolute;
bottom: -4px;
left: 10px;
display: none;
}
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:before {
bottom: auto;
top: -3px;
border-top: 7px solid #ccc;
border-bottom: 0;
border-top-color: rgba(0, 0, 0, 0.2);
}
.bootstrap-select.show-menu-arrow.dropup .dropdown-toggle:after {
bottom: auto;
top: -3px;
border-top: 6px solid #ffffff;
border-bottom: 0;
}
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:before {
right: 12px;
left: auto;
}
.bootstrap-select.show-menu-arrow.pull-right .dropdown-toggle:after {
right: 13px;
left: auto;
}
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:before,
.bootstrap-select.show-menu-arrow.open > .dropdown-toggle:after {
display: block;
}
.bootstrap-select.btn-group .no-results {
padding: 3px;
background: #f5f5f5;
margin: 0 5px;
}
.bootstrap-select.btn-group .dropdown-menu .notify {
position: absolute;
bottom: 5px;
width: 96%;
margin: 0 2%;
min-height: 26px;
padding: 3px 5px;
background: #f5f5f5;
border: 1px solid #e3e3e3;
box-shadow: inset 0 1px 1px rgba(0,0,0,0.05);
pointer-events: none;
opacity: 0.9;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.mobile-device {
position: absolute;
top: 0;
left: 0;
display: block !important;
width: 100%;
height: 100% !important;
opacity: 0;
}
.bootstrap-select.fit-width {
width: auto !important;
}
.bootstrap-select.btn-group.fit-width .btn .filter-option {
position: static;
}
.bootstrap-select.btn-group.fit-width .btn .caret {
position: static;
top: auto;
margin-top: -1px;
}
.control-group.error .bootstrap-select .dropdown-toggle{
border-color: #b94a48;
}
.bootstrap-select-searchbox,
.bootstrap-select .bs-actionsbox {
padding: 4px 8px;
}
.bootstrap-select .bs-actionsbox {
float: left;
width: 100%;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.bootstrap-select-searchbox + .bs-actionsbox {
padding: 0 8px 4px;
}
.bootstrap-select-searchbox input {
margin-bottom: 0;
}
.bootstrap-select .bs-actionsbox .btn-group button {
width: 50%;
}

View file

@ -0,0 +1,29 @@
{
"name": "bootstrap-select",
"title": "Bootstrap Select",
"description": "A custom select / multiselect for Bootstrap using button dropdown, designed to behave like regular Bootstrap selects",
"keywords": [
"form",
"bootstrap",
"select",
"replacement"
],
"version": "1.5.4",
"author": {
"name": "Silvio Moreto",
"url": "https://github.com/silviomoreto/"
},
"licenses": [
{
"type": "MIT",
"url": "https://github.com/silviomoreto/bootstrap-select#copyright-and-license"
}
],
"bugs": "https://github.com/silviomoreto/bootstrap-select/issues",
"homepage": "https://github.com/silviomoreto/bootstrap-select",
"docs": "https://github.com/silviomoreto/bootstrap-select",
"download": "https://github.com/silviomoreto/bootstrap-select/releases",
"dependencies": {
"jquery": ">=1.7"
}
}

View file

@ -0,0 +1,972 @@
/*!
* bootstrap-select v1.5.4
* http://silviomoreto.github.io/bootstrap-select/
*
* Copyright 2013 bootstrap-select
* Licensed under the MIT license
*/
!function($) {
'use strict';
$.expr[':'].icontains = function(obj, index, meta) {
return $(obj).text().toUpperCase().indexOf(meta[3].toUpperCase()) >= 0;
};
var Selectpicker = function(element, options, e) {
if (e) {
e.stopPropagation();
e.preventDefault();
}
this.$element = $(element);
this.$newElement = null;
this.$button = null;
this.$menu = null;
this.$lis = null;
//Merge defaults, options and data-attributes to make our options
this.options = $.extend({}, $.fn.selectpicker.defaults, this.$element.data(), typeof options == 'object' && options);
//If we have no title yet, check the attribute 'title' (this is missed by jq as its not a data-attribute
if (this.options.title === null) {
this.options.title = this.$element.attr('title');
}
//Expose public methods
this.val = Selectpicker.prototype.val;
this.render = Selectpicker.prototype.render;
this.refresh = Selectpicker.prototype.refresh;
this.setStyle = Selectpicker.prototype.setStyle;
this.selectAll = Selectpicker.prototype.selectAll;
this.deselectAll = Selectpicker.prototype.deselectAll;
this.init();
};
Selectpicker.prototype = {
constructor: Selectpicker,
init: function() {
var that = this,
id = this.$element.attr('id');
this.$element.hide();
this.multiple = this.$element.prop('multiple');
this.autofocus = this.$element.prop('autofocus');
this.$newElement = this.createView();
this.$element.after(this.$newElement);
this.$menu = this.$newElement.find('> .dropdown-menu');
this.$button = this.$newElement.find('> button');
this.$searchbox = this.$newElement.find('input');
if (id !== undefined) {
this.$button.attr('data-id', id);
$('label[for="' + id + '"]').click(function(e) {
e.preventDefault();
that.$button.focus();
});
}
this.checkDisabled();
this.clickListener();
if (this.options.liveSearch) this.liveSearchListener();
this.render();
this.liHeight();
this.setStyle();
this.setWidth();
if (this.options.container) this.selectPosition();
this.$menu.data('this', this);
this.$newElement.data('this', this);
},
createDropdown: function() {
//If we are multiple, then add the show-tick class by default
var multiple = this.multiple ? ' show-tick' : '';
var inputGroup = this.$element.parent().hasClass('input-group') ? ' input-group-btn' : '';
var autofocus = this.autofocus ? ' autofocus' : '';
var header = this.options.header ? '<div class="popover-title"><button type="button" class="close" aria-hidden="true">&times;</button>' + this.options.header + '</div>' : '';
var searchbox = this.options.liveSearch ? '<div class="bootstrap-select-searchbox"><input type="text" class="input-block-level form-control" autocomplete="off" /></div>' : '';
var actionsbox = this.options.actionsBox ? '<div class="bs-actionsbox">' +
'<div class="btn-group btn-block">' +
'<button class="actions-btn bs-select-all btn btn-sm btn-default">' +
'Select All' +
'</button>' +
'<button class="actions-btn bs-deselect-all btn btn-sm btn-default">' +
'Deselect All' +
'</button>' +
'</div>' +
'</div>' : '';
var drop =
'<div class="btn-group bootstrap-select' + multiple + inputGroup + '">' +
'<button type="button" class="btn dropdown-toggle selectpicker" data-toggle="dropdown"'+ autofocus +'>' +
'<span class="filter-option pull-left"></span>&nbsp;' +
'<span class="caret"></span>' +
'</button>' +
'<div class="dropdown-menu open">' +
header +
searchbox +
actionsbox +
'<ul class="dropdown-menu inner selectpicker" role="menu">' +
'</ul>' +
'</div>' +
'</div>';
return $(drop);
},
createView: function() {
var $drop = this.createDropdown();
var $li = this.createLi();
$drop.find('ul').append($li);
return $drop;
},
reloadLi: function() {
//Remove all children.
this.destroyLi();
//Re build
var $li = this.createLi();
this.$menu.find('ul').append( $li );
},
destroyLi: function() {
this.$menu.find('li').remove();
},
createLi: function() {
var that = this,
_liA = [],
_liHtml = '';
this.$element.find('option').each(function() {
var $this = $(this);
//Get the class and text for the option
var optionClass = $this.attr('class') || '';
var inline = $this.attr('style') || '';
var text = $this.data('content') ? $this.data('content') : $this.html();
var subtext = $this.data('subtext') !== undefined ? '<small class="muted text-muted">' + $this.data('subtext') + '</small>' : '';
var icon = $this.data('icon') !== undefined ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '';
if (icon !== '' && ($this.is(':disabled') || $this.parent().is(':disabled'))) {
icon = '<span>'+icon+'</span>';
}
if (!$this.data('content')) {
//Prepend any icon and append any subtext to the main text.
text = icon + '<span class="text">' + text + subtext + '</span>';
}
if (that.options.hideDisabled && ($this.is(':disabled') || $this.parent().is(':disabled'))) {
_liA.push('<a style="min-height: 0; padding: 0"></a>');
} else if ($this.parent().is('optgroup') && $this.data('divider') !== true) {
if ($this.index() === 0) {
//Get the opt group label
var label = $this.parent().attr('label');
var labelSubtext = $this.parent().data('subtext') !== undefined ? '<small class="muted text-muted">'+$this.parent().data('subtext')+'</small>' : '';
var labelIcon = $this.parent().data('icon') ? '<i class="'+$this.parent().data('icon')+'"></i> ' : '';
label = labelIcon + '<span class="text">' + label + labelSubtext + '</span>';
if ($this[0].index !== 0) {
_liA.push(
'<div class="div-contain"><div class="divider"></div></div>'+
'<dt>'+label+'</dt>'+
that.createA(text, 'opt ' + optionClass, inline )
);
} else {
_liA.push(
'<dt>'+label+'</dt>'+
that.createA(text, 'opt ' + optionClass, inline ));
}
} else {
_liA.push(that.createA(text, 'opt ' + optionClass, inline ));
}
} else if ($this.data('divider') === true) {
_liA.push('<div class="div-contain"><div class="divider"></div></div>');
} else if ($(this).data('hidden') === true) {
_liA.push('<a></a>');
} else {
_liA.push(that.createA(text, optionClass, inline ));
}
});
$.each(_liA, function(i, item) {
var hide = item === '<a></a>' ? 'class="hide is-hidden"' : '';
_liHtml += '<li rel="' + i + '"' + hide + '>' + item + '</li>';
});
//If we are not multiple, and we dont have a selected item, and we dont have a title, select the first element so something is set in the button
if (!this.multiple && this.$element.find('option:selected').length===0 && !this.options.title) {
this.$element.find('option').eq(0).prop('selected', true).attr('selected', 'selected');
}
return $(_liHtml);
},
createA: function(text, classes, inline) {
return '<a tabindex="0" class="'+classes+'" style="'+inline+'">' +
text +
'<i class="' + this.options.iconBase + ' ' + this.options.tickIcon + ' icon-ok check-mark"></i>' +
'</a>';
},
render: function(updateLi) {
var that = this;
//Update the LI to match the SELECT
if (updateLi !== false) {
this.$element.find('option').each(function(index) {
that.setDisabled(index, $(this).is(':disabled') || $(this).parent().is(':disabled') );
that.setSelected(index, $(this).is(':selected') );
});
}
this.tabIndex();
var selectedItems = this.$element.find('option:selected').map(function() {
var $this = $(this);
var icon = $this.data('icon') && that.options.showIcon ? '<i class="' + that.options.iconBase + ' ' + $this.data('icon') + '"></i> ' : '';
var subtext;
if (that.options.showSubtext && $this.attr('data-subtext') && !that.multiple) {
subtext = ' <small class="muted text-muted">'+$this.data('subtext') +'</small>';
} else {
subtext = '';
}
if ($this.data('content') && that.options.showContent) {
return $this.data('content');
} else if ($this.attr('title') !== undefined) {
return $this.attr('title');
} else {
return icon + $this.html() + subtext;
}
}).toArray();
//Fixes issue in IE10 occurring when no default option is selected and at least one option is disabled
//Convert all the values into a comma delimited string
var title = !this.multiple ? selectedItems[0] : selectedItems.join(this.options.multipleSeparator);
//If this is multi select, and the selectText type is count, the show 1 of 2 selected etc..
if (this.multiple && this.options.selectedTextFormat.indexOf('count') > -1) {
var max = this.options.selectedTextFormat.split('>');
var notDisabled = this.options.hideDisabled ? ':not([disabled])' : '';
if ( (max.length>1 && selectedItems.length > max[1]) || (max.length==1 && selectedItems.length>=2)) {
title = this.options.countSelectedText.replace('{0}', selectedItems.length).replace('{1}', this.$element.find('option:not([data-divider="true"]):not([data-hidden="true"])'+notDisabled).length);
}
}
this.options.title = this.$element.attr('title');
//If we dont have a title, then use the default, or if nothing is set at all, use the not selected text
if (!title) {
title = this.options.title !== undefined ? this.options.title : this.options.noneSelectedText;
}
this.$button.attr('title', $.trim(title));
this.$newElement.find('.filter-option').html(title);
},
setStyle: function(style, status) {
if (this.$element.attr('class')) {
this.$newElement.addClass(this.$element.attr('class').replace(/selectpicker|mobile-device|validate\[.*\]/gi, ''));
}
var buttonClass = style ? style : this.options.style;
if (status == 'add') {
this.$button.addClass(buttonClass);
} else if (status == 'remove') {
this.$button.removeClass(buttonClass);
} else {
this.$button.removeClass(this.options.style);
this.$button.addClass(buttonClass);
}
},
liHeight: function() {
if (this.options.size === false) return;
var $selectClone = this.$menu.parent().clone().find('> .dropdown-toggle').prop('autofocus', false).end().appendTo('body'),
$menuClone = $selectClone.addClass('open').find('> .dropdown-menu'),
liHeight = $menuClone.find('li > a').outerHeight(),
headerHeight = this.options.header ? $menuClone.find('.popover-title').outerHeight() : 0,
searchHeight = this.options.liveSearch ? $menuClone.find('.bootstrap-select-searchbox').outerHeight() : 0,
actionsHeight = this.options.actionsBox ? $menuClone.find('.bs-actionsbox').outerHeight() : 0;
$selectClone.remove();
this.$newElement
.data('liHeight', liHeight)
.data('headerHeight', headerHeight)
.data('searchHeight', searchHeight)
.data('actionsHeight', actionsHeight);
},
setSize: function() {
var that = this,
menu = this.$menu,
menuInner = menu.find('.inner'),
selectHeight = this.$newElement.outerHeight(),
liHeight = this.$newElement.data('liHeight'),
headerHeight = this.$newElement.data('headerHeight'),
searchHeight = this.$newElement.data('searchHeight'),
actionsHeight = this.$newElement.data('actionsHeight'),
divHeight = menu.find('li .divider').outerHeight(true),
menuPadding = parseInt(menu.css('padding-top')) +
parseInt(menu.css('padding-bottom')) +
parseInt(menu.css('border-top-width')) +
parseInt(menu.css('border-bottom-width')),
notDisabled = this.options.hideDisabled ? ':not(.disabled)' : '',
$window = $(window),
menuExtras = menuPadding + parseInt(menu.css('margin-top')) + parseInt(menu.css('margin-bottom')) + 2,
menuHeight,
selectOffsetTop,
selectOffsetBot,
posVert = function() {
selectOffsetTop = that.$newElement.offset().top - $window.scrollTop();
selectOffsetBot = $window.height() - selectOffsetTop - selectHeight;
};
posVert();
if (this.options.header) menu.css('padding-top', 0);
if (this.options.size == 'auto') {
var getSize = function() {
var minHeight,
lisVis = that.$lis.not('.hide');
posVert();
menuHeight = selectOffsetBot - menuExtras;
if (that.options.dropupAuto) {
that.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && ((menuHeight - menuExtras) < menu.height()));
}
if (that.$newElement.hasClass('dropup')) {
menuHeight = selectOffsetTop - menuExtras;
}
if ((lisVis.length + lisVis.find('dt').length) > 3) {
minHeight = liHeight*3 + menuExtras - 2;
} else {
minHeight = 0;
}
menu.css({'max-height' : menuHeight + 'px', 'overflow' : 'hidden', 'min-height' : minHeight + headerHeight + searchHeight + actionsHeight + 'px'});
menuInner.css({'max-height' : menuHeight - headerHeight - searchHeight - actionsHeight - menuPadding + 'px', 'overflow-y' : 'auto', 'min-height' : Math.max(minHeight - menuPadding, 0) + 'px'});
};
getSize();
this.$searchbox.off('input.getSize propertychange.getSize').on('input.getSize propertychange.getSize', getSize);
$(window).off('resize.getSize').on('resize.getSize', getSize);
$(window).off('scroll.getSize').on('scroll.getSize', getSize);
} else if (this.options.size && this.options.size != 'auto' && menu.find('li'+notDisabled).length > this.options.size) {
var optIndex = menu.find('li'+notDisabled+' > *').filter(':not(.div-contain)').slice(0,this.options.size).last().parent().index();
var divLength = menu.find('li').slice(0,optIndex + 1).find('.div-contain').length;
menuHeight = liHeight*this.options.size + divLength*divHeight + menuPadding;
if (that.options.dropupAuto) {
this.$newElement.toggleClass('dropup', (selectOffsetTop > selectOffsetBot) && (menuHeight < menu.height()));
}
menu.css({'max-height' : menuHeight + headerHeight + searchHeight + actionsHeight + 'px', 'overflow' : 'hidden'});
menuInner.css({'max-height' : menuHeight - menuPadding + 'px', 'overflow-y' : 'auto'});
}
},
setWidth: function() {
if (this.options.width == 'auto') {
this.$menu.css('min-width', '0');
// Get correct width if element hidden
var selectClone = this.$newElement.clone().appendTo('body');
var ulWidth = selectClone.find('> .dropdown-menu').css('width');
var btnWidth = selectClone.css('width', 'auto').find('> button').css('width');
selectClone.remove();
// Set width to whatever's larger, button title or longest option
this.$newElement.css('width', Math.max(parseInt(ulWidth), parseInt(btnWidth)) + 'px');
} else if (this.options.width == 'fit') {
// Remove inline min-width so width can be changed from 'auto'
this.$menu.css('min-width', '');
this.$newElement.css('width', '').addClass('fit-width');
} else if (this.options.width) {
// Remove inline min-width so width can be changed from 'auto'
this.$menu.css('min-width', '');
this.$newElement.css('width', this.options.width);
} else {
// Remove inline min-width/width so width can be changed
this.$menu.css('min-width', '');
this.$newElement.css('width', '');
}
// Remove fit-width class if width is changed programmatically
if (this.$newElement.hasClass('fit-width') && this.options.width !== 'fit') {
this.$newElement.removeClass('fit-width');
}
},
selectPosition: function() {
var that = this,
drop = '<div />',
$drop = $(drop),
pos,
actualHeight,
getPlacement = function($element) {
$drop.addClass($element.attr('class').replace(/form-control/gi, '')).toggleClass('dropup', $element.hasClass('dropup'));
pos = $element.offset();
actualHeight = $element.hasClass('dropup') ? 0 : $element[0].offsetHeight;
$drop.css({'top' : pos.top + actualHeight, 'left' : pos.left, 'width' : $element[0].offsetWidth, 'position' : 'absolute'});
};
this.$newElement.on('click', function() {
if (that.isDisabled()) {
return;
}
getPlacement($(this));
$drop.appendTo(that.options.container);
$drop.toggleClass('open', !$(this).hasClass('open'));
$drop.append(that.$menu);
});
$(window).resize(function() {
getPlacement(that.$newElement);
});
$(window).on('scroll', function() {
getPlacement(that.$newElement);
});
$('html').on('click', function(e) {
if ($(e.target).closest(that.$newElement).length < 1) {
$drop.removeClass('open');
}
});
},
mobile: function() {
this.$element.addClass('mobile-device').appendTo(this.$newElement);
if (this.options.container) this.$menu.hide();
},
refresh: function() {
this.$lis = null;
this.reloadLi();
this.render();
this.setWidth();
this.setStyle();
this.checkDisabled();
this.liHeight();
},
update: function() {
this.reloadLi();
this.setWidth();
this.setStyle();
this.checkDisabled();
this.liHeight();
},
setSelected: function(index, selected) {
if (this.$lis == null) this.$lis = this.$menu.find('li');
$(this.$lis[index]).toggleClass('selected', selected);
},
setDisabled: function(index, disabled) {
if (this.$lis == null) this.$lis = this.$menu.find('li');
if (disabled) {
$(this.$lis[index]).addClass('disabled').find('a').attr('href', '#').attr('tabindex', -1);
} else {
$(this.$lis[index]).removeClass('disabled').find('a').removeAttr('href').attr('tabindex', 0);
}
},
isDisabled: function() {
return this.$element.is(':disabled');
},
checkDisabled: function() {
var that = this;
if (this.isDisabled()) {
this.$button.addClass('disabled').attr('tabindex', -1);
} else {
if (this.$button.hasClass('disabled')) {
this.$button.removeClass('disabled');
}
if (this.$button.attr('tabindex') == -1) {
if (!this.$element.data('tabindex')) this.$button.removeAttr('tabindex');
}
}
this.$button.click(function() {
return !that.isDisabled();
});
},
tabIndex: function() {
if (this.$element.is('[tabindex]')) {
this.$element.data('tabindex', this.$element.attr('tabindex'));
this.$button.attr('tabindex', this.$element.data('tabindex'));
}
},
clickListener: function() {
var that = this;
$('body').on('touchstart.dropdown', '.dropdown-menu', function(e) {
e.stopPropagation();
});
this.$newElement.on('click', function() {
that.setSize();
if (!that.options.liveSearch && !that.multiple) {
setTimeout(function() {
that.$menu.find('.selected a').focus();
}, 10);
}
});
this.$menu.on('click', 'li a', function(e) {
var clickedIndex = $(this).parent().index(),
prevValue = that.$element.val(),
prevIndex = that.$element.prop('selectedIndex');
//Dont close on multi choice menu
if (that.multiple) {
e.stopPropagation();
}
e.preventDefault();
//Dont run if we have been disabled
if (!that.isDisabled() && !$(this).parent().hasClass('disabled')) {
var $options = that.$element.find('option'),
$option = $options.eq(clickedIndex),
state = $option.prop('selected'),
$optgroup = $option.parent('optgroup'),
maxOptions = that.options.maxOptions,
maxOptionsGrp = $optgroup.data('maxOptions') || false;
//Deselect all others if not multi select box
if (!that.multiple) {
$options.prop('selected', false);
$option.prop('selected', true);
that.$menu.find('.selected').removeClass('selected');
that.setSelected(clickedIndex, true);
}
//Else toggle the one we have chosen if we are multi select.
else {
$option.prop('selected', !state);
that.setSelected(clickedIndex, !state);
if ((maxOptions !== false) || (maxOptionsGrp !== false)) {
var maxReached = maxOptions < $options.filter(':selected').length,
maxReachedGrp = maxOptionsGrp < $optgroup.find('option:selected').length,
maxOptionsArr = that.options.maxOptionsText,
maxTxt = maxOptionsArr[0].replace('{n}', maxOptions),
maxTxtGrp = maxOptionsArr[1].replace('{n}', maxOptionsGrp),
$notify = $('<div class="notify"></div>');
if ((maxOptions && maxReached) || (maxOptionsGrp && maxReachedGrp)) {
// If {var} is set in array, replace it
if (maxOptionsArr[2]) {
maxTxt = maxTxt.replace('{var}', maxOptionsArr[2][maxOptions > 1 ? 0 : 1]);
maxTxtGrp = maxTxtGrp.replace('{var}', maxOptionsArr[2][maxOptionsGrp > 1 ? 0 : 1]);
}
$option.prop('selected', false);
that.$menu.append($notify);
if (maxOptions && maxReached) {
$notify.append($('<div>' + maxTxt + '</div>'));
that.$element.trigger('maxReached.bs.select');
}
if (maxOptionsGrp && maxReachedGrp) {
$notify.append($('<div>' + maxTxtGrp + '</div>'));
that.$element.trigger('maxReachedGrp.bs.select');
}
setTimeout(function() {
that.setSelected(clickedIndex, false);
}, 10);
$notify.delay(750).fadeOut(300, function() { $(this).remove(); });
}
}
}
if (!that.multiple) {
that.$button.focus();
} else if (that.options.liveSearch) {
that.$searchbox.focus();
}
// Trigger select 'change'
if ((prevValue != that.$element.val() && that.multiple) || (prevIndex != that.$element.prop('selectedIndex') && !that.multiple)) {
that.$element.change();
}
}
});
this.$menu.on('click', 'li.disabled a, li dt, li .div-contain, .popover-title, .popover-title :not(.close)', function(e) {
if (e.target == this) {
e.preventDefault();
e.stopPropagation();
if (!that.options.liveSearch) {
that.$button.focus();
} else {
that.$searchbox.focus();
}
}
});
this.$menu.on('click', '.popover-title .close', function() {
that.$button.focus();
});
this.$searchbox.on('click', function(e) {
e.stopPropagation();
});
this.$menu.on('click', '.actions-btn', function(e) {
if (that.options.liveSearch) {
that.$searchbox.focus();
} else {
that.$button.focus();
}
e.preventDefault();
e.stopPropagation();
if ($(this).is('.bs-select-all')) {
that.selectAll();
} else {
that.deselectAll();
}
that.$element.change();
});
this.$element.change(function() {
that.render(false);
});
},
liveSearchListener: function() {
var that = this,
no_results = $('<li class="no-results"></li>');
this.$newElement.on('click.dropdown.data-api', function() {
that.$menu.find('.active').removeClass('active');
if (!!that.$searchbox.val()) {
that.$searchbox.val('');
that.$lis.not('.is-hidden').removeClass('hide');
if (!!no_results.parent().length) no_results.remove();
}
if (!that.multiple) that.$menu.find('.selected').addClass('active');
setTimeout(function() {
that.$searchbox.focus();
}, 10);
});
this.$searchbox.on('input propertychange', function() {
if (that.$searchbox.val()) {
that.$lis.not('.is-hidden').removeClass('hide').find('a').not(':icontains(' + that.$searchbox.val() + ')').parent().addClass('hide');
if (!that.$menu.find('li').filter(':visible:not(.no-results)').length) {
if (!!no_results.parent().length) no_results.remove();
no_results.html(that.options.noneResultsText + ' "'+ that.$searchbox.val() + '"').show();
that.$menu.find('li').last().after(no_results);
} else if (!!no_results.parent().length) {
no_results.remove();
}
} else {
that.$lis.not('.is-hidden').removeClass('hide');
if (!!no_results.parent().length) no_results.remove();
}
that.$menu.find('li.active').removeClass('active');
that.$menu.find('li').filter(':visible:not(.divider)').eq(0).addClass('active').find('a').focus();
$(this).focus();
});
this.$menu.on('mouseenter', 'a', function(e) {
that.$menu.find('.active').removeClass('active');
$(e.currentTarget).parent().not('.disabled').addClass('active');
});
this.$menu.on('mouseleave', 'a', function() {
that.$menu.find('.active').removeClass('active');
});
},
val: function(value) {
if (value !== undefined) {
this.$element.val( value );
this.$element.change();
return this.$element;
} else {
return this.$element.val();
}
},
selectAll: function() {
if (this.$lis == null) this.$lis = this.$menu.find('li');
this.$element.find('option:enabled').prop('selected', true);
$(this.$lis).filter(':not(.disabled)').addClass('selected');
this.render(false);
},
deselectAll: function() {
if (this.$lis == null) this.$lis = this.$menu.find('li');
this.$element.find('option:enabled').prop('selected', false);
$(this.$lis).filter(':not(.disabled)').removeClass('selected');
this.render(false);
},
keydown: function(e) {
var $this,
$items,
$parent,
index,
next,
first,
last,
prev,
nextPrev,
that,
prevIndex,
isActive,
keyCodeMap = {
32:' ', 48:'0', 49:'1', 50:'2', 51:'3', 52:'4', 53:'5', 54:'6', 55:'7', 56:'8', 57:'9', 59:';',
65:'a', 66:'b', 67:'c', 68:'d', 69:'e', 70:'f', 71:'g', 72:'h', 73:'i', 74:'j', 75:'k', 76:'l',
77:'m', 78:'n', 79:'o', 80:'p', 81:'q', 82:'r', 83:'s', 84:'t', 85:'u', 86:'v', 87:'w', 88:'x',
89:'y', 90:'z', 96:'0', 97:'1', 98:'2', 99:'3', 100:'4', 101:'5', 102:'6', 103:'7', 104:'8', 105:'9'
};
$this = $(this);
$parent = $this.parent();
if ($this.is('input')) $parent = $this.parent().parent();
that = $parent.data('this');
if (that.options.liveSearch) $parent = $this.parent().parent();
if (that.options.container) $parent = that.$menu;
$items = $('[role=menu] li:not(.divider) a', $parent);
isActive = that.$menu.parent().hasClass('open');
if (!isActive && /([0-9]|[A-z])/.test(String.fromCharCode(e.keyCode))) {
if (!that.options.container) {
that.setSize();
that.$menu.parent().addClass('open');
isActive = that.$menu.parent().hasClass('open');
} else {
that.$newElement.trigger('click');
}
that.$searchbox.focus();
}
if (that.options.liveSearch) {
if (/(^9$|27)/.test(e.keyCode) && isActive && that.$menu.find('.active').length === 0) {
e.preventDefault();
that.$menu.parent().removeClass('open');
that.$button.focus();
}
$items = $('[role=menu] li:not(.divider):visible', $parent);
if (!$this.val() && !/(38|40)/.test(e.keyCode)) {
if ($items.filter('.active').length === 0) {
$items = that.$newElement.find('li').filter(':icontains(' + keyCodeMap[e.keyCode] + ')');
}
}
}
if (!$items.length) return;
if (/(38|40)/.test(e.keyCode)) {
index = $items.index($items.filter(':focus'));
first = $items.parent(':not(.disabled):visible').first().index();
last = $items.parent(':not(.disabled):visible').last().index();
next = $items.eq(index).parent().nextAll(':not(.disabled):visible').eq(0).index();
prev = $items.eq(index).parent().prevAll(':not(.disabled):visible').eq(0).index();
nextPrev = $items.eq(next).parent().prevAll(':not(.disabled):visible').eq(0).index();
if (that.options.liveSearch) {
$items.each(function(i) {
if ($(this).is(':not(.disabled)')) {
$(this).data('index', i);
}
});
index = $items.index($items.filter('.active'));
first = $items.filter(':not(.disabled):visible').first().data('index');
last = $items.filter(':not(.disabled):visible').last().data('index');
next = $items.eq(index).nextAll(':not(.disabled):visible').eq(0).data('index');
prev = $items.eq(index).prevAll(':not(.disabled):visible').eq(0).data('index');
nextPrev = $items.eq(next).prevAll(':not(.disabled):visible').eq(0).data('index');
}
prevIndex = $this.data('prevIndex');
if (e.keyCode == 38) {
if (that.options.liveSearch) index -= 1;
if (index != nextPrev && index > prev) index = prev;
if (index < first) index = first;
if (index == prevIndex) index = last;
}
if (e.keyCode == 40) {
if (that.options.liveSearch) index += 1;
if (index == -1) index = 0;
if (index != nextPrev && index < next) index = next;
if (index > last) index = last;
if (index == prevIndex) index = first;
}
$this.data('prevIndex', index);
if (!that.options.liveSearch) {
$items.eq(index).focus();
} else {
e.preventDefault();
if (!$this.is('.dropdown-toggle')) {
$items.removeClass('active');
$items.eq(index).addClass('active').find('a').focus();
$this.focus();
}
}
} else if (!$this.is('input')) {
var keyIndex = [],
count,
prevKey;
$items.each(function() {
if ($(this).parent().is(':not(.disabled)')) {
if ($.trim($(this).text().toLowerCase()).substring(0,1) == keyCodeMap[e.keyCode]) {
keyIndex.push($(this).parent().index());
}
}
});
count = $(document).data('keycount');
count++;
$(document).data('keycount',count);
prevKey = $.trim($(':focus').text().toLowerCase()).substring(0,1);
if (prevKey != keyCodeMap[e.keyCode]) {
count = 1;
$(document).data('keycount', count);
} else if (count >= keyIndex.length) {
$(document).data('keycount', 0);
if (count > keyIndex.length) count = 1;
}
$items.eq(keyIndex[count - 1]).focus();
}
// Select focused option if "Enter", "Spacebar", "Tab" are pressed inside the menu.
if (/(13|32|^9$)/.test(e.keyCode) && isActive) {
if (!/(32)/.test(e.keyCode)) e.preventDefault();
if (!that.options.liveSearch) {
$(':focus').click();
} else if (!/(32)/.test(e.keyCode)) {
that.$menu.find('.active a').click();
$this.focus();
}
$(document).data('keycount',0);
}
if ((/(^9$|27)/.test(e.keyCode) && isActive && (that.multiple || that.options.liveSearch)) || (/(27)/.test(e.keyCode) && !isActive)) {
that.$menu.parent().removeClass('open');
that.$button.focus();
}
},
hide: function() {
this.$newElement.hide();
},
show: function() {
this.$newElement.show();
},
destroy: function() {
this.$newElement.remove();
this.$element.remove();
}
};
$.fn.selectpicker = function(option, event) {
//get the args of the outer function..
var args = arguments;
var value;
var chain = this.each(function() {
if ($(this).is('select')) {
var $this = $(this),
data = $this.data('selectpicker'),
options = typeof option == 'object' && option;
if (!data) {
$this.data('selectpicker', (data = new Selectpicker(this, options, event)));
} else if (options) {
for(var i in options) {
data.options[i] = options[i];
}
}
if (typeof option == 'string') {
//Copy the value of option, as once we shift the arguments
//it also shifts the value of option.
var property = option;
if (data[property] instanceof Function) {
[].shift.apply(args);
value = data[property].apply(data, args);
} else {
value = data.options[property];
}
}
}
});
if (value !== undefined) {
return value;
} else {
return chain;
}
};
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Nothing selected',
noneResultsText : 'No results match',
countSelectedText: '{0} of {1} selected',
maxOptionsText: ['Limit reached ({n} {var} max)', 'Group limit reached ({n} {var} max)', ['items','item']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
actionsBox: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok',
maxOptions: false
};
$(document)
.data('keycount', 0)
.on('keydown', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bootstrap-select-searchbox input', Selectpicker.prototype.keydown)
.on('focusin.modal', '.bootstrap-select [data-toggle=dropdown], .bootstrap-select [role=menu], .bootstrap-select-searchbox input', function (e) { e.stopPropagation(); });
}(window.jQuery);

View file

@ -0,0 +1,29 @@
{
"name": "bootstrap-select",
"main": [
"bootstrap-select.css",
"bootstrap-select.js"
],
"version": "1.5.4",
"homepage": "https://github.com/silviomoreto/bootstrap-select",
"authors": [
"silviomoreto"
],
"keywords": [
"form",
"bootstrap",
"select",
"replacement"
],
"dependencies": {
"jquery": ">=1.7"
},
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
]
}

View file

@ -0,0 +1,17 @@
{
"name": "bootstrap-select/bootstrap-select",
"description": "A custom <select> for Bootstrap using button dropdown as replacement",
"keywords": ["form", "bootstrap", "select", "replacement"],
"homepage": "https://github.com/silviomoreto/bootstrap-select",
"version": "1.5.4",
"authors": [
{
"name": "Silvio Moreto",
"homepage": "https://github.com/silviomoreto/"
}
],
"license": "MIT",
"suggest": {
"components/jquery": "1.8.*"
}
}

View file

@ -0,0 +1,29 @@
/*
* Translated default messages for bootstrap-select.
* Locale: CZ (Czech Republic)
* Region: EU
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Nic není výbráno',
noneResultsText : 'Žádné výsledky',
countSelectedText : 'Označeno {0} z {1}',
maxOptionsText: ['Limit překročen ({n} {var} max)', 'Limit skupiny překročen ({n} {var} max)', ['položek','položka']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: CZ (Czech Republic)
* Region: EU
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Nic není výbráno",noneResultsText:"Žádné výsledky",countSelectedText:"Označeno {0} z {1}",maxOptionsText:["Limit překročen ({n} {var} max)","Limit skupiny překročen ({n} {var} max)",["položek","položka"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}})(jQuery)

View file

@ -0,0 +1,29 @@
/*
* Translated default messages for bootstrap-select.
* Locale: DE (German, deutsch)
* Region: DE (Germany, Deutschland)
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'ausgewählt',
noneSelectedText : 'Bitte wählen...',
noneResultsText : 'Keine Ergebnisse für',
countSelectedText : '{0} von {1} ausgewählt',
maxOptionsText: ['Limit erreicht ({n} {var} max.)', 'Gruppen-Limit erreicht ({n} {var} max.)', ['Eintrag','Einträge']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: DE (German, deutsch)
* Region: DE (Germany, Deutschland)
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"ausgewählt",noneSelectedText:"Bitte wählen...",noneResultsText:"Keine Ergebnisse für",countSelectedText:"{0} von {1} ausgewählt",maxOptionsText:["Limit erreicht ({n} {var} max.)","Gruppen-Limit erreicht ({n} {var} max.)",["Eintrag","Einträge"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}})(jQuery)

View file

@ -0,0 +1,29 @@
/*
* Translated default messages for bootstrap-select.
* Locale: ES (Spanish)
* Region: CL (Chile)
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'No hay selección',
noneResultsText : 'No hay resultados',
countSelectedText : 'Seleccionados {0} de {1}',
maxOptionsText: ['Límite alcanzado ({n} {var} max)', 'Límite del grupo alcanzado({n} {var} max)', ['elementos','element']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: ES (Spanish)
* Region: CL (Chile)
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"No hay selección",noneResultsText:"No hay resultados",countSelectedText:"Seleccionados {0} de {1}",maxOptionsText:["Límite alcanzado ({n} {var} max)","Límite del grupo alcanzado({n} {var} max)",["elementos","element"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}})(jQuery)

View file

@ -0,0 +1,30 @@
/*
* Translated default messages for bootstrap-select.
* Locale: EU (Basque)
* Region:
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Hautapenik ez',
noneResultsText : 'Emaitzarik ez',
countSelectedText : '{1}(e)tik {0} hautatuta',
maxOptionsText: ['Mugara iritsita ({n} {var} gehienez)', 'Taldearen mugara iritsita ({n} {var} gehienez)', ['elementu','elementu']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: EU (Basque)
* Region:
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Hautapenik ez",noneResultsText:"Emaitzarik ez",countSelectedText:"{1}(e)tik {0} hautatuta",maxOptionsText:["Mugara iritsita ({n} {var} gehienez)","Taldearen mugara iritsita ({n} {var} gehienez)",["elementu","elementu"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}})(jQuery)

View file

@ -0,0 +1,32 @@
/*
* Translated default messages for bootstrap-select.
* Locale: IT (Italian; italiano)
* Region: IT (Italy; Italia)
* Author: Michele Beltrame <mb@cattlegrid.info>
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Nessuna selezione',
noneResultsText : 'Nessun risultato',
countSelectedText : 'Selezionati {0} di {1}',
maxOptionsText: ['Limite raggiunto ({n} {var} max)', 'Limite del gruppo raggiunto ({n} {var} max)', ['elementi','elemento']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
actionsBox: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok',
maxOptions: false
};
}(jQuery));

View file

@ -0,0 +1 @@
(function($){$.fn.selectpicker.defaults={style:'btn-default',size:'auto',title:null,selectedTextFormat:'values',noneSelectedText:'Nessuna selezione',noneResultsText:'Nessun risultato',countSelectedText:'Selezionati {0} di {1}',maxOptionsText:['Limite raggiunto ({n} {var} max)','Limite del gruppo raggiunto ({n} {var} max)',['elementi','elemento']],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,actionsBox:false,multipleSeparator:', ',iconBase:'glyphicon',tickIcon:'glyphicon-ok',maxOptions:false}}(jQuery));

View file

@ -0,0 +1,32 @@
/*
* Translated default messages for bootstrap-select.
* Locale: NL (Dutch; Nederlands)
* Region: EU (Europe)
* Author: Daan Rosbergen (Badmuts)
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Niets geselecteerd',
noneResultsText : 'Geen resultaten gevonden voor',
countSelectedText: '{0} van {1} geselecteerd',
maxOptionsText: ['Limiet bereikt ({n} {var} max)', 'Groep limiet bereikt ({n} {var} max)', ['items','item']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
actionsBox: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok',
maxOptions: false
};
}(jQuery));

View file

@ -0,0 +1,7 @@
/*
* Translated default messages for bootstrap-select.
* Locale: NL (Dutch; Nederlands)
* Region: EU (Europe)
* Author: Daan Rosbergen (Badmuts)
*/
(function(a){a.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Niets geselecteerd",noneResultsText:"Geen resultaten gevonden voor",countSelectedText:"{0} van {1} geselecteerd",maxOptionsText:["Limiet bereikt ({n} {var} max)","Groep limiet bereikt ({n} {var} max)",["items","item"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,actionsBox:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok",maxOptions:false}}(jQuery));

View file

@ -0,0 +1,29 @@
/*
* Translated default messages for bootstrap-select.
* Locale: PL (Polish)
* Region: EU (Europe)
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Nic nie zaznaczono',
noneResultsText : 'Brak wyników wyszukiwania',
countSelectedText : 'Zaznaczono {0} z {1}',
maxOptionsText: ['Osiągnięto limit ({n} {var} max)', 'Limit grupy osiągnięty ({n} {var} max)', ['elementy','element']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: PL (Polish)
* Region: EU (Europe)
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Nic nie zaznaczono",noneResultsText:"Brak wyników wyszukiwania",countSelectedText:"Zaznaczono {0} z {1}",maxOptionsText:["Osiągnięto limit ({n} {var} max)","Limit grupy osiągnięty ({n} {var} max)",["elementy","element"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}})(jQuery)

View file

@ -0,0 +1,33 @@
/*
* Translated default messages for bootstrap-select.
* Locale: PT (Portuguese; português)
* Region: BR (Brazil; Brasil)
* Author: Rodrigo de Avila <rodrigo@avila.net.br>
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Nada selecionado',
noneResultsText : 'Nada encontrado contendo',
countSelectedText : 'Selecionado {0} de {1}',
maxOptionsText: ['Limite excedido (máx. {n} {var})', 'Limite do grupo excedido (máx. {n} {var})', ['itens','item']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
actionsBox: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok',
maxOptions: false
};
}(jQuery));

View file

@ -0,0 +1,7 @@
/*
* Translated default messages for bootstrap-select.
* Locale: PT (Portuguese; português)
* Region: BR (Brazil; Brasil)
* Author: Rodrigo de Avila <rodrigo@avila.net.br>
*/
!function(a){a.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Nada selecionado",noneResultsText:"Nada encontrado contendo",countSelectedText:"Selecionado {0} de {1}",maxOptionsText:["Limite excedido (m\xe1x. {n} {var})","Limite do grupo excedido (m\xe1x. {n} {var})",["itens","item"]],width:!1,container:!1,hideDisabled:!1,showSubtext:!1,showIcon:!0,showContent:!0,dropupAuto:!0,header:!1,liveSearch:!1,actionsBox:!1,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok",maxOptions:!1}}(jQuery);

View file

@ -0,0 +1,31 @@
/*
* Translated default messages for bootstrap-select.
* Locale: RU (Russian; Русский)
* Region: RU (Russian Federation)
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : 'Ничего не выбрано',
noneResultsText : 'Не найдено совпадений',
countSelectedText : 'Выбрано {0} из {1}',
maxOptionsText: ['Достигнут предел ({n} {var} максимум)', 'Достигнут предел в группе ({n} {var} максимум)', ['items','item']],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
actionsBox: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok',
maxOptions: false
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: RU (Russian; Русский)
* Region: RU (Russian Federation)
*/
(function(e){e.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"Ничего не выбрано",noneResultsText:"Не нейдено Совпадений",countSelectedText:"Выбрано {0} из {1}",maxOptionsText:["Достигнут предел ({n} {var} максимум)","Достигнут предел в группе ({n} {var} максимум)",["items","item"]],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,actionsBox:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok",maxOptions:false}})(jQuery)

View file

@ -0,0 +1,30 @@
/*
* Translated default messages for bootstrap-select.
* Locale: zh_CN (Chinese)
* Region:
*/
(function($) {
$.fn.selectpicker.defaults = {
style: 'btn-default',
size: 'auto',
title: null,
selectedTextFormat : 'values',
noneSelectedText : '没有选中任何项',
noneResultsText : '没有找到匹配项',
countSelectedText : '选中{1}中的{0}项',
maxOptionsText: ['超出限制 (最多选择{n}项)', '组选择超出限制(最多选择{n}组)'],
width: false,
container: false,
hideDisabled: false,
showSubtext: false,
showIcon: true,
showContent: true,
dropupAuto: true,
header: false,
liveSearch: false,
multipleSeparator: ', ',
iconBase: 'glyphicon',
tickIcon: 'glyphicon-ok'
};
}(jQuery));

View file

@ -0,0 +1,6 @@
/*
* Translated default messages for bootstrap-select.
* Locale: zh_CN (Chinese)
* Region:
*/
(function(a){a.fn.selectpicker.defaults={style:"btn-default",size:"auto",title:null,selectedTextFormat:"values",noneSelectedText:"没有选中任何项",noneResultsText:"没有找到匹配项",countSelectedText:"选中{1}中的{0}项",maxOptionsText:["超出限制 (最多选择{n}项)","组选择超出限制(最多选择{n}组)"],width:false,container:false,hideDisabled:false,showSubtext:false,showIcon:true,showContent:true,dropupAuto:true,header:false,liveSearch:false,multipleSeparator:", ",iconBase:"glyphicon",tickIcon:"glyphicon-ok"}}(jQuery));

View file

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
<script type="text/javascript" src="bootstrap-select.js"></script>
<link rel="stylesheet" type="text/css" href="bootstrap-select.css">
<!-- 3.0 -->
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<!-- 2.3.2
<link href="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/css/bootstrap-combined.min.css" rel="stylesheet">
<script src="http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.2/js/bootstrap.js"></script>
-->
<script type="text/javascript">
$(window).on('load', function () {
$('.selectpicker').selectpicker({
'selectedText': 'cat'
});
// $('.selectpicker').selectpicker('hide');
});
</script>
</head>
<body>
<label for="id_select">Test label YEag</label>
<select id="id_select" class="selectpicker bla bla bli" multiple data-live-search="true">
<option>cow</option>
<option>bull</option>
<option class="get-class" disabled>ox</option>
<optgroup label="test" data-subtext="another test" data-icon="icon-ok">
<option>ASD</option>
<option selected>Bla</option>
<option>Ble</option>
</optgroup>
</select>
<div class="container">
<form class="form-horizontal" role="form">
<div class="form-group">
<label for="bs3Select" class="col-lg-2 control-label">Test bootstrap 3 form</label>
<div class="col-lg-10">
<select id="bs3Select" class="selectpicker show-tick form-control" multiple data-live-search="true">
<option>cow</option>
<option>bull</option>
<option class="get-class" disabled>ox</option>
<optgroup label="test" data-subtext="another test" data-icon="icon-ok">
<option>ASD</option>
<option selected>Bla</option>
<option>Ble</option>
</optgroup>
</select>
</div>
</div>
<form>
</div>
</body>
</html>

View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,279 @@
# Bootstrap Tree View
---
A simple and elegant solution to displaying hierarchical tree structures (i.e. a Tree View) while levering the best that Twitter Bootstrap has to offer.
![Bootstrap Tree View Default](https://raw.github.com/jondmiles/bootstrap-treeview/master/screenshot/default.PNG)
<!--For full documentation and examples, please visit [Bootstrap Tree View Website](http://www.jondmiles.com/bootstrap-treeview/ "Click to visit Bootstrap Tree View")-->
## Requirements
Where provided these are the actual versions bootstrap-treeview has been tested against. Other versions should work but you use them as your own risk.
- [Bootstrap v3.0.3](http://getbootstrap.com/)
- [jQuery v2.0.3](http://jquery.com/)
Sorry no support planned for Bootstrap 2.
## Usage
A full list of dependencies required for the bootstrap-treeview to function correctly.
<!-- Required Stylesheets -->
<link href="./css/bootstrap.css" rel="stylesheet">
<!-- Required Javascript -->
<script src="./js/jquery.js"></script>
<script src="./js/bootstrap-treeview.js"></script>
The component will bind to any existing DOM element.
<div id="tree"></div>
Basic usage may look something like this.
function getTree() {
// Some logic to retrieve, or generate tree structure
return data;
}
$('#tree').treeview({data: getTree()});
## Data Structure
In order to define the hierarchical structure needed for the tree it's necessary to provide a nested array of JavaScript objects.
Example
var tree = [
{
text: "Parent 1"
nodes: [
{
text: "Child 1"
nodes: [
{
text: "Grandchild 1"
},
{
text: "Grandchild 2"
}
]
},
{
text: "Child 2"
}
]
},
{
text: "Parent 2"
},
{
text: "Parent 3"
},
{
text: "Parent 4"
},
{
text: "Parent 5"
}
];
At the lowest level a tree node is a represented as a simple JavaScript object. Just one required property `text` will build you a tree.
{
text: "Node 1"
}
If you want to do more, here's the full node specification
{
text: "Node 1",
icon: "glyphicon glyphicon-stop",
color: "#000000",
backColor: "#FFFFFF",
href: "#node-1",
tags: ['available'],
nodes: [
{},
...
]
}
## Node Properties
The following properties are defined to allow node level overrides, such as node specific icons, colours and tags.
### text
String. Mandatory
The text value displayed for a given tree node, typically to the right of the nodes icon.
### icon
String. Optional
The icon displayed on a given node, typically to the left of the text.
For simplicity we directly leverage [Bootstraps Glyphicons support](http://getbootstrap.com/components/#glyphicons) and as such you should provide both the base class and individual icon class separated by a space.
By providing the base class you retain full control over the icons used. If you want to use your own then just add your class to this icon field.
### color
String. Optional
The foreground color used on a given node, overrides global color option.
### backColor
String. Optional
The background color used on a given node, overrides global color option.
### href
String. Optional
Used in conjunction with global enableLinks option to specify anchor tag URL on a given node.
### tags
Array of Strings. Optional
Used in conjunction with global showTags option to add additional information to the right of each node; using [Bootstrap Badges](http://getbootstrap.com/components/#badges)
### Extendible
You can extend the node object by adding any number of additional key value pairs that you require for your application. Remember this is the object which will be passed around during selection events.
## Options
### data
Array of Objects. No default, expects data
This is the core data to be displayed by the tree view.
### backColor
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
Sets the default background color used by all nodes, except when overridden on a per node basis in data.
### borderColor
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
Sets the border color for the component; set showBorder to false if you don't want a visible border.
### collapseIcon
String, class name(s). Default: "glyphicon glyphicon-minus" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
Sets the icon to be used on a collapsible tree node.
### color
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: inherits from Bootstrap.css.
Sets the default foreground color used by all nodes, except when overridden on a per node basis in data.
### enableLinks
Boolean. Default: false
Whether or not to present node text as a hyperlink. The href value of which must be provided in the data structure on a per node basis.
### expandIcon
String, class name(s). Default: "glyphicon glyphicon-plus" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
Sets the icon to be used on an expandable tree node.
### highlightSelected
Boolean. Default: true
Whether or not to highlight the selected node.
### onhoverColor
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#F5F5F5'.
Sets the default background color activated when the users cursor hovers over a node.
### levels
Integer. Default: 2
Sets the number of hierarchical levels deep the tree will be expanded to by default.
### nodeIcon
String, class name(s). Default: "glyphicon glyphicon-stop" as defined by [Bootstrap Glyphicons](http://getbootstrap.com/components/#glyphicons)
Sets the default icon to be used on all nodes, except when overridden on a per node basis in data.
### selectedColor
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#FFFFFF'.
Sets the foreground color of the selected node.
### selectedBackColor
String, [any legal color value](http://www.w3schools.com/cssref/css_colors_legal.asp). Default: '#FFFFFF'.
Sets the background color of the selected node.
### showBorder
Boolean. Default: true
Whether or not to display a border around nodes.
### showTags
Boolean. Default: false
Whether or not to display tags to the right of each node. The values of which must be provided in the data structure on a per node basis.
## Methods
### remove
Removes the tree view component. Removing attached events, internal attached objects, and added HTML elements.
$('#tree').treeview('remove');
## Events
### nodeSelected
Fired when a user selects a node. You can bind to it using either the callback handler or the standard jQuery .on method
Example using options callback handler:
var options = {
onNodeSelected: function(event, node) {
// Your logic goes here
}
}
$('#tree').treeview(options);
and using jQuery .on method
$('#tree').on('nodeSelected', function(event, node) {
// Your logic goes here
});
## Copyright and Licensing
Copyright 2013 Jonathan Miles
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at <http://www.apache.org/licenses/LICENSE-2.0>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1,29 @@
/**
* Module dependencies.
*/
var express = require('express');
var http = require('http');
var path = require('path');
var app = express();
// all environments
app.set('port', process.env.PORT || 3000);
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.json());
app.use(express.urlencoded());
app.use(express.methodOverride());
app.use(express.static(path.join(__dirname, '/public')));
app.use(express.static(path.join(__dirname, '/tests')));
// development only
if ('development' == app.get('env')) {
app.use(express.errorHandler());
}
http.createServer(app).listen(app.get('port'), function(){
console.log('Express server listening on port ' + app.get('port'));
});

View file

@ -0,0 +1,26 @@
{
"name": "bootstrap-treeview",
"version": "1.0.1",
"homepage": "https://github.com/jonmiles/bootstrap-treeview",
"description": "Tree View for Twitter Bootstrap",
"main": [ "dist/bootstrap-treeview.min.js", "dist/bootstrap-treeview.min.css" ],
"keywords": [
"Twitter",
"Bootstrap",
"Tree",
"TreeView",
"Navigation"
],
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"dependencies": {
"bootstrap": "~3.1.1",
"jquery": "~2.0.3"
},
"devDependencies": {}
}

View file

@ -0,0 +1 @@
.list-group-item{cursor:pointer}span.indent{margin-left:10px;margin-right:10px}span.icon{margin-right:5px}

View file

@ -0,0 +1,35 @@
/* =========================================================
* bootstrap-treeview.css v1.0.0
* =========================================================
* Copyright 2013 Jonathan Miles
* Project URL : http://www.jondmiles.com/bootstrap-treeview
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
.list-group-item {
cursor: pointer;
}
/*.list-group-item:hover {
background-color: #f5f5f5;
}*/
span.indent {
margin-left: 10px;
margin-right: 10px;
}
span.icon {
margin-right: 5px;
}

View file

@ -0,0 +1,59 @@
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Tree View</title>
<link href="./bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
<link href="./css/bootstrap-treeview.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h1>Bootstrap Tree View - DOM Tree</h1>
<br/>
<div class="row">
<div class="col-sm-12">
<label for="treeview"></label>
<div id="treeview"/>
</div>
</div>
</div>
<script src="./bower_components/jquery/jquery.js"></script>
<script src="./js/bootstrap-treeview.js"></script>
<script type="text/javascript">
function buildDomTree() {
var data = [];
function walk(nodes, data) {
if (!nodes) { return; }
$.each(nodes, function (id, node) {
var obj = {
id: id,
text: node.nodeName + " - " + (node.innerText ? node.innerText : ''),
tags: [node.childElementCount > 0 ? node.childElementCount + ' child elements' : '']
};
if (node.childElementCount > 0) {
obj.nodes = [];
walk(node.children, obj.nodes);
}
data.push(obj);
});
}
walk($('html')[0].children, data);
return data;
}
$(function() {
var options = {
bootstrap2: false,
showTags: true,
levels: 5,
data: buildDomTree()
};
$('#treeview').treeview(options);
});
</script>
</body>

View file

@ -0,0 +1,333 @@
<!DOCTYPE html>
<html>
<head>
<title>Bootstrap Tree View</title>
<link href="./bower_components/bootstrap/dist/css/bootstrap.css" rel="stylesheet">
<!-- <link href="./css/bootstrap-treeview.css" rel="stylesheet"> -->
</head>
<body>
<div class="container">
<h1>Bootstrap Tree View</h1>
<br/>
<div class="row">
<div class="col-sm-4">
<h2>Default</h2>
<div id="treeview1" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Collapsed</h2>
<div id="treeview2" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Expanded</h2>
<div id="treeview3" class="test"></div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<h2>Blue Theme</h2>
<div id="treeview4" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Custom Icons</h2>
<div id="treeview5" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Tags as Badges</h2>
<div id="treeview6" class="test"></div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<h2>Without Border</h2>
<div id="treeview7" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Colourful</h2>
<div id="treeview8" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Node Overrides</h2>
<div id="treeview9" class="test"></div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<h2>Link enabled, or</h2>
<div id="treeview10" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Events</h2>
<div id="treeview11" class="test"></div>
</div>
<div class="col-sm-4">
<h2>Output</h2>
<div id="event_output"></div>
</div>
</div>
<div class="row">
<div class="col-sm-4">
<h2>JSON Data</h2>
<div id="treeview12" class="test"></div>
</div>
<div class="col-sm-4">
<h2></h2>
<div id="treeview13" class="test"></div>
</div>
<div class="col-sm-4">
<h2></h2>
<div id="treeview14"></div>
</div>
</div>
<br/>
<br/>
<br/>
<br/>
</div>
<script src="./bower_components/jquery/jquery.js"></script>
<script src="./js/bootstrap-treeview.js"></script>
<script type="text/javascript">
$(function() {
var defaultData = [
{
text: 'Parent 1',
href: '#parent1',
tags: ['4'],
nodes: [
{
text: 'Child 1',
href: '#child1',
tags: ['2'],
nodes: [
{
text: 'Grandchild 1',
href: '#grandchild1',
tags: ['0']
},
{
text: 'Grandchild 2',
href: '#grandchild2',
tags: ['0']
}
]
},
{
text: 'Child 2',
href: '#child2',
tags: ['0']
}
]
},
{
text: 'Parent 2',
href: '#parent2',
tags: ['0']
},
{
text: 'Parent 3',
href: '#parent3',
tags: ['0']
},
{
text: 'Parent 4',
href: '#parent4',
tags: ['0']
},
{
text: 'Parent 5',
href: '#parent5' ,
tags: ['0']
}
];
var alternateData = [
{
text: 'Parent 1',
tags: ['2'],
nodes: [
{
text: 'Child 1',
tags: ['3'],
nodes: [
{
text: 'Grandchild 1',
tags: ['6']
},
{
text: 'Grandchild 2',
tags: ['3']
}
]
},
{
text: 'Child 2',
tags: ['3']
}
]
},
{
text: 'Parent 2',
tags: ['7']
},
{
text: 'Parent 3',
icon: 'glyphicon glyphicon-earphone',
href: '#demo',
tags: ['11']
},
{
text: 'Parent 4',
icon: 'glyphicon glyphicon-cloud-download',
href: '/demo.html',
tags: ['19'],
selected: true
},
{
text: 'Parent 5',
icon: 'glyphicon glyphicon-certificate',
color: 'pink',
backColor: 'red',
href: 'http://www.tesco.com',
tags: ['available','0']
}
];
var json = '[' +
'{' +
'"text": "Parent 1",' +
'"nodes": [' +
'{' +
'"text": "Child 1",' +
'"nodes": [' +
'{' +
'"text": "Grandchild 1"' +
'},' +
'{' +
'"text": "Grandchild 2"' +
'}' +
']' +
'},' +
'{' +
'"text": "Child 2"' +
'}' +
']' +
'},' +
'{' +
'"text": "Parent 2"' +
'},' +
'{' +
'"text": "Parent 3"' +
'},' +
'{' +
'"text": "Parent 4"' +
'},' +
'{' +
'"text": "Parent 5"' +
'}' +
']';
$('#treeview1').treeview({
data: defaultData
});
$('#treeview2').treeview({
levels: 1,
data: defaultData
});
$('#treeview3').treeview({
levels: 99,
data: defaultData
});
$('#treeview4').treeview({
color: "#428bca",
data: defaultData
});
$('#treeview5').treeview({
color: "#428bca",
expandIcon: 'glyphicon glyphicon-chevron-right',
collapseIcon: 'glyphicon glyphicon-chevron-down',
nodeIcon: 'glyphicon glyphicon-bookmark',
data: defaultData
});
$('#treeview6').treeview({
color: "#428bca",
expandIcon: "glyphicon glyphicon-stop",
collapseIcon: "glyphicon glyphicon-unchecked",
nodeIcon: "glyphicon glyphicon-user",
showTags: true,
data: defaultData
});
$('#treeview7').treeview({
color: "#428bca",
showBorder: false,
data: defaultData
});
$('#treeview8').treeview({
expandIcon: "glyphicon glyphicon-stop",
collapseIcon: "glyphicon glyphicon-unchecked",
nodeIcon: "glyphicon glyphicon-user",
color: "yellow",
backColor: "purple",
onhoverColor: "orange",
borderColor: "red",
showBorder: false,
showTags: true,
highlightSelected: true,
selectedColor: "yellow",
selectedBackColor: "darkorange",
data: defaultData
});
$('#treeview9').treeview({
expandIcon: "glyphicon glyphicon-stop",
collapseIcon: "glyphicon glyphicon-unchecked",
nodeIcon: "glyphicon glyphicon-user",
color: "yellow",
backColor: "purple",
onhoverColor: "orange",
borderColor: "red",
showBorder: false,
showTags: true,
highlightSelected: true,
selectedColor: "yellow",
selectedBackColor: "darkorange",
data: alternateData
});
$('#treeview10').treeview({
color: "#428bca",
enableLinks: true,
data: defaultData
});
$('#treeview11').treeview({
color: "#428bca",
data: defaultData,
onNodeSelected: function(event, node) {
$('#event_output').prepend('<p>You clicked ' + node.text + '</p>');
}
});
// $('#treeview11').on('nodeSelected', function (event, node) {
// $('#event_output').prepend('<p>You clicked ' + node.text + '</p>');
// });
$('#treeview12').treeview({
data: json
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,444 @@
/* =========================================================
* bootstrap-treeview.js v1.0.0
* =========================================================
* Copyright 2013 Jonathan Miles
* Project URL : http://www.jondmiles.com/bootstrap-treeview
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
;(function($, window, document, undefined) {
/*global jQuery, console*/
'use strict';
var pluginName = 'treeview';
var Tree = function(element, options) {
this.$element = $(element);
this._element = element;
this._elementId = this._element.id;
this._styleId = this._elementId + '-style';
this.tree = [];
this.nodes = [];
this.selectedNode = {};
this._init(options);
};
Tree.defaults = {
injectStyle: true,
levels: 2,
expandIcon: 'glyphicon glyphicon-plus',
collapseIcon: 'glyphicon glyphicon-minus',
nodeIcon: 'glyphicon glyphicon-stop',
color: undefined, // '#000000',
backColor: undefined, // '#FFFFFF',
borderColor: undefined, // '#dddddd',
onhoverColor: '#F5F5F5',
selectedColor: '#FFFFFF',
selectedBackColor: '#428bca',
enableLinks: false,
highlightSelected: true,
showBorder: true,
showTags: false,
// Event handler for when a node is selected
onNodeSelected: undefined
};
Tree.prototype = {
remove: function() {
this._destroy();
$.removeData(this, 'plugin_' + pluginName);
$('#' + this._styleId).remove();
},
_destroy: function() {
if (this.initialized) {
this.$wrapper.remove();
this.$wrapper = null;
// Switch off events
this._unsubscribeEvents();
}
// Reset initialized flag
this.initialized = false;
},
_init: function(options) {
if (options.data) {
if (typeof options.data === 'string') {
options.data = $.parseJSON(options.data);
}
this.tree = $.extend(true, [], options.data);
delete options.data;
}
this.options = $.extend({}, Tree.defaults, options);
this._setInitialLevels(this.tree, 0);
this._destroy();
this._subscribeEvents();
this._render();
},
_unsubscribeEvents: function() {
this.$element.off('click');
},
_subscribeEvents: function() {
this._unsubscribeEvents();
this.$element.on('click', $.proxy(this._clickHandler, this));
if (typeof (this.options.onNodeSelected) === 'function') {
this.$element.on('nodeSelected', this.options.onNodeSelected);
}
},
_clickHandler: function(event) {
if (!this.options.enableLinks) { event.preventDefault(); }
var target = $(event.target),
classList = target.attr('class') ? target.attr('class').split(' ') : [],
node = this._findNode(target);
if ((classList.indexOf('click-expand') != -1) ||
(classList.indexOf('click-collapse') != -1)) {
// Expand or collapse node by toggling child node visibility
this._toggleNodes(node);
this._render();
}
else if (node) {
this._setSelectedNode(node);
}
},
// Looks up the DOM for the closest parent list item to retrieve the
// data attribute nodeid, which is used to lookup the node in the flattened structure.
_findNode: function(target) {
var nodeId = target.closest('li.list-group-item').attr('data-nodeid'),
node = this.nodes[nodeId];
if (!node) {
console.log('Error: node does not exist');
}
return node;
},
// Actually triggers the nodeSelected event
_triggerNodeSelectedEvent: function(node) {
this.$element.trigger('nodeSelected', [$.extend(true, {}, node)]);
},
// Handles selecting and unselecting of nodes,
// as well as determining whether or not to trigger the nodeSelected event
_setSelectedNode: function(node) {
if (!node) { return; }
if (node === this.selectedNode) {
this.selectedNode = {};
}
else {
this._triggerNodeSelectedEvent(this.selectedNode = node);
}
this._render();
},
// On initialization recurses the entire tree structure
// setting expanded / collapsed states based on initial levels
_setInitialLevels: function(nodes, level) {
if (!nodes) { return; }
level += 1;
var self = this;
$.each(nodes, function addNodes(id, node) {
if (level >= self.options.levels) {
self._toggleNodes(node);
}
// Need to traverse both nodes and _nodes to ensure
// all levels collapsed beyond levels
var nodes = node.nodes ? node.nodes : node._nodes ? node._nodes : undefined;
if (nodes) {
return self._setInitialLevels(nodes, level);
}
});
},
// Toggle renaming nodes -> _nodes, _nodes -> nodes
// to simulate expanding or collapsing a node.
_toggleNodes: function(node) {
if (!node.nodes && !node._nodes) {
return;
}
if (node.nodes) {
node._nodes = node.nodes;
delete node.nodes;
}
else {
node.nodes = node._nodes;
delete node._nodes;
}
},
_render: function() {
var self = this;
if (!self.initialized) {
// Setup first time only components
self.$element.addClass(pluginName);
self.$wrapper = $(self._template.list);
self._injectStyle();
self.initialized = true;
}
self.$element.empty().append(self.$wrapper.empty());
// Build tree
self.nodes = [];
self._buildTree(self.tree, 0);
},
// Starting from the root node, and recursing down the
// structure we build the tree one node at a time
_buildTree: function(nodes, level) {
if (!nodes) { return; }
level += 1;
var self = this;
$.each(nodes, function addNodes(id, node) {
node.nodeId = self.nodes.length;
self.nodes.push(node);
var treeItem = $(self._template.item)
.addClass('node-' + self._elementId)
.addClass((node === self.selectedNode) ? 'node-selected' : '')
.attr('data-nodeid', node.nodeId)
.attr('style', self._buildStyleOverride(node));
// Add indent/spacer to mimic tree structure
for (var i = 0; i < (level - 1); i++) {
treeItem.append(self._template.indent);
}
// Add expand, collapse or empty spacer icons
// to facilitate tree structure navigation
if (node._nodes) {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('click-expand')
.addClass(self.options.expandIcon))
);
}
else if (node.nodes) {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('click-collapse')
.addClass(self.options.collapseIcon))
);
}
else {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('glyphicon'))
);
}
// Add node icon
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass(node.icon ? node.icon : self.options.nodeIcon))
);
// Add text
if (self.options.enableLinks) {
// Add hyperlink
treeItem
.append($(self._template.link)
.attr('href', node.href)
.append(node.text)
);
}
else {
// otherwise just text
treeItem
.append(node.text);
}
// Add tags as badges
if (self.options.showTags && node.tags) {
$.each(node.tags, function addTag(id, tag) {
treeItem
.append($(self._template.badge)
.append(tag)
);
});
}
// Add item to the tree
self.$wrapper.append(treeItem);
// Recursively add child ndoes
if (node.nodes) {
return self._buildTree(node.nodes, level);
}
});
},
// Define any node level style override for
// 1. selectedNode
// 2. node|data assigned color overrides
_buildStyleOverride: function(node) {
var style = '';
if (this.options.highlightSelected && (node === this.selectedNode)) {
style += 'color:' + this.options.selectedColor + ';';
}
else if (node.color) {
style += 'color:' + node.color + ';';
}
if (this.options.highlightSelected && (node === this.selectedNode)) {
style += 'background-color:' + this.options.selectedBackColor + ';';
}
else if (node.backColor) {
style += 'background-color:' + node.backColor + ';';
}
return style;
},
// Add inline style into head
_injectStyle: function() {
if (this.options.injectStyle && !document.getElementById(this._styleId)) {
$('<style type="text/css" id="' + this._styleId + '"> ' + this._buildStyle() + ' </style>').appendTo('head');
}
},
// Construct trees style based on user options
_buildStyle: function() {
var style = '.node-' + this._elementId + '{';
if (this.options.color) {
style += 'color:' + this.options.color + ';';
}
if (this.options.backColor) {
style += 'background-color:' + this.options.backColor + ';';
}
if (!this.options.showBorder) {
style += 'border:none;';
}
else if (this.options.borderColor) {
style += 'border:1px solid ' + this.options.borderColor + ';';
}
style += '}';
if (this.options.onhoverColor) {
style += '.node-' + this._elementId + ':hover{' +
'background-color:' + this.options.onhoverColor + ';' +
'}';
}
return this._css + style;
},
_template: {
list: '<ul class="list-group"></ul>',
item: '<li class="list-group-item"></li>',
indent: '<span class="indent"></span>',
iconWrapper: '<span class="icon"></span>',
icon: '<i></i>',
link: '<a href="#" style="color:inherit;"></a>',
badge: '<span class="badge"></span>'
},
_css: '.list-group-item{cursor:pointer;}span.indent{margin-left:10px;margin-right:10px}span.icon{margin-right:5px}'
// _css: '.list-group-item{cursor:pointer;}.list-group-item:hover{background-color:#f5f5f5;}span.indent{margin-left:10px;margin-right:10px}span.icon{margin-right:5px}'
};
var logError = function(message) {
if(window.console) {
window.console.error(message);
}
};
// Prevent against multiple instantiations,
// handle updates and method calls
$.fn[pluginName] = function(options, args) {
return this.each(function() {
var self = $.data(this, 'plugin_' + pluginName);
if (typeof options === 'string') {
if (!self) {
logError('Not initialized, can not call method : ' + options);
}
else if (!$.isFunction(self[options]) || options.charAt(0) === '_') {
logError('No such method : ' + options);
}
else {
if (typeof args === 'string') {
args = [args];
}
self[options].apply(self, args);
}
}
else {
if (!self) {
$.data(this, 'plugin_' + pluginName, new Tree(this, $.extend(true, {}, options)));
}
else {
self._init(options);
}
}
});
};
})(jQuery, window, document);

View file

@ -0,0 +1,35 @@
/* =========================================================
* bootstrap-treeview.css v1.0.0
* =========================================================
* Copyright 2013 Jonathan Miles
* Project URL : http://www.jondmiles.com/bootstrap-treeview
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
.list-group-item {
cursor: pointer;
}
/*.list-group-item:hover {
background-color: #f5f5f5;
}*/
span.indent {
margin-left: 10px;
margin-right: 10px;
}
span.icon {
margin-right: 5px;
}

View file

@ -0,0 +1,444 @@
/* =========================================================
* bootstrap-treeview.js v1.0.0
* =========================================================
* Copyright 2013 Jonathan Miles
* Project URL : http://www.jondmiles.com/bootstrap-treeview
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* ========================================================= */
;(function($, window, document, undefined) {
/*global jQuery, console*/
'use strict';
var pluginName = 'treeview';
var Tree = function(element, options) {
this.$element = $(element);
this._element = element;
this._elementId = this._element.id;
this._styleId = this._elementId + '-style';
this.tree = [];
this.nodes = [];
this.selectedNode = {};
this._init(options);
};
Tree.defaults = {
injectStyle: true,
levels: 2,
expandIcon: 'glyphicon glyphicon-plus',
collapseIcon: 'glyphicon glyphicon-minus',
nodeIcon: 'glyphicon glyphicon-stop',
color: undefined, // '#000000',
backColor: undefined, // '#FFFFFF',
borderColor: undefined, // '#dddddd',
onhoverColor: '#F5F5F5',
selectedColor: '#FFFFFF',
selectedBackColor: '#428bca',
enableLinks: false,
highlightSelected: true,
showBorder: true,
showTags: false,
// Event handler for when a node is selected
onNodeSelected: undefined
};
Tree.prototype = {
remove: function() {
this._destroy();
$.removeData(this, 'plugin_' + pluginName);
$('#' + this._styleId).remove();
},
_destroy: function() {
if (this.initialized) {
this.$wrapper.remove();
this.$wrapper = null;
// Switch off events
this._unsubscribeEvents();
}
// Reset initialized flag
this.initialized = false;
},
_init: function(options) {
if (options.data) {
if (typeof options.data === 'string') {
options.data = $.parseJSON(options.data);
}
this.tree = $.extend(true, [], options.data);
delete options.data;
}
this.options = $.extend({}, Tree.defaults, options);
this._setInitialLevels(this.tree, 0);
this._destroy();
this._subscribeEvents();
this._render();
},
_unsubscribeEvents: function() {
this.$element.off('click');
},
_subscribeEvents: function() {
this._unsubscribeEvents();
this.$element.on('click', $.proxy(this._clickHandler, this));
if (typeof (this.options.onNodeSelected) === 'function') {
this.$element.on('nodeSelected', this.options.onNodeSelected);
}
},
_clickHandler: function(event) {
if (!this.options.enableLinks) { event.preventDefault(); }
var target = $(event.target),
classList = target.attr('class') ? target.attr('class').split(' ') : [],
node = this._findNode(target);
if ((classList.indexOf('click-expand') != -1) ||
(classList.indexOf('click-collapse') != -1)) {
// Expand or collapse node by toggling child node visibility
this._toggleNodes(node);
this._render();
}
else if (node) {
this._setSelectedNode(node);
}
},
// Looks up the DOM for the closest parent list item to retrieve the
// data attribute nodeid, which is used to lookup the node in the flattened structure.
_findNode: function(target) {
var nodeId = target.closest('li.list-group-item').attr('data-nodeid'),
node = this.nodes[nodeId];
if (!node) {
console.log('Error: node does not exist');
}
return node;
},
// Actually triggers the nodeSelected event
_triggerNodeSelectedEvent: function(node) {
this.$element.trigger('nodeSelected', [$.extend(true, {}, node)]);
},
// Handles selecting and unselecting of nodes,
// as well as determining whether or not to trigger the nodeSelected event
_setSelectedNode: function(node) {
if (!node) { return; }
if (node === this.selectedNode) {
this.selectedNode = {};
}
else {
this._triggerNodeSelectedEvent(this.selectedNode = node);
}
this._render();
},
// On initialization recurses the entire tree structure
// setting expanded / collapsed states based on initial levels
_setInitialLevels: function(nodes, level) {
if (!nodes) { return; }
level += 1;
var self = this;
$.each(nodes, function addNodes(id, node) {
if (level >= self.options.levels) {
self._toggleNodes(node);
}
// Need to traverse both nodes and _nodes to ensure
// all levels collapsed beyond levels
var nodes = node.nodes ? node.nodes : node._nodes ? node._nodes : undefined;
if (nodes) {
return self._setInitialLevels(nodes, level);
}
});
},
// Toggle renaming nodes -> _nodes, _nodes -> nodes
// to simulate expanding or collapsing a node.
_toggleNodes: function(node) {
if (!node.nodes && !node._nodes) {
return;
}
if (node.nodes) {
node._nodes = node.nodes;
delete node.nodes;
}
else {
node.nodes = node._nodes;
delete node._nodes;
}
},
_render: function() {
var self = this;
if (!self.initialized) {
// Setup first time only components
self.$element.addClass(pluginName);
self.$wrapper = $(self._template.list);
self._injectStyle();
self.initialized = true;
}
self.$element.empty().append(self.$wrapper.empty());
// Build tree
self.nodes = [];
self._buildTree(self.tree, 0);
},
// Starting from the root node, and recursing down the
// structure we build the tree one node at a time
_buildTree: function(nodes, level) {
if (!nodes) { return; }
level += 1;
var self = this;
$.each(nodes, function addNodes(id, node) {
node.nodeId = self.nodes.length;
self.nodes.push(node);
var treeItem = $(self._template.item)
.addClass('node-' + self._elementId)
.addClass((node === self.selectedNode) ? 'node-selected' : '')
.attr('data-nodeid', node.nodeId)
.attr('style', self._buildStyleOverride(node));
// Add indent/spacer to mimic tree structure
for (var i = 0; i < (level - 1); i++) {
treeItem.append(self._template.indent);
}
// Add expand, collapse or empty spacer icons
// to facilitate tree structure navigation
if (node._nodes) {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('click-expand')
.addClass(self.options.expandIcon))
);
}
else if (node.nodes) {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('click-collapse')
.addClass(self.options.collapseIcon))
);
}
else {
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass('glyphicon'))
);
}
// Add node icon
treeItem
.append($(self._template.iconWrapper)
.append($(self._template.icon)
.addClass(node.icon ? node.icon : self.options.nodeIcon))
);
// Add text
if (self.options.enableLinks) {
// Add hyperlink
treeItem
.append($(self._template.link)
.attr('href', node.href)
.append(node.text)
);
}
else {
// otherwise just text
treeItem
.append(node.text);
}
// Add tags as badges
if (self.options.showTags && node.tags) {
$.each(node.tags, function addTag(id, tag) {
treeItem
.append($(self._template.badge)
.append(tag)
);
});
}
// Add item to the tree
self.$wrapper.append(treeItem);
// Recursively add child ndoes
if (node.nodes) {
return self._buildTree(node.nodes, level);
}
});
},
// Define any node level style override for
// 1. selectedNode
// 2. node|data assigned color overrides
_buildStyleOverride: function(node) {
var style = '';
if (this.options.highlightSelected && (node === this.selectedNode)) {
style += 'color:' + this.options.selectedColor + ';';
}
else if (node.color) {
style += 'color:' + node.color + ';';
}
if (this.options.highlightSelected && (node === this.selectedNode)) {
style += 'background-color:' + this.options.selectedBackColor + ';';
}
else if (node.backColor) {
style += 'background-color:' + node.backColor + ';';
}
return style;
},
// Add inline style into head
_injectStyle: function() {
if (this.options.injectStyle && !document.getElementById(this._styleId)) {
$('<style type="text/css" id="' + this._styleId + '"> ' + this._buildStyle() + ' </style>').appendTo('head');
}
},
// Construct trees style based on user options
_buildStyle: function() {
var style = '.node-' + this._elementId + '{';
if (this.options.color) {
style += 'color:' + this.options.color + ';';
}
if (this.options.backColor) {
style += 'background-color:' + this.options.backColor + ';';
}
if (!this.options.showBorder) {
style += 'border:none;';
}
else if (this.options.borderColor) {
style += 'border:1px solid ' + this.options.borderColor + ';';
}
style += '}';
if (this.options.onhoverColor) {
style += '.node-' + this._elementId + ':hover{' +
'background-color:' + this.options.onhoverColor + ';' +
'}';
}
return this._css + style;
},
_template: {
list: '<ul class="list-group"></ul>',
item: '<li class="list-group-item"></li>',
indent: '<span class="indent"></span>',
iconWrapper: '<span class="icon"></span>',
icon: '<i></i>',
link: '<a href="#" style="color:inherit;"></a>',
badge: '<span class="badge"></span>'
},
_css: '.list-group-item{cursor:pointer;}span.indent{margin-left:10px;margin-right:10px}span.icon{margin-right:5px}'
// _css: '.list-group-item{cursor:pointer;}.list-group-item:hover{background-color:#f5f5f5;}span.indent{margin-left:10px;margin-right:10px}span.icon{margin-right:5px}'
};
var logError = function(message) {
if(window.console) {
window.console.error(message);
}
};
// Prevent against multiple instantiations,
// handle updates and method calls
$.fn[pluginName] = function(options, args) {
return this.each(function() {
var self = $.data(this, 'plugin_' + pluginName);
if (typeof options === 'string') {
if (!self) {
logError('Not initialized, can not call method : ' + options);
}
else if (!$.isFunction(self[options]) || options.charAt(0) === '_') {
logError('No such method : ' + options);
}
else {
if (typeof args === 'string') {
args = [args];
}
self[options].apply(self, args);
}
}
else {
if (!self) {
$.data(this, 'plugin_' + pluginName, new Tree(this, $.extend(true, {}, options)));
}
else {
self._init(options);
}
}
});
};
})(jQuery, window, document);

View file

@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2011-2015 Twitter, Inc
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

Some files were not shown because too many files have changed in this diff Show more