diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2af7cef --- /dev/null +++ b/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/.mvn/wrapper/maven-wrapper.jar b/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000..5fd4d50 Binary files /dev/null and b/.mvn/wrapper/maven-wrapper.jar differ diff --git a/.mvn/wrapper/maven-wrapper.properties b/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c954cec --- /dev/null +++ b/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1 @@ +distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.9/apache-maven-3.3.9-bin.zip diff --git a/mvnw b/mvnw new file mode 100644 index 0000000..a1ba1bf --- /dev/null +++ b/mvnw @@ -0,0 +1,233 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven2 Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # + # Look for the Apple JDKs first to preserve the existing behaviour, and then look + # for the new JDKs provided by Oracle. + # + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Versions/CurrentJDK/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L /System/Library/Java/JavaVirtualMachines/CurrentJDK ] ; then + # + # Apple JDKs + # + export JAVA_HOME=/System/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -L "/Library/Java/JavaVirtualMachines/CurrentJDK" ] ; then + # + # Oracle JDKs + # + export JAVA_HOME=/Library/Java/JavaVirtualMachines/CurrentJDK/Contents/Home + fi + + if [ -z "$JAVA_HOME" ] && [ -x "/usr/libexec/java_home" ]; then + # + # Apple JDKs + # + export JAVA_HOME=`/usr/libexec/java_home` + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Migwn, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" + # TODO classpath? +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + local basedir=$(pwd) + local wdir=$(pwd) + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + wdir=$(cd "$wdir/.."; pwd) + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-$(find_maven_basedir)} +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} "$@" diff --git a/mvnw.cmd b/mvnw.cmd new file mode 100644 index 0000000..2b934e8 --- /dev/null +++ b/mvnw.cmd @@ -0,0 +1,145 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM http://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven2 Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM enable echoing my setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +set MAVEN_CMD_LINE_ARGS=%* + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" + +set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar"" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS% +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..8df1805 --- /dev/null +++ b/pom.xml @@ -0,0 +1,86 @@ + + + 4.0.0 + + net.crunchdroid + crunchdroid-contact-form + 0.0.1-SNAPSHOT + jar + + crunchdroid-contact-form + Demo project for Spring Boot + + + org.springframework.boot + spring-boot-starter-parent + 1.4.1.RELEASE + + + + UTF-8 + UTF-8 + 1.8 + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-mail + + + org.springframework.boot + spring-boot-devtools + + + org.thymeleaf + thymeleaf + 3.0.0.RELEASE + + + org.thymeleaf + thymeleaf-spring4 + 3.0.0.RELEASE + + + org.webjars + bootstrap + 3.3.7 + + + org.webjars + font-awesome + 4.6.3 + + + org.webjars + jquery + 1.11.3 + + + org.webjars + webjars-locator + 0.30 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + true + + + + + + + + diff --git a/src/main/java/net/crunchdroid/BootstrapApp.java b/src/main/java/net/crunchdroid/BootstrapApp.java new file mode 100644 index 0000000..58e8d59 --- /dev/null +++ b/src/main/java/net/crunchdroid/BootstrapApp.java @@ -0,0 +1,12 @@ +package net.crunchdroid; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BootstrapApp { + + public static void main(String[] args) { + SpringApplication.run(BootstrapApp.class, args); + } +} diff --git a/src/main/java/net/crunchdroid/Contact.java b/src/main/java/net/crunchdroid/Contact.java new file mode 100644 index 0000000..6829e7b --- /dev/null +++ b/src/main/java/net/crunchdroid/Contact.java @@ -0,0 +1,75 @@ +package net.crunchdroid; + +import org.hibernate.validator.constraints.NotBlank; + +import javax.validation.constraints.Pattern; + +/** + * @author CrunchDroid + */ +public class Contact { + + @NotBlank +// @Pattern(regexp = "[a-zA-Z]", message = "This field must contain only letters") + @Pattern(regexp = "[\\p{L} '-]+", message = "{net.crunchdroid.constraints.Name.message}") + private String name; + + @NotBlank +// @Email + @Pattern(regexp = "(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21-\\x5a\\x53-\\x7f]|\\\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])+)\\])", + message = "{net.crunchdroid.constraints.Email.message}") + private String email; + + @NotBlank + @Pattern(regexp = "\\+(?:[0-9] ?){6,14}[0-9]", message = "{net.crunchdroid.constraints.Phone.message}") + private String phone; + + @NotBlank + private String subject; + + @NotBlank + private String message; + + public Contact() { + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } + + public String getPhone() { + return phone; + } + + public void setPhone(String phone) { + this.phone = phone; + } + + public String getSubject() { + return subject; + } + + public void setSubject(String subject) { + this.subject = subject; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/net/crunchdroid/MailComponent.java b/src/main/java/net/crunchdroid/MailComponent.java new file mode 100644 index 0000000..8bb8433 --- /dev/null +++ b/src/main/java/net/crunchdroid/MailComponent.java @@ -0,0 +1,65 @@ +package net.crunchdroid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.mail.MailException; +import org.springframework.mail.MailSender; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.stereotype.Component; +import org.thymeleaf.TemplateEngine; +import org.thymeleaf.context.Context; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; + +/** + * @author CrunchDroid + */ +@Component +public class MailComponent { + + @Autowired + MailSender mailSender; + + @Autowired + JavaMailSender javaMailSender; + + @Autowired + TemplateEngine templateEngine; + + public boolean sendSimpleMail(Contact contact) { + SimpleMailMessage mailMessage = new SimpleMailMessage(); + mailMessage.setFrom(contact.getEmail()); + mailMessage.setSubject(contact.getSubject()); + mailMessage.setText(contact.getMessage()); + mailMessage.setTo("contact@crunchdroid.net"); + + try { + mailSender.send(mailMessage); + return true; + } catch (MailException e) { + return false; + } + } + + public boolean sendHtmlMail(Contact contact) { + + Context context = new Context(); + context.setVariable("contact", contact); + final String messageHtml = templateEngine.process("email/contact", context); + + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + MimeMessageHelper mailMessage = new MimeMessageHelper(mimeMessage); + try { + mailMessage.setTo("contact@crunchdroid.net"); + mailMessage.setFrom(contact.getEmail()); + mailMessage.setSubject(contact.getSubject()); + mailMessage.setText(messageHtml, true); + javaMailSender.send(mimeMessage); + return true; + } catch (MessagingException | MailException e) { + return false; + } + } +} diff --git a/src/main/java/net/crunchdroid/MailConfig.java b/src/main/java/net/crunchdroid/MailConfig.java new file mode 100644 index 0000000..3457363 --- /dev/null +++ b/src/main/java/net/crunchdroid/MailConfig.java @@ -0,0 +1,29 @@ +package net.crunchdroid; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.JavaMailSenderImpl; + +/** + * @author CrunchDroid + */ +@Configuration +public class MailConfig { + + @Value("${spring.mail.host}") + private String host; + + @Value("${spring.mail.port}") + private int port; + + @Bean + public JavaMailSender javaMailSender() { + JavaMailSenderImpl mailSender = new JavaMailSenderImpl(); + mailSender.setHost(host); + mailSender.setPort(port); + return mailSender; + } + +} diff --git a/src/main/java/net/crunchdroid/OnePageController.java b/src/main/java/net/crunchdroid/OnePageController.java new file mode 100644 index 0000000..33182f5 --- /dev/null +++ b/src/main/java/net/crunchdroid/OnePageController.java @@ -0,0 +1,46 @@ +package net.crunchdroid; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.Model; +import org.springframework.validation.BindingResult; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.servlet.mvc.support.RedirectAttributes; + +/** + * @author CrunchDroid + */ +@Controller +public class OnePageController { + + @Autowired + MailComponent mail; + + @GetMapping("/") + public String index(@ModelAttribute Contact contact) { + return "index"; + } + + @PostMapping("/") + public String processContact(@Validated Contact contact, RedirectAttributes redirectAttributes, Model model, BindingResult bindingResult) { + + if (bindingResult.hasErrors()) + return "index"; + + if (!mail.sendHtmlMail(contact)) { + model.addAttribute("success", false); + model.addAttribute("message", "An unexpected error occurred thank you to repeat your request later"); + return "index"; + } + + redirectAttributes.addFlashAttribute("success", true); + redirectAttributes.addFlashAttribute("message", "Your message has been sent"); + + return "redirect:/"; + } + + +} diff --git a/src/main/java/net/crunchdroid/ThymeleafWebMvcConfig.java b/src/main/java/net/crunchdroid/ThymeleafWebMvcConfig.java new file mode 100644 index 0000000..c9001e4 --- /dev/null +++ b/src/main/java/net/crunchdroid/ThymeleafWebMvcConfig.java @@ -0,0 +1,45 @@ +package net.crunchdroid; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.ViewResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; +import org.thymeleaf.ITemplateEngine; +import org.thymeleaf.spring4.SpringTemplateEngine; +import org.thymeleaf.spring4.templateresolver.SpringResourceTemplateResolver; +import org.thymeleaf.spring4.view.ThymeleafViewResolver; +import org.thymeleaf.templatemode.TemplateMode; +import org.thymeleaf.templateresolver.ITemplateResolver; + +/** + * @author CrunchDroid + */ +@Configuration +public class ThymeleafWebMvcConfig extends WebMvcConfigurerAdapter { + + + @Bean + public ViewResolver viewResolver() { + ThymeleafViewResolver viewResolver = new ThymeleafViewResolver(); + viewResolver.setCharacterEncoding("UTF-8"); + viewResolver.setTemplateEngine(templateEngine()); + return viewResolver; + } + + @Bean + public ITemplateEngine templateEngine() { + SpringTemplateEngine templateEngine = new SpringTemplateEngine(); + templateEngine.setTemplateResolver(templateResolver()); + return templateEngine; + } + + private ITemplateResolver templateResolver() { + SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); + templateResolver.setCharacterEncoding("UTF-8"); + templateResolver.setCacheable(false); + templateResolver.setPrefix("classpath:/templates/"); + templateResolver.setSuffix(".html"); + templateResolver.setTemplateMode(TemplateMode.HTML); + return templateResolver; + } +} diff --git a/src/main/resources/ValidationMessages.properties b/src/main/resources/ValidationMessages.properties new file mode 100644 index 0000000..69d2617 --- /dev/null +++ b/src/main/resources/ValidationMessages.properties @@ -0,0 +1,37 @@ + +javax.validation.constraints.AssertFalse.message = must be false +javax.validation.constraints.AssertTrue.message = must be true +javax.validation.constraints.DecimalMax.message = must be less than ${inclusive == true ? 'or equal to ' : ''}{value} +javax.validation.constraints.DecimalMin.message = must be greater than ${inclusive == true ? 'or equal to ' : ''}{value} +javax.validation.constraints.Digits.message = numeric value out of bounds (<{integer} digits>.<{fraction} digits> expected) +javax.validation.constraints.Future.message = must be in the future +javax.validation.constraints.Max.message = must be less than or equal to {value} +javax.validation.constraints.Min.message = must be greater than or equal to {value} +javax.validation.constraints.NotNull.message = may not be null +javax.validation.constraints.Null.message = must be null +javax.validation.constraints.Past.message = must be in the past +javax.validation.constraints.Pattern.message = must match "{regexp}" +javax.validation.constraints.Size.message = size must be between {min} and {max} + +org.hibernate.validator.constraints.CreditCardNumber.message = invalid credit card number +org.hibernate.validator.constraints.EAN.message = invalid {type} barcode +org.hibernate.validator.constraints.Email.message = not a well-formed email address +org.hibernate.validator.constraints.Length.message = length must be between {min} and {max} +org.hibernate.validator.constraints.LuhnCheck.message = The check digit for ${validatedValue} is invalid, Luhn Modulo 10 checksum failed +org.hibernate.validator.constraints.Mod10Check.message = The check digit for ${validatedValue} is invalid, Modulo 10 checksum failed +org.hibernate.validator.constraints.Mod11Check.message = The check digit for ${validatedValue} is invalid, Modulo 11 checksum failed +org.hibernate.validator.constraints.ModCheck.message = The check digit for ${validatedValue} is invalid, ${modType} checksum failed +org.hibernate.validator.constraints.NotBlank.message = This field is required +org.hibernate.validator.constraints.NotEmpty.message = may not be empty +org.hibernate.validator.constraints.ParametersScriptAssert.message = script expression "{script}" didn't evaluate to true +org.hibernate.validator.constraints.Range.message = must be between {min} and {max} +org.hibernate.validator.constraints.SafeHtml.message = may have unsafe html content +org.hibernate.validator.constraints.ScriptAssert.message = script expression "{script}" didn't evaluate to true +org.hibernate.validator.constraints.URL.message = must be a valid URL + +org.hibernate.validator.constraints.br.CNPJ.message = invalid Brazilian corporate taxpayer registry number (CNPJ) +org.hibernate.validator.constraints.br.CPF.message = invalid Brazilian individual taxpayer registry number (CPF) +org.hibernate.validator.constraints.br.TituloEleitoral.message = invalid Brazilian Voter ID card number +net.crunchdroid.constraints.Name.message = This field must contain only letters +net.crunchdroid.constraints.Email.message = Invalid email format +net.crunchdroid.constraints.Phone.message = Invalid phone number \ No newline at end of file diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..9d0f91b --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,3 @@ +spring.mail.default-encoding=UTF-8 +spring.mail.host=127.0.0.1 +spring.mail.port=1025 \ No newline at end of file diff --git a/src/main/resources/static/css/agency.css b/src/main/resources/static/css/agency.css new file mode 100644 index 0000000..1e3a14e --- /dev/null +++ b/src/main/resources/static/css/agency.css @@ -0,0 +1,746 @@ +/*! + * Start Bootstrap - Agency v3.3.7+1 (http://startbootstrap.com/template-overviews/agency) + * Copyright 2013-2016 Start Bootstrap + * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) + */ +body { + overflow-x: hidden; + font-family: "Roboto Slab", "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.text-muted { + color: #777777; +} +.text-primary { + color: #fed136; +} +p { + font-size: 14px; + line-height: 1.75; +} +p.large { + font-size: 16px; +} +a, +a:hover, +a:focus, +a:active, +a.active { + outline: none; +} +a { + color: #fed136; +} +a:hover, +a:focus, +a:active, +a.active { + color: #fec503; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; +} +.img-centered { + margin: 0 auto; +} +.bg-light-gray { + background-color: #eeeeee; +} +.bg-darkest-gray { + background-color: #222222; +} +.btn-primary { + color: white; + background-color: #fed136; + border-color: #fed136; + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; +} +.btn-primary:hover, +.btn-primary:focus, +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + color: white; + background-color: #fec503; + border-color: #f6bf01; +} +.btn-primary:active, +.btn-primary.active, +.open .dropdown-toggle.btn-primary { + background-image: none; +} +.btn-primary.disabled, +.btn-primary[disabled], +fieldset[disabled] .btn-primary, +.btn-primary.disabled:hover, +.btn-primary[disabled]:hover, +fieldset[disabled] .btn-primary:hover, +.btn-primary.disabled:focus, +.btn-primary[disabled]:focus, +fieldset[disabled] .btn-primary:focus, +.btn-primary.disabled:active, +.btn-primary[disabled]:active, +fieldset[disabled] .btn-primary:active, +.btn-primary.disabled.active, +.btn-primary[disabled].active, +fieldset[disabled] .btn-primary.active { + background-color: #fed136; + border-color: #fed136; +} +.btn-primary .badge { + color: #fed136; + background-color: white; +} +.btn-xl { + color: white; + background-color: #fed136; + border-color: #fed136; + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + border-radius: 3px; + font-size: 18px; + padding: 20px 40px; +} +.btn-xl:hover, +.btn-xl:focus, +.btn-xl:active, +.btn-xl.active, +.open .dropdown-toggle.btn-xl { + color: white; + background-color: #fec503; + border-color: #f6bf01; +} +.btn-xl:active, +.btn-xl.active, +.open .dropdown-toggle.btn-xl { + background-image: none; +} +.btn-xl.disabled, +.btn-xl[disabled], +fieldset[disabled] .btn-xl, +.btn-xl.disabled:hover, +.btn-xl[disabled]:hover, +fieldset[disabled] .btn-xl:hover, +.btn-xl.disabled:focus, +.btn-xl[disabled]:focus, +fieldset[disabled] .btn-xl:focus, +.btn-xl.disabled:active, +.btn-xl[disabled]:active, +fieldset[disabled] .btn-xl:active, +.btn-xl.disabled.active, +.btn-xl[disabled].active, +fieldset[disabled] .btn-xl.active { + background-color: #fed136; + border-color: #fed136; +} +.btn-xl .badge { + color: #fed136; + background-color: white; +} +.navbar-custom { + background-color: #222222; + border-color: transparent; +} +.navbar-custom .navbar-brand { + color: #fed136; + font-family: "Kaushan Script", "Helvetica Neue", Helvetica, Arial, cursive; +} +.navbar-custom .navbar-brand:hover, +.navbar-custom .navbar-brand:focus, +.navbar-custom .navbar-brand:active, +.navbar-custom .navbar-brand.active { + color: #fec503; +} +.navbar-custom .navbar-collapse { + border-color: rgba(255, 255, 255, 0.02); +} +.navbar-custom .navbar-toggle { + background-color: #fed136; + border-color: #fed136; + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + color: white; + font-size: 12px; +} +.navbar-custom .navbar-toggle:hover, +.navbar-custom .navbar-toggle:focus { + background-color: #fed136; +} +.navbar-custom .nav li a { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 400; + letter-spacing: 1px; + color: white; +} +.navbar-custom .nav li a:hover, +.navbar-custom .nav li a:focus { + color: #fed136; + outline: none; +} +.navbar-custom .navbar-nav > .active > a { + border-radius: 0; + color: white; + background-color: #fed136; +} +.navbar-custom .navbar-nav > .active > a:hover, +.navbar-custom .navbar-nav > .active > a:focus { + color: white; + background-color: #fec503; +} +@media (min-width: 768px) { + .navbar-custom { + background-color: transparent; + padding: 25px 0; + -webkit-transition: padding 0.3s; + -moz-transition: padding 0.3s; + transition: padding 0.3s; + border: none; + } + .navbar-custom .navbar-brand { + font-size: 2em; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + transition: all 0.3s; + } + .navbar-custom .navbar-nav > .active > a { + border-radius: 3px; + } +} +@media (min-width: 768px) { + .navbar-custom.affix { + background-color: #222222; + padding: 10px 0; + } + .navbar-custom.affix .navbar-brand { + font-size: 1.5em; + } +} +header { + background-image: url('../img/header-bg.jpg'); + background-repeat: no-repeat; + background-attachment: scroll; + background-position: center center; + -webkit-background-size: cover; + -moz-background-size: cover; + background-size: cover; + -o-background-size: cover; + text-align: center; + color: white; +} +header .intro-text { + padding-top: 100px; + padding-bottom: 50px; +} +header .intro-text .intro-lead-in { + font-family: "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: italic; + font-size: 22px; + line-height: 22px; + margin-bottom: 25px; +} +header .intro-text .intro-heading { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + font-size: 50px; + line-height: 50px; + margin-bottom: 25px; +} +@media (min-width: 768px) { + header .intro-text { + padding-top: 300px; + padding-bottom: 200px; + } + header .intro-text .intro-lead-in { + font-family: "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: italic; + font-size: 40px; + line-height: 40px; + margin-bottom: 25px; + } + header .intro-text .intro-heading { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + font-size: 75px; + line-height: 75px; + margin-bottom: 50px; + } +} +section { + padding: 100px 0; +} +section h2.section-heading { + font-size: 40px; + margin-top: 0; + margin-bottom: 15px; +} +section h3.section-subheading { + font-size: 16px; + font-family: "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: none; + font-style: italic; + font-weight: 400; + margin-bottom: 75px; +} +@media (min-width: 768px) { + section { + padding: 150px 0; + } +} +.service-heading { + margin: 15px 0; + text-transform: none; +} +#portfolio .portfolio-item { + margin: 0 0 15px; + right: 0; +} +#portfolio .portfolio-item .portfolio-link { + display: block; + position: relative; + max-width: 400px; + margin: 0 auto; +} +#portfolio .portfolio-item .portfolio-link .portfolio-hover { + background: rgba(254, 209, 54, 0.9); + position: absolute; + width: 100%; + height: 100%; + opacity: 0; + transition: all ease 0.5s; + -webkit-transition: all ease 0.5s; + -moz-transition: all ease 0.5s; +} +#portfolio .portfolio-item .portfolio-link .portfolio-hover:hover { + opacity: 1; +} +#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content { + position: absolute; + width: 100%; + height: 20px; + font-size: 20px; + text-align: center; + top: 50%; + margin-top: -12px; + color: white; +} +#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content i { + margin-top: -12px; +} +#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content h3, +#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content h4 { + margin: 0; +} +#portfolio .portfolio-item .portfolio-caption { + max-width: 400px; + margin: 0 auto; + background-color: white; + text-align: center; + padding: 25px; +} +#portfolio .portfolio-item .portfolio-caption h4 { + text-transform: none; + margin: 0; +} +#portfolio .portfolio-item .portfolio-caption p { + font-family: "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: italic; + font-size: 16px; + margin: 0; +} +#portfolio * { + z-index: 2; +} +@media (min-width: 767px) { + #portfolio .portfolio-item { + margin: 0 0 30px; + } +} +.timeline { + list-style: none; + padding: 0; + position: relative; +} +.timeline:before { + top: 0; + bottom: 0; + position: absolute; + content: ""; + width: 2px; + background-color: #f1f1f1; + left: 40px; + margin-left: -1.5px; +} +.timeline > li { + margin-bottom: 50px; + position: relative; + min-height: 50px; +} +.timeline > li:before, +.timeline > li:after { + content: " "; + display: table; +} +.timeline > li:after { + clear: both; +} +.timeline > li .timeline-panel { + width: 100%; + float: right; + padding: 0 20px 0 100px; + position: relative; + text-align: left; +} +.timeline > li .timeline-panel:before { + border-left-width: 0; + border-right-width: 15px; + left: -15px; + right: auto; +} +.timeline > li .timeline-panel:after { + border-left-width: 0; + border-right-width: 14px; + left: -14px; + right: auto; +} +.timeline > li .timeline-image { + left: 0; + margin-left: 0; + width: 80px; + height: 80px; + position: absolute; + z-index: 100; + background-color: #fed136; + color: white; + border-radius: 100%; + border: 7px solid #f1f1f1; + text-align: center; +} +.timeline > li .timeline-image h4 { + font-size: 10px; + margin-top: 12px; + line-height: 14px; +} +.timeline > li.timeline-inverted > .timeline-panel { + float: right; + text-align: left; + padding: 0 20px 0 100px; +} +.timeline > li.timeline-inverted > .timeline-panel:before { + border-left-width: 0; + border-right-width: 15px; + left: -15px; + right: auto; +} +.timeline > li.timeline-inverted > .timeline-panel:after { + border-left-width: 0; + border-right-width: 14px; + left: -14px; + right: auto; +} +.timeline > li:last-child { + margin-bottom: 0; +} +.timeline .timeline-heading h4 { + margin-top: 0; + color: inherit; +} +.timeline .timeline-heading h4.subheading { + text-transform: none; +} +.timeline .timeline-body > p, +.timeline .timeline-body > ul { + margin-bottom: 0; +} +@media (min-width: 768px) { + .timeline:before { + left: 50%; + } + .timeline > li { + margin-bottom: 100px; + min-height: 100px; + } + .timeline > li .timeline-panel { + width: 41%; + float: left; + padding: 0 20px 20px 30px; + text-align: right; + } + .timeline > li .timeline-image { + width: 100px; + height: 100px; + left: 50%; + margin-left: -50px; + } + .timeline > li .timeline-image h4 { + font-size: 13px; + margin-top: 16px; + line-height: 18px; + } + .timeline > li.timeline-inverted > .timeline-panel { + float: right; + text-align: left; + padding: 0 30px 20px 20px; + } +} +@media (min-width: 992px) { + .timeline > li { + min-height: 150px; + } + .timeline > li .timeline-panel { + padding: 0 20px 20px; + } + .timeline > li .timeline-image { + width: 150px; + height: 150px; + margin-left: -75px; + } + .timeline > li .timeline-image h4 { + font-size: 18px; + margin-top: 30px; + line-height: 26px; + } + .timeline > li.timeline-inverted > .timeline-panel { + padding: 0 20px 20px; + } +} +@media (min-width: 1200px) { + .timeline > li { + min-height: 170px; + } + .timeline > li .timeline-panel { + padding: 0 20px 20px 100px; + } + .timeline > li .timeline-image { + width: 170px; + height: 170px; + margin-left: -85px; + } + .timeline > li .timeline-image h4 { + margin-top: 40px; + } + .timeline > li.timeline-inverted > .timeline-panel { + padding: 0 100px 20px 20px; + } +} +.team-member { + text-align: center; + margin-bottom: 50px; +} +.team-member img { + margin: 0 auto; + border: 7px solid white; +} +.team-member h4 { + margin-top: 25px; + margin-bottom: 0; + text-transform: none; +} +.team-member p { + margin-top: 0; +} +aside.clients img { + margin: 50px auto; +} +section#contact { + background-color: #222222; + background-image: url('../img/map-image.png'); + background-position: center; + background-repeat: no-repeat; +} +section#contact .section-heading { + color: white; +} +section#contact .form-group { + margin-bottom: 25px; +} +section#contact .form-group input, +section#contact .form-group textarea { + padding: 20px; +} +section#contact .form-group input.form-control { + height: auto; +} +section#contact .form-group textarea.form-control { + height: 150px; +} +section#contact .form-control:focus { + border-color: #fed136; + box-shadow: none; +} +section#contact ::-webkit-input-placeholder { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + color: #eeeeee; +} +section#contact :-moz-placeholder { + /* Firefox 18- */ + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + color: #eeeeee; +} +section#contact ::-moz-placeholder { + /* Firefox 19+ */ + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + color: #eeeeee; +} +section#contact :-ms-input-placeholder { + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + font-weight: 700; + color: #eeeeee; +} +section#contact .text-danger { + color: #e74c3c; +} +footer { + padding: 25px 0; + text-align: center; +} +footer span.copyright { + line-height: 40px; + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + text-transform: none; +} +footer ul.quicklinks { + margin-bottom: 0; + line-height: 40px; + font-family: "Montserrat", "Helvetica Neue", Helvetica, Arial, sans-serif; + text-transform: uppercase; + text-transform: none; +} +ul.social-buttons { + margin-bottom: 0; +} +ul.social-buttons li a { + display: block; + background-color: #222222; + height: 40px; + width: 40px; + border-radius: 100%; + font-size: 20px; + line-height: 40px; + color: white; + outline: none; + -webkit-transition: all 0.3s; + -moz-transition: all 0.3s; + transition: all 0.3s; +} +ul.social-buttons li a:hover, +ul.social-buttons li a:focus, +ul.social-buttons li a:active { + background-color: #fed136; +} +.btn:focus, +.btn:active, +.btn.active, +.btn:active:focus { + outline: none; +} +.portfolio-modal .modal-dialog { + margin: 0; + height: 100%; + width: auto; +} +.portfolio-modal .modal-content { + border-radius: 0; + background-clip: border-box; + -webkit-box-shadow: none; + box-shadow: none; + border: none; + min-height: 100%; + padding: 100px 0; + text-align: center; +} +.portfolio-modal .modal-content h2 { + margin-bottom: 15px; + font-size: 3em; +} +.portfolio-modal .modal-content p { + margin-bottom: 30px; +} +.portfolio-modal .modal-content p.item-intro { + margin: 20px 0 30px; + font-family: "Droid Serif", "Helvetica Neue", Helvetica, Arial, sans-serif; + font-style: italic; + font-size: 16px; +} +.portfolio-modal .modal-content ul.list-inline { + margin-bottom: 30px; + margin-top: 0; +} +.portfolio-modal .modal-content img { + margin-bottom: 30px; +} +.portfolio-modal .close-modal { + position: absolute; + width: 75px; + height: 75px; + background-color: transparent; + top: 25px; + right: 25px; + cursor: pointer; +} +.portfolio-modal .close-modal:hover { + opacity: 0.3; +} +.portfolio-modal .close-modal .lr { + height: 75px; + width: 1px; + margin-left: 35px; + background-color: #222222; + transform: rotate(45deg); + -ms-transform: rotate(45deg); + /* IE 9 */ + -webkit-transform: rotate(45deg); + /* Safari and Chrome */ + z-index: 1051; +} +.portfolio-modal .close-modal .lr .rl { + height: 75px; + width: 1px; + background-color: #222222; + transform: rotate(90deg); + -ms-transform: rotate(90deg); + /* IE 9 */ + -webkit-transform: rotate(90deg); + /* Safari and Chrome */ + z-index: 1052; +} +.portfolio-modal .modal-backdrop { + opacity: 0; + display: none; +} +::-moz-selection { + text-shadow: none; + background: #fed136; +} +::selection { + text-shadow: none; + background: #fed136; +} +img::selection { + background: transparent; +} +img::-moz-selection { + background: transparent; +} +body { + webkit-tap-highlight-color: #fed136; +} diff --git a/src/main/resources/static/css/agency.min.css b/src/main/resources/static/css/agency.min.css new file mode 100644 index 0000000..7615c22 --- /dev/null +++ b/src/main/resources/static/css/agency.min.css @@ -0,0 +1,5 @@ +/*! + * Start Bootstrap - Agency v3.3.7+1 (http://startbootstrap.com/template-overviews/agency) + * Copyright 2013-2016 Start Bootstrap + * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) + */.btn-primary.active,.btn-primary:active,.btn-xl.active,.btn-xl:active,.open .dropdown-toggle.btn-primary,.open .dropdown-toggle.btn-xl{background-image:none}body{overflow-x:hidden;font-family:"Roboto Slab","Helvetica Neue",Helvetica,Arial,sans-serif;webkit-tap-highlight-color:#fed136}.btn-primary,.btn-xl,h1,h2,h3,h4,h5,h6{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700}.text-muted{color:#777}.text-primary,a{color:#fed136}p{font-size:14px;line-height:1.75}p.large{font-size:16px}a,a.active,a:active,a:focus,a:hover{outline:0}a.active,a:active,a:focus,a:hover{color:#fec503}.img-centered{margin:0 auto}.bg-light-gray{background-color:#eee}.bg-darkest-gray{background-color:#222}.btn-primary{color:#fff;background-color:#fed136;border-color:#fed136}.btn-primary.active,.btn-primary:active,.btn-primary:focus,.btn-primary:hover,.open .dropdown-toggle.btn-primary{color:#fff;background-color:#fec503;border-color:#f6bf01}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#fed136;border-color:#fed136}.btn-primary .badge{color:#fed136;background-color:#fff}.btn-xl{color:#fff;background-color:#fed136;border-color:#fed136;border-radius:3px;font-size:18px;padding:20px 40px}.btn-xl.active,.btn-xl:active,.btn-xl:focus,.btn-xl:hover,.open .dropdown-toggle.btn-xl{color:#fff;background-color:#fec503;border-color:#f6bf01}.btn-xl.disabled,.btn-xl.disabled.active,.btn-xl.disabled:active,.btn-xl.disabled:focus,.btn-xl.disabled:hover,.btn-xl[disabled],.btn-xl[disabled].active,.btn-xl[disabled]:active,.btn-xl[disabled]:focus,.btn-xl[disabled]:hover,fieldset[disabled] .btn-xl,fieldset[disabled] .btn-xl.active,fieldset[disabled] .btn-xl:active,fieldset[disabled] .btn-xl:focus,fieldset[disabled] .btn-xl:hover{background-color:#fed136;border-color:#fed136}.btn-xl .badge{color:#fed136;background-color:#fff}.navbar-custom{background-color:#222;border-color:transparent}.navbar-custom .navbar-brand{color:#fed136;font-family:"Kaushan Script","Helvetica Neue",Helvetica,Arial,cursive}.navbar-custom .navbar-brand.active,.navbar-custom .navbar-brand:active,.navbar-custom .navbar-brand:focus,.navbar-custom .navbar-brand:hover{color:#fec503}.navbar-custom .nav li a,.navbar-custom .navbar-toggle{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;color:#fff;text-transform:uppercase}.navbar-custom .navbar-collapse{border-color:rgba(255,255,255,.02)}.navbar-custom .navbar-toggle{background-color:#fed136;border-color:#fed136;font-size:12px}.navbar-custom .navbar-toggle:focus,.navbar-custom .navbar-toggle:hover{background-color:#fed136}.navbar-custom .nav li a{font-weight:400;letter-spacing:1px}.navbar-custom .nav li a:focus,.navbar-custom .nav li a:hover{color:#fed136;outline:0}.navbar-custom .navbar-nav>.active>a{border-radius:0;color:#fff;background-color:#fed136}.navbar-custom .navbar-nav>.active>a:focus,.navbar-custom .navbar-nav>.active>a:hover{color:#fff;background-color:#fec503}@media (min-width:768px){.navbar-custom{background-color:transparent;padding:25px 0;-webkit-transition:padding .3s;-moz-transition:padding .3s;transition:padding .3s;border:none}.navbar-custom .navbar-brand{font-size:2em;-webkit-transition:all .3s;-moz-transition:all .3s;transition:all .3s}.navbar-custom .navbar-nav>.active>a{border-radius:3px}.navbar-custom.affix{background-color:#222;padding:10px 0}.navbar-custom.affix .navbar-brand{font-size:1.5em}}header{background-image:url(../img/header-bg.jpg);background-repeat:no-repeat;background-attachment:scroll;background-position:center center;-webkit-background-size:cover;-moz-background-size:cover;background-size:cover;-o-background-size:cover;text-align:center;color:#fff}header .intro-text{padding-top:100px;padding-bottom:50px}header .intro-text .intro-lead-in{font-family:"Droid Serif","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:italic;font-size:22px;line-height:22px;margin-bottom:25px}header .intro-text .intro-heading{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;font-size:50px;line-height:50px;margin-bottom:25px}@media (min-width:768px){header .intro-text{padding-top:300px;padding-bottom:200px}header .intro-text .intro-lead-in{font-family:"Droid Serif","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:italic;font-size:40px;line-height:40px;margin-bottom:25px}header .intro-text .intro-heading{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;font-size:75px;line-height:75px;margin-bottom:50px}}#portfolio .portfolio-item .portfolio-caption p,section h3.section-subheading{font-family:"Droid Serif","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:italic}section{padding:100px 0}section h2.section-heading{font-size:40px;margin-top:0;margin-bottom:15px}section h3.section-subheading{font-size:16px;text-transform:none;font-weight:400;margin-bottom:75px}@media (min-width:768px){section{padding:150px 0}}.service-heading{margin:15px 0;text-transform:none}#portfolio .portfolio-item{margin:0 0 15px;right:0}#portfolio .portfolio-item .portfolio-link{display:block;position:relative;max-width:400px;margin:0 auto}#portfolio .portfolio-item .portfolio-link .portfolio-hover{background:rgba(254,209,54,.9);position:absolute;width:100%;height:100%;opacity:0;transition:all ease .5s;-webkit-transition:all ease .5s;-moz-transition:all ease .5s}#portfolio .portfolio-item .portfolio-link .portfolio-hover:hover{opacity:1}#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content{position:absolute;width:100%;height:20px;font-size:20px;text-align:center;top:50%;margin-top:-12px;color:#fff}#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content i{margin-top:-12px}#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content h3,#portfolio .portfolio-item .portfolio-link .portfolio-hover .portfolio-hover-content h4{margin:0}#portfolio .portfolio-item .portfolio-caption{max-width:400px;margin:0 auto;background-color:#fff;text-align:center;padding:25px}#portfolio .portfolio-item .portfolio-caption h4{text-transform:none;margin:0}#portfolio .portfolio-item .portfolio-caption p{font-size:16px;margin:0}footer span.copyright,footer ul.quicklinks{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif}#portfolio *{z-index:2}@media (min-width:767px){#portfolio .portfolio-item{margin:0 0 30px}}.timeline{list-style:none;padding:0;position:relative}.timeline:before{top:0;bottom:0;position:absolute;content:"";width:2px;background-color:#f1f1f1;left:40px;margin-left:-1.5px}.timeline>li{margin-bottom:50px;position:relative;min-height:50px}.timeline>li:after,.timeline>li:before{content:" ";display:table}.timeline>li:after{clear:both}.timeline>li .timeline-panel{width:100%;float:right;padding:0 20px 0 100px;position:relative;text-align:left}.timeline>li .timeline-panel:before{border-left-width:0;border-right-width:15px;left:-15px;right:auto}.timeline>li .timeline-panel:after{border-left-width:0;border-right-width:14px;left:-14px;right:auto}.timeline>li .timeline-image{left:0;margin-left:0;width:80px;height:80px;position:absolute;z-index:100;background-color:#fed136;color:#fff;border-radius:100%;border:7px solid #f1f1f1;text-align:center}.timeline>li .timeline-image h4{font-size:10px;margin-top:12px;line-height:14px}.timeline>li.timeline-inverted>.timeline-panel{float:right;text-align:left;padding:0 20px 0 100px}.timeline>li.timeline-inverted>.timeline-panel:before{border-left-width:0;border-right-width:15px;left:-15px;right:auto}.timeline>li.timeline-inverted>.timeline-panel:after{border-left-width:0;border-right-width:14px;left:-14px;right:auto}.timeline>li:last-child{margin-bottom:0}.timeline .timeline-heading h4{margin-top:0;color:inherit}.timeline .timeline-heading h4.subheading{text-transform:none}.timeline .timeline-body>p,.timeline .timeline-body>ul{margin-bottom:0}@media (min-width:768px){.timeline:before{left:50%}.timeline>li{margin-bottom:100px;min-height:100px}.timeline>li .timeline-panel{width:41%;float:left;padding:0 20px 20px 30px;text-align:right}.timeline>li .timeline-image{width:100px;height:100px;left:50%;margin-left:-50px}.timeline>li .timeline-image h4{font-size:13px;margin-top:16px;line-height:18px}.timeline>li.timeline-inverted>.timeline-panel{float:right;text-align:left;padding:0 30px 20px 20px}}@media (min-width:992px){.timeline>li .timeline-panel,.timeline>li.timeline-inverted>.timeline-panel{padding:0 20px 20px}.timeline>li{min-height:150px}.timeline>li .timeline-image{width:150px;height:150px;margin-left:-75px}.timeline>li .timeline-image h4{font-size:18px;margin-top:30px;line-height:26px}}@media (min-width:1200px){.timeline>li{min-height:170px}.timeline>li .timeline-panel{padding:0 20px 20px 100px}.timeline>li .timeline-image{width:170px;height:170px;margin-left:-85px}.timeline>li .timeline-image h4{margin-top:40px}.timeline>li.timeline-inverted>.timeline-panel{padding:0 100px 20px 20px}}.team-member{text-align:center;margin-bottom:50px}.team-member img{margin:0 auto;border:7px solid #fff}.team-member h4{margin-top:25px;margin-bottom:0;text-transform:none}.team-member p{margin-top:0}aside.clients img{margin:50px auto}section#contact{background-color:#222;background-image:url(../img/map-image.png);background-position:center;background-repeat:no-repeat}section#contact .section-heading{color:#fff}section#contact .form-group{margin-bottom:25px}section#contact .form-group input,section#contact .form-group textarea{padding:20px}section#contact .form-group input.form-control{height:auto}section#contact .form-group textarea.form-control{height:236px}section#contact .form-control:focus{border-color:#fed136;box-shadow:none}section#contact ::-webkit-input-placeholder{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;color:#eee}section#contact :-moz-placeholder{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;color:#eee}section#contact ::-moz-placeholder{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;color:#eee}section#contact :-ms-input-placeholder{font-family:Montserrat,"Helvetica Neue",Helvetica,Arial,sans-serif;text-transform:uppercase;font-weight:700;color:#eee}section#contact .text-danger{color:#e74c3c}footer{padding:25px 0;text-align:center}footer span.copyright{line-height:40px;text-transform:uppercase;text-transform:none}footer ul.quicklinks{margin-bottom:0;line-height:40px;text-transform:uppercase;text-transform:none}ul.social-buttons{margin-bottom:0}ul.social-buttons li a{display:block;background-color:#222;height:40px;width:40px;border-radius:100%;font-size:20px;line-height:40px;color:#fff;outline:0;-webkit-transition:all .3s;-moz-transition:all .3s;transition:all .3s}ul.social-buttons li a:active,ul.social-buttons li a:focus,ul.social-buttons li a:hover{background-color:#fed136}.btn.active,.btn:active,.btn:active:focus,.btn:focus{outline:0}.portfolio-modal .modal-dialog{margin:0;height:100%;width:auto}.portfolio-modal .modal-content{border-radius:0;background-clip:border-box;-webkit-box-shadow:none;box-shadow:none;border:none;min-height:100%;padding:100px 0;text-align:center}.portfolio-modal .modal-content h2{margin-bottom:15px;font-size:3em}.portfolio-modal .modal-content p{margin-bottom:30px}.portfolio-modal .modal-content p.item-intro{margin:20px 0 30px;font-family:"Droid Serif","Helvetica Neue",Helvetica,Arial,sans-serif;font-style:italic;font-size:16px}.portfolio-modal .modal-content ul.list-inline{margin-bottom:30px;margin-top:0}.portfolio-modal .modal-content img{margin-bottom:30px}.portfolio-modal .close-modal{position:absolute;width:75px;height:75px;background-color:transparent;top:25px;right:25px;cursor:pointer}.portfolio-modal .close-modal:hover{opacity:.3}.portfolio-modal .close-modal .lr{height:75px;width:1px;margin-left:35px;background-color:#222;transform:rotate(45deg);-ms-transform:rotate(45deg);-webkit-transform:rotate(45deg);z-index:1051}.portfolio-modal .close-modal .lr .rl{height:75px;width:1px;background-color:#222;transform:rotate(90deg);-ms-transform:rotate(90deg);-webkit-transform:rotate(90deg);z-index:1052}.portfolio-modal .modal-backdrop{opacity:0;display:none}::-moz-selection{text-shadow:none;background:#fed136}::selection{text-shadow:none;background:#fed136}img::selection{background:0 0}img::-moz-selection{background:0 0} \ No newline at end of file diff --git a/src/main/resources/static/img/about/1.jpg b/src/main/resources/static/img/about/1.jpg new file mode 100644 index 0000000..0eadb79 Binary files /dev/null and b/src/main/resources/static/img/about/1.jpg differ diff --git a/src/main/resources/static/img/about/2.jpg b/src/main/resources/static/img/about/2.jpg new file mode 100644 index 0000000..24b4e5b Binary files /dev/null and b/src/main/resources/static/img/about/2.jpg differ diff --git a/src/main/resources/static/img/about/3.jpg b/src/main/resources/static/img/about/3.jpg new file mode 100644 index 0000000..6ed1b35 Binary files /dev/null and b/src/main/resources/static/img/about/3.jpg differ diff --git a/src/main/resources/static/img/about/4.jpg b/src/main/resources/static/img/about/4.jpg new file mode 100644 index 0000000..4a43210 Binary files /dev/null and b/src/main/resources/static/img/about/4.jpg differ diff --git a/src/main/resources/static/img/header-bg.jpg b/src/main/resources/static/img/header-bg.jpg new file mode 100644 index 0000000..eaf775e Binary files /dev/null and b/src/main/resources/static/img/header-bg.jpg differ diff --git a/src/main/resources/static/img/logos/aetuts.jpg b/src/main/resources/static/img/logos/aetuts.jpg new file mode 100644 index 0000000..c75adda Binary files /dev/null and b/src/main/resources/static/img/logos/aetuts.jpg differ diff --git a/src/main/resources/static/img/logos/creative-market.jpg b/src/main/resources/static/img/logos/creative-market.jpg new file mode 100644 index 0000000..3f30853 Binary files /dev/null and b/src/main/resources/static/img/logos/creative-market.jpg differ diff --git a/src/main/resources/static/img/logos/designmodo.jpg b/src/main/resources/static/img/logos/designmodo.jpg new file mode 100644 index 0000000..44ce889 Binary files /dev/null and b/src/main/resources/static/img/logos/designmodo.jpg differ diff --git a/src/main/resources/static/img/logos/envato.jpg b/src/main/resources/static/img/logos/envato.jpg new file mode 100644 index 0000000..5d70a87 Binary files /dev/null and b/src/main/resources/static/img/logos/envato.jpg differ diff --git a/src/main/resources/static/img/logos/microlancer.jpg b/src/main/resources/static/img/logos/microlancer.jpg new file mode 100644 index 0000000..c4b9111 Binary files /dev/null and b/src/main/resources/static/img/logos/microlancer.jpg differ diff --git a/src/main/resources/static/img/logos/themeforest.jpg b/src/main/resources/static/img/logos/themeforest.jpg new file mode 100644 index 0000000..1dbba6f Binary files /dev/null and b/src/main/resources/static/img/logos/themeforest.jpg differ diff --git a/src/main/resources/static/img/logos/wordpress.jpg b/src/main/resources/static/img/logos/wordpress.jpg new file mode 100644 index 0000000..29be11d Binary files /dev/null and b/src/main/resources/static/img/logos/wordpress.jpg differ diff --git a/src/main/resources/static/img/map-image.png b/src/main/resources/static/img/map-image.png new file mode 100644 index 0000000..a047a27 Binary files /dev/null and b/src/main/resources/static/img/map-image.png differ diff --git a/src/main/resources/static/img/portfolio/dreams-preview.png b/src/main/resources/static/img/portfolio/dreams-preview.png new file mode 100644 index 0000000..e2773b2 Binary files /dev/null and b/src/main/resources/static/img/portfolio/dreams-preview.png differ diff --git a/src/main/resources/static/img/portfolio/dreams.png b/src/main/resources/static/img/portfolio/dreams.png new file mode 100644 index 0000000..1b925d8 Binary files /dev/null and b/src/main/resources/static/img/portfolio/dreams.png differ diff --git a/src/main/resources/static/img/portfolio/escape-preview.png b/src/main/resources/static/img/portfolio/escape-preview.png new file mode 100644 index 0000000..a2343b4 Binary files /dev/null and b/src/main/resources/static/img/portfolio/escape-preview.png differ diff --git a/src/main/resources/static/img/portfolio/escape.png b/src/main/resources/static/img/portfolio/escape.png new file mode 100644 index 0000000..d5fcee8 Binary files /dev/null and b/src/main/resources/static/img/portfolio/escape.png differ diff --git a/src/main/resources/static/img/portfolio/golden-preview.png b/src/main/resources/static/img/portfolio/golden-preview.png new file mode 100644 index 0000000..b8fe735 Binary files /dev/null and b/src/main/resources/static/img/portfolio/golden-preview.png differ diff --git a/src/main/resources/static/img/portfolio/golden.png b/src/main/resources/static/img/portfolio/golden.png new file mode 100644 index 0000000..9b971ae Binary files /dev/null and b/src/main/resources/static/img/portfolio/golden.png differ diff --git a/src/main/resources/static/img/portfolio/roundicons-free.png b/src/main/resources/static/img/portfolio/roundicons-free.png new file mode 100644 index 0000000..dec0278 Binary files /dev/null and b/src/main/resources/static/img/portfolio/roundicons-free.png differ diff --git a/src/main/resources/static/img/portfolio/roundicons.png b/src/main/resources/static/img/portfolio/roundicons.png new file mode 100644 index 0000000..97c0e9a Binary files /dev/null and b/src/main/resources/static/img/portfolio/roundicons.png differ diff --git a/src/main/resources/static/img/portfolio/startup-framework-preview.png b/src/main/resources/static/img/portfolio/startup-framework-preview.png new file mode 100644 index 0000000..0b612f3 Binary files /dev/null and b/src/main/resources/static/img/portfolio/startup-framework-preview.png differ diff --git a/src/main/resources/static/img/portfolio/startup-framework.png b/src/main/resources/static/img/portfolio/startup-framework.png new file mode 100644 index 0000000..3516bbc Binary files /dev/null and b/src/main/resources/static/img/portfolio/startup-framework.png differ diff --git a/src/main/resources/static/img/portfolio/treehouse-preview.png b/src/main/resources/static/img/portfolio/treehouse-preview.png new file mode 100644 index 0000000..df04474 Binary files /dev/null and b/src/main/resources/static/img/portfolio/treehouse-preview.png differ diff --git a/src/main/resources/static/img/portfolio/treehouse.png b/src/main/resources/static/img/portfolio/treehouse.png new file mode 100644 index 0000000..a800611 Binary files /dev/null and b/src/main/resources/static/img/portfolio/treehouse.png differ diff --git a/src/main/resources/static/img/team/1.jpg b/src/main/resources/static/img/team/1.jpg new file mode 100644 index 0000000..cabfc56 Binary files /dev/null and b/src/main/resources/static/img/team/1.jpg differ diff --git a/src/main/resources/static/img/team/2.jpg b/src/main/resources/static/img/team/2.jpg new file mode 100644 index 0000000..49d1c70 Binary files /dev/null and b/src/main/resources/static/img/team/2.jpg differ diff --git a/src/main/resources/static/img/team/3.jpg b/src/main/resources/static/img/team/3.jpg new file mode 100644 index 0000000..f34ef1f Binary files /dev/null and b/src/main/resources/static/img/team/3.jpg differ diff --git a/src/main/resources/static/js/agency.js b/src/main/resources/static/js/agency.js new file mode 100644 index 0000000..7e6c72a --- /dev/null +++ b/src/main/resources/static/js/agency.js @@ -0,0 +1,33 @@ +// Agency Theme JavaScript + +(function($) { + "use strict"; // Start of use strict + + // jQuery for page scrolling feature - requires jQuery Easing plugin + $('a.page-scroll').bind('click', function(event) { + var $anchor = $(this); + $('html, body').stop().animate({ + scrollTop: ($($anchor.attr('href')).offset().top - 50) + }, 1250, 'easeInOutExpo'); + event.preventDefault(); + }); + + // Highlight the top nav as scrolling occurs + $('body').scrollspy({ + target: '.navbar-fixed-top', + offset: 51 + }); + + // Closes the Responsive Menu on Menu Item Click + $('.navbar-collapse ul li a').click(function(){ + $('.navbar-toggle:visible').click(); + }); + + // Offset for Main Navigation + $('#mainNav').affix({ + offset: { + top: 100 + } + }) + +})(jQuery); // End of use strict diff --git a/src/main/resources/static/js/agency.min.js b/src/main/resources/static/js/agency.min.js new file mode 100644 index 0000000..472e398 --- /dev/null +++ b/src/main/resources/static/js/agency.min.js @@ -0,0 +1,6 @@ +/*! + * Start Bootstrap - Agency v3.3.7+1 (http://startbootstrap.com/template-overviews/agency) + * Copyright 2013-2016 Start Bootstrap + * Licensed under MIT (https://github.com/BlackrockDigital/startbootstrap/blob/gh-pages/LICENSE) + */ +!function(t){"use strict";t("a.page-scroll").bind("click",function(a){var o=t(this);t("html, body").stop().animate({scrollTop:t(o.attr("href")).offset().top-50},1250,"easeInOutExpo"),a.preventDefault()}),t("body").scrollspy({target:".navbar-fixed-top",offset:51}),t(".navbar-collapse ul li a").click(function(){t(".navbar-toggle:visible").click()}),t("#mainNav").affix({offset:{top:100}})}(jQuery); \ No newline at end of file diff --git a/src/main/resources/static/js/contact_me.js b/src/main/resources/static/js/contact_me.js new file mode 100644 index 0000000..c3d8ecc --- /dev/null +++ b/src/main/resources/static/js/contact_me.js @@ -0,0 +1,72 @@ +// Contact Form Scripts + +$(function() { + + $("#contactForm input,#contactForm textarea").jqBootstrapValidation({ + preventSubmit: true, + submitError: function($form, event, errors) { + // additional error messages or events + }, + submitSuccess: function($form, event) { + event.preventDefault(); // prevent default submit behaviour + // get values from FORM + var name = $("input#name").val(); + var email = $("input#email").val(); + var phone = $("input#phone").val(); + var message = $("textarea#message").val(); + var firstName = name; // For Success/Failure Message + // Check for white space in name for Success/Fail message + if (firstName.indexOf(' ') >= 0) { + firstName = name.split(' ').slice(0, -1).join(' '); + } + $.ajax({ + url: "././mail/contact_me.php", + type: "POST", + data: { + name: name, + phone: phone, + email: email, + message: message + }, + cache: false, + success: function() { + // Success message + $('#success').html("
"); + $('#success > .alert-success').html(""); + $('#success > .alert-success') + .append("Your message has been sent. "); + $('#success > .alert-success') + .append('
'); + + //clear all fields + $('#contactForm').trigger("reset"); + }, + error: function() { + // Fail message + $('#success').html("
"); + $('#success > .alert-danger').html(""); + $('#success > .alert-danger').append("Sorry " + firstName + ", it seems that my mail server is not responding. Please try again later!"); + $('#success > .alert-danger').append('
'); + //clear all fields + $('#contactForm').trigger("reset"); + }, + }); + }, + filter: function() { + return $(this).is(":visible"); + }, + }); + + $("a[data-toggle=\"tab\"]").click(function(e) { + e.preventDefault(); + $(this).tab("show"); + }); +}); + + +/*When clicking on Full hide fail/success boxes */ +$('#name').focus(function() { + $('#success').html(''); +}); diff --git a/src/main/resources/static/js/jqBootstrapValidation.js b/src/main/resources/static/js/jqBootstrapValidation.js new file mode 100644 index 0000000..7b3b922 --- /dev/null +++ b/src/main/resources/static/js/jqBootstrapValidation.js @@ -0,0 +1,912 @@ +/* jqBootstrapValidation + * A plugin for automating validation on Twitter Bootstrap formatted forms. + * + * v1.3.6 + * + * License: MIT - see LICENSE file + * + * http://ReactiveRaven.github.com/jqBootstrapValidation/ + */ + +(function( $ ){ + + var createdElements = []; + + var defaults = { + options: { + prependExistingHelpBlock: false, + sniffHtml: true, // sniff for 'required', 'maxlength', etc + preventSubmit: true, // stop the form submit event from firing if validation fails + submitError: false, // function called if there is an error when trying to submit + submitSuccess: false, // function called just before a successful submit event is sent to the server + semanticallyStrict: false, // set to true to tidy up generated HTML output + autoAdd: { + helpBlocks: true + }, + filter: function () { + // return $(this).is(":visible"); // only validate elements you can see + return true; // validate everything + } + }, + methods: { + init : function( options ) { + + var settings = $.extend(true, {}, defaults); + + settings.options = $.extend(true, settings.options, options); + + var $siblingElements = this; + + var uniqueForms = $.unique( + $siblingElements.map( function () { + return $(this).parents("form")[0]; + }).toArray() + ); + + $(uniqueForms).bind("submit", function (e) { + var $form = $(this); + var warningsFound = 0; + var $inputs = $form.find("input,textarea,select").not("[type=submit],[type=image]").filter(settings.options.filter); + $inputs.trigger("submit.validation").trigger("validationLostFocus.validation"); + + $inputs.each(function (i, el) { + var $this = $(el), + $controlGroup = $this.parents(".form-group").first(); + if ( + $controlGroup.hasClass("warning") + ) { + $controlGroup.removeClass("warning").addClass("error"); + warningsFound++; + } + }); + + $inputs.trigger("validationLostFocus.validation"); + + if (warningsFound) { + if (settings.options.preventSubmit) { + e.preventDefault(); + } + $form.addClass("error"); + if ($.isFunction(settings.options.submitError)) { + settings.options.submitError($form, e, $inputs.jqBootstrapValidation("collectErrors", true)); + } + } else { + $form.removeClass("error"); + if ($.isFunction(settings.options.submitSuccess)) { + settings.options.submitSuccess($form, e); + } + } + }); + + return this.each(function(){ + + // Get references to everything we're interested in + var $this = $(this), + $controlGroup = $this.parents(".form-group").first(), + $helpBlock = $controlGroup.find(".help-block").first(), + $form = $this.parents("form").first(), + validatorNames = []; + + // create message container if not exists + if (!$helpBlock.length && settings.options.autoAdd && settings.options.autoAdd.helpBlocks) { + $helpBlock = $('
'); + $controlGroup.find('.controls').append($helpBlock); + createdElements.push($helpBlock[0]); + } + + // ============================================================= + // SNIFF HTML FOR VALIDATORS + // ============================================================= + + // *snort sniff snuffle* + + if (settings.options.sniffHtml) { + var message = ""; + // --------------------------------------------------------- + // PATTERN + // --------------------------------------------------------- + if ($this.attr("pattern") !== undefined) { + message = "Not in the expected format"; + if ($this.data("validationPatternMessage")) { + message = $this.data("validationPatternMessage"); + } + $this.data("validationPatternMessage", message); + $this.data("validationPatternRegex", $this.attr("pattern")); + } + // --------------------------------------------------------- + // MAX + // --------------------------------------------------------- + if ($this.attr("max") !== undefined || $this.attr("aria-valuemax") !== undefined) { + var max = ($this.attr("max") !== undefined ? $this.attr("max") : $this.attr("aria-valuemax")); + message = "Too high: Maximum of '" + max + "'"; + if ($this.data("validationMaxMessage")) { + message = $this.data("validationMaxMessage"); + } + $this.data("validationMaxMessage", message); + $this.data("validationMaxMax", max); + } + // --------------------------------------------------------- + // MIN + // --------------------------------------------------------- + if ($this.attr("min") !== undefined || $this.attr("aria-valuemin") !== undefined) { + var min = ($this.attr("min") !== undefined ? $this.attr("min") : $this.attr("aria-valuemin")); + message = "Too low: Minimum of '" + min + "'"; + if ($this.data("validationMinMessage")) { + message = $this.data("validationMinMessage"); + } + $this.data("validationMinMessage", message); + $this.data("validationMinMin", min); + } + // --------------------------------------------------------- + // MAXLENGTH + // --------------------------------------------------------- + if ($this.attr("maxlength") !== undefined) { + message = "Too long: Maximum of '" + $this.attr("maxlength") + "' characters"; + if ($this.data("validationMaxlengthMessage")) { + message = $this.data("validationMaxlengthMessage"); + } + $this.data("validationMaxlengthMessage", message); + $this.data("validationMaxlengthMaxlength", $this.attr("maxlength")); + } + // --------------------------------------------------------- + // MINLENGTH + // --------------------------------------------------------- + if ($this.attr("minlength") !== undefined) { + message = "Too short: Minimum of '" + $this.attr("minlength") + "' characters"; + if ($this.data("validationMinlengthMessage")) { + message = $this.data("validationMinlengthMessage"); + } + $this.data("validationMinlengthMessage", message); + $this.data("validationMinlengthMinlength", $this.attr("minlength")); + } + // --------------------------------------------------------- + // REQUIRED + // --------------------------------------------------------- + if ($this.attr("required") !== undefined || $this.attr("aria-required") !== undefined) { + message = settings.builtInValidators.required.message; + if ($this.data("validationRequiredMessage")) { + message = $this.data("validationRequiredMessage"); + } + $this.data("validationRequiredMessage", message); + } + // --------------------------------------------------------- + // NUMBER + // --------------------------------------------------------- + if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "number") { + message = settings.builtInValidators.number.message; + if ($this.data("validationNumberMessage")) { + message = $this.data("validationNumberMessage"); + } + $this.data("validationNumberMessage", message); + } + // --------------------------------------------------------- + // EMAIL + // --------------------------------------------------------- + if ($this.attr("type") !== undefined && $this.attr("type").toLowerCase() === "email") { + message = "Not a valid email address"; + if ($this.data("validationValidemailMessage")) { + message = $this.data("validationValidemailMessage"); + } else if ($this.data("validationEmailMessage")) { + message = $this.data("validationEmailMessage"); + } + $this.data("validationValidemailMessage", message); + } + // --------------------------------------------------------- + // MINCHECKED + // --------------------------------------------------------- + if ($this.attr("minchecked") !== undefined) { + message = "Not enough options checked; Minimum of '" + $this.attr("minchecked") + "' required"; + if ($this.data("validationMincheckedMessage")) { + message = $this.data("validationMincheckedMessage"); + } + $this.data("validationMincheckedMessage", message); + $this.data("validationMincheckedMinchecked", $this.attr("minchecked")); + } + // --------------------------------------------------------- + // MAXCHECKED + // --------------------------------------------------------- + if ($this.attr("maxchecked") !== undefined) { + message = "Too many options checked; Maximum of '" + $this.attr("maxchecked") + "' required"; + if ($this.data("validationMaxcheckedMessage")) { + message = $this.data("validationMaxcheckedMessage"); + } + $this.data("validationMaxcheckedMessage", message); + $this.data("validationMaxcheckedMaxchecked", $this.attr("maxchecked")); + } + } + + // ============================================================= + // COLLECT VALIDATOR NAMES + // ============================================================= + + // Get named validators + if ($this.data("validation") !== undefined) { + validatorNames = $this.data("validation").split(","); + } + + // Get extra ones defined on the element's data attributes + $.each($this.data(), function (i, el) { + var parts = i.replace(/([A-Z])/g, ",$1").split(","); + if (parts[0] === "validation" && parts[1]) { + validatorNames.push(parts[1]); + } + }); + + // ============================================================= + // NORMALISE VALIDATOR NAMES + // ============================================================= + + var validatorNamesToInspect = validatorNames; + var newValidatorNamesToInspect = []; + + do // repeatedly expand 'shortcut' validators into their real validators + { + // Uppercase only the first letter of each name + $.each(validatorNames, function (i, el) { + validatorNames[i] = formatValidatorName(el); + }); + + // Remove duplicate validator names + validatorNames = $.unique(validatorNames); + + // Pull out the new validator names from each shortcut + newValidatorNamesToInspect = []; + $.each(validatorNamesToInspect, function(i, el) { + if ($this.data("validation" + el + "Shortcut") !== undefined) { + // Are these custom validators? + // Pull them out! + $.each($this.data("validation" + el + "Shortcut").split(","), function(i2, el2) { + newValidatorNamesToInspect.push(el2); + }); + } else if (settings.builtInValidators[el.toLowerCase()]) { + // Is this a recognised built-in? + // Pull it out! + var validator = settings.builtInValidators[el.toLowerCase()]; + if (validator.type.toLowerCase() === "shortcut") { + $.each(validator.shortcut.split(","), function (i, el) { + el = formatValidatorName(el); + newValidatorNamesToInspect.push(el); + validatorNames.push(el); + }); + } + } + }); + + validatorNamesToInspect = newValidatorNamesToInspect; + + } while (validatorNamesToInspect.length > 0) + + // ============================================================= + // SET UP VALIDATOR ARRAYS + // ============================================================= + + var validators = {}; + + $.each(validatorNames, function (i, el) { + // Set up the 'override' message + var message = $this.data("validation" + el + "Message"); + var hasOverrideMessage = (message !== undefined); + var foundValidator = false; + message = + ( + message + ? message + : "'" + el + "' validation failed " + ) + ; + + $.each( + settings.validatorTypes, + function (validatorType, validatorTemplate) { + if (validators[validatorType] === undefined) { + validators[validatorType] = []; + } + if (!foundValidator && $this.data("validation" + el + formatValidatorName(validatorTemplate.name)) !== undefined) { + validators[validatorType].push( + $.extend( + true, + { + name: formatValidatorName(validatorTemplate.name), + message: message + }, + validatorTemplate.init($this, el) + ) + ); + foundValidator = true; + } + } + ); + + if (!foundValidator && settings.builtInValidators[el.toLowerCase()]) { + + var validator = $.extend(true, {}, settings.builtInValidators[el.toLowerCase()]); + if (hasOverrideMessage) { + validator.message = message; + } + var validatorType = validator.type.toLowerCase(); + + if (validatorType === "shortcut") { + foundValidator = true; + } else { + $.each( + settings.validatorTypes, + function (validatorTemplateType, validatorTemplate) { + if (validators[validatorTemplateType] === undefined) { + validators[validatorTemplateType] = []; + } + if (!foundValidator && validatorType === validatorTemplateType.toLowerCase()) { + $this.data("validation" + el + formatValidatorName(validatorTemplate.name), validator[validatorTemplate.name.toLowerCase()]); + validators[validatorType].push( + $.extend( + validator, + validatorTemplate.init($this, el) + ) + ); + foundValidator = true; + } + } + ); + } + } + + if (! foundValidator) { + $.error("Cannot find validation info for '" + el + "'"); + } + }); + + // ============================================================= + // STORE FALLBACK VALUES + // ============================================================= + + $helpBlock.data( + "original-contents", + ( + $helpBlock.data("original-contents") + ? $helpBlock.data("original-contents") + : $helpBlock.html() + ) + ); + + $helpBlock.data( + "original-role", + ( + $helpBlock.data("original-role") + ? $helpBlock.data("original-role") + : $helpBlock.attr("role") + ) + ); + + $controlGroup.data( + "original-classes", + ( + $controlGroup.data("original-clases") + ? $controlGroup.data("original-classes") + : $controlGroup.attr("class") + ) + ); + + $this.data( + "original-aria-invalid", + ( + $this.data("original-aria-invalid") + ? $this.data("original-aria-invalid") + : $this.attr("aria-invalid") + ) + ); + + // ============================================================= + // VALIDATION + // ============================================================= + + $this.bind( + "validation.validation", + function (event, params) { + + var value = getValue($this); + + // Get a list of the errors to apply + var errorsFound = []; + + $.each(validators, function (validatorType, validatorTypeArray) { + if (value || value.length || (params && params.includeEmpty) || (!!settings.validatorTypes[validatorType].blockSubmit && params && !!params.submitting)) { + $.each(validatorTypeArray, function (i, validator) { + if (settings.validatorTypes[validatorType].validate($this, value, validator)) { + errorsFound.push(validator.message); + } + }); + } + }); + + return errorsFound; + } + ); + + $this.bind( + "getValidators.validation", + function () { + return validators; + } + ); + + // ============================================================= + // WATCH FOR CHANGES + // ============================================================= + $this.bind( + "submit.validation", + function () { + return $this.triggerHandler("change.validation", {submitting: true}); + } + ); + $this.bind( + [ + "keyup", + "focus", + "blur", + "click", + "keydown", + "keypress", + "change" + ].join(".validation ") + ".validation", + function (e, params) { + + var value = getValue($this); + + var errorsFound = []; + + $controlGroup.find("input,textarea,select").each(function (i, el) { + var oldCount = errorsFound.length; + $.each($(el).triggerHandler("validation.validation", params), function (j, message) { + errorsFound.push(message); + }); + if (errorsFound.length > oldCount) { + $(el).attr("aria-invalid", "true"); + } else { + var original = $this.data("original-aria-invalid"); + $(el).attr("aria-invalid", (original !== undefined ? original : false)); + } + }); + + $form.find("input,select,textarea").not($this).not("[name=\"" + $this.attr("name") + "\"]").trigger("validationLostFocus.validation"); + + errorsFound = $.unique(errorsFound.sort()); + + // Were there any errors? + if (errorsFound.length) { + // Better flag it up as a warning. + $controlGroup.removeClass("success error").addClass("warning"); + + // How many errors did we find? + if (settings.options.semanticallyStrict && errorsFound.length === 1) { + // Only one? Being strict? Just output it. + $helpBlock.html(errorsFound[0] + + ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); + } else { + // Multiple? Being sloppy? Glue them together into an UL. + $helpBlock.html("
  • " + errorsFound.join("
  • ") + "
" + + ( settings.options.prependExistingHelpBlock ? $helpBlock.data("original-contents") : "" )); + } + } else { + $controlGroup.removeClass("warning error success"); + if (value.length > 0) { + $controlGroup.addClass("success"); + } + $helpBlock.html($helpBlock.data("original-contents")); + } + + if (e.type === "blur") { + $controlGroup.removeClass("success"); + } + } + ); + $this.bind("validationLostFocus.validation", function () { + $controlGroup.removeClass("success"); + }); + }); + }, + destroy : function( ) { + + return this.each( + function() { + + var + $this = $(this), + $controlGroup = $this.parents(".form-group").first(), + $helpBlock = $controlGroup.find(".help-block").first(); + + // remove our events + $this.unbind('.validation'); // events are namespaced. + // reset help text + $helpBlock.html($helpBlock.data("original-contents")); + // reset classes + $controlGroup.attr("class", $controlGroup.data("original-classes")); + // reset aria + $this.attr("aria-invalid", $this.data("original-aria-invalid")); + // reset role + $helpBlock.attr("role", $this.data("original-role")); + // remove all elements we created + if (createdElements.indexOf($helpBlock[0]) > -1) { + $helpBlock.remove(); + } + + } + ); + + }, + collectErrors : function(includeEmpty) { + + var errorMessages = {}; + this.each(function (i, el) { + var $el = $(el); + var name = $el.attr("name"); + var errors = $el.triggerHandler("validation.validation", {includeEmpty: true}); + errorMessages[name] = $.extend(true, errors, errorMessages[name]); + }); + + $.each(errorMessages, function (i, el) { + if (el.length === 0) { + delete errorMessages[i]; + } + }); + + return errorMessages; + + }, + hasErrors: function() { + + var errorMessages = []; + + this.each(function (i, el) { + errorMessages = errorMessages.concat( + $(el).triggerHandler("getValidators.validation") ? $(el).triggerHandler("validation.validation", {submitting: true}) : [] + ); + }); + + return (errorMessages.length > 0); + }, + override : function (newDefaults) { + defaults = $.extend(true, defaults, newDefaults); + } + }, + validatorTypes: { + callback: { + name: "callback", + init: function ($this, name) { + return { + validatorName: name, + callback: $this.data("validation" + name + "Callback"), + lastValue: $this.val(), + lastValid: true, + lastFinished: true + }; + }, + validate: function ($this, value, validator) { + if (validator.lastValue === value && validator.lastFinished) { + return !validator.lastValid; + } + + if (validator.lastFinished === true) + { + validator.lastValue = value; + validator.lastValid = true; + validator.lastFinished = false; + + var rrjqbvValidator = validator; + var rrjqbvThis = $this; + executeFunctionByName( + validator.callback, + window, + $this, + value, + function (data) { + if (rrjqbvValidator.lastValue === data.value) { + rrjqbvValidator.lastValid = data.valid; + if (data.message) { + rrjqbvValidator.message = data.message; + } + rrjqbvValidator.lastFinished = true; + rrjqbvThis.data("validation" + rrjqbvValidator.validatorName + "Message", rrjqbvValidator.message); + // Timeout is set to avoid problems with the events being considered 'already fired' + setTimeout(function () { + rrjqbvThis.trigger("change.validation"); + }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst + } + } + ); + } + + return false; + + } + }, + ajax: { + name: "ajax", + init: function ($this, name) { + return { + validatorName: name, + url: $this.data("validation" + name + "Ajax"), + lastValue: $this.val(), + lastValid: true, + lastFinished: true + }; + }, + validate: function ($this, value, validator) { + if (""+validator.lastValue === ""+value && validator.lastFinished === true) { + return validator.lastValid === false; + } + + if (validator.lastFinished === true) + { + validator.lastValue = value; + validator.lastValid = true; + validator.lastFinished = false; + $.ajax({ + url: validator.url, + data: "value=" + value + "&field=" + $this.attr("name"), + dataType: "json", + success: function (data) { + if (""+validator.lastValue === ""+data.value) { + validator.lastValid = !!(data.valid); + if (data.message) { + validator.message = data.message; + } + validator.lastFinished = true; + $this.data("validation" + validator.validatorName + "Message", validator.message); + // Timeout is set to avoid problems with the events being considered 'already fired' + setTimeout(function () { + $this.trigger("change.validation"); + }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst + } + }, + failure: function () { + validator.lastValid = true; + validator.message = "ajax call failed"; + validator.lastFinished = true; + $this.data("validation" + validator.validatorName + "Message", validator.message); + // Timeout is set to avoid problems with the events being considered 'already fired' + setTimeout(function () { + $this.trigger("change.validation"); + }, 1); // doesn't need a long timeout, just long enough for the event bubble to burst + } + }); + } + + return false; + + } + }, + regex: { + name: "regex", + init: function ($this, name) { + return {regex: regexFromString($this.data("validation" + name + "Regex"))}; + }, + validate: function ($this, value, validator) { + return (!validator.regex.test(value) && ! validator.negative) + || (validator.regex.test(value) && validator.negative); + } + }, + required: { + name: "required", + init: function ($this, name) { + return {}; + }, + validate: function ($this, value, validator) { + return !!(value.length === 0 && ! validator.negative) + || !!(value.length > 0 && validator.negative); + }, + blockSubmit: true + }, + match: { + name: "match", + init: function ($this, name) { + var element = $this.parents("form").first().find("[name=\"" + $this.data("validation" + name + "Match") + "\"]").first(); + element.bind("validation.validation", function () { + $this.trigger("change.validation", {submitting: true}); + }); + return {"element": element}; + }, + validate: function ($this, value, validator) { + return (value !== validator.element.val() && ! validator.negative) + || (value === validator.element.val() && validator.negative); + }, + blockSubmit: true + }, + max: { + name: "max", + init: function ($this, name) { + return {max: $this.data("validation" + name + "Max")}; + }, + validate: function ($this, value, validator) { + return (parseFloat(value, 10) > parseFloat(validator.max, 10) && ! validator.negative) + || (parseFloat(value, 10) <= parseFloat(validator.max, 10) && validator.negative); + } + }, + min: { + name: "min", + init: function ($this, name) { + return {min: $this.data("validation" + name + "Min")}; + }, + validate: function ($this, value, validator) { + return (parseFloat(value) < parseFloat(validator.min) && ! validator.negative) + || (parseFloat(value) >= parseFloat(validator.min) && validator.negative); + } + }, + maxlength: { + name: "maxlength", + init: function ($this, name) { + return {maxlength: $this.data("validation" + name + "Maxlength")}; + }, + validate: function ($this, value, validator) { + return ((value.length > validator.maxlength) && ! validator.negative) + || ((value.length <= validator.maxlength) && validator.negative); + } + }, + minlength: { + name: "minlength", + init: function ($this, name) { + return {minlength: $this.data("validation" + name + "Minlength")}; + }, + validate: function ($this, value, validator) { + return ((value.length < validator.minlength) && ! validator.negative) + || ((value.length >= validator.minlength) && validator.negative); + } + }, + maxchecked: { + name: "maxchecked", + init: function ($this, name) { + var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); + elements.bind("click.validation", function () { + $this.trigger("change.validation", {includeEmpty: true}); + }); + return {maxchecked: $this.data("validation" + name + "Maxchecked"), elements: elements}; + }, + validate: function ($this, value, validator) { + return (validator.elements.filter(":checked").length > validator.maxchecked && ! validator.negative) + || (validator.elements.filter(":checked").length <= validator.maxchecked && validator.negative); + }, + blockSubmit: true + }, + minchecked: { + name: "minchecked", + init: function ($this, name) { + var elements = $this.parents("form").first().find("[name=\"" + $this.attr("name") + "\"]"); + elements.bind("click.validation", function () { + $this.trigger("change.validation", {includeEmpty: true}); + }); + return {minchecked: $this.data("validation" + name + "Minchecked"), elements: elements}; + }, + validate: function ($this, value, validator) { + return (validator.elements.filter(":checked").length < validator.minchecked && ! validator.negative) + || (validator.elements.filter(":checked").length >= validator.minchecked && validator.negative); + }, + blockSubmit: true + } + }, + builtInValidators: { + email: { + name: "Email", + type: "shortcut", + shortcut: "validemail" + }, + validemail: { + name: "Validemail", + type: "regex", + regex: "[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\\.[A-Za-z]{2,4}", + message: "Not a valid email address" + }, + passwordagain: { + name: "Passwordagain", + type: "match", + match: "password", + message: "Does not match the given password" + }, + positive: { + name: "Positive", + type: "shortcut", + shortcut: "number,positivenumber" + }, + negative: { + name: "Negative", + type: "shortcut", + shortcut: "number,negativenumber" + }, + number: { + name: "Number", + type: "regex", + regex: "([+-]?\\\d+(\\\.\\\d*)?([eE][+-]?[0-9]+)?)?", + message: "Must be a number" + }, + integer: { + name: "Integer", + type: "regex", + regex: "[+-]?\\\d+", + message: "No decimal places allowed" + }, + positivenumber: { + name: "Positivenumber", + type: "min", + min: 0, + message: "Must be a positive number" + }, + negativenumber: { + name: "Negativenumber", + type: "max", + max: 0, + message: "Must be a negative number" + }, + required: { + name: "Required", + type: "required", + message: "This is required" + }, + checkone: { + name: "Checkone", + type: "minchecked", + minchecked: 1, + message: "Check at least one option" + } + } + }; + + var formatValidatorName = function (name) { + return name + .toLowerCase() + .replace( + /(^|\s)([a-z])/g , + function(m,p1,p2) { + return p1+p2.toUpperCase(); + } + ) + ; + }; + + var getValue = function ($this) { + // Extract the value we're talking about + var value = $this.val(); + var type = $this.attr("type"); + if (type === "checkbox") { + value = ($this.is(":checked") ? value : ""); + } + if (type === "radio") { + value = ($('input[name="' + $this.attr("name") + '"]:checked').length > 0 ? value : ""); + } + return value; + }; + + function regexFromString(inputstring) { + return new RegExp("^" + inputstring + "$"); + } + + /** + * Thanks to Jason Bunting via StackOverflow.com + * + * http://stackoverflow.com/questions/359788/how-to-execute-a-javascript-function-when-i-have-its-name-as-a-string#answer-359910 + * Short link: http://tinyurl.com/executeFunctionByName + **/ + function executeFunctionByName(functionName, context /*, args*/) { + var args = Array.prototype.slice.call(arguments).splice(2); + var namespaces = functionName.split("."); + var func = namespaces.pop(); + for(var i = 0; i < namespaces.length; i++) { + context = context[namespaces[i]]; + } + return context[func].apply(this, args); + } + + $.fn.jqBootstrapValidation = function( method ) { + + if ( defaults.methods[method] ) { + return defaults.methods[method].apply( this, Array.prototype.slice.call( arguments, 1 )); + } else if ( typeof method === 'object' || ! method ) { + return defaults.methods.init.apply( this, arguments ); + } else { + $.error( 'Method ' + method + ' does not exist on jQuery.jqBootstrapValidation' ); + return null; + } + + }; + + $.jqBootstrapValidation = function (options) { + $(":input").not("[type=image],[type=submit]").jqBootstrapValidation.apply(this,arguments); + }; + +})( jQuery ); diff --git a/src/main/resources/templates/email/contact.html b/src/main/resources/templates/email/contact.html new file mode 100644 index 0000000..5d1ffd8 --- /dev/null +++ b/src/main/resources/templates/email/contact.html @@ -0,0 +1,16 @@ + + + + + Title + + + +

+

+

+ +

+ + + \ No newline at end of file diff --git a/src/main/resources/templates/index.html b/src/main/resources/templates/index.html new file mode 100644 index 0000000..3804d5b --- /dev/null +++ b/src/main/resources/templates/index.html @@ -0,0 +1,675 @@ + + + + + + + + + + + + Agency - Start Bootstrap Theme + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
Welcome To Our Studio!
+
It's Nice To Meet You
+ Tell Me More +
+
+
+ + +
+
+
+
+

Services

+

Lorem ipsum dolor sit amet consectetur.

+
+
+
+
+ + + + +

E-Commerce

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima maxime quam architecto quo inventore harum ex magni, dicta impedit.

+
+
+ + + + +

Responsive Design

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima maxime quam architecto quo inventore harum ex magni, dicta impedit.

+
+
+ + + + +

Web Security

+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minima maxime quam architecto quo inventore harum ex magni, dicta impedit.

+
+
+
+
+ + +
+
+
+
+

Portfolio

+

Lorem ipsum dolor sit amet consectetur.

+
+
+
+
+ +
+
+ +
+
+ +
+
+

Round Icons

+

Graphic Design

+
+
+
+ +
+
+ +
+
+ +
+
+

Startup Framework

+

Website Design

+
+
+
+ +
+
+ +
+
+ +
+
+

Treehouse

+

Website Design

+
+
+
+ +
+
+ +
+
+ +
+
+

Golden

+

Website Design

+
+
+
+ +
+
+ +
+
+ +
+
+

Escape

+

Website Design

+
+
+
+ +
+
+ +
+
+ +
+
+

Dreams

+

Website Design

+
+
+
+
+
+ + +
+
+
+
+

About

+

Lorem ipsum dolor sit amet consectetur.

+
+
+
+
+
    +
  • +
    + +
    +
    +
    +

    2009-2011

    +

    Our Humble Beginnings

    +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt ut voluptatum eius sapiente, totam reiciendis temporibus qui quibusdam, recusandae sit vero unde, sed, incidunt et ea quo dolore laudantium consectetur!

    +
    +
    +
  • +
  • +
    + +
    +
    +
    +

    March 2011

    +

    An Agency is Born

    +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt ut voluptatum eius sapiente, totam reiciendis temporibus qui quibusdam, recusandae sit vero unde, sed, incidunt et ea quo dolore laudantium consectetur!

    +
    +
    +
  • +
  • +
    + +
    +
    +
    +

    December 2012

    +

    Transition to Full Service

    +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt ut voluptatum eius sapiente, totam reiciendis temporibus qui quibusdam, recusandae sit vero unde, sed, incidunt et ea quo dolore laudantium consectetur!

    +
    +
    +
  • +
  • +
    + +
    +
    +
    +

    July 2014

    +

    Phase Two Expansion

    +
    +
    +

    Lorem ipsum dolor sit amet, consectetur adipisicing elit. Sunt ut voluptatum eius sapiente, totam reiciendis temporibus qui quibusdam, recusandae sit vero unde, sed, incidunt et ea quo dolore laudantium consectetur!

    +
    +
    +
  • +
  • +
    +

    Be Part +
    Of Our +
    Story!

    +
    +
  • +
+
+
+
+
+ + +
+
+
+
+

Our Amazing Team

+

Lorem ipsum dolor sit amet consectetur.

+
+
+
+
+
+ +

Kay Garland

+

Lead Designer

+ +
+
+
+
+ +

Larry Parker

+

Lead Marketer

+ +
+
+
+
+ +

Diana Pertersen

+

Lead Developer

+ +
+
+
+
+
+

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aut eaque, laboriosam veritatis, quos non quis ad perspiciatis, totam corporis ea, alias ut unde.

+
+
+
+
+ + + + + +
+
+
+
+

Contact Us

+

Lorem ipsum dolor sit amet consectetur.

+
+
+
+
+
+
+
+
+
+ +

+
+
+ +

+
+
+ +

+
+
+
+
+ +

+
+
+ +

+
+
+
+
+
+ +
+
+
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file