├── .gitignore ├── .gradle └── 1.0-milestone-3 │ └── taskArtifacts │ ├── cache.bin │ └── cache.properties ├── README ├── build.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── sample.iml └── src ├── DSLD_meta_script.dsld ├── functionalTest └── groovy │ ├── GebConfig.groovy │ └── SmokeSpec.groovy ├── gaelyk.dsld ├── gaelyk.gdsl ├── main ├── bloogaey.iml ├── groovy │ └── bloogy │ │ └── Utilities.groovy └── webapp │ ├── WEB-INF │ ├── appengine-web.xml │ ├── groovy │ │ ├── __testMailParsing2__.groovy │ │ ├── __testMailParsing__.groovy │ │ ├── admin │ │ │ ├── adminCategories.groovy │ │ │ ├── adminMedia.groovy │ │ │ ├── adminPosts.groovy │ │ │ ├── categoryAdd.groovy │ │ │ ├── categoryDelete.groovy │ │ │ ├── clearCache.groovy │ │ │ ├── email.groovy │ │ │ ├── mediaAdd.groovy │ │ │ ├── mediaDelete.groovy │ │ │ ├── mediaSelector.groovy │ │ │ ├── postDelete.groovy │ │ │ ├── postSave.groovy │ │ │ └── titleExists.groovy │ │ ├── archive.groovy │ │ ├── article.groovy │ │ ├── category.groovy │ │ ├── error.groovy │ │ ├── feed.groovy │ │ ├── home.groovy │ │ ├── media.groovy │ │ ├── search.groovy │ │ ├── social.groovy │ │ └── viewRawEmail.groovy │ ├── includes │ │ ├── bottom.gtpl │ │ ├── footer.gtpl │ │ ├── header.gtpl │ │ ├── left.gtpl │ │ ├── meta.gtpl │ │ ├── navigation.gtpl │ │ └── syntaxHighlighting.gtpl │ ├── lib │ │ ├── antlr-2.7.7.jar │ │ ├── appengine-api-1.0-sdk-1.8.0.jar │ │ ├── appengine-api-labs-1.8.0.jar │ │ ├── asm-4.0.jar │ │ ├── asm-analysis-4.0.jar │ │ ├── asm-commons-4.0.jar │ │ ├── asm-tree-4.0.jar │ │ ├── asm-util-4.0.jar │ │ ├── gaelyk-2.0.jar │ │ ├── groovy-2.1.3.jar │ │ ├── groovy-all-2.1.3.jar │ │ ├── groovy-json-2.1.3.jar │ │ ├── groovy-servlet-2.1.3.jar │ │ ├── groovy-templates-2.1.3.jar │ │ ├── groovy-xml-2.1.3.jar │ │ ├── ocpsoft-pretty-time-1.0.7.jar │ │ └── servlet-api-2.5.jar │ ├── logging.properties │ ├── pages │ │ ├── admin │ │ │ ├── adminCategories.gtpl │ │ │ ├── adminMedia.gtpl │ │ │ ├── adminPosts.gtpl │ │ │ └── postEdit.gtpl │ │ ├── archive.gtpl │ │ ├── article.gtpl │ │ ├── error.gtpl │ │ ├── home.gtpl │ │ ├── notAllowed.gtpl │ │ ├── notFound.gtpl │ │ ├── search.gtpl │ │ └── social.gtpl │ ├── routes.groovy │ └── web.xml │ ├── css │ ├── chosen.css │ ├── google-search.css │ ├── idea.css │ ├── jquery.cleditor.css │ ├── stabs.css │ ├── style.css │ └── wysiwyg.css │ ├── images │ ├── add.png │ ├── atom.gif │ ├── box.gif │ ├── buttons.gif │ ├── chosen-sprite.png │ ├── clipboard.png │ ├── content-two-columns.gif │ ├── content-wrapper.gif │ ├── cross.png │ ├── feed.png │ ├── footer-wrapper.gif │ ├── gaelyk-favicon.png │ ├── gradient-light.gif │ ├── header-wrapper-2.gif │ ├── header.gif │ ├── help.gif │ ├── icon-delicious.png │ ├── icon-gplus.png │ ├── icon-greader.png │ ├── icon-twitter.png │ ├── image-not-found.png │ ├── images.png │ ├── images2.png │ ├── navigation-arrow-2.gif │ ├── navigation-arrow.gif │ ├── navigation-wrapper-2.gif │ ├── navigation.gif │ ├── newspaper.png │ ├── page_white_text.png │ ├── pencil.png │ ├── sample-gravatar.jpg │ ├── separator-vertical.gif │ ├── subnav-wrapper-2.gif │ ├── subnav-wrapper.gif │ ├── toolbar.gif │ └── transparent.png │ ├── js │ ├── chosen.jquery.min.js │ ├── highlight.js │ ├── highlight.pack.js │ ├── jquery-1.6.2.min.js │ ├── jquery.cleditor.js │ ├── jquery.sTabs.min.js │ ├── languages │ │ ├── css.js │ │ ├── diff.js │ │ ├── go.js │ │ ├── groovy.js │ │ ├── haskell.js │ │ ├── ini.js │ │ ├── java.js │ │ ├── javascript.js │ │ ├── lisp.js │ │ ├── objectivec.js │ │ ├── perl.js │ │ ├── php.js │ │ ├── python.js │ │ ├── ruby.js │ │ ├── scala.js │ │ ├── smalltalk.js │ │ ├── sql.js │ │ ├── vbscript.js │ │ └── xml.js │ ├── mediaChoserPlugin.js │ └── postEdit.js │ ├── msg.txt │ ├── robots.txt │ └── sitemap.xml └── test └── groovy ├── RegisterSpec.groovy └── RoutesSpec.groovy /.gitignore: -------------------------------------------------------------------------------- 1 | appengine-generated 2 | classes 3 | build 4 | webapp/WEB-INF/lib 5 | out 6 | *.iml 7 | *.ipr 8 | *.iws 9 | *.swp 10 | *.*~ 11 | .vim 12 | .idea 13 | .gradle 14 | /.settings 15 | /.classpath 16 | /.project 17 | 18 | -------------------------------------------------------------------------------- /.gradle/1.0-milestone-3/taskArtifacts/cache.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/.gradle/1.0-milestone-3/taskArtifacts/cache.bin -------------------------------------------------------------------------------- /.gradle/1.0-milestone-3/taskArtifacts/cache.properties: -------------------------------------------------------------------------------- 1 | #Thu Jul 28 16:50:19 CEST 2011 2 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Bloogaey (pronounced "bloogie") is a small blog engine written in Groovy, using the Gaelyk lightweight toolkit for Google App Engine. 2 | You can have a look at Gaelyk on GitHub: https://github.com/glaforge/gaelyk 3 | A demo can be seen on Guillaume Laforge's blog: http://glaforge.appspot.com 4 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'gaelyk' 2 | apply plugin: 'gae-geb' 3 | apply plugin: 'eclipse' 4 | apply plugin: 'idea' 5 | 6 | def compatibilityVersion = 1.7 7 | sourceCompatibility = compatibilityVersion 8 | targetCompatibility = compatibilityVersion 9 | 10 | buildscript { 11 | repositories { 12 | mavenCentral() 13 | } 14 | 15 | dependencies { 16 | classpath 'org.gradle.api.plugins:gradle-gaelyk-plugin:0.4.1' 17 | classpath 'org.gradle.api.plugins:gradle-gae-plugin:0.8', { 18 | exclude module: "gradle-fatjar-plugin" 19 | } 20 | classpath 'eu.appsatori:gradle-fatjar-plugin:0.2-rc1' 21 | classpath 'org.gradle.api.plugins:gradle-gae-geb-plugin:0.3' 22 | } 23 | } 24 | 25 | repositories { 26 | mavenCentral() 27 | mavenLocal() 28 | } 29 | 30 | /* 31 | configurations { 32 | precompile 33 | } 34 | 35 | gaelykPrecompileGroovlet.runtimeClasspath += project.configurations.precompile 36 | gaelykPrecompileTemplate.runtimeClasspath += project.configurations.precompile 37 | */ 38 | 39 | dependencies { 40 | def gaeVersion = '1.8.0' 41 | def groovyVersion = '2.1.3' 42 | groovy "org.codehaus.groovy:groovy-all:${groovyVersion}" 43 | // precompile "org.codehaus.groovy:groovy-ant:${groovyVersion}" 44 | // precompile "org.ow2.asm:asm:4.0" 45 | // precompile "commons-cli:commons-cli:1.2" 46 | compile "org.codehaus.groovy:groovy-json:${groovyVersion}" 47 | compile "org.codehaus.groovy:groovy-servlet:${groovyVersion}" 48 | compile "com.google.appengine:appengine-api-1.0-sdk:$gaeVersion", 49 | "com.google.appengine:appengine-api-labs:$gaeVersion" 50 | compile 'org.gaelyk:gaelyk:2.0' 51 | compile "com.ocpsoft:ocpsoft-pretty-time:1.0.7" 52 | 53 | 54 | /** 55 | * To add binary plugin just declare it as a dependency. For example, 56 | * uncomment following to add GPars support to your Gaelyk project. 57 | * @see https://github.com/musketyr/gpars-appengine 58 | */ 59 | // compile 'org.codehaus.gpars:gpars-appengine:0.1' 60 | 61 | /** 62 | * Gaelyk console serves as playground or key-hole surgery tool for 63 | * your application 64 | * @see https://github.com/gaelyk/gaelyk-console 65 | */ 66 | // compile 'org.gaelyk:gaelyk-console:2.0' 67 | 68 | testCompile 'org.gaelyk:gaelyk-spock:0.4' 69 | testCompile "com.google.appengine:appengine-api-stubs:$gaeVersion", 70 | "com.google.appengine:appengine-testing:$gaeVersion" 71 | 72 | functionalTestCompile 'org.codehaus.geb:geb-spock:0.7.0', 73 | 'org.seleniumhq.selenium:selenium-firefox-driver:2.22.0' 74 | gaeSdk "com.google.appengine:appengine-java-sdk:$gaeVersion" 75 | } 76 | 77 | idea { 78 | project { 79 | jdkName = compatibilityVersion 80 | 81 | ipr.withXml { provider -> 82 | def node = provider.asNode() 83 | 84 | // Set Gradle home 85 | def gradleSettings = node.appendNode('component', [name: 'GradleSettings']) 86 | gradleSettings.appendNode('option', [name: 'SDK_HOME', value: gradle.gradleHomeDir]) 87 | } 88 | } 89 | } 90 | 91 | eclipse { 92 | project { 93 | name 'gaelyk-project' 94 | file { 95 | whenMerged { project -> 96 | project.natures << 'com.google.appengine.eclipse.core.gaeNature' 97 | project.natures << 'com.google.gdt.eclipse.core.webAppNature' 98 | project.buildCommands << [name: 'com.google.appengine.eclipse.core.enhancerbuilder'] 99 | project.buildCommands << [name: 'com.google.appengine.eclipse.core.projectValidator'] 100 | project.buildCommands << [name: 'com.google.gdt.eclipse.core.webAppProjectValidator'] 101 | } 102 | } 103 | } 104 | classpath { 105 | file { 106 | withXml { xml -> 107 | xml.asNode().classpathentry.find { it.@kind == 'output' && it.@path == 'bin' }.@path = 'src/main/webapp/WEB-INF/classes' 108 | xml.asNode().appendNode('classpathentry', [kind: 'con', path: 'com.google.appengine.eclipse.core.GAE_CONTAINER']) 109 | .appendNode('attributes') 110 | .appendNode('attribute', [name: 'org.eclipse.jst.component.nondependency', value: '/src/main/webapp/WEB-INF/lib']) 111 | xml.asNode().appendNode('classpathentry', [exported: 'true', kind: 'con', path: 'GROOVY_SUPPORT']) 112 | .appendNode('attributes') 113 | .appendNode('attribute', [name: 'org.eclipse.jst.component.nondependency', value: '/src/main/webapp/WEB-INF/lib']) 114 | } 115 | } 116 | } 117 | } 118 | 119 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Fri May 17 00:02:30 CEST 2013 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /sample.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | /Library/GoogleAppEngine 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/DSLD_meta_script.dsld: -------------------------------------------------------------------------------- 1 | import org.codehaus.groovy.ast.ASTNode 2 | import org.codehaus.groovy.ast.ClassNode 3 | import org.codehaus.groovy.ast.expr.MapEntryExpression 4 | 5 | /** 6 | * This is the meta DSL descriptor for *.dsld files. 7 | */ 8 | 9 | // first thing to do is to check that versions are correct 10 | // for this script to be evaluated any further, all conditions must be met 11 | // also supports grailsTooling and sts, which are synonyms and correspond to the STS version eg- 2.6.0 12 | // we can add more version checking on request 13 | supportsVersion(groovy:"1.7.8",groovyEclipse:"2.1.3") 14 | 15 | interface IPointcut { 16 | /** 17 | * Accepts a contribution group to this Pointcut. What this means 18 | * is that whenever this pointcut evaluates to a match, then the 19 | * contribution group is evaluated with the bindings that have 20 | * been generated from the pointcut match 21 | * 22 | * @param c the contribution group to accept 23 | */ 24 | def accept(Closure c); 25 | } 26 | 27 | 28 | // You can store shared pointcuts in a variable 29 | // This particular pointcut matches all join points that are inside of a 30 | // groovy project and inside a file with a *.dsld extension and are scripts 31 | def dsldFile = nature("org.eclipse.jdt.groovy.core.groovyNature") & fileExtension("dsld") & isScript() 32 | 33 | // You can also create a closure around pointcuts and assign them to 34 | // a variable. Note that when using these variables, you must include parens. 35 | def insideContribution = { enclosingCallName("accept") & inClosure() } 36 | 37 | // Ensure that the 'accept' method is available for all closures and variables that correspond to pointcuts 38 | (dsldFile & ( ~ insideContribution() ) & ( ~currentType(subType(Script)) )).accept { 39 | delegatesTo IPointcut 40 | } 41 | 42 | // here we store all bound names inside of the wormhole so that they can be available later 43 | (dsldFile & enclosingCallDeclaringType(subType(Script)) & (~ enclosingCallName("supportsVersion")) & 44 | ( ~ inClosure() ) & bind(var : currentIdentifier())).accept { 45 | if (enclosingNode instanceof MapEntryExpression && 46 | var.contains(((MapEntryExpression) enclosingNode).keyExpression)) { 47 | def bindings = wormhole.bindings 48 | if (!bindings) { 49 | bindings = [ ] 50 | wormhole.bindings = bindings 51 | } 52 | var.each { bindings << it.text } 53 | } 54 | } 55 | 56 | // Define the kinds of pointcuts 57 | // note the different ways of calling the two composite pointcuts 58 | // Also, be careful to use parens around negation '~' since operator precedence may make the '~' apply to the call to 'accept' 59 | (dsldFile & ( ~ insideContribution() ) & currentType(subType(Script)) & (~enclosingCallName("registerPointcut")) & 60 | currentTypeIsEnclosingType()).accept { 61 | provider = "the meta-DSLD script" 62 | 63 | // in here, we can list all pointcuts explicitly, or we can access the internal PointcutFactory object 64 | // A little bit naughty, but this is the easiest way to maintain consistency with all possible pointcuts 65 | // ...the PointcutFactory class is a secret class that is declared by groovy-eclipse 66 | // Yes, you can use many Eclipse classes here. The editor won't like them, so they must be fully qualified 67 | // and you cannot import them or use them as types for variables 68 | Map pointcutNames = org.codehaus.groovy.eclipse.dsl.script.PointcutFactory.docRegistry 69 | for (pointcutName in pointcutNames.entrySet()) { 70 | method name : pointcutName.key, type: IPointcut, params : [pointcutArg : Object], doc : pointcutName.value 71 | } 72 | 73 | method name : "supportsVersion", type : void, params : [versionKindToName : Map.class ], 74 | doc : '''Specifies that this script is only active when the specified version constraints are met. 75 | Currently, only 3 constraints are available: groovy, groovyEclipse, sts, and grailsTooling.

76 | Use like this: 77 |
supportsVersion(groovy:"1.7.10",groovyEclipse:"2.1.3")
78 | This means that the current scipt requires both Groovy 1.7.10 or later and Groovy-Eclipse 2.1.3 or later''' 79 | 80 | method name : "registerPointcut", type : void, params : [name : String, pointcutBody : Closure], 81 | doc : ''' 82 | Registers a custom pointcut. This pointcut is only available from within the current script. 83 | You must specify a name for the pointcut as well as a closure that evaluates whether or not there is a match''' 84 | 85 | } 86 | 87 | // Here, specify everything that can be used inside of an accept block (also called a Contribution Group) 88 | (dsldFile & insideContribution()).accept { 89 | provider = "the meta-DSLD script" 90 | property name : "provider", type : String, doc : """Specifies a Provider for the current contribution. 91 | This provider is displayed during content assist and in other places to give a quick hint as to where this 92 | contribution elementcomes from.""" 93 | method name : "property", 94 | useNamedArgs : true, 95 | params : [name : String, 96 | type : Object, 97 | isStatic : boolean, 98 | declaringType : Object, 99 | provider: String, 100 | doc : String], 101 | doc : """ 102 | Specifies a new property contribution. name is mandatory, but all other parameters are optional. 103 | """ 104 | 105 | method name : "method", 106 | useNamedArgs : true, 107 | params : [name : String, 108 | type : Object, 109 | params : Map, 110 | useNamedArgs : boolean, 111 | isStatic : boolean, 112 | declaringType : Object, 113 | provider: String, 114 | doc : String], 115 | doc : """ 116 | Specifies a new method contribution. name is mandatory, but all other parameters are optional. 117 | """ 118 | 119 | method name : "delegatesTo", params : [ type : Object ], doc : """ 120 | Specify that the currentType delegates tp the given type. The currentType is the type being analyzed. 121 | And the given type is specified as a parameter (either a String, Class, or ClassNode). All fields and 122 | methods of the given type will be available from the currentType. 123 | """ 124 | method name : "delegatesToUseNamedArgs", params : [ type : Object ], doc : """ 125 | Specify that the currentType delegates tp the given type. The currentType is the type being analyzed. 126 | And the given type is specified as a parameter (either a String, Class, or ClassNode). All fields and 127 | methods of the given type will be available from the currentType.

128 | Named arguments will be used for all methods. 129 | """ 130 | 131 | property name : "wormhole", type : Map, doc : """Use the wormhole to stuff in values calculated in one contribution group 132 | to make it available later in another contribution group""" 133 | 134 | property name : "currentType", type : ClassNode, 135 | doc : "This is the declaring type of the current expression being evaluated." 136 | property name : "currentNode", type : ASTNode, doc : "This is the ASTNode being evaluated" 137 | property name : "enclosingNode", type : ASTNode, doc : "This is the ASTNode enclosing the ASTNode being evaluated" 138 | 139 | // Now, extract all bindings from the wormhole and add them as contributions 140 | for (binding in wormhole.bindings) { 141 | property name : binding, doc : "Binding created from pointcut" 142 | } 143 | } 144 | 145 | // Add the contributions for inside a "registerPointcut" call. User-registered pointcuts are 146 | // not fully fleshed out yet, so best not to use them yet. 147 | (dsldFile & inClosure() & enclosingCallName("registerPointcut")).accept { 148 | property name : "currentScope", type : org.eclipse.jdt.groovy.search.VariableScope 149 | property name : "currenType", type : ClassNode 150 | } -------------------------------------------------------------------------------- /src/functionalTest/groovy/GebConfig.groovy: -------------------------------------------------------------------------------- 1 | baseUrl = 'http://localhost:8080/' 2 | -------------------------------------------------------------------------------- /src/functionalTest/groovy/SmokeSpec.groovy: -------------------------------------------------------------------------------- 1 | import geb.spock.GebSpec 2 | import geb.Browser 3 | import groovyx.net.http.RESTClient 4 | import spock.lang.Shared 5 | import groovyx.gaelyk.logging.GroovyLogger 6 | 7 | class SmokeSpec extends GebSpec { 8 | 9 | @Shared 10 | def log = new GroovyLogger("myLogger") 11 | 12 | @Shared 13 | private def restUrl = "${browser.baseUrl}gcm/register/" 14 | 15 | @Shared 16 | private def client = new RESTClient() 17 | 18 | void "main page title should be 'SimpleSMS'"() { 19 | when: 20 | go 'http://localhost:8080' 21 | 22 | then: 23 | title == "SimpleSMS" 24 | } 25 | 26 | void "verify grm register with rest"() { 27 | when: 28 | log.info "******** URL $restUrl" 29 | //def resp = client.post(uri: restUrl, path: "person/${personId}.json") 30 | def resp = client.post(uri: restUrl) 31 | assert resp.status == 200 32 | assert resp.contentType == "application/json" 33 | def json = resp.data 34 | 35 | then: 36 | assert json.status == "ERROR" 37 | assert json.code == "99" 38 | assert json.message == "INVALID PARAMETES" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/gaelyk.gdsl: -------------------------------------------------------------------------------- 1 | def all = context(scope: scriptScope(), filetypes: ['groovy', 'gtpl']) 2 | 3 | def jabber = context(scope: scriptScope(name: 'jabber.groovy')) 4 | def mail = context(scope: scriptScope(name: 'email.groovy')) 5 | 6 | def routes = context(scope: scriptScope(name: 'routes.groovy')) 7 | 8 | contributor([all, jabber, mail]) { 9 | property name: "request", type: "javax.servlet.http.HttpServletRequest" 10 | property name: "response", type: "javax.servlet.http.HttpServletResponse" 11 | property name: "context", type: "javax.servlet.ServletContext" 12 | property name: "application", type: "javax.servlet.ServletContext" 13 | property name: "session", type: "javax.servlet.http.HttpSession" 14 | property name: "params", type: "java.util.Map" 15 | property name: "headers", type: "java.util.Map" 16 | property name: "out", type: "java.io.PrintWriter" 17 | property name: "sout", type: "javax.servlet.ServletOutputStream" 18 | property name: "html", type: "groovy.xml.MarkupBuilder" 19 | } 20 | 21 | contributor([all, jabber, mail, routes]) { 22 | property name: "app", type: "java.util.Map" 23 | property name: "queues", type: "com.google.appengine.api.labs.taskqueue.Queue" 24 | property name: "defaultQueue", type: "com.google.appengine.api.labs.taskqueue.Queue" 25 | property name: "mail", type: "com.google.appengine.api.mail.MailService" 26 | property name: "namespace", type: "com.google.appengine.api.NamespaceManager" 27 | property name: "logger", type: "groovyx.gaelyk.logging.LoggerAccessor" 28 | property name: "log", type: "groovyx.gaelyk.logging.GroovyLogger" 29 | 30 | property name: "datastore", type: "com.google.appengine.api.datastore.DatastoreService" 31 | property name: "memcache", type: "com.google.appengine.api.memcache.MemcacheService" 32 | property name: "urlFetch", type: "com.google.appengine.api.urlfetch.URLFetchService" 33 | property name: "images", type: "groovyx.gaelyk.ImagesServiceWrapper" 34 | property name: "users", type: "com.google.appengine.api.users.UserService" 35 | property name: "user", type: "com.google.appengine.api.users.User" 36 | property name: "xmpp", type: "com.google.appengine.api.xmpp.XMPPService" 37 | property name: "blobstore", type: "com.google.appengine.api.blobstore.BlobstoreService" 38 | property name: "oauth", type: "com.google.appengine.api.oauth.OAuthService" 39 | 40 | property name: "localMode", type: "java.lang.Boolean" 41 | 42 | method name: 'forward', type: 'void', params: [path: 'java.lang.String'] 43 | method name: 'include', type: 'void', params: [path: 'java.lang.String'] 44 | method name: 'redirect', type: 'void', params: [path: 'java.lang.String'] 45 | } 46 | 47 | contributor([jabber]) { 48 | property name: "message", type: "com.google.appengine.api.xmpp.Message" 49 | } 50 | 51 | contributor([mail]) { 52 | property name: "message", type: "javax.mail.MimeMessage" 53 | } 54 | 55 | contributor([routes]) { 56 | 57 | } -------------------------------------------------------------------------------- /src/main/bloogaey.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | /Library/GoogleAppEngine 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /src/main/groovy/bloogy/Utilities.groovy: -------------------------------------------------------------------------------- 1 | package bloogy 2 | 3 | import com.ocpsoft.pretty.time.PrettyTime 4 | import java.text.Normalizer 5 | 6 | class Utilities { 7 | 8 | /** 9 | * Transform a post article into a simplified url-friendly string. 10 | * "Cool! A groovy, very groovy, title :-)" is transformed into "cool-a-groovy-very-groovy-title 11 | */ 12 | static String streamline(String title) { 13 | Normalizer.normalize(title, Normalizer.Form.NFD) 14 | .replaceAll("\\p{InCombiningDiacriticalMarks}+", "") 15 | .replaceAll(/\W+/, '-') 16 | .replaceAll(/(-+$|^-+)/, '') 17 | .toLowerCase() 18 | } 19 | 20 | static String pretty(Date date) { 21 | new PrettyTime().format(date) 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/appengine-web.xml: -------------------------------------------------------------------------------- 1 | 2 | bloogaey 3 | 4 | 1 5 | 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | mail 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | true 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/__testMailParsing2__.groovy: -------------------------------------------------------------------------------- 1 | import javax.mail.internet.MimeMessage 2 | import javax.mail.Session 3 | import javax.mail.Authenticator 4 | import javax.mail.internet.MimeMultipart 5 | 6 | def msg = new MimeMessage(new Session(new Properties(), new Authenticator() {}), new FileInputStream('msg.txt')) 7 | 8 | def sb = new StringBuilder() 9 | 10 | def handleMultipart 11 | handleMultipart = { MimeMultipart mmp -> 12 | for (int i = 0; i < mmp.count; i++) { 13 | def part = mmp.getBodyPart(i) 14 | if (part.content instanceof MimeMultipart) { 15 | handleMultipart(part.content) 16 | } else { 17 | if (part.contentType.contains('text/plain')) { 18 | 19 | } else if (part.contentType.contains('text/html')) { 20 | 21 | } else if (part.contentType.contains('image/')) { 22 | 23 | } else { 24 | 25 | } 26 | } 27 | } 28 | } 29 | 30 | handleMultipart(msg.content) 31 | 32 | out << sb.toString() 33 | 34 | 35 | /* 36 | 37 | mixed 38 | related 39 | alternative 40 | text/plain 41 | text/html 42 | image-png (inline) 43 | image-png (attachment) 44 | 45 | 46 | */ 47 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/__testMailParsing__.groovy: -------------------------------------------------------------------------------- 1 | import javax.mail.internet.MimeMessage 2 | import javax.mail.Session 3 | import javax.mail.Authenticator 4 | import javax.mail.internet.MimeMultipart 5 | 6 | def msg = new MimeMessage(new Session(new Properties(), new Authenticator() {}), new FileInputStream('msg.txt')) 7 | 8 | html.html { 9 | head { 10 | title "Parsed email from GMail" 11 | } 12 | body { 13 | handleMultipart(msg.content) 14 | } 15 | } 16 | 17 | def handleMultipart(MimeMultipart mmp) { 18 | html.div "Parts: ${mmp.count}" 19 | html.div "Content-type: ${mmp.contentType}" 20 | 21 | for (int i = 0; i < mmp.count; i++) { 22 | def part = mmp.getBodyPart(i) 23 | html.h1 "Part #$i: ${part}" 24 | html.h2 "Content ID: ${part.getHeader('Content-ID')}" 25 | html.h2 "X-Attachment ID: ${part.getHeader('X-Attachment-Id')}" 26 | html.h2 "Content-type: $part.contentType" 27 | html.h2 "Content-disposition: $part.disposition" 28 | html.h2 "File name: ${part.fileName}" 29 | if (part.content instanceof MimeMultipart) { 30 | html.blockquote { 31 | handleMultipart(part.content) 32 | } 33 | } else { 34 | if (part.contentType.contains('text/plain')) { 35 | html.mkp.yieldUnescaped part.content 36 | } else if (part.contentType.contains('text/html')) { 37 | html.mkp.yieldUnescaped part.content 38 | } else if (part.contentType.contains('image/')) { 39 | html.img src:"data:${part.contentType.find('image/(.*);')}base64,${part.content.bytes.encodeBase64()}" 40 | } else { 41 | html.mkp.yieldUnescaped part.content.bytes.encodeBase64() 42 | } 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/adminCategories.groovy: -------------------------------------------------------------------------------- 1 | 2 | request.categories = datastore.execute { 3 | from categories 4 | sort asc by name 5 | } 6 | 7 | request.categoriesCount = request.categories.collectEntries { category -> 8 | [(category): datastore.execute { 9 | select count 10 | from posts 11 | where categories == category.name 12 | }] 13 | } 14 | 15 | forward '/WEB-INF/pages/admin/adminCategories.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/adminMedia.groovy: -------------------------------------------------------------------------------- 1 | 2 | forward '/WEB-INF/pages/admin/adminMedia.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/adminPosts.groovy: -------------------------------------------------------------------------------- 1 | 2 | request.posts = datastore.execute { 3 | from posts 4 | sort desc by created 5 | where draft == false 6 | and type == 'post' 7 | } 8 | 9 | request.pages = datastore.execute { 10 | from posts 11 | sort desc by created 12 | where draft == false 13 | and type == 'page' 14 | } 15 | 16 | request.drafts = datastore.execute { 17 | from posts 18 | sort desc by created 19 | where draft == true 20 | } 21 | 22 | forward '/WEB-INF/pages/admin/adminPosts.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/categoryAdd.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.datastore.Entity 2 | 3 | def categoryName = params.categoryName 4 | def categoryDescription = params.categoryDescription 5 | 6 | new Entity('categories').with { 7 | name = categoryName 8 | description = categoryDescription 9 | save() 10 | } 11 | 12 | redirect '/admin/categories' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/categoryDelete.groovy: -------------------------------------------------------------------------------- 1 | 2 | datastore.execute { select single from categories where name == params.categoryName }.delete() 3 | 4 | redirect '/admin/categories' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/clearCache.groovy: -------------------------------------------------------------------------------- 1 | 2 | memcache.clearCacheForUri '/' 3 | memcache.clearCacheForUri '/archives' 4 | 5 | 100.times { 6 | memcache.clearCacheForUri "/p${it}" 7 | memcache.clearCacheForUri "/archives/p${it}" 8 | } 9 | 10 | memcache.clearCacheForUri '/search' 11 | memcache.clearCacheForUri '/social' 12 | 13 | memcache.clearCacheForUri '/feed/atom' 14 | 15 | datastore.execute { 16 | from posts 17 | sort desc by created 18 | where draft == false 19 | }.each { 20 | memcache.clearCacheForUri "/${it.type == 'post' ? 'article' : 'page'}/${it.key.name}" 21 | } 22 | 23 | datastore.execute { 24 | from categories 25 | sort asc by name 26 | }.each { 27 | memcache.clearCacheForUri "/category/${it.name}" 28 | memcache.clearCacheForUri "/feed/atom/${it.name}" 29 | } 30 | 31 | redirect '/admin/posts' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/email.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.datastore.Entity 2 | import javax.mail.internet.MimeMultipart 3 | import javax.mail.BodyPart 4 | import javax.mail.internet.MimeMessage 5 | 6 | def content = request.inputStream.text 7 | new Entity('email').with { 8 | rawContent = content 9 | save() 10 | } 11 | 12 | MimeMessage msg = mail.parseMessage(request) 13 | 14 | log.info "Subject ${msg.subject}, to ${msg.allRecipients.join(', ')}, from ${msg.from[0]}" 15 | 16 | String fullContent = "" 17 | 18 | msg.contentStream.withReader { Reader reader -> 19 | fullContent = reader.text 20 | } 21 | 22 | def sb = new StringBuilder() 23 | 24 | if (msg.content instanceof String) { 25 | log.info "Received a string" 26 | sb << msg.content 27 | } else if (msg.content instanceof MimeMultipart) { 28 | log.info "Received a mime multipart" 29 | for (int i = 0; i < msg.content.count; i++) { 30 | BodyPart part = msg.content.getBodyPart(i) 31 | log.info("Part $i: $part") 32 | log.info("Content: " + part.content) 33 | sb << part.content 34 | } 35 | } 36 | 37 | log.info "ALL: ${sb.toString()}" 38 | 39 | new Entity('posts').with { 40 | title = msg.subject 41 | urlTitle = msg.subject.streamline() 42 | created = new Date() 43 | categories = [] 44 | draft = false 45 | type = 'post' 46 | 47 | content = "
$fullContent
" 48 | 49 | save() 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/mediaAdd.groovy: -------------------------------------------------------------------------------- 1 | 2 | def blobs = blobstore.getUploadedBlobs(request) 3 | def blob = blobs["fileName"] 4 | 5 | redirect '/admin/media' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/mediaDelete.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.blobstore.BlobKey 2 | 3 | new BlobKey(params.blobKey).delete() 4 | 5 | def page = params.page.toInteger() 6 | 7 | def singleOnPage = params.singleOnPage == 'true' 8 | if (singleOnPage && page > 0) page -= 1 9 | 10 | redirect "/admin/media${page > 0 ? "/p${params.page}" : ''}#media-browser" -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/mediaSelector.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.blobstore.BlobInfoFactory 2 | 3 | def blobstoreKind = com.google.appengine.api.blobstore.BlobInfoFactory.KIND 4 | 5 | def numberPerPage = 5 6 | 7 | def page = params.page ? params.page.toInteger() : 0 8 | def offsetParam = page * numberPerPage 9 | 10 | datastore.execute { 11 | from blobstoreKind 12 | offset offsetParam limit numberPerPage 13 | sort desc by creation 14 | }.each { media -> 15 | def info = new BlobInfoFactory().createBlobInfo(media) 16 | def mediaUrl = "/media/${java.net.URLEncoder.encode(info.filename)}" 17 | def croppedUrl = images.getServingUrl(info.blobKey) + '=s100-c' 18 | 19 | html.img src: croppedUrl, fullsrc: mediaUrl 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/postDelete.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.datastore.Key 2 | 3 | def key = ['posts', params.id] as Key 4 | key.delete() 5 | 6 | redirect '/admin/posts' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/postSave.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.datastore.Entity 2 | 3 | import static bloogy.Utilities.* 4 | 5 | def keyName = params.id 6 | def created = Date.parse('yyyy/MM/dd HH:mm', params.created) 7 | 8 | Entity postOrPage 9 | 10 | if (keyName) { 11 | postOrPage = datastore.get('posts', keyName) 12 | postOrPage.modified = new Date() 13 | } else { 14 | postOrPage = new Entity('posts', streamline(params.title)) 15 | postOrPage.modified = created 16 | } 17 | 18 | postOrPage.title = params.title 19 | postOrPage.content = params.content 20 | postOrPage.created = created 21 | postOrPage.draft = params.draft == 'draft' ?: false 22 | postOrPage.type = params.type 23 | 24 | if (params.categories == null) { 25 | postOrPage.categories = null 26 | } else if (params.categories instanceof String) { 27 | postOrPage.categories = [params.categories] 28 | } else if (params.categories) { 29 | postOrPage.categories = params.categories.toList() 30 | } 31 | 32 | postOrPage.save() 33 | 34 | memcache.clearCacheForUri "/${postOrPage.type == 'page' ? 'page' : 'article'}/${postOrPage.key.name}" 35 | memcache.clearCacheForUri '/archives' 36 | memcache.clearCacheForUri '/' 37 | 38 | redirect "/live/${postOrPage.key.name}" 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/admin/titleExists.groovy: -------------------------------------------------------------------------------- 1 | try { 2 | datastore.get('posts', params.title.streamline()) 3 | out << 'true' 4 | } catch (any) { 5 | out << 'false' 6 | } 7 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/archive.groovy: -------------------------------------------------------------------------------- 1 | // Max number of articles per page 2 | int pageSize = 10 3 | 4 | // Page number 5 | int page = params.page ? params.page.toInteger() : 0 6 | 7 | // Retrieve the latest 10 posts 8 | def posts = datastore.execute { 9 | from posts 10 | limit pageSize offset pageSize * page 11 | where created < new Date() 12 | and draft == false 13 | and type == 'post' 14 | sort desc by created 15 | }.groupBy { it.created.year + 1900 } 16 | 17 | request.page = page 18 | request.posts = posts 19 | 20 | forward '/WEB-INF/pages/archive.gtpl' 21 | 22 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/article.groovy: -------------------------------------------------------------------------------- 1 | def title = params.title 2 | 3 | def post = datastore.get('posts', title) 4 | 5 | if (post) { 6 | request.post = post 7 | forward '/WEB-INF/pages/article.gtpl' 8 | } else { 9 | request.title = params.title 10 | forward '/WEB-INF/pages/notFound.gtpl' 11 | } -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/category.groovy: -------------------------------------------------------------------------------- 1 | 2 | if (params.category) { 3 | 4 | // Max number of articles per page 5 | int pageSize = 10 6 | 7 | // Page number 8 | int page = params.page ? params.page.toInteger() : 0 9 | 10 | def posts = datastore.execute { 11 | from posts 12 | limit pageSize offset pageSize * page 13 | where created < new Date() + 1 14 | and draft == false 15 | and type == 'post' 16 | and categories == params.category 17 | sort desc by created 18 | }.groupBy { it.created.year + 1900 } 19 | 20 | request.page = page 21 | request.posts = posts 22 | request.category = params.category 23 | 24 | forward '/WEB-INF/pages/archive.gtpl' 25 | } else { 26 | forward '/WEB-INF/pages/notfound.gtpl' 27 | } -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/error.groovy: -------------------------------------------------------------------------------- 1 | 2 | request.code = request.getAttribute("javax.servlet.error.status_code"); 3 | request.ex = request.getAttribute("javax.servlet.error.exception"); 4 | request.msg = request.getAttribute("javax.servlet.error.message"); 5 | 6 | forward '/WEB-INF/pages/error.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/feed.groovy: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | 3 | response.contentType = "text/xml;charset=utf-8" 4 | 5 | def isoTime = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US) 6 | 7 | def posts = datastore.execute { 8 | from posts limit 10 9 | where created < new Date() 10 | and draft == false 11 | and type == 'post' 12 | if (params.category) { 13 | and categories == params.category 14 | } 15 | sort desc by created 16 | } 17 | 18 | def serverRoot = "http://${request.serverName}${request.serverPort != 80 ? ":$request.serverPort" : ''}" 19 | 20 | html.feed(xmlns: "http://www.w3.org/2005/Atom") { 21 | title "Guillaume Laforge's blog feed" 22 | subtitle "On all things Groovy!" 23 | link href: serverRoot, rel: "self" 24 | updated isoTime.format(new Date()) 25 | generator(uri: "http://gaelyk.appspot.com", version: app.gaelyk.version, "Gaelyk lightweight Groovy toolkit for Google App Engine") 26 | 27 | posts.each { post -> 28 | entry { 29 | // create the summary to show in the Atom feed 30 | int min = Math.min(post.content.size(), 1000) 31 | def content = post.content[0.. 39 | category term: cat, scheme: "$serverRoot/category/${cat}" 40 | } 41 | summary(type: 'html') { 42 | mkp.yield content 43 | } 44 | author { 45 | name "Guillaume Laforge" 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/home.groovy: -------------------------------------------------------------------------------- 1 | 2 | // Max number of articles per page 3 | int pageSize = 5 4 | 5 | // Page number 6 | int page = params.page ? params.page.toInteger() : 0 7 | 8 | // Retrieve 10 posts 9 | def posts = datastore.execute { 10 | from posts 11 | limit pageSize offset pageSize * page 12 | where created < upperDate 13 | and draft == false 14 | and type == 'post' 15 | sort desc by created 16 | } 17 | 18 | request.posts = posts 19 | request.page = page 20 | 21 | forward '/WEB-INF/pages/home.gtpl' 22 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/media.groovy: -------------------------------------------------------------------------------- 1 | import com.google.appengine.api.datastore.Entity 2 | import com.google.appengine.api.blobstore.BlobInfoFactory 3 | import com.google.appengine.api.blobstore.BlobInfo 4 | 5 | Entity blobEntity = datastore.execute { select single from BlobInfoFactory.KIND where filename == params.fileName } 6 | 7 | if (blobEntity) { 8 | BlobInfo blobInfo = new BlobInfoFactory().createBlobInfo(blobEntity) 9 | 10 | response.contentType = blobInfo.contentType 11 | 12 | if (localMode) { 13 | // for some mysterious reason, bkey.serve response doesn't work on local SDK but works in production 14 | // so we use a workaround here instead 15 | files.getBlobFile(blobInfo.blobKey).withInputStream { BufferedInputStream stream -> 16 | sout << stream 17 | } 18 | } else { 19 | blobInfo.blobKey.serve response 20 | } 21 | } else { 22 | response.contentType = 'image/png' 23 | sout << new File('images/image-not-found.png').bytes 24 | } 25 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/search.groovy: -------------------------------------------------------------------------------- 1 | forward '/WEB-INF/pages/search.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/social.groovy: -------------------------------------------------------------------------------- 1 | import java.text.SimpleDateFormat 2 | import groovy.json.JsonSlurper 3 | 4 | def myKey = "AIzaSyCZW6egHI5Qa-3hfwT-P_BTirH3zjgCHu4" 5 | def myProfileId = "114130972232398734985" 6 | def gplus = "https://www.googleapis.com/plus/v1/people/${myProfileId}/activities/public?key=${myKey}".toURL().get(async: true) 7 | def delicious = "http://feeds.delicious.com/v2/rss/glaforge?count=15".toURL().get(async: true) 8 | def greader = "http://www.google.com/reader/public/atom/user%2F16866715143536937448%2Fstate%2Fcom.google%2Fbroadcast".toURL().get(async: true) 9 | def twitter = "http://search.twitter.com/search.atom?q=from%3Aglaforge&rpp=200".toURL().get(async: true) 10 | 11 | def items = [] 12 | 13 | def sdf 14 | def slurper = new XmlSlurper() 15 | 16 | try { 17 | // date format: 2011-09-09T08:34:07.000Z 18 | sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") 19 | 20 | def gplusDoc = new JsonSlurper().parseText(gplus.get().text) 21 | gplusDoc.items.each { item -> 22 | items << [ 23 | origin: 'gplus', 24 | title: item.title.replaceAll(/\s+/, ' '), 25 | published: sdf.parse(item.published), 26 | link: item.url 27 | ] 28 | } 29 | } catch (any) { 30 | any.printStackTrace() 31 | } 32 | 33 | 34 | try { 35 | // date format: 2011-07-29T09:00:10Z 36 | sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") 37 | 38 | def twitterDoc = slurper.parseText(twitter.get().text) 39 | twitterDoc.entry.each { entry -> 40 | items << [ 41 | origin: 'twitter', 42 | title: entry.title.text(), 43 | published: sdf.parse(entry.published.text()), 44 | link: entry.link.find { it.@type == 'text/html' }.@href.text() 45 | ] 46 | } 47 | } catch (any) { 48 | any.printStackTrace() 49 | } 50 | 51 | try { 52 | def greaderDoc = slurper.parseText(greader.get().text) 53 | greaderDoc.entry.each { entry -> 54 | items << [ 55 | origin: 'greader', 56 | title: entry.title.text(), 57 | published: sdf.parse(entry.published.text()), 58 | link: entry.link.find { it.@type == 'text/html' }.@href.text() 59 | ] 60 | } 61 | } catch (any) { 62 | any.printStackTrace() 63 | } 64 | 65 | try { 66 | // date format: Thu, 28 Jul 2011 07:32:22 +0000 67 | sdf = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US) 68 | 69 | def deliciousDoc = slurper.parseText(delicious.get().text) 70 | deliciousDoc.channel.item.each { entry -> 71 | items << [ 72 | origin: 'delicious', 73 | title: entry.title.text(), 74 | published: sdf.parse(entry.pubDate.text()), 75 | link: entry.link.text() 76 | ] 77 | } 78 | } catch (any) { 79 | any.printStackTrace() 80 | } 81 | 82 | request.items = items.sort { it.published }.reverse().each { it.published.clearTime() }.groupBy { it.published } 83 | 84 | forward '/WEB-INF/pages/social.gtpl' -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/groovy/viewRawEmail.groovy: -------------------------------------------------------------------------------- 1 | def e = datastore.execute { select single from email } 2 | 3 | response.contentType = "text/plain" 4 | 5 | out << e.rawContent -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/bottom.gtpl: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | 5 |
6 | © 2012 Guillaume Laforge | 7 | The views and opinions expressed here are mine and don't reflect the ones from my employer. 8 |
9 | 10 |
11 | Website template by Arcsin 12 |
13 | 14 |
 
15 | 16 |
17 | 18 |
-------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/footer.gtpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/header.gtpl: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 28 | 29 |
30 |
31 |
-------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/left.gtpl: -------------------------------------------------------------------------------- 1 | 89 | 90 |
 
91 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/meta.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | 9 | 10 | <% if (!request.getAttribute('originalURI').contains('/admin')) { %> 11 | 25 | <% } %> 26 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/navigation.gtpl: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/includes/syntaxHighlighting.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/antlr-2.7.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/antlr-2.7.7.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/appengine-api-1.0-sdk-1.8.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/appengine-api-1.0-sdk-1.8.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/appengine-api-labs-1.8.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/appengine-api-labs-1.8.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/asm-4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/asm-4.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/asm-analysis-4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/asm-analysis-4.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/asm-commons-4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/asm-commons-4.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/asm-tree-4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/asm-tree-4.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/asm-util-4.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/asm-util-4.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/gaelyk-2.0.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/gaelyk-2.0.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-all-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-all-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-json-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-json-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-servlet-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-servlet-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-templates-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-templates-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/groovy-xml-2.1.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/groovy-xml-2.1.3.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/ocpsoft-pretty-time-1.0.7.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/ocpsoft-pretty-time-1.0.7.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/lib/servlet-api-2.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/WEB-INF/lib/servlet-api-2.5.jar -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/logging.properties: -------------------------------------------------------------------------------- 1 | # Set the default logging level for all loggers to INFO 2 | .level = INFO 3 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/admin/adminCategories.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% include '/WEB-INF/includes/meta.gtpl' %> 6 | Administration: Categories 7 | 8 | 21 | 22 | 23 | 24 | 25 | <% include '/WEB-INF/includes/header.gtpl' %> 26 | <% include '/WEB-INF/includes/navigation.gtpl' %> 27 | 28 |
29 |
30 | 31 |
32 | 33 |
34 |
35 | 36 |
37 | 38 |

Categories

39 | 40 |
41 | 42 |
    43 | <% request.categories.each { category -> %> 44 |
  • 45 | <% if (request.categoriesCount[category] == 0) { %> 46 |
    47 | 49 |
    50 | <% } %> 51 | ${category.name} — 52 | ${category.description} — 53 | (${request.categoriesCount[category]} posts) 54 | 55 |
  • 56 | <% } %> 57 |
58 |
59 |

Create a new category

60 |
61 | 62 |
63 |
64 |
Category name
65 | 66 |
67 | 68 | 69 | 71 |
72 | 73 |
 
74 |
75 | 76 |
77 |
Description
78 | 79 |
81 | 82 |
 
83 |
84 |
85 | 86 |
87 |
89 | 90 |
 
91 |
92 |
93 |
94 | 95 |
96 | 97 |
98 | 99 |
100 |
101 | 102 | <% include '/WEB-INF/includes/left.gtpl' %> 103 |
104 | 105 |
106 |
107 | 108 | <% include '/WEB-INF/includes/footer.gtpl' %> 109 | <% include '/WEB-INF/includes/bottom.gtpl' %> 110 | 111 | 112 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/admin/adminMedia.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% import com.google.appengine.api.blobstore.BlobInfoFactory %> 4 | 5 | 6 | Administration: Media Browser 7 | <% include '/WEB-INF/includes/meta.gtpl' %> 8 | 9 | 10 | 11 | 12 | 13 | 34 | 35 | 36 | 37 | 38 | 39 | <% include '/WEB-INF/includes/header.gtpl' %> 40 | <% include '/WEB-INF/includes/navigation.gtpl' %> 41 | 42 |
43 |
44 | 45 |
46 | 47 |
48 |
49 | 50 |
51 | 52 |

Media browser

53 | 54 |
55 | 56 |
57 |

Store new media

58 |
59 | 60 |
62 |
63 |
64 | 66 |   67 | 69 | 70 |
71 | 72 |
 
73 |
74 |
75 | 76 |
77 |
79 | 80 |
 
81 |
82 |
83 |
84 | 85 | 86 |
87 | 88 |
89 | <% 90 | def blobstoreKind = com.google.appengine.api.blobstore.BlobInfoFactory.KIND 91 | def numberPerPage = 8 92 | 93 | def page = params.page ? params.page.toInteger() : 0 94 | def offsetParam = page * numberPerPage 95 | 96 | def medias = datastore.execute { 97 | from blobstoreKind 98 | offset offsetParam limit numberPerPage 99 | sort desc by creation 100 | } 101 | medias.each { media -> 102 | def mediaUrl = "/media/${java.net.URLEncoder.encode(media.filename)}" 103 | %> 104 |
105 | 114 | 115 |
116 | 117 | 118 | 120 | 121 |
122 | ${blobInfo.filename}
123 | ${blobInfo.creation.format('yyyy/MM/dd')} — ${blobInfo.size.intdiv(1024)} KB 124 |
125 |
126 |
127 | <% } %> 128 |

 

129 | 130 |
131 | 132 |
133 | <% 134 | int entityCount = datastore.execute { select count from blobstoreKind } 135 | int pageCount = (entityCount - 1).intdiv(numberPerPage) + 1 136 | 137 | boolean hasPrev = offsetParam > 0 138 | boolean hasNext = page + 1 < pageCount 139 | 140 | %> 141 | 144 |   145 | 148 |   149 | 152 |
153 |
154 | 155 |
156 | 157 |
158 | 159 |
160 |
161 | 162 | <% include '/WEB-INF/includes/left.gtpl' %> 163 |
164 | 165 |
166 |
167 | 168 | <% include '/WEB-INF/includes/footer.gtpl' %> 169 | <% include '/WEB-INF/includes/bottom.gtpl' %> 170 | 171 | 172 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/admin/adminPosts.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Administration: Posts 6 | <% include '/WEB-INF/includes/meta.gtpl' %> 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | <% include '/WEB-INF/includes/header.gtpl' %> 20 | <% include '/WEB-INF/includes/navigation.gtpl' %> 21 | 22 |
23 |
24 | 25 |
26 | 27 |
28 |
29 | 30 |
31 | 32 |

Drafts, posts, and pages

33 | 34 |
35 | 36 |
37 | 48 | 49 | <% 50 | ['Drafts': request.drafts, 'Posts': request.posts, 'Pages': request.pages].each { type, posts -> 51 | %> 52 |
53 |
    54 | <% posts.each { post -> %> 55 |
  • 56 |
    57 | 58 |
    59 | 60 |
    61 | 62 |
    63 | <% if (post.type == 'page') { %> 64 | Page  65 | <% } else if (post.type == 'post') { %> 66 | Post  67 | <% } %> 68 | ${post.title} 70 | 71 |
    72 | 73 | ${post.created.format('yyyy / MM / dd')} 74 | <% if (post.categories) { %> — ${post.categories?.join(', ') ?: 'none'} <% } %> 75 |
  • 76 | <% } %> 77 |
78 |
79 | <% } %> 80 | 81 |
82 | 83 |
84 | 85 |
86 |
87 | 88 | <% include '/WEB-INF/includes/left.gtpl' %> 89 |
90 | 91 |
92 |
93 | 94 | <% include '/WEB-INF/includes/footer.gtpl' %> 95 | <% include '/WEB-INF/includes/bottom.gtpl' %> 96 | 97 | 98 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/admin/postEdit.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | <% import com.google.appengine.api.datastore.Key %> 4 | 5 | 6 | Administration: Edit Posts 7 | <% include '/WEB-INF/includes/meta.gtpl' %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | <% include '/WEB-INF/includes/header.gtpl' %> 22 | <% include '/WEB-INF/includes/navigation.gtpl' %> 23 | 24 | <% 25 | def keyName = params.id 26 | def post = keyName ? datastore.get('posts', keyName) : null 27 | %> 28 | 29 |
30 |
31 | 32 |
33 | 34 |
35 |
36 | 37 |
38 | 39 |

Edit post

40 | 41 |
42 |
43 |
44 | <% if (post) { %> 45 | 46 | <% } %> 47 |
48 |
Title
49 | 50 |
51 | 54 | 55 | 58 |
59 | 60 |
 
61 |
62 | 63 | 64 | 65 | 66 | 67 | 83 | 95 | 107 | 108 |
68 |
69 |
Created (GMT time) 70 |
71 | 72 |
73 | 76 | 77 | 80 |
81 |
82 |
84 |
85 |
Type
86 | 87 |
88 | 92 |
93 |
94 |
96 |
97 |
Status
98 | 99 |
100 | 104 |
105 |
106 |
109 | 110 |
111 |
Categories
113 | 114 |
115 | 122 |
123 | 124 |
 
125 |
126 |
127 | 128 |
129 |
Content
130 | 131 |
132 | 134 |
135 | 136 |
 
137 |
138 |
139 | 140 |
141 |
142 | 144 |
145 | 146 |
 
147 |
148 |
149 |
150 |
151 | 152 |
153 | 154 |
155 |
156 | 157 | <% include '/WEB-INF/includes/left.gtpl' %> 158 |
159 | 160 |
161 |
162 | 163 | <% include '/WEB-INF/includes/footer.gtpl' %> 164 | <% include '/WEB-INF/includes/bottom.gtpl' %> 165 | 166 | 167 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/archive.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <% 5 | int page = params.page ? params.page.toInteger() : 0 6 | 7 | def originalURI = request.originalURI 8 | 9 | def titlePrefix = '' 10 | def origin = "archives" 11 | if (originalURI.contains('category')) { 12 | origin = "category/${params.category}" 13 | titlePrefix = "Category ${params.category} -- " 14 | } else { 15 | titlePrefix = "Archives -- " 16 | } 17 | %> 18 | 19 | 20 | ${titlePrefix}Guillaume Laforge's Blog 21 | <% include '/WEB-INF/includes/meta.gtpl' %> 22 | 23 | 24 | 25 | 26 | 27 | <% include '/WEB-INF/includes/header.gtpl' %> 28 | <% include '/WEB-INF/includes/navigation.gtpl' %> 29 | 30 |
31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 | <% 39 | if (origin.startsWith("archives")) { 40 | def date = [request.year, request.month, request.day].grep { it }*.toString()*.padLeft(2, '0') %> 41 |

Archives ${date ? 'for' : ''} ${date.join('-')}

42 | <% } else if (origin.startsWith("category")) { %> 43 |

Category ${params.category}

44 | <% } %> 45 |
46 | <% 47 | request.posts.each { year, posts -> 48 | %> 49 |

${year}

50 | 51 |
52 | <% 53 | posts.each { post -> 54 | String day = post.created.date.toString().padLeft(2, '0') 55 | String monthLetters = post.created.format('MMM').toUpperCase() 56 | %> 57 | 58 |
59 | 60 | 65 | 66 |
67 |

${post.title}

68 | 69 | 79 |
80 | 81 |
 
82 | 83 |
84 | 85 |
86 | <% 87 | } 88 | } 89 | %> 90 | 91 | 92 | <% if (request.posts || page) { %> 93 | 107 | <% } %> 108 |
109 |
110 | 111 | <% include '/WEB-INF/includes/left.gtpl' %> 112 |
113 | 114 |
115 |
116 | 117 | <% include '/WEB-INF/includes/footer.gtpl' %> 118 | <% include '/WEB-INF/includes/bottom.gtpl' %> 119 | 120 | 121 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/article.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% def post = request.post %> 6 | 7 | ${post.title} -- Guillaume Laforge's Blog 8 | <% include '/WEB-INF/includes/syntaxHighlighting.gtpl' %> 9 | <% include '/WEB-INF/includes/meta.gtpl' %> 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <% include '/WEB-INF/includes/header.gtpl' %> 24 | <% include '/WEB-INF/includes/navigation.gtpl' %> 25 | 26 |
27 |
28 | 29 |
30 | 31 |
32 |
33 | 34 |
35 | 36 |

${post.title}

37 | 38 | 51 | 52 | <% if (request.getAttribute('originalURI').contains('article')) { %> 53 |
54 |
55 | 63 | 66 |
67 | <% } %> 68 | 69 |
70 | ${post.content} 71 |
72 | 73 | <% if (post.categories) { %> 74 | 80 | <% } %> 81 | 82 |
83 | 84 | <% if (request.getAttribute('originalURI').contains('article')) { %> 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |

 

100 |
101 | 102 |
103 | 104 |
105 | 110 | 111 | 113 |
114 | <% } %> 115 | 116 |
117 |
118 | 119 | <% include '/WEB-INF/includes/left.gtpl' %> 120 |
121 | 122 |
123 |
124 | 125 | <% include '/WEB-INF/includes/footer.gtpl' %> 126 | <% include '/WEB-INF/includes/bottom.gtpl' %> 127 | 128 | 129 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/error.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% include '/WEB-INF/includes/meta.gtpl' %> 6 | An error occured -- Guillaume Laforge's Blog 7 | 8 | 9 | 10 | 11 | <% include '/WEB-INF/includes/header.gtpl' %> 12 | <% include '/WEB-INF/includes/navigation.gtpl' %> 13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 |

An error occured

25 | 26 |
27 | <% if (request.getAttribute('code')) { %> 28 |
Error code:
29 |
${request.getAttribute('code')}
30 | <% } else if (request.getAttribute('ex')) { %> 31 |
Exception:
32 |
${request.getAttribute('ex')}
33 | <% } %> 34 |
Message:
35 |
${request.getAttribute('msg')}
36 |
37 | 38 |
39 | 40 |
41 |
42 | 43 | <% include '/WEB-INF/includes/left.gtpl' %> 44 |
45 | 46 |
47 |
48 | 49 | <% include '/WEB-INF/includes/footer.gtpl' %> 50 | <% include '/WEB-INF/includes/bottom.gtpl' %> 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/home.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Guillaume Laforge's Blog 6 | <% include '/WEB-INF/includes/syntaxHighlighting.gtpl' %> 7 | <% include '/WEB-INF/includes/meta.gtpl' %> 8 | 9 | 10 | 11 | 12 | <% include '/WEB-INF/includes/header.gtpl' %> 13 | <% include '/WEB-INF/includes/navigation.gtpl' %> 14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 |
22 | 23 | <% 24 | // no articles to display 25 | if (!request.posts) { 26 | %> 27 |

No more posts

28 | <% 29 | } 30 | %> 31 | <% 32 | request.posts.each { post -> 33 | %> 34 | 35 |
36 | 37 |

${post.title}

38 | 39 | 47 | 48 |
49 | ${post.content} 50 |
51 | 52 | <% if (post.categories) { %> 53 | 59 | <% } %> 60 | 61 |
62 | 63 | <% 64 | } 65 | %> 66 | 67 | 87 | 88 |
89 |
90 | 91 | <% include '/WEB-INF/includes/left.gtpl' %> 92 |
93 | 94 |
95 |
96 | 97 | <% include '/WEB-INF/includes/footer.gtpl' %> 98 | <% include '/WEB-INF/includes/bottom.gtpl' %> 99 | 100 | 101 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/notAllowed.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% include '/WEB-INF/includes/meta.gtpl' %> 6 | Not allowed -- Guillaume Laforge's Blog 7 | 8 | 9 | 10 | 11 | <% include '/WEB-INF/includes/header.gtpl' %> 12 | <% include '/WEB-INF/includes/navigation.gtpl' %> 13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 |

Access not allowed

25 | 26 |
27 |

You must be administrator to be able to administer this weblog.

28 | 29 |

Please sign-in back with an administrator account 31 |

32 |
33 | 34 |
35 | 36 |
37 |
38 | 39 | <% include '/WEB-INF/includes/left.gtpl' %> 40 |
41 | 42 |
43 |
44 | 45 | <% include '/WEB-INF/includes/footer.gtpl' %> 46 | <% include '/WEB-INF/includes/bottom.gtpl' %> 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/notFound.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% include '/WEB-INF/includes/meta.gtpl' %> 6 | Page not found -- Guillaume Laforge's Blog 7 | 8 | 9 | 10 | 11 | <% include '/WEB-INF/includes/header.gtpl' %> 12 | <% include '/WEB-INF/includes/navigation.gtpl' %> 13 | 14 |
15 |
16 | 17 |
18 | 19 |
20 |
21 | 22 |
23 | 24 |

Page not found

25 | 26 |
27 |

The page you were looking for couldn't be found.

28 | 29 |

Otherwise, please one of the links in the navigation bars 30 | to find your way in this website.

31 |
32 | 33 |
34 | 35 |
36 |
37 | 38 | <% include '/WEB-INF/includes/left.gtpl' %> 39 |
40 | 41 |
42 |
43 | 44 | <% include '/WEB-INF/includes/footer.gtpl' %> 45 | <% include '/WEB-INF/includes/bottom.gtpl' %> 46 | 47 | 48 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/search.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Search Guillaume Laforge's Blog 6 | 7 | 15 | 16 | 17 | <% include '/WEB-INF/includes/meta.gtpl' %> 18 | 19 | 20 | 21 | 22 | <% include '/WEB-INF/includes/header.gtpl' %> 23 | <% include '/WEB-INF/includes/navigation.gtpl' %> 24 | 25 |
26 |
27 | 28 |
29 | 30 |
31 |
32 | 33 |
34 | 35 |

Search this site

36 | 37 |
38 |
Loading
39 |
40 | 41 |
42 | 43 |
44 |
45 | 46 | <% include '/WEB-INF/includes/left.gtpl' %> 47 |
48 | 49 |
50 |
51 | 52 | <% include '/WEB-INF/includes/footer.gtpl' %> 53 | <% include '/WEB-INF/includes/bottom.gtpl' %> 54 | 55 | 56 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/pages/social.gtpl: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Social (twitter, delicious, google reader) -- Guillaume Laforge's Blog 6 | 7 | <% include '/WEB-INF/includes/meta.gtpl' %> 8 | 9 | 10 | 11 | 12 | <% include '/WEB-INF/includes/header.gtpl' %> 13 | <% include '/WEB-INF/includes/navigation.gtpl' %> 14 | 15 |
16 |
17 | 18 |
19 | 20 |
21 |
22 | 23 |
24 | 25 |

Social

26 | 27 |
28 | 29 |

30 | This page gathers: 31 |

32 | 43 | 44 | <% request.items.each { date, entries -> %> 45 |

${date.format('yyyy / MM / dd')}

46 |
    47 | <% entries.each { entry -> %> 48 |
  • 49 | 50 | ${entry.title} 51 |
  • 52 | <% } %> 53 |
54 | <% } %> 55 |
56 | 57 |
58 | 59 |
60 |
61 | 62 | <% include '/WEB-INF/includes/left.gtpl' %> 63 |
64 | 65 |
66 |
67 | 68 | <% include '/WEB-INF/includes/footer.gtpl' %> 69 | <% include '/WEB-INF/includes/bottom.gtpl' %> 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/routes.groovy: -------------------------------------------------------------------------------- 1 | def cache = localMode ? 0 : 1.hour 2 | 3 | get "/", forward: '/home.groovy', cache: cache 4 | get "/p@p", forward: '/home.groovy?page=@p', validate: { p ==~ /\d+/ }, cache: cache 5 | 6 | get "/article/@title", forward: '/article.groovy?title=@title', cache: cache 7 | get "/page/@title", forward: '/article.groovy?title=@title', cache: cache 8 | get "/live/@title", forward: '/article.groovy?title=@title' 9 | 10 | get "/archives/p@p", forward: '/archive.groovy?page=@p', validate: { p ==~ /\d+/ }, cache: cache 11 | get "/archives", forward: '/archive.groovy', cache: cache 12 | 13 | get "/category/@cat/p@p", forward: '/category.groovy?category=@cat&page=@p', validate: { p ==~ /\d+/ }, cache: cache 14 | get "/category/@cat", forward: '/category.groovy?category=@cat', cache: cache 15 | 16 | get "/media/@file.@ext", forward: '/media.groovy?fileName=@file.@ext', cache: cache 17 | 18 | get "/feed/atom/@cat", forward: '/feed.groovy?category=@cat', cache: cache 19 | get "/feed/atom", forward: '/feed.groovy', cache: cache 20 | 21 | get "/social", redirect301: '/' 22 | 23 | get "/search", forward: '/search.groovy', cache: 24.hours 24 | 25 | get "/admin/categories", forward: '/admin/adminCategories.groovy' 26 | get "/admin/posts", forward: '/admin/adminPosts.groovy' 27 | get "/admin/posts/create", forward: '/WEB-INF/pages/admin/postEdit.gtpl' 28 | get "/admin/media", forward: '/admin/adminMedia.groovy' 29 | get "/admin/media/p@p", forward: '/admin/adminMedia.groovy?page=@p' 30 | get "/admin/mediaSelector", forward: '/admin/mediaSelector.groovy' 31 | get "/admin/clearCache", forward: '/admin/clearCache.groovy' 32 | get "/admin/titleExists", forward: '/admin/titleExists.groovy' 33 | 34 | //get "/admin/export", forward: '/admin/export.groovy' 35 | //get "/admin/import", forward: '/admin/import.groovy' 36 | 37 | post "/admin/media/add", forward: '/admin/mediaAdd.groovy' 38 | post "/admin/media/delete/@bk", forward: '/admin/mediaDelete.groovy?blobKey=@bk' 39 | post "/admin/posts/delete/@id", forward: '/admin/postDelete.groovy?id=@id' 40 | post "/admin/posts/edit/@id", forward: '/WEB-INF/pages/admin/postEdit.gtpl?id=@id' 41 | post "/admin/posts/save", forward: '/admin/postSave.groovy' 42 | post "/admin/categories/add", forward: '/admin/categoryAdd.groovy' 43 | post "/admin/categories/delete/@cat", forward: '/admin/categoryDelete.groovy?categoryName=@cat' 44 | 45 | // route for 404 errors defined in web.xml 46 | get "/not-found", forward: '/WEB-INF/pages/notFound.gtpl', cache: 24.hours 47 | // route for 403 errors defined in web.xml 48 | get "/not-allowed", forward: '/WEB-INF/pages/notAllowed.gtpl', cache: 24.hours 49 | // when some error happens 50 | get "/error", forward: '/WEB-INF/pages/error.gtpl' 51 | 52 | get "/favicon.ico", redirect: "/images/gaelyk-favicon.png" 53 | 54 | email to: "/admin/email.groovy" 55 | -------------------------------------------------------------------------------- /src/main/webapp/WEB-INF/web.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | groovyx.gaelyk.GaelykServletContextListener 4 | 5 | 6 | 7 | GroovletServlet 8 | groovyx.gaelyk.GaelykServlet 9 | 10 | verbose 11 | 12 | false 13 | 14 | 15 | 1 16 | 17 | 18 | TemplateServlet 19 | groovyx.gaelyk.GaelykTemplateServlet 20 | 21 | 22 | generated.by 23 | false 24 | 25 | 26 | verbose 27 | 28 | false 29 | 30 | 31 | preferPrecompiled 32 | false 33 | 34 | 35 | 1 36 | 37 | 38 | 39 | RoutesFilter 40 | groovyx.gaelyk.routes.RoutesFilter 41 | 42 | 43 | 44 | GroovletServlet 45 | *.groovy 46 | 47 | 48 | TemplateServlet 49 | *.gtpl 50 | 51 | 52 | 53 | RoutesFilter 54 | /* 55 | INCLUDE 56 | FORWARD 57 | REQUEST 58 | 62 | ERROR 63 | 64 | 65 | 66 | 67 | 68 | 69 | /admin/* 70 | 71 | 72 | admin 73 | 74 | 75 | 76 | 77 | /_ah/mail/* 78 | 79 | 80 | admin 81 | 82 | 83 | 84 | 85 | 86 | 404 87 | 91 | /not-found 92 | 93 | 94 | 403 95 | /not-allowed 96 | 97 | 98 | 500 99 | /error 100 | 101 | 102 | java.lang.Throwable 103 | /error 104 | 105 | 106 | 107 | 112 | 113 | -------------------------------------------------------------------------------- /src/main/webapp/css/chosen.css: -------------------------------------------------------------------------------- 1 | div.chzn-container { 2 | font-size: 13px; 3 | position: relative; 4 | } 5 | 6 | div.chzn-container input { 7 | background: #fff; 8 | background: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 9 | background: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 10 | border: 1px solid #aaa; 11 | font-family: sans-serif; 12 | font-size: 1em; 13 | margin: 0px; 14 | padding: 4px 5px; 15 | outline: none; 16 | -moz-border-radius: 3px; 17 | -webkit-border-radius: 3px; 18 | -o-border-radius: 3px; 19 | -ms-border-radius: 3px; 20 | -khtml-border-radius: 3px; 21 | border-radius: 3px; 22 | } 23 | div.chzn-container textarea:focus { 24 | border-color: #058cf5; 25 | -moz-box-shadow: 0px 0px 3px #aaa; 26 | -webkit-box-shadow: 0px 0px 3px #aaa; 27 | box-shadow: 0px 0px 3px #aaa; 28 | } 29 | 30 | 31 | div.chzn-container div.chzn-drop { 32 | background: #FFF; 33 | border: 1px solid #aaa; 34 | border-width: 0 1px 1px; 35 | left: 0; 36 | position: absolute; 37 | top: 29px; 38 | -webkit-box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15); 39 | -moz-box-shadow: 0px 4px 5px rgba(0, 0, 0, 0.15); 40 | box-shadow: 0px 2px 4px rgba(0, 0, 0, 0.15); 41 | z-index: 20; 42 | } 43 | div.chzn-container-single div.chzn-drop { 44 | -moz-border-radius: 0 0 4px 4px; 45 | -webkit-border-radius: 0 0 4px 4px; 46 | -o-border-radius: 0 0 4px 4px; 47 | -ms-border-radius: 0 0 4px 4px; 48 | -khtml-border-radius: 0 0 4px 4px; 49 | border-radius: 0 0 4px 4px; 50 | } 51 | 52 | 53 | /* SINGLE */ 54 | div.chzn-container a.chzn-single { 55 | background: #FFF; 56 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); 57 | background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); 58 | border: 1px solid #aaa; 59 | display: block; 60 | overflow: hidden; 61 | -moz-border-radius: 4px; 62 | -webkit-border-radius: 4px; 63 | -o-border-radius: 4px; 64 | -ms-border-radius: 4px; 65 | -khtml-border-radius: 4px; 66 | border-radius: 4px; 67 | height: 25px; 68 | color: #444; 69 | line-height: 26px; 70 | padding: 0px 0px 0px 8px; 71 | position: relative; 72 | text-decoration: none; 73 | z-index: 19; 74 | white-space: nowrap; 75 | } 76 | div.chzn-container a.chzn-single span { 77 | display: block; 78 | margin-right: 26px; 79 | overflow: hidden; 80 | text-overflow: ellipsis; 81 | } 82 | div.chzn-container a.chzn-single div { 83 | -moz-border-radius-topright: 4px; 84 | -webkit-border-top-right-radius: 4px; 85 | -o-border-top-right-radius: 4px; 86 | -ms-border-top-right-radius: 4px; 87 | -khtml-border-top-right-radius: 4px; 88 | border-top-right-radius: 4px; 89 | -moz-border-radius-bottomright: 4px; 90 | -webkit-border-bottom-right-radius: 42px; 91 | -o-border-bottom-right-radius: 4px; 92 | -ms-border-bottom-right-radius: 4px; 93 | -khtml-border-bottom-right-radius: 4px; 94 | border-bottom-right-radius: 4px; 95 | background: #ccc; 96 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); 97 | background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); 98 | border-left: 1px solid #aaa; 99 | display: block; 100 | height: 100%; 101 | position: absolute; 102 | right: 0; 103 | top: 0; 104 | width: 18px; 105 | } 106 | div.chzn-container a.chzn-single div b { 107 | background: url('/images/chosen-sprite.png') no-repeat 0 1px; 108 | display: block; 109 | width: 100%; 110 | height: 100%; 111 | } 112 | div.chzn-container div.chzn-search { 113 | padding: 3px 4px; 114 | margin: 0px; 115 | white-space: nowrap; 116 | } 117 | div.chzn-container div.chzn-search input { 118 | background: url('/images/chosen-sprite.png') no-repeat 97% -35px, #ffffff; 119 | background: url('/images/chosen-sprite.png') no-repeat 97% -35px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 120 | background: url('/images/chosen-sprite.png') no-repeat 97% -35px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 121 | -moz-border-radius: 0px; 122 | -webkit-border-radius: 0px; 123 | -o-border-radius: 0px; 124 | -ms-border-radius: 0px; 125 | -khtml-border-radius: 0px; 126 | border-radius: 0px; 127 | margin: 1px 0; 128 | outline: 0; 129 | } 130 | 131 | 132 | /* Multi */ 133 | div.chzn-container ul.chzn-choices { 134 | background: #fff; 135 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); 136 | background-image: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); 137 | margin: 0; 138 | cursor: text; 139 | border: 1px solid #aaa; 140 | overflow: hidden; 141 | height: auto !important; 142 | height: 1%; 143 | padding: 0; 144 | position: relative; 145 | } 146 | div.chzn-container ul.chzn-choices:focus { 147 | border-color: #058cf5; 148 | -moz-box-shadow: 0px 0px 5px #999; 149 | -webkit-box-shadow: 0px 0px 5px #999; 150 | box-shadow: 0px 0px 5px #999; 151 | } 152 | div.chzn-container ul.chzn-choices li { 153 | float: left; 154 | list-style-type: none; 155 | margin: 0px; 156 | } 157 | div.chzn-container ul.chzn-choices li.search-field { 158 | margin: 0px; 159 | white-space: nowrap; 160 | padding: 0px; 161 | } 162 | div.chzn-container ul.chzn-choices li.search-field input { 163 | color: #666; 164 | background: transparent !important; 165 | border: 0px !important; 166 | padding: 5px; 167 | margin: 1px 0; 168 | outline: 0; 169 | -webkit-box-shadow: none; 170 | -moz-box-shadow: none; 171 | box-shadow: none; 172 | } 173 | div.chzn-container ul.chzn-choices li.search-field input.default { 174 | color: #999; 175 | } 176 | div.chzn-container ul.chzn-choices li.search-choice { 177 | -moz-border-radius: 3px; 178 | -webkit-border-radius: 3px; 179 | border-radius: 3px; 180 | background: #e4e4e4; 181 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e4e4e4), color-stop(0.7, #eeeeee)); 182 | background-image: -moz-linear-gradient(center bottom, #e4e4e4 0%, #eeeeee 70%); 183 | color: #333; 184 | border: 1px solid #b4b4b4; 185 | line-height: 13px; 186 | padding: 3px 19px 3px 6px; 187 | position: relative; 188 | margin: 3px 0px 3px 5px; 189 | } 190 | div.chzn-container ul.chzn-choices li.search-choice span { 191 | cursor: default; 192 | } 193 | div.chzn-container ul.chzn-choices li.search-choice.search-choice-focus { 194 | background: #d4d4d4; 195 | } 196 | div.chzn-container ul.chzn-choices li.search-choice a.search-choice-close { 197 | position: absolute; 198 | right: 5px; 199 | top: 6px; 200 | display: block; 201 | width: 8px; 202 | height: 9px; 203 | font-size: 1px; 204 | background: url(/images/chosen-sprite.png) right top no-repeat; 205 | } 206 | div.chzn-container ul.chzn-choices li.search-choice a.search-choice-close:hover { 207 | background-position: right -9px; 208 | } 209 | div.chzn-container ul.chzn-choices li.search-choice.search-choice-focus a.search-choice-close { 210 | background-position: right -9px; 211 | } 212 | 213 | 214 | /* Results */ 215 | div.chzn-container ul.chzn-results { 216 | margin: 0 4px 4px 0; 217 | max-height: 190px; 218 | padding: 0 0 0 4px; 219 | position: relative; 220 | overflow-x: hidden; 221 | overflow-y: auto; 222 | z-index: 20; 223 | } 224 | div.chzn-container-multi ul.chzn-results { 225 | margin: -1px 0 0; 226 | padding: 0; 227 | } 228 | div.chzn-container-multi ul.chzn-results li { 229 | border-left: 0px !important; 230 | border-right: 0px !important; 231 | } 232 | div.chzn-container ul.chzn-results li { 233 | line-height: 80%; 234 | padding: 7px 7px 8px; 235 | z-index: 22; 236 | margin: 0; 237 | list-style-type: none; 238 | } 239 | div.chzn-container ul.chzn-results li.active-result { 240 | cursor: pointer; 241 | } 242 | div.chzn-container ul.chzn-results li em { 243 | font-style: normal; 244 | background: #FEFFDC; 245 | } 246 | div.chzn-container ul.chzn-results li.highlighted { 247 | background: #3875d7; 248 | color: #fff; 249 | } 250 | div.chzn-container ul.chzn-results li.highlighted em { 251 | background: transparent; 252 | } 253 | div.chzn-container ul.chzn-results li.no-results { 254 | background: #F4F4F4; 255 | } 256 | div.chzn-container ul.chzn-results li.group-result { 257 | cursor: default; 258 | color: #999; 259 | font-weight: bold; 260 | } 261 | div.chzn-container ul.chzn-results li.group-option { 262 | padding-left: 20px; 263 | } 264 | 265 | div.chzn-container-multi div.chzn-drop li.result-selected { 266 | display: none; 267 | } 268 | 269 | 270 | 271 | /* Active */ 272 | div.chzn-container-active a.chzn-single { 273 | -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 274 | -moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 275 | box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 276 | border: 1px solid #5897fb; 277 | } 278 | div.chzn-container-active a.chzn-single-with-drop { 279 | border: 1px solid #aaa; 280 | border-width: 1px 1px 1px; 281 | -moz-box-shadow: 0px 1px 0px #FFF inset; 282 | -webkit-box-shadow: 0px 1px 0px #FFF inset; 283 | box-shadow: 0px 1px 0px #FFF inset; 284 | background: #EEE; 285 | background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); 286 | background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); 287 | -webkit-border-bottom-left-radius: 0px; 288 | -webkit-border-bottom-right-radius: 0px; 289 | -moz-border-radius-bottomleft: 0px; 290 | -moz-border-radius-bottomright: 0px; 291 | border-bottom-left-radius: 0px; 292 | border-bottom-right-radius: 0px; 293 | } 294 | div.chzn-container-active a.chzn-single-with-drop div { 295 | background: transparent; 296 | border-left: none; 297 | } 298 | div.chzn-container-active a.chzn-single-with-drop div b { 299 | background-position: -18px 1px; 300 | } 301 | div.chzn-container-active ul.chzn-choices { 302 | z-index: 21; 303 | -webkit-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 304 | -moz-box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 305 | box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3); 306 | border: 1px solid #5897fb; 307 | } 308 | div.chzn-container-active ul.chzn-choices input { 309 | color: #111 !important; 310 | } 311 | -------------------------------------------------------------------------------- /src/main/webapp/css/google-search.css: -------------------------------------------------------------------------------- 1 | .gsc-control-cse { 2 | font-family: Arial, sans-serif; 3 | border-color: #FFFFFF; 4 | background-color: #FFFFFF; 5 | } 6 | 7 | input.gsc-input { 8 | border-color: #DFDFDA; 9 | 10 | height: 28px; 11 | 12 | -moz-box-shadow: 2px 1px 3px #AAA; 13 | -webkit-box-shadow: 2px 1px 3px #AAA; 14 | box-shadow: 2px 1px 3px #AAA; 15 | 16 | -webkit-border-radius: 4px; 17 | -moz-border-radius: 4px; 18 | border-radius: 4px; 19 | } 20 | 21 | input.gsc-search-button { 22 | border-color: #666666; 23 | background-color: #CECECE; 24 | } 25 | 26 | .gsc-tabHeader.gsc-tabhInactive { 27 | border-color: #E9E9E9; 28 | background-color: #E9E9E9; 29 | } 30 | 31 | .gsc-tabHeader.gsc-tabhActive { 32 | border-top-color: #905010; 33 | border-left-color: #E9E9E9; 34 | border-right-color: #E9E9E9; 35 | background-color: #FFFFFF; 36 | } 37 | 38 | .gsc-tabsArea { 39 | border-color: #E9E9E9; 40 | } 41 | 42 | .gsc-webResult.gsc-result, 43 | .gsc-results .gsc-imageResult { 44 | border-color: #FFFFFF; 45 | background-color: #FFFFFF; 46 | } 47 | 48 | .gsc-webResult.gsc-result:hover, 49 | .gsc-imageResult:hover { 50 | border-color: #FFFFFF; 51 | background-color: #FFFFFF; 52 | } 53 | 54 | .gs-webResult.gs-result a.gs-title:link, 55 | .gs-webResult.gs-result a.gs-title:link b, 56 | .gs-imageResult a.gs-title:link, 57 | .gs-imageResult a.gs-title:link b { 58 | color: #204060; 59 | } 60 | 61 | .gs-webResult.gs-result a.gs-title:visited, 62 | .gs-webResult.gs-result a.gs-title:visited b, 63 | .gs-imageResult a.gs-title:visited, 64 | .gs-imageResult a.gs-title:visited b { 65 | color: #204060; 66 | } 67 | 68 | .gs-webResult.gs-result a.gs-title:hover, 69 | .gs-webResult.gs-result a.gs-title:hover b, 70 | .gs-imageResult a.gs-title:hover, 71 | .gs-imageResult a.gs-title:hover b { 72 | color: #204060; 73 | } 74 | 75 | .gs-webResult.gs-result a.gs-title:active, 76 | .gs-webResult.gs-result a.gs-title:active b, 77 | .gs-imageResult a.gs-title:active, 78 | .gs-imageResult a.gs-title:active b { 79 | color: #204060; 80 | } 81 | 82 | .gsc-cursor-page { 83 | color: #204060; 84 | } 85 | 86 | a.gsc-trailing-more-results:link { 87 | color: #204060; 88 | } 89 | 90 | .gs-webResult .gs-snippet, 91 | .gs-imageResult .gs-snippet { 92 | color: #000000; 93 | } 94 | 95 | .gs-webResult div.gs-visibleUrl, 96 | .gs-imageResult div.gs-visibleUrl { 97 | color: #905010; 98 | } 99 | 100 | .gs-webResult div.gs-visibleUrl-short { 101 | color: #905010; 102 | } 103 | 104 | .gs-webResult div.gs-visibleUrl-short { 105 | display: none; 106 | } 107 | 108 | .gs-webResult div.gs-visibleUrl-long { 109 | display: block; 110 | } 111 | 112 | .gsc-cursor-box { 113 | border-color: #FFFFFF; 114 | text-align: center; 115 | } 116 | 117 | .gsc-results .gsc-cursor-box .gsc-cursor-page, 118 | .gsc-results .gsc-cursor-box .gsc-cursor-current-page { 119 | margin: 5px; 120 | padding: 5px; 121 | border: 1px solid #E9E9E9; 122 | 123 | -webkit-border-radius: 5px; 124 | -moz-border-radius: 5px; 125 | border-radius: 5px; 126 | } 127 | 128 | .gsc-results .gsc-cursor-box .gsc-cursor-page { 129 | border-color: #E9E9E9; 130 | background-color: #FFFFFF; 131 | color: #204060; 132 | } 133 | 134 | .gsc-results .gsc-cursor-box .gsc-cursor-current-page { 135 | border-color: #905010; 136 | background-color: #F7F7F2; 137 | color: #204060; 138 | } 139 | 140 | .gs-promotion { 141 | border-color: #204060; 142 | background-color: #FFFFFF; 143 | } 144 | 145 | .gs-promotion a.gs-title:link, 146 | .gs-promotion a.gs-title:link *, 147 | .gs-promotion .gs-snippet a:link { 148 | color: #204060; 149 | } 150 | 151 | .gs-promotion a.gs-title:visited, 152 | .gs-promotion a.gs-title:visited *, 153 | .gs-promotion .gs-snippet a:visited { 154 | color: #204060; 155 | } 156 | 157 | .gs-promotion a.gs-title:hover, 158 | .gs-promotion a.gs-title:hover *, 159 | .gs-promotion .gs-snippet a:hover { 160 | color: #204060; 161 | } 162 | 163 | .gs-promotion a.gs-title:active, 164 | .gs-promotion a.gs-title:active *, 165 | .gs-promotion .gs-snippet a:active { 166 | color: #204060; 167 | } 168 | 169 | .gs-promotion .gs-snippet, 170 | .gs-promotion .gs-title .gs-promotion-title-right, 171 | .gs-promotion .gs-title .gs-promotion-title-right * { 172 | color: #000000; 173 | } 174 | 175 | .gs-promotion .gs-visibleUrl, 176 | .gs-promotion .gs-visibleUrl-short { 177 | color: #905010; 178 | } 179 | 180 | .gs-no-results-result .gs-snippet, .gs-error-result .gs-snippet { 181 | background-color: #F7F7F2; 182 | border-color: #E6E6E6; 183 | } 184 | -------------------------------------------------------------------------------- /src/main/webapp/css/idea.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Intellij Idea-like styling (c) Vasily Polovnyov 4 | 5 | */ 6 | 7 | pre code { 8 | display: block; padding: 0.5em; 9 | color: #000; 10 | background: #fff; 11 | } 12 | 13 | pre .subst, 14 | pre .title { 15 | font-weight: normal; 16 | color: #000; 17 | } 18 | 19 | pre .comment, 20 | pre .template_comment, 21 | pre .javadoc, 22 | pre .diff .header { 23 | color: #808080; 24 | font-style: italic; 25 | } 26 | 27 | pre .annotation, 28 | pre .decorator, 29 | pre .preprocessor, 30 | pre .doctype, 31 | pre .pi, 32 | pre .chunk, 33 | pre .shebang, 34 | pre .apache .cbracket, 35 | pre .input_number { 36 | color: #808000; 37 | } 38 | 39 | pre .tag, 40 | pre .pi { 41 | background: #efefef; 42 | } 43 | 44 | pre .tag .title, 45 | pre .id, 46 | pre .attr_selector, 47 | pre .pseudo, 48 | pre .literal, 49 | pre .keyword, 50 | pre .hexcolor, 51 | pre .css .function, 52 | pre .ini .title, 53 | pre .css .class, 54 | pre .list .title, 55 | pre .tex .command { 56 | font-weight: bold; 57 | color: #000080; 58 | } 59 | 60 | pre .attribute, 61 | pre .rules .keyword, 62 | pre .number, 63 | pre .date, 64 | pre .regexp, 65 | pre .tex .special { 66 | font-weight: bold; 67 | color: #0000ff; 68 | } 69 | 70 | pre .number, 71 | pre .regexp { 72 | font-weight: normal; 73 | } 74 | 75 | pre .string, 76 | pre .value, 77 | pre .filter .argument, 78 | pre .css .function .params, 79 | pre .apache .tag { 80 | color: #008000; 81 | font-weight: bold; 82 | } 83 | 84 | pre .symbol, 85 | pre .ruby .symbol .string, 86 | pre .ruby .symbol .keyword, 87 | pre .ruby .symbol .keymethods, 88 | pre .char, 89 | pre .tex .formula { 90 | color: #000; 91 | background: #d0eded; 92 | font-style: italic; 93 | } 94 | 95 | pre .phpdoc, 96 | pre .yardoctag, 97 | pre .javadoctag { 98 | text-decoration: underline; 99 | } 100 | 101 | pre .variable, 102 | pre .envvar, 103 | pre .apache .sqbracket, 104 | pre .nginx .built_in { 105 | color: #660e7a; 106 | } 107 | 108 | pre .addition { 109 | background: #baeeba; 110 | } 111 | 112 | pre .deletion { 113 | background: #ffc8bd; 114 | } 115 | 116 | pre .diff .change { 117 | background: #bccff9; 118 | } 119 | -------------------------------------------------------------------------------- /src/main/webapp/css/jquery.cleditor.css: -------------------------------------------------------------------------------- 1 | .cleditorMain { 2 | border: 1px solid #999; 3 | padding: 0 1px 1px; 4 | background-color: white 5 | } 6 | 7 | .cleditorMain iframe { 8 | border: none; 9 | margin: 0; 10 | padding: 0 11 | } 12 | 13 | .cleditorMain textarea { 14 | border: none; 15 | margin: 0; 16 | padding: 0; 17 | overflow-y: scroll; 18 | font: 10pt Arial, Verdana; 19 | resize: none; 20 | outline: none /* webkit grip focus */ 21 | } 22 | 23 | .cleditorToolbar { 24 | background: url('/images/toolbar.gif') repeat 25 | } 26 | 27 | .cleditorGroup { 28 | float: left; 29 | height: 26px 30 | } 31 | 32 | .cleditorButton { 33 | float: left; 34 | width: 24px; 35 | height: 24px; 36 | margin: 1px 0 1px 0; 37 | background: url('/images/buttons.gif') 38 | } 39 | 40 | .cleditorDisabled { 41 | opacity: 0.3; 42 | filter: alpha(opacity = 30) 43 | } 44 | 45 | .cleditorDivider { 46 | float: left; 47 | width: 1px; 48 | height: 23px; 49 | margin: 1px 0 1px 0; 50 | background: #CCC 51 | } 52 | 53 | .cleditorPopup { 54 | border: solid 1px #999; 55 | background-color: white; 56 | position: absolute; 57 | font: 10pt Arial, Verdana; 58 | cursor: default; 59 | z-index: 10000 60 | } 61 | 62 | .cleditorList div { 63 | padding: 2px 4px 2px 4px 64 | } 65 | 66 | .cleditorList p, 67 | .cleditorList h1, 68 | .cleditorList h2, 69 | .cleditorList h3, 70 | .cleditorList h4, 71 | .cleditorList h5, 72 | .cleditorList h6, 73 | .cleditorList font { 74 | padding: 0; 75 | margin: 0; 76 | background-color: Transparent 77 | } 78 | 79 | .cleditorColor { 80 | width: 150px; 81 | padding: 1px 0 0 1px 82 | } 83 | 84 | .cleditorColor div { 85 | float: left; 86 | width: 14px; 87 | height: 14px; 88 | margin: 0 1px 1px 0 89 | } 90 | 91 | .cleditorPrompt { 92 | background-color: #F6F7F9; 93 | padding: 4px; 94 | font-size: 8.5pt 95 | } 96 | 97 | .cleditorPrompt input, 98 | .cleditorPrompt textarea { 99 | font: 8.5pt Arial, Verdana; 100 | margin: 4px; 101 | } 102 | 103 | .cleditorPrompt input { 104 | padding: 2px; 105 | } 106 | 107 | .cleditorMsg { 108 | background-color: #FDFCEE; 109 | width: 150px; 110 | padding: 4px; 111 | font-size: 8.5pt 112 | } 113 | -------------------------------------------------------------------------------- /src/main/webapp/css/stabs.css: -------------------------------------------------------------------------------- 1 | /* 2 | .tabs, .tabs li { 3 | margin: 0; 4 | padding: 0; 5 | list-style: none; 6 | float: left; 7 | } 8 | 9 | .tabs { 10 | width: 100%; 11 | border-bottom: 0; 12 | } 13 | 14 | .tabs li { 15 | margin-left: 4px; 16 | } 17 | 18 | .tabs a { 19 | 20 | border: 1px solid #ddd; 21 | background: #f5f5f5; 22 | padding: 0 50px; 23 | line-height: 30px; 24 | display: block; 25 | text-decoration: none; 26 | margin-bottom: -1px 27 | } 28 | 29 | .tabs a.active { 30 | background: #fff; 31 | font-weight: bold; 32 | border-bottom: 1px solid white; 33 | } 34 | 35 | .tabs a:hover { 36 | background: #fff 37 | } 38 | 39 | .tab { 40 | border-top: 1px solid #ddd; 41 | clear: both; 42 | position: relative; 43 | padding: 10px 44 | } 45 | 46 | .tab h2 { 47 | margin-top: 0 48 | } 49 | */ 50 | 51 | 52 | .tabs, .tabs li { 53 | margin: 0; 54 | padding: 0; 55 | list-style: none; 56 | float: left 57 | } 58 | 59 | .tabs { 60 | width: 100%; 61 | border-bottom: 1px solid #ddd; 62 | } 63 | 64 | .tabs li { 65 | margin-left: 4px; 66 | } 67 | 68 | .tabs a { 69 | -webkit-border-top-left-radius: 10px; 70 | -webkit-border-top-right-radius: 10px; 71 | -moz-border-radius-topleft: 10px; 72 | -moz-border-radius-topright: 10px; 73 | border-top-left-radius: 10px; 74 | border-top-right-radius: 10px; 75 | 76 | border: 1px solid #ddd; 77 | background: #f5f5f5; 78 | padding: 0 50px; 79 | line-height: 25px; 80 | display: block; 81 | height: 24px; 82 | text-decoration: none; 83 | margin-bottom: -1px; 84 | } 85 | 86 | .tabs a.active { 87 | background: #fff; 88 | border-bottom: 1px solid white; 89 | font-weight: bold; 90 | } 91 | 92 | .tabs a:hover { 93 | background: #f6e5d6; 94 | text-decoration: none; 95 | color: black; 96 | } 97 | 98 | .tab { 99 | border-top: 0; 100 | clear: both; 101 | position: relative; 102 | padding: 10px; 103 | margin-bottom: 10px; 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/main/webapp/css/wysiwyg.css: -------------------------------------------------------------------------------- 1 | @import '/css/style.css'; 2 | 3 | body { 4 | background-color: white; 5 | } 6 | 7 | blockquote { 8 | width: 70%; 9 | } -------------------------------------------------------------------------------- /src/main/webapp/images/add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/add.png -------------------------------------------------------------------------------- /src/main/webapp/images/atom.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/atom.gif -------------------------------------------------------------------------------- /src/main/webapp/images/box.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/box.gif -------------------------------------------------------------------------------- /src/main/webapp/images/buttons.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/buttons.gif -------------------------------------------------------------------------------- /src/main/webapp/images/chosen-sprite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/chosen-sprite.png -------------------------------------------------------------------------------- /src/main/webapp/images/clipboard.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/clipboard.png -------------------------------------------------------------------------------- /src/main/webapp/images/content-two-columns.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/content-two-columns.gif -------------------------------------------------------------------------------- /src/main/webapp/images/content-wrapper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/content-wrapper.gif -------------------------------------------------------------------------------- /src/main/webapp/images/cross.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/cross.png -------------------------------------------------------------------------------- /src/main/webapp/images/feed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/feed.png -------------------------------------------------------------------------------- /src/main/webapp/images/footer-wrapper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/footer-wrapper.gif -------------------------------------------------------------------------------- /src/main/webapp/images/gaelyk-favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/gaelyk-favicon.png -------------------------------------------------------------------------------- /src/main/webapp/images/gradient-light.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/gradient-light.gif -------------------------------------------------------------------------------- /src/main/webapp/images/header-wrapper-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/header-wrapper-2.gif -------------------------------------------------------------------------------- /src/main/webapp/images/header.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/header.gif -------------------------------------------------------------------------------- /src/main/webapp/images/help.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/help.gif -------------------------------------------------------------------------------- /src/main/webapp/images/icon-delicious.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/icon-delicious.png -------------------------------------------------------------------------------- /src/main/webapp/images/icon-gplus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/icon-gplus.png -------------------------------------------------------------------------------- /src/main/webapp/images/icon-greader.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/icon-greader.png -------------------------------------------------------------------------------- /src/main/webapp/images/icon-twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/icon-twitter.png -------------------------------------------------------------------------------- /src/main/webapp/images/image-not-found.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/image-not-found.png -------------------------------------------------------------------------------- /src/main/webapp/images/images.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/images.png -------------------------------------------------------------------------------- /src/main/webapp/images/images2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/images2.png -------------------------------------------------------------------------------- /src/main/webapp/images/navigation-arrow-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/navigation-arrow-2.gif -------------------------------------------------------------------------------- /src/main/webapp/images/navigation-arrow.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/navigation-arrow.gif -------------------------------------------------------------------------------- /src/main/webapp/images/navigation-wrapper-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/navigation-wrapper-2.gif -------------------------------------------------------------------------------- /src/main/webapp/images/navigation.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/navigation.gif -------------------------------------------------------------------------------- /src/main/webapp/images/newspaper.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/newspaper.png -------------------------------------------------------------------------------- /src/main/webapp/images/page_white_text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/page_white_text.png -------------------------------------------------------------------------------- /src/main/webapp/images/pencil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/pencil.png -------------------------------------------------------------------------------- /src/main/webapp/images/sample-gravatar.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/sample-gravatar.jpg -------------------------------------------------------------------------------- /src/main/webapp/images/separator-vertical.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/separator-vertical.gif -------------------------------------------------------------------------------- /src/main/webapp/images/subnav-wrapper-2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/subnav-wrapper-2.gif -------------------------------------------------------------------------------- /src/main/webapp/images/subnav-wrapper.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/subnav-wrapper.gif -------------------------------------------------------------------------------- /src/main/webapp/images/toolbar.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/toolbar.gif -------------------------------------------------------------------------------- /src/main/webapp/images/transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/glaforge/bloogaey/103d920626a433180717811d039313a60e1c41da/src/main/webapp/images/transparent.png -------------------------------------------------------------------------------- /src/main/webapp/js/jquery.sTabs.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * sTabs - simple tabs jQuery plugin 3 | * http://labs.smasty.net/jquery/stabs/ 4 | * 5 | * Copyright (c) 2010 Martin Srank (http://smasty.net) 6 | * Licensed under the MIT license (http://www.opensource.org/licenses/mit-license.php). 7 | * 8 | * Built for jQuery library 9 | * http://jquery.com 10 | * 11 | */ 12 | (function($){$.fn.sTabs=function(opts){var options=$.extend({},$.fn.sTabs.defaults,opts);return this.each(function(){$(this).addClass('tabs');$(this).find('a').each(function(){$($(this).attr('href')).addClass('tab').hide();$(this).bind(options.eventType,function(e){e.preventDefault();$(this).addClass('active');options.animate?$($(this).attr('href')).fadeIn(options.duration):$($(this).attr('href')).show();$($(this).parent().siblings().find('a')).each(function(){$(this).removeClass('active');$($(this).attr('href')).hide();});})});var first=$(this).find('li:nth-child('+options.startWith+')').children('a');$(first).addClass('active');$($(first).attr('href')).show();});} 13 | $.fn.sTabs.defaults={animate:false,duration:300,startWith:1,eventType:'click'}})(jQuery); 14 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/css.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: CSS 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.css = function() { 7 | var FUNCTION = { 8 | className: 'function', 9 | begin: hljs.IDENT_RE + '\\(', end: '\\)', 10 | contains: [{ 11 | endsWithParent: true, excludeEnd: true, 12 | contains: [hljs.NUMBER_MODE, hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE] 13 | }] 14 | }; 15 | return { 16 | case_insensitive: true, 17 | defaultMode: { 18 | illegal: '[=/|\']', 19 | contains: [ 20 | hljs.C_BLOCK_COMMENT_MODE, 21 | { 22 | className: 'id', begin: '\\#[A-Za-z0-9_-]+' 23 | }, 24 | { 25 | className: 'class', begin: '\\.[A-Za-z0-9_-]+', 26 | relevance: 0 27 | }, 28 | { 29 | className: 'attr_selector', 30 | begin: '\\[', end: '\\]', 31 | illegal: '$' 32 | }, 33 | { 34 | className: 'pseudo', 35 | begin: ':(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\"\\\']+' 36 | }, 37 | { 38 | className: 'at_rule', 39 | begin: '@font-face', 40 | lexems: '[a-z-]+', 41 | keywords: {'font-face': 1} 42 | }, 43 | { 44 | className: 'at_rule', 45 | begin: '@', end: '[{;]', // at_rule eating first "{" is a good thing 46 | // because it doesn't let it to be parsed as 47 | // a rule set but instead drops parser into 48 | // the defaultMode which is how it should be. 49 | excludeEnd: true, 50 | keywords: {'import': 1, 'page': 1, 'media': 1, 'charset': 1}, 51 | contains: [ 52 | FUNCTION, 53 | hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE, 54 | hljs.NUMBER_MODE 55 | ] 56 | }, 57 | { 58 | className: 'tag', begin: hljs.IDENT_RE, 59 | relevance: 0 60 | }, 61 | { 62 | className: 'rules', 63 | begin: '{', end: '}', 64 | illegal: '[^\\s]', 65 | relevance: 0, 66 | contains: [ 67 | hljs.C_BLOCK_COMMENT_MODE, 68 | { 69 | className: 'rule', 70 | begin: '[^\\s]', returnBegin: true, end: ';', endsWithParent: true, 71 | contains: [ 72 | { 73 | className: 'attribute', 74 | begin: '[A-Z\\_\\.\\-]+', end: ':', 75 | excludeEnd: true, 76 | illegal: '[^\\s]', 77 | starts: { 78 | className: 'value', 79 | endsWithParent: true, excludeEnd: true, 80 | contains: [ 81 | FUNCTION, 82 | hljs.NUMBER_MODE, 83 | hljs.QUOTE_STRING_MODE, 84 | hljs.APOS_STRING_MODE, 85 | hljs.C_BLOCK_COMMENT_MODE, 86 | { 87 | className: 'hexcolor', begin: '\\#[0-9A-F]+' 88 | }, 89 | { 90 | className: 'important', begin: '!important' 91 | } 92 | ] 93 | } 94 | } 95 | ] 96 | } 97 | ] 98 | } 99 | ] 100 | } 101 | }; 102 | }(); 103 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/diff.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Diff 3 | Description: Unified and context diff 4 | Author: Vasily Polovnyov 5 | Category: common 6 | */ 7 | 8 | hljs.LANGUAGES.diff = { 9 | case_insensitive: true, 10 | defaultMode: { 11 | contains: [ 12 | { 13 | className: 'chunk', 14 | begin: '^\\@\\@ +\\-\\d+,\\d+ +\\+\\d+,\\d+ +\\@\\@$', 15 | relevance: 10 16 | }, 17 | { 18 | className: 'chunk', 19 | begin: '^\\*\\*\\* +\\d+,\\d+ +\\*\\*\\*\\*$', 20 | relevance: 10 21 | }, 22 | { 23 | className: 'chunk', 24 | begin: '^\\-\\-\\- +\\d+,\\d+ +\\-\\-\\-\\-$', 25 | relevance: 10 26 | }, 27 | { 28 | className: 'header', 29 | begin: 'Index: ', end: '$' 30 | }, 31 | { 32 | className: 'header', 33 | begin: '=====', end: '=====$' 34 | }, 35 | { 36 | className: 'header', 37 | begin: '^\\-\\-\\-', end: '$' 38 | }, 39 | { 40 | className: 'header', 41 | begin: '^\\*{3} ', end: '$' 42 | }, 43 | { 44 | className: 'header', 45 | begin: '^\\+\\+\\+', end: '$' 46 | }, 47 | { 48 | className: 'header', 49 | begin: '\\*{5}', end: '\\*{5}$' 50 | }, 51 | { 52 | className: 'addition', 53 | begin: '^\\+', end: '$' 54 | }, 55 | { 56 | className: 'deletion', 57 | begin: '^\\-', end: '$' 58 | }, 59 | { 60 | className: 'change', 61 | begin: '^\\!', end: '$' 62 | } 63 | ] 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/go.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Go 3 | Author: Stephan Kountso aka StepLg 4 | Description: Google go language (golang). For info about language see http://golang.org/ 5 | */ 6 | 7 | hljs.LANGUAGES.go = function(){ 8 | var GO_KEYWORDS = { 9 | 'keyword': { 10 | 'break' : 1, 'default' : 1, 'func' : 1, 'interface' : 1, 'select' : 1, 11 | 'case' : 1, 'map' : 1, 'struct' : 1, 'chan' : 1, 12 | 'else' : 1, 'goto' : 1, 'package' : 1, 'switch' : 1, 'const' : 1, 13 | 'fallthrough' : 1, 'if' : 1, 'range' : 1, 'type' : 1, 'continue' : 1, 14 | 'for' : 1, 'import' : 1, 'return' : 1, 'var' : 1, 'go': 1, 'defer' : 1 15 | }, 16 | 'constant': { 17 | 'true': 1, 'false': 1, 'iota': 1, 'nil': 1 18 | }, 19 | 'typename': { 20 | 'bool': 1, 'byte': 1, 'complex64': 1, 'complex128': 1, 'float32': 1, 21 | 'float64': 1, 'int8': 1, 'int16': 1, 'int32': 1, 'int64': 1, 'string': 1, 22 | 'uint8': 1, 'uint16': 1, 'uint32': 1, 'uint64': 1, 'int': 1, 'uint': 1, 23 | 'uintptr': 1 24 | }, 25 | 'built_in': { 26 | 'append': 1, 'cap': 1, 'close': 1, 'complex': 1, 'copy': 1, 'imag': 1, 27 | 'len': 1, 'make': 1, 'new': 1, 'panic': 1, 'print': 1, 'println': 1, 28 | 'real': 1, 'recover': 1 29 | } 30 | }; 31 | return { 32 | defaultMode: { 33 | keywords: GO_KEYWORDS, 34 | illegal: ' 4 | Category: Inspired from Vsevolod's Java mode, but adapted to work with Groovy. 5 | */ 6 | hljs.LANGUAGES.groovy = { 7 | defaultMode: { 8 | keywords: { 9 | 'def': 1, 'as': 1, 'in': 1, 'false': 1, 'synchronized': 1, 'int': 1, 'abstract': 1, 'float': 1, 10 | 'private': 1, 'char': 1, 'interface': 1, 'boolean': 1, 'static': 1, 'null': 1, 'if': 1, 'const': 1, 11 | 'for': 1, 'true': 1, 'while': 1, 'long': 1, 'throw': 1, 'strictfp': 1, 'finally': 1, 'protected': 1, 12 | 'extends': 1, 'import': 1, 'native': 1, 'final': 1, 'implements': 1, 'return': 1, 'void': 1, 'enum': 1, 13 | 'else': 1, 'break': 1, 'transient': 1, 'new': 1, 'catch': 1, 'instanceof': 1, 'byte': 1, 'super': 1, 14 | 'class': 1, 'volatile': 1, 'case': 1, 'assert': 1, 'short': 1, 'package': 1, 'default': 1, 'double': 1, 15 | 'public': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'throws': 1}, 16 | contains: [ 17 | { 18 | className: 'javadoc', 19 | begin: '/\\*\\*', end: '\\*/', 20 | contains: [{ 21 | className: 'javadoctag', begin: '@[A-Za-z]+' 22 | }], 23 | relevance: 10 24 | }, 25 | { 26 | className: 'string', 27 | begin: '"""', end: '"""', 28 | relevance: 10 29 | }, 30 | { 31 | className: 'string', 32 | begin: "'''", end: "'''", 33 | relevance: 10 34 | }, 35 | { 36 | className: 'string', 37 | begin: "\\$/", end: "/\\$", 38 | relevance: 10 39 | }, 40 | hljs.C_LINE_COMMENT_MODE, 41 | hljs.C_BLOCK_COMMENT_MODE, 42 | hljs.APOS_STRING_MODE, 43 | hljs.QUOTE_STRING_MODE, 44 | hljs.HASH_COMMENT_MODE, 45 | { 46 | className: 'class', 47 | begin: '(class |interface )', end: '{', 48 | keywords: {'class': 1, 'interface': 1}, 49 | illegal: ':', 50 | contains: [ 51 | { 52 | begin: '(implements|extends)', 53 | keywords: {'extends': 1, 'implements': 1}, 54 | relevance: 10 55 | }, 56 | { 57 | className: 'title', 58 | begin: hljs.UNDERSCORE_IDENT_RE 59 | } 60 | ] 61 | }, 62 | hljs.C_NUMBER_MODE, 63 | { 64 | className: 'annotation', begin: '@[A-Za-z]+' 65 | } 66 | ] 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/haskell.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Haskell 3 | Author: Jeremy Hull 4 | */ 5 | 6 | hljs.LANGUAGES.haskell = function(){ 7 | var LABEL = { 8 | className: 'label', 9 | begin: '\\b[A-Z][\\w\\\']*', 10 | relevance: 0 11 | }; 12 | var CONTAINER = { 13 | className: 'container', 14 | begin: '\\(', end: '\\)', 15 | contains: [ 16 | {className: 'label', begin: '\\b[A-Z][\\w\\(\\)\\.\\\']*'}, 17 | {className: 'title', begin: '[_a-z][\\w\\\']*'} 18 | ] 19 | }; 20 | 21 | return { 22 | defaultMode: { 23 | keywords: { 24 | 'keyword': {'let': 1,'in': 1,'if': 1,'then': 1,'else': 1,'case': 1,'of': 1,'where': 1,'do': 1,'module': 1,'import': 1, 'hiding': 1,'qualified': 1,'type': 1,'data': 1,'newtype': 1,'deriving': 1,'class': 1,'instance': 1,'null': 1,'not': 1,'as': 1}, 25 | 'built_in': {'Bool': 1,'True': 1,'False': 1,'Int': 1,'Char': 1,'Maybe': 1,'Nothing': 1,'String': 1} 26 | }, 27 | contains: [ 28 | { 29 | className: 'comment', 30 | begin: '--', end: '$' 31 | }, 32 | { 33 | className: 'comment', 34 | begin: '{-', end: '-}' 35 | }, 36 | hljs.APOS_STRING_MODE, 37 | hljs.QUOTE_STRING_MODE, 38 | { 39 | className: 'import', 40 | begin: '\\bimport', end: '$', 41 | keywords: {'import': 1, 'qualified': 1, 'as': 1, 'hiding': 1}, 42 | contains: [CONTAINER] 43 | }, 44 | { 45 | className: 'module', 46 | begin: '\\bmodule', end: 'where', 47 | keywords: {'module': 1, 'where': 1}, 48 | contains: [CONTAINER] 49 | }, 50 | { 51 | className: 'class', 52 | begin: '\\b(class|instance|data|(new)?type)', end: '(where|$)', 53 | keywords: {'class': 1, 'where': 1, 'instance': 1,'data': 1,'type': 1,'newtype': 1, 'deriving': 1}, 54 | contains: [LABEL] 55 | }, 56 | hljs.C_NUMBER_MODE, 57 | { 58 | className: 'shebang', 59 | begin: '#!\\/usr\\/bin\\/env\ runhaskell', end: '$' 60 | }, 61 | LABEL, 62 | { 63 | className: 'title', begin: '^[_a-z][\\w\\\']*' 64 | } 65 | ] 66 | } 67 | }; 68 | }(); 69 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/ini.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Ini 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.ini = { 7 | case_insensitive: true, 8 | defaultMode: { 9 | illegal: '[^\\s]', 10 | contains: [ 11 | { 12 | className: 'comment', 13 | begin: ';', end: '$' 14 | }, 15 | { 16 | className: 'title', 17 | begin: '^\\[', end: '\\]' 18 | }, 19 | { 20 | className: 'setting', 21 | begin: '^[a-z0-9_\\[\\]]+[ \\t]*=[ \\t]*', end: '$', 22 | contains: [ 23 | { 24 | className: 'value', 25 | endsWithParent: true, 26 | keywords: {'on': 1, 'off': 1, 'true': 1, 'false': 1, 'yes': 1, 'no': 1}, 27 | contains: [hljs.QUOTE_STRING_MODE, hljs.NUMBER_MODE] 28 | } 29 | ] 30 | } 31 | ] 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/java.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Java 3 | Author: Vsevolod Solovyov 4 | Category: common 5 | */ 6 | 7 | hljs.LANGUAGES.java = { 8 | defaultMode: { 9 | keywords: {'false': 1, 'synchronized': 1, 'int': 1, 'abstract': 1, 'float': 1, 'private': 1, 'char': 1, 'interface': 1, 'boolean': 1, 'static': 1, 'null': 1, 'if': 1, 'const': 1, 'for': 1, 'true': 1, 'while': 1, 'long': 1, 'throw': 1, 'strictfp': 1, 'finally': 1, 'protected': 1, 'extends': 1, 'import': 1, 'native': 1, 'final': 1, 'implements': 1, 'return': 1, 'void': 1, 'enum': 1, 'else': 1, 'break': 1, 'transient': 1, 'new': 1, 'catch': 1, 'instanceof': 1, 'byte': 1, 'super': 1, 'class': 1, 'volatile': 1, 'case': 1, 'assert': 1, 'short': 1, 'package': 1, 'default': 1, 'double': 1, 'public': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'throws': 1}, 10 | contains: [ 11 | { 12 | className: 'javadoc', 13 | begin: '/\\*\\*', end: '\\*/', 14 | contains: [{ 15 | className: 'javadoctag', begin: '@[A-Za-z]+' 16 | }], 17 | relevance: 10 18 | }, 19 | hljs.C_LINE_COMMENT_MODE, 20 | hljs.C_BLOCK_COMMENT_MODE, 21 | hljs.APOS_STRING_MODE, 22 | hljs.QUOTE_STRING_MODE, 23 | { 24 | className: 'class', 25 | begin: '(class |interface )', end: '{', 26 | keywords: {'class': 1, 'interface': 1}, 27 | illegal: ':', 28 | contains: [ 29 | { 30 | begin: '(implements|extends)', 31 | keywords: {'extends': 1, 'implements': 1}, 32 | relevance: 10 33 | }, 34 | { 35 | className: 'title', 36 | begin: hljs.UNDERSCORE_IDENT_RE 37 | } 38 | ] 39 | }, 40 | hljs.C_NUMBER_MODE, 41 | { 42 | className: 'annotation', begin: '@[A-Za-z]+' 43 | } 44 | ] 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/javascript.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Javascript 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.javascript = { 7 | defaultMode: { 8 | keywords: { 9 | 'keyword': {'in': 1, 'if': 1, 'for': 1, 'while': 1, 'finally': 1, 'var': 1, 'new': 1, 'function': 1, 'do': 1, 'return': 1, 'void': 1, 'else': 1, 'break': 1, 'catch': 1, 'instanceof': 1, 'with': 1, 'throw': 1, 'case': 1, 'default': 1, 'try': 1, 'this': 1, 'switch': 1, 'continue': 1, 'typeof': 1, 'delete': 1}, 10 | 'literal': {'true': 1, 'false': 1, 'null': 1} 11 | }, 12 | contains: [ 13 | hljs.APOS_STRING_MODE, 14 | hljs.QUOTE_STRING_MODE, 15 | hljs.C_LINE_COMMENT_MODE, 16 | hljs.C_BLOCK_COMMENT_MODE, 17 | hljs.C_NUMBER_MODE, 18 | { // regexp container 19 | begin: '(' + hljs.RE_STARTERS_RE + '|case|return|throw)\\s*', 20 | keywords: {'return': 1, 'throw': 1, 'case': 1}, 21 | contains: [ 22 | hljs.C_LINE_COMMENT_MODE, 23 | hljs.C_BLOCK_COMMENT_MODE, 24 | { 25 | className: 'regexp', 26 | begin: '/.*?[^\\\\/]/[gim]*' 27 | } 28 | ], 29 | relevance: 0 30 | }, 31 | { 32 | className: 'function', 33 | begin: '\\bfunction\\b', end: '{', 34 | keywords: {'function': 1}, 35 | contains: [ 36 | { 37 | className: 'title', begin: '[A-Za-z$_][0-9A-Za-z$_]*' 38 | }, 39 | { 40 | className: 'params', 41 | begin: '\\(', end: '\\)', 42 | contains: [ 43 | hljs.APOS_STRING_MODE, 44 | hljs.QUOTE_STRING_MODE, 45 | hljs.C_LINE_COMMENT_MODE, 46 | hljs.C_BLOCK_COMMENT_MODE 47 | ] 48 | } 49 | ] 50 | } 51 | ] 52 | } 53 | }; 54 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/lisp.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Lisp 3 | Description: Generic lisp syntax 4 | Author: Vasily Polovnyov 5 | */ 6 | 7 | hljs.LANGUAGES.lisp = function(){ 8 | var LISP_IDENT_RE = '[a-zA-Z_\\-\\+\\*\\/\\<\\=\\>\\&\\#][a-zA-Z0-9_\\-\\+\\*\\/\\<\\=\\>\\&\\#]*'; 9 | var LISP_SIMPLE_NUMBER_RE = '(\\-|\\+)?\\d+(\\.\\d+|\\/\\d+)?((d|e|f|l|s)(\\+|\\-)?\\d+)?'; 10 | var LITERAL = { 11 | className: 'literal', 12 | begin: '\\b(t{1}|nil)\\b' 13 | }; 14 | var NUMBER1 = { 15 | className: 'number', begin: LISP_SIMPLE_NUMBER_RE 16 | }; 17 | var NUMBER2 = { 18 | className: 'number', begin: '#b[0-1]+(/[0-1]+)?' 19 | }; 20 | var NUMBER3 = { 21 | className: 'number', begin: '#o[0-7]+(/[0-7]+)?' 22 | }; 23 | var NUMBER4 = { 24 | className: 'number', begin: '#x[0-9a-f]+(/[0-9a-f]+)?' 25 | }; 26 | var NUMBER5 = { 27 | className: 'number', begin: '#c\\(' + LISP_SIMPLE_NUMBER_RE + ' +' + LISP_SIMPLE_NUMBER_RE, end: '\\)' 28 | }; 29 | var STRING = { 30 | className: 'string', 31 | begin: '"', end: '"', 32 | contains: [hljs.BACKSLASH_ESCAPE], 33 | relevance: 0 34 | }; 35 | var COMMENT = { 36 | className: 'comment', 37 | begin: ';', end: '$' 38 | }; 39 | var VARIABLE = { 40 | className: 'variable', 41 | begin: '\\*', end: '\\*' 42 | }; 43 | var KEYWORD = { 44 | className: 'keyword', 45 | begin: '[:&]' + LISP_IDENT_RE 46 | }; 47 | var QUOTED_LIST = { 48 | begin: '\\(', end: '\\)' 49 | }; 50 | QUOTED_LIST.contains = [QUOTED_LIST, LITERAL, NUMBER1, NUMBER2, NUMBER3, NUMBER4, NUMBER5, STRING]; 51 | var QUOTED1 = { 52 | className: 'quoted', 53 | begin: '[\'`]\\(', end: '\\)', 54 | contains: [NUMBER1, NUMBER2, NUMBER3, NUMBER4, NUMBER5, STRING, VARIABLE, KEYWORD, QUOTED_LIST] 55 | }; 56 | var QUOTED2 = { 57 | className: 'quoted', 58 | begin: '\\(quote ', end: '\\)', 59 | keywords: {'title': {'quote': 1}}, 60 | contains: [NUMBER1, NUMBER2, NUMBER3, NUMBER4, NUMBER5, STRING, VARIABLE, KEYWORD, QUOTED_LIST] 61 | }; 62 | var LIST = { 63 | className: 'list', 64 | begin: '\\(', end: '\\)' 65 | }; 66 | var BODY = { 67 | className: 'body', 68 | endsWithParent: true, excludeEnd: true 69 | }; 70 | LIST.contains = [{className: 'title', begin: LISP_IDENT_RE}, BODY]; 71 | BODY.contains = [QUOTED1, QUOTED2, LIST, LITERAL, NUMBER1, NUMBER2, NUMBER3, NUMBER4, NUMBER5, STRING, COMMENT, VARIABLE, KEYWORD]; 72 | 73 | return { 74 | case_insensitive: true, 75 | defaultMode: { 76 | illegal: '[^\\s]', 77 | contains: [ 78 | LITERAL, 79 | NUMBER1, NUMBER2, NUMBER3, NUMBER4, NUMBER5, 80 | STRING, 81 | COMMENT, 82 | QUOTED1, QUOTED2, 83 | LIST 84 | ] 85 | } 86 | }; 87 | }(); 88 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/objectivec.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Objective C 3 | Author: Valerii Hiora 4 | */ 5 | 6 | hljs.LANGUAGES.objectivec = function(){ 7 | var OBJC_KEYWORDS = { 8 | 'keyword': { 9 | 'false': 1, 'int': 1, 'float': 1, 'while': 1, 'private': 1, 'char': 1, 10 | 'catch': 1, 'export': 1, 'sizeof': 2, 'typedef': 2, 'const': 1, 11 | 'struct': 1, 'for': 1, 'union': 1, 'unsigned': 1, 'long': 1, 12 | 'volatile': 2, 'static': 1, 'protected': 1, 'bool': 1, 'mutable': 1, 13 | 'if': 1, 'public': 1, 'do': 1, 'return': 1, 'goto': 1, 'void': 2, 14 | 'enum': 1, 'else': 1, 'break': 1, 'extern': 1, 'true': 1, 'class': 1, 15 | 'asm': 1, 'case': 1, 'short': 1, 'default': 1, 'double': 1, 'throw': 1, 16 | 'register': 1, 'explicit': 1, 'signed': 1, 'typename': 1, 'try': 1, 17 | 'this': 1, 'switch': 1, 'continue': 1, 'wchar_t': 1, 'inline': 1, 18 | 'readonly': 1, 'assign': 1, 'property': 1, 'protocol': 10, 'self': 1, 19 | 'synchronized': 1, 'end': 1, 'synthesize': 50, 'id': 1, 'optional': 1, 20 | 'required': 1, 'implementation': 10, 'nonatomic': 1,'interface': 1, 21 | 'super': 1, 'unichar': 1, 'finally': 2, 'dynamic': 2, 'nil': 1 22 | }, 23 | 'built_in': { 24 | 'YES': 5, 'NO': 5, 'NULL': 1, 'IBOutlet': 50, 'IBAction': 50, 25 | 'NSString': 50, 'NSDictionary': 50, 'CGRect': 50, 'CGPoint': 50, 26 | 'NSRange': 50, 'release': 1, 'retain': 1, 'autorelease': 50, 27 | 'UIButton': 50, 'UILabel': 50, 'UITextView': 50, 'UIWebView': 50, 28 | 'MKMapView': 50, 'UISegmentedControl': 50, 'NSObject': 50, 29 | 'UITableViewDelegate': 50, 'UITableViewDataSource': 50, 'NSThread': 50, 30 | 'UIActivityIndicator': 50, 'UITabbar': 50, 'UIToolBar': 50, 31 | 'UIBarButtonItem': 50, 'UIImageView': 50, 'NSAutoreleasePool': 50, 32 | 'UITableView': 50, 'BOOL': 1, 'NSInteger': 20, 'CGFloat': 20, 33 | 'NSException': 50, 'NSLog': 50, 'NSMutableString': 50, 34 | 'NSMutableArray': 50, 'NSMutableDictionary': 50, 'NSURL': 50 35 | } 36 | }; 37 | return { 38 | defaultMode: { 39 | keywords: OBJC_KEYWORDS, 40 | illegal: '' 67 | } 68 | ] 69 | }, 70 | { 71 | className: 'preprocessor', 72 | begin: '#', 73 | end: '$' 74 | }, 75 | { 76 | className: 'class', 77 | begin: 'interface|class|protocol|implementation', 78 | end: '({|$)', 79 | keywords: { 80 | 'interface': 1, 81 | 'class': 1, 82 | 'protocol': 5, 83 | 'implementation': 5 84 | }, 85 | contains: [{ 86 | className: 'id', 87 | begin: hljs.UNDERSCORE_IDENT_RE 88 | } 89 | ] 90 | } 91 | ] 92 | } 93 | }; 94 | }(); 95 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/perl.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Perl 3 | Author: Peter Leonov 4 | Category: common 5 | */ 6 | 7 | hljs.LANGUAGES.perl = function(){ 8 | var PERL_KEYWORDS = {'getpwent': 1, 'getservent': 1, 'quotemeta': 1, 'msgrcv': 1, 'scalar': 1, 'kill': 1, 'dbmclose': 1, 'undef': 1, 'lc': 1, 'ma': 1, 'syswrite': 1, 'tr': 1, 'send': 1, 'umask': 1, 'sysopen': 1, 'shmwrite': 1, 'vec': 1, 'qx': 1, 'utime': 1, 'local': 1, 'oct': 1, 'semctl': 1, 'localtime': 1, 'readpipe': 1, 'do': 1, 'return': 1, 'format': 1, 'read': 1, 'sprintf': 1, 'dbmopen': 1, 'pop': 1, 'getpgrp': 1, 'not': 1, 'getpwnam': 1, 'rewinddir': 1, 'qq': 1, 'fileno': 1, 'qw': 1, 'endprotoent': 1, 'wait': 1, 'sethostent': 1, 'bless': 1, 's': 1, 'opendir': 1, 'continue': 1, 'each': 1, 'sleep': 1, 'endgrent': 1, 'shutdown': 1, 'dump': 1, 'chomp': 1, 'connect': 1, 'getsockname': 1, 'die': 1, 'socketpair': 1, 'close': 1, 'flock': 1, 'exists': 1, 'index': 1, 'shmget': 1, 'sub': 1, 'for': 1, 'endpwent': 1, 'redo': 1, 'lstat': 1, 'msgctl': 1, 'setpgrp': 1, 'abs': 1, 'exit': 1, 'select': 1, 'print': 1, 'ref': 1, 'gethostbyaddr': 1, 'unshift': 1, 'fcntl': 1, 'syscall': 1, 'goto': 1, 'getnetbyaddr': 1, 'join': 1, 'gmtime': 1, 'symlink': 1, 'semget': 1, 'splice': 1, 'x': 1, 'getpeername': 1, 'recv': 1, 'log': 1, 'setsockopt': 1, 'cos': 1, 'last': 1, 'reverse': 1, 'gethostbyname': 1, 'getgrnam': 1, 'study': 1, 'formline': 1, 'endhostent': 1, 'times': 1, 'chop': 1, 'length': 1, 'gethostent': 1, 'getnetent': 1, 'pack': 1, 'getprotoent': 1, 'getservbyname': 1, 'rand': 1, 'mkdir': 1, 'pos': 1, 'chmod': 1, 'y': 1, 'substr': 1, 'endnetent': 1, 'printf': 1, 'next': 1, 'open': 1, 'msgsnd': 1, 'readdir': 1, 'use': 1, 'unlink': 1, 'getsockopt': 1, 'getpriority': 1, 'rindex': 1, 'wantarray': 1, 'hex': 1, 'system': 1, 'getservbyport': 1, 'endservent': 1, 'int': 1, 'chr': 1, 'untie': 1, 'rmdir': 1, 'prototype': 1, 'tell': 1, 'listen': 1, 'fork': 1, 'shmread': 1, 'ucfirst': 1, 'setprotoent': 1, 'else': 1, 'sysseek': 1, 'link': 1, 'getgrgid': 1, 'shmctl': 1, 'waitpid': 1, 'unpack': 1, 'getnetbyname': 1, 'reset': 1, 'chdir': 1, 'grep': 1, 'split': 1, 'require': 1, 'caller': 1, 'lcfirst': 1, 'until': 1, 'warn': 1, 'while': 1, 'values': 1, 'shift': 1, 'telldir': 1, 'getpwuid': 1, 'my': 1, 'getprotobynumber': 1, 'delete': 1, 'and': 1, 'sort': 1, 'uc': 1, 'defined': 1, 'srand': 1, 'accept': 1, 'package': 1, 'seekdir': 1, 'getprotobyname': 1, 'semop': 1, 'our': 1, 'rename': 1, 'seek': 1, 'if': 1, 'q': 1, 'chroot': 1, 'sysread': 1, 'setpwent': 1, 'no': 1, 'crypt': 1, 'getc': 1, 'chown': 1, 'sqrt': 1, 'write': 1, 'setnetent': 1, 'setpriority': 1, 'foreach': 1, 'tie': 1, 'sin': 1, 'msgget': 1, 'map': 1, 'stat': 1, 'getlogin': 1, 'unless': 1, 'elsif': 1, 'truncate': 1, 'exec': 1, 'keys': 1, 'glob': 1, 'tied': 1, 'closedir': 1, 'ioctl': 1, 'socket': 1, 'readlink': 1, 'eval': 1, 'xor': 1, 'readline': 1, 'binmode': 1, 'setservent': 1, 'eof': 1, 'ord': 1, 'bind': 1, 'alarm': 1, 'pipe': 1, 'atan2': 1, 'getgrent': 1, 'exp': 1, 'time': 1, 'push': 1, 'setgrent': 1, 'gt': 1, 'lt': 1, 'or': 1, 'ne': 1, 'm': 1}; 9 | var SUBST = { 10 | className: 'subst', 11 | begin: '[$@]\\{', end: '\}', 12 | keywords: PERL_KEYWORDS, 13 | relevance: 10 14 | }; 15 | var VAR1 = { 16 | className: 'variable', 17 | begin: '\\$\\d' 18 | }; 19 | var VAR2 = { 20 | className: 'variable', 21 | begin: '[\\$\\%\\@\\*](\\^\\w\\b|#\\w+(\\:\\:\\w+)*|[^\\s\\w{]|{\\w+}|\\w+(\\:\\:\\w*)*)' 22 | }; 23 | var STRING_CONTAINS = [hljs.BACKSLASH_ESCAPE, SUBST, VAR1, VAR2]; 24 | var PERL_DEFAULT_CONTAINS = [ 25 | hljs.HASH_COMMENT_MODE, 26 | { 27 | className: 'comment', 28 | begin: '^(__END__|__DATA__)', end: '\\n$', 29 | relevance: 5 30 | }, 31 | { 32 | className: 'string', 33 | begin: 'q[qwxr]?\\s*\\(', end: '\\)', 34 | contains: STRING_CONTAINS, 35 | relevance: 5 36 | }, 37 | { 38 | className: 'string', 39 | begin: 'q[qwxr]?\\s*\\[', end: '\\]', 40 | contains: STRING_CONTAINS, 41 | relevance: 5 42 | }, 43 | { 44 | className: 'string', 45 | begin: 'q[qwxr]?\\s*\\{', end: '\\}', 46 | contains: STRING_CONTAINS, 47 | relevance: 5 48 | }, 49 | { 50 | className: 'string', 51 | begin: 'q[qwxr]?\\s*\\|', end: '\\|', 52 | contains: STRING_CONTAINS, 53 | relevance: 5 54 | }, 55 | { 56 | className: 'string', 57 | begin: 'q[qwxr]?\\s*\\<', end: '\\>', 58 | contains: STRING_CONTAINS, 59 | relevance: 5 60 | }, 61 | { 62 | className: 'string', 63 | begin: 'qw\\s+q', end: 'q', 64 | contains: STRING_CONTAINS, 65 | relevance: 5 66 | }, 67 | { 68 | className: 'string', 69 | begin: '\'', end: '\'', 70 | contains: [hljs.BACKSLASH_ESCAPE], 71 | relevance: 0 72 | }, 73 | { 74 | className: 'string', 75 | begin: '"', end: '"', 76 | contains: STRING_CONTAINS, 77 | relevance: 0 78 | }, 79 | { 80 | className: 'string', 81 | begin: '`', end: '`', 82 | contains: [hljs.BACKSLASH_ESCAPE] 83 | }, 84 | { 85 | className: 'string', 86 | begin: '{\\w+}', 87 | relevance: 0 88 | }, 89 | { 90 | className: 'string', 91 | begin: '\-?\\w+\\s*\\=\\>', 92 | relevance: 0 93 | }, 94 | { 95 | className: 'number', 96 | begin: '(\\b0[0-7_]+)|(\\b0x[0-9a-fA-F_]+)|(\\b[1-9][0-9_]*(\\.[0-9_]+)?)|[0_]\\b', 97 | relevance: 0 98 | }, 99 | { 100 | className: 'regexp', 101 | begin: '(s|tr|y)/(\\\\.|[^/])*/(\\\\.|[^/])*/[a-z]*', 102 | relevance: 10 103 | }, 104 | { 105 | className: 'regexp', 106 | begin: '(m|qr)?/', end: '/[a-z]*', 107 | contains: [hljs.BACKSLASH_ESCAPE], 108 | relevance: 0 // allows empty "//" which is a common comment delimiter in other languages 109 | }, 110 | { 111 | className: 'sub', 112 | begin: '\\bsub\\b', end: '(\\s*\\(.*?\\))?[;{]', 113 | keywords: {'sub':1}, 114 | relevance: 5 115 | }, 116 | VAR1, VAR2, 117 | { 118 | className: 'operator', 119 | begin: '-\\w\\b', 120 | relevance: 0 121 | }, 122 | { 123 | className: 'pod', 124 | begin: '\\=\\w', end: '\\=cut' 125 | } 126 | ]; 127 | SUBST.contains = PERL_DEFAULT_CONTAINS; 128 | 129 | return { 130 | defaultMode: { 131 | keywords: PERL_KEYWORDS, 132 | contains: PERL_DEFAULT_CONTAINS 133 | } 134 | }; 135 | }(); 136 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/php.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: PHP 3 | Author: Victor Karamzin 4 | Category: common 5 | */ 6 | 7 | hljs.LANGUAGES.php = { 8 | case_insensitive: true, 9 | defaultMode: { 10 | keywords: { 11 | 'and': 1, 'include_once': 1, 'list': 1, 'abstract': 1, 'global': 1, 12 | 'private': 1, 'echo': 1, 'interface': 1, 'as': 1, 'static': 1, 13 | 'endswitch': 1, 'array': 1, 'null': 1, 'if': 1, 'endwhile': 1, 'or': 1, 14 | 'const': 1, 'for': 1, 'endforeach': 1, 'self': 1, 'var': 1, 'while': 1, 15 | 'isset': 1, 'public': 1, 'protected': 1, 'exit': 1, 'foreach': 1, 16 | 'throw': 1, 'elseif': 1, 'extends': 1, 'include': 1, '__FILE__': 1, 17 | 'empty': 1, 'require_once': 1, 'function': 1, 'do': 1, 'xor': 1, 18 | 'return': 1, 'implements': 1, 'parent': 1, 'clone': 1, 'use': 1, 19 | '__CLASS__': 1, '__LINE__': 1, 'else': 1, 'break': 1, 'print': 1, 20 | 'eval': 1, 'new': 1, 'catch': 1, '__METHOD__': 1, 'class': 1, 'case': 1, 21 | 'exception': 1, 'php_user_filter': 1, 'default': 1, 'die': 1, 22 | 'require': 1, '__FUNCTION__': 1, 'enddeclare': 1, 'final': 1, 'try': 1, 23 | 'this': 1, 'switch': 1, 'continue': 1, 'endfor': 1, 'endif': 1, 24 | 'declare': 1, 'unset': 1, 'true': 1, 'false': 1, 'namespace': 1 25 | }, 26 | contains: [ 27 | hljs.C_LINE_COMMENT_MODE, 28 | hljs.HASH_COMMENT_MODE, 29 | { 30 | className: 'comment', 31 | begin: '/\\*', end: '\\*/', 32 | contains: [{ 33 | className: 'phpdoc', 34 | begin: '\\s@[A-Za-z]+', 35 | relevance: 10 36 | }] 37 | }, 38 | hljs.C_NUMBER_MODE, 39 | hljs.inherit(hljs.APOS_STRING_MODE, {illegal: null}), 40 | hljs.inherit(hljs.QUOTE_STRING_MODE, {illegal: null}), 41 | { 42 | className: 'variable', 43 | begin: '\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' 44 | }, 45 | { 46 | className: 'preprocessor', 47 | begin: '<\\?php', 48 | relevance: 10 49 | }, 50 | { 51 | className: 'preprocessor', 52 | begin: '\\?>' 53 | } 54 | ] 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/python.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Python 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.python = function() { 7 | var STR1 = { 8 | className: 'string', 9 | begin: 'u?r?\'\'\'', end: '\'\'\'', 10 | relevance: 10 11 | }; 12 | var STR2 = { 13 | className: 'string', 14 | begin: 'u?r?"""', end: '"""', 15 | relevance: 10 16 | }; 17 | var STR3 = { 18 | className: 'string', 19 | begin: '(u|r|ur)\'', end: '\'', 20 | contains: [hljs.BACKSLASH_ESCAPE], 21 | relevance: 10 22 | }; 23 | var STR4 = { 24 | className: 'string', 25 | begin: '(u|r|ur)"', end: '"', 26 | contains: [hljs.BACKSLASH_ESCAPE], 27 | relevance: 10 28 | }; 29 | var TITLE = { 30 | className: 'title', begin: hljs.UNDERSCORE_IDENT_RE 31 | }; 32 | var PARAMS = { 33 | className: 'params', 34 | begin: '\\(', end: '\\)', 35 | contains: [STR1, STR2, STR3, STR4, hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE] 36 | }; 37 | 38 | return { 39 | defaultMode: { 40 | keywords: { 41 | 'keyword': {'and': 1, 'elif': 1, 'is': 1, 'global': 1, 'as': 1, 'in': 1, 'if': 1, 'from': 1, 'raise': 1, 'for': 1, 'except': 1, 'finally': 1, 'print': 1, 'import': 1, 'pass': 1, 'return': 1, 'exec': 1, 'else': 1, 'break': 1, 'not': 1, 'with': 1, 'class': 1, 'assert': 1, 'yield': 1, 'try': 1, 'while': 1, 'continue': 1, 'del': 1, 'or': 1, 'def': 1, 'lambda': 1, 'nonlocal': 10}, 42 | 'built_in': {'None': 1, 'True': 1, 'False': 1, 'Ellipsis': 1, 'NotImplemented': 1} 43 | }, 44 | illegal: '(|\\?)', 45 | contains: [ 46 | hljs.HASH_COMMENT_MODE, 47 | STR1, STR2, STR3, STR4, hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE, 48 | { 49 | className: 'function', 50 | begin: '\\bdef ', end: ':', 51 | illegal: '$', 52 | keywords: {'def': 1}, 53 | contains: [TITLE, PARAMS], 54 | relevance: 10 55 | }, 56 | { 57 | className: 'class', 58 | begin: '\\bclass ', end: ':', 59 | illegal: '[${]', 60 | keywords: {'class': 1}, 61 | contains: [TITLE, PARAMS], 62 | relevance: 10 63 | }, 64 | hljs.C_NUMBER_MODE, 65 | { 66 | className: 'decorator', 67 | begin: '@', end: '$' 68 | } 69 | ] 70 | } 71 | }; 72 | }(); 73 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/scala.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Scala 3 | Author: Jan Berkel 4 | */ 5 | 6 | hljs.LANGUAGES.scala = function() { 7 | var ANNOTATION = { 8 | className: 'annotation', begin: '@[A-Za-z]+' 9 | }; 10 | var STRING = { 11 | className: 'string', 12 | begin: 'u?r?"""', end: '"""', 13 | relevance: 10 14 | }; 15 | return { 16 | defaultMode: { 17 | keywords: { 'type': 1, 'yield': 1, 'lazy': 1, 'override': 1, 'def': 1, 'with': 1, 'val':1, 'var': 1, 'false': 1, 'true': 1, 'sealed': 1, 'abstract': 1, 'private': 1, 'trait': 1, 'object': 1, 'null': 1, 'if': 1, 'for': 1, 'while': 1, 'throw': 1, 'finally': 1, 'protected': 1, 'extends': 1, 'import': 1, 'final': 1, 'return': 1, 'else': 1, 'break': 1, 'new': 1, 'catch': 1, 'super': 1, 'class': 1, 'case': 1,'package': 1, 'default': 1, 'try': 1, 'this': 1, 'match': 1, 'continue': 1, 'throws': 1}, 18 | contains: [ 19 | { 20 | className: 'javadoc', 21 | begin: '/\\*\\*', end: '\\*/', 22 | contains: [{ 23 | className: 'javadoctag', 24 | begin: '@[A-Za-z]+' 25 | }], 26 | relevance: 10 27 | }, 28 | hljs.C_LINE_COMMENT_MODE, hljs.C_BLOCK_COMMENT_MODE, 29 | hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE, STRING, 30 | { 31 | className: 'class', 32 | begin: '((case )?class |object |trait )', end: '({|$)', 33 | illegal: ':', 34 | keywords: {'case' : 1, 'class': 1, 'trait': 1, 'object': 1}, 35 | contains: [ 36 | { 37 | begin: '(extends|with)', 38 | keywords: {'extends': 1, 'with': 1}, 39 | relevance: 10 40 | }, 41 | { 42 | className: 'title', 43 | begin: hljs.UNDERSCORE_IDENT_RE 44 | }, 45 | { 46 | className: 'params', 47 | begin: '\\(', end: '\\)', 48 | contains: [ 49 | hljs.APOS_STRING_MODE, hljs.QUOTE_STRING_MODE, STRING, 50 | ANNOTATION 51 | ] 52 | } 53 | ] 54 | }, 55 | hljs.C_NUMBER_MODE, 56 | ANNOTATION 57 | ] 58 | } 59 | }; 60 | }(); 61 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/smalltalk.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: Smalltalk 3 | Author: Vladimir Gubarkov 4 | */ 5 | 6 | hljs.LANGUAGES.smalltalk = function() { 7 | var VAR_IDENT_RE = '[a-z][a-zA-Z0-9_]*'; 8 | var CHAR = { 9 | className: 'char', 10 | begin: '\\$.{1}' 11 | }; 12 | var SYMBOL = { 13 | className: 'symbol', 14 | begin: '#' + hljs.UNDERSCORE_IDENT_RE 15 | }; 16 | return { 17 | defaultMode: { 18 | keywords: {'self': 1, 'super': 1, 'nil': 1, 'true': 1, 'false': 1, 'thisContext': 1}, // only 6 19 | contains: [ 20 | { 21 | className: 'comment', 22 | begin: '"', end: '"', 23 | relevance: 0 24 | }, 25 | hljs.APOS_STRING_MODE, 26 | { 27 | className: 'class', 28 | begin: '\\b[A-Z][A-Za-z0-9_]*', 29 | relevance: 0 30 | }, 31 | { 32 | className: 'method', 33 | begin: VAR_IDENT_RE + ':' 34 | }, 35 | hljs.C_NUMBER_MODE, 36 | SYMBOL, 37 | CHAR, 38 | { 39 | className: 'localvars', 40 | begin: '\\|\\s*((' + VAR_IDENT_RE + ')\\s*)+\\|' 41 | }, 42 | { 43 | className: 'array', 44 | begin: '\\#\\(', end: '\\)', 45 | contains: [ 46 | hljs.APOS_STRING_MODE, 47 | CHAR, 48 | hljs.C_NUMBER_MODE, 49 | SYMBOL 50 | ] 51 | } 52 | ] 53 | } 54 | }; 55 | }(); 56 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/sql.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: SQL 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.sql = { 7 | case_insensitive: true, 8 | defaultMode: { 9 | illegal: '[^\\s]', 10 | contains: [ 11 | { 12 | className: 'operator', 13 | begin: '(begin|start|commit|rollback|savepoint|lock|alter|create|drop|rename|call|delete|do|handler|insert|load|replace|select|truncate|update|set|show|pragma)\\b', end: ';|$', 14 | keywords: { 15 | 'keyword': { 16 | 'all': 1, 'partial': 1, 'global': 1, 'month': 1, 17 | 'current_timestamp': 1, 'using': 1, 'go': 1, 'revoke': 1, 18 | 'smallint': 1, 'indicator': 1, 'end-exec': 1, 'disconnect': 1, 19 | 'zone': 1, 'with': 1, 'character': 1, 'assertion': 1, 'to': 1, 20 | 'add': 1, 'current_user': 1, 'usage': 1, 'input': 1, 'local': 1, 21 | 'alter': 1, 'match': 1, 'collate': 1, 'real': 1, 'then': 1, 22 | 'rollback': 1, 'get': 1, 'read': 1, 'timestamp': 1, 23 | 'session_user': 1, 'not': 1, 'integer': 1, 'bit': 1, 'unique': 1, 24 | 'day': 1, 'minute': 1, 'desc': 1, 'insert': 1, 'execute': 1, 25 | 'like': 1, 'ilike': 2, 'level': 1, 'decimal': 1, 'drop': 1, 26 | 'continue': 1, 'isolation': 1, 'found': 1, 'where': 1, 27 | 'constraints': 1, 'domain': 1, 'right': 1, 'national': 1, 'some': 1, 28 | 'module': 1, 'transaction': 1, 'relative': 1, 'second': 1, 29 | 'connect': 1, 'escape': 1, 'close': 1, 'system_user': 1, 'for': 1, 30 | 'deferred': 1, 'section': 1, 'cast': 1, 'current': 1, 'sqlstate': 1, 31 | 'allocate': 1, 'intersect': 1, 'deallocate': 1, 'numeric': 1, 32 | 'public': 1, 'preserve': 1, 'full': 1, 'goto': 1, 'initially': 1, 33 | 'asc': 1, 'no': 1, 'key': 1, 'output': 1, 'collation': 1, 'group': 1, 34 | 'by': 1, 'union': 1, 'session': 1, 'both': 1, 'last': 1, 35 | 'language': 1, 'constraint': 1, 'column': 1, 'of': 1, 'space': 1, 36 | 'foreign': 1, 'deferrable': 1, 'prior': 1, 'connection': 1, 37 | 'unknown': 1, 'action': 1, 'commit': 1, 'view': 1, 'or': 1, 38 | 'first': 1, 'into': 1, 'float': 1, 'year': 1, 'primary': 1, 39 | 'cascaded': 1, 'except': 1, 'restrict': 1, 'set': 1, 'references': 1, 40 | 'names': 1, 'table': 1, 'outer': 1, 'open': 1, 'select': 1, 41 | 'size': 1, 'are': 1, 'rows': 1, 'from': 1, 'prepare': 1, 42 | 'distinct': 1, 'leading': 1, 'create': 1, 'only': 1, 'next': 1, 43 | 'inner': 1, 'authorization': 1, 'schema': 1, 'corresponding': 1, 44 | 'option': 1, 'declare': 1, 'precision': 1, 'immediate': 1, 'else': 1, 45 | 'timezone_minute': 1, 'external': 1, 'varying': 1, 'translation': 1, 46 | 'true': 1, 'case': 1, 'exception': 1, 'join': 1, 'hour': 1, 47 | 'default': 1, 'double': 1, 'scroll': 1, 'value': 1, 'cursor': 1, 48 | 'descriptor': 1, 'values': 1, 'dec': 1, 'fetch': 1, 'procedure': 1, 49 | 'delete': 1, 'and': 1, 'false': 1, 'int': 1, 'is': 1, 'describe': 1, 50 | 'char': 1, 'as': 1, 'at': 1, 'in': 1, 'varchar': 1, 'null': 1, 51 | 'trailing': 1, 'any': 1, 'absolute': 1, 'current_time': 1, 'end': 1, 52 | 'grant': 1, 'privileges': 1, 'when': 1, 'cross': 1, 'check': 1, 53 | 'write': 1, 'current_date': 1, 'pad': 1, 'begin': 1, 'temporary': 1, 54 | 'exec': 1, 'time': 1, 'update': 1, 'catalog': 1, 'user': 1, 'sql': 1, 55 | 'date': 1, 'on': 1, 'identity': 1, 'timezone_hour': 1, 'natural': 1, 56 | 'whenever': 1, 'interval': 1, 'work': 1, 'order': 1, 'cascade': 1, 57 | 'diagnostics': 1, 'nchar': 1, 'having': 1, 'left': 1, 'call': 1, 58 | 'do': 1, 'handler': 1, 'load': 1, 'replace': 1, 'truncate': 1, 59 | 'start': 1, 'lock': 1, 'show': 1, 'pragma': 1}, 60 | 'aggregate': {'count': 1, 'sum': 1, 'min': 1, 'max': 1, 'avg': 1} 61 | }, 62 | contains: [ 63 | { 64 | className: 'string', 65 | begin: '\'', end: '\'', 66 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '\'\''}], 67 | relevance: 0 68 | }, 69 | { 70 | className: 'string', 71 | begin: '"', end: '"', 72 | contains: [hljs.BACKSLASH_ESCAPE, {begin: '""'}], 73 | relevance: 0 74 | }, 75 | { 76 | className: 'string', 77 | begin: '`', end: '`', 78 | contains: [hljs.BACKSLASH_ESCAPE] 79 | }, 80 | hljs.C_NUMBER_MODE, 81 | {begin: '\\n'} 82 | ] 83 | }, 84 | hljs.C_BLOCK_COMMENT_MODE, 85 | { 86 | className: 'comment', 87 | begin: '--', end: '$' 88 | } 89 | ] 90 | } 91 | }; 92 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/vbscript.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: VBScript 3 | Author: Nikita Ledyaev 4 | Contributors: Michal Gabrukiewicz 5 | */ 6 | 7 | hljs.LANGUAGES.vbscript = { 8 | case_insensitive: true, 9 | defaultMode: { 10 | keywords: { 11 | 'keyword': {'call' : 1,'class' : 1,'const' : 1,'dim' : 1,'do' : 1,'loop' : 1,'erase' : 1,'execute' : 1,'executeglobal' : 1,'exit' : 1,'for' : 1,'each' : 1,'next' : 1,'function' : 1,'if' : 1,'then' : 1,'else' : 1,'on' : 1, 'error' : 1,'option' : 1, 'explicit' : 1, 'new': 1, 'private' : 1,'property' : 1,'let' : 1,'get' : 1,'public' : 1,'randomize' : 1,'redim' : 1,'rem' : 1,'select' : 1,'case' : 1,'set' : 1,'stop' : 1,'sub' : 1,'while' : 1,'wend' : 1,'with' : 1, 'end' : 1, 'to' : 1, 'elseif': 1, 'is': 1, 'or': 1, 'xor': 1, 'and': 1, 'not': 1, 'class_initialize': 1, 'class_terminate': 1, 'default': 1, 'preserve': 1, 'in': 1, 'me': 1, 'byval': 1, 'byref': 1, 'step': 1, 'resume': 1, 'goto': 1}, 12 | 'built_in': {'lcase': 1, 'month': 1, 'vartype': 1, 'instrrev': 1, 'ubound': 1, 'setlocale': 1, 'getobject': 1, 'rgb': 1, 'getref': 1, 'string': 1, 'weekdayname': 1, 'rnd': 1, 'dateadd': 1, 'monthname': 1, 'now': 1, 'day': 1, 'minute': 1, 'isarray': 1, 'cbool': 1, 'round': 1, 'formatcurrency': 1, 'conversions': 1, 'csng': 1, 'timevalue': 1, 'second': 1, 'year': 1, 'space': 1, 'abs': 1, 'clng': 1, 'timeserial': 1, 'fixs': 1, 'len': 1, 'asc': 1, 'isempty': 1, 'maths': 1, 'dateserial': 1, 'atn': 1, 'timer': 1, 'isobject': 1, 'filter': 1, 'weekday': 1, 'datevalue': 1, 'ccur': 1, 'isdate': 1, 'instr': 1, 'datediff': 1, 'formatdatetime': 1, 'replace': 1, 'isnull': 1, 'right': 1, 'sgn': 1, 'array': 1, 'snumeric': 1, 'log': 1, 'cdbl': 1, 'hex': 1, 'chr': 1, 'lbound': 1, 'msgbox': 1, 'ucase': 1, 'getlocale': 1, 'cos': 1, 'cdate': 1, 'cbyte': 1, 'rtrim': 1, 'join': 1, 'hour': 1, 'oct': 1, 'typename': 1, 'trim': 1, 'strcomp': 1, 'int': 1, 'createobject': 1, 'loadpicture': 1, 'tan': 1, 'formatnumber': 1, 'mid': 1, 'scriptenginebuildversion': 1, 'scriptengine': 1, 'split': 1, 'scriptengineminorversion': 1, 'cint': 1, 'sin': 1, 'datepart': 1, 'ltrim': 1, 'sqr': 1, 'scriptenginemajorversion': 1, 'time': 1, 'derived': 1, 'eval': 1, 'date': 1, 'formatpercent': 1, 'exp': 1, 'inputbox': 1, 'left': 1, 'ascw': 1, 'chrw': 1, 'regexp': 1, 'server': 1, 'response': 1, 'request': 1, 'cstr': 1, 'err': 1}, 13 | 'literal': {'true': 1, 'false': 1, 'null': 1, 'nothing': 1, 'empty': 1} 14 | }, 15 | contains: [ 16 | { // can't use standard QUOTE_STRING_MODE since it's compiled with its own escape and doesn't use the local one 17 | className: 'string', 18 | begin: '"', end: '"', 19 | illegal: '\\n', 20 | contains: [{begin: '""'}], 21 | relevance: 0 22 | }, 23 | { 24 | className: 'comment', 25 | begin: '\'', end: '$' 26 | }, 27 | hljs.C_NUMBER_MODE 28 | ] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/main/webapp/js/languages/xml.js: -------------------------------------------------------------------------------- 1 | /* 2 | Language: HTML, XML 3 | Category: common 4 | */ 5 | 6 | hljs.LANGUAGES.xml = function(){ 7 | var XML_IDENT_RE = '[A-Za-z0-9\\._:-]+'; 8 | var TAG_INTERNALS = { 9 | endsWithParent: true, 10 | contains: [ 11 | { 12 | className: 'attribute', 13 | begin: XML_IDENT_RE, 14 | relevance: 0 15 | }, 16 | { 17 | begin: '="', returnBegin: true, end: '"', 18 | contains: [{ 19 | className: 'value', 20 | begin: '"', endsWithParent: true 21 | }] 22 | }, 23 | { 24 | begin: '=\'', returnBegin: true, end: '\'', 25 | contains: [{ 26 | className: 'value', 27 | begin: '\'', endsWithParent: true 28 | }] 29 | }, 30 | { 31 | begin: '=', 32 | contains: [{ 33 | className: 'value', 34 | begin: '[^\\s/>]+' 35 | }] 36 | } 37 | ] 38 | }; 39 | return { 40 | case_insensitive: true, 41 | defaultMode: { 42 | contains: [ 43 | { 44 | className: 'pi', 45 | begin: '<\\?', end: '\\?>', 46 | relevance: 10 47 | }, 48 | { 49 | className: 'doctype', 50 | begin: '', 51 | relevance: 10 52 | }, 53 | { 54 | className: 'comment', 55 | begin: '', 56 | relevance: 10 57 | }, 58 | { 59 | className: 'cdata', 60 | begin: '<\\!\\[CDATA\\[', end: '\\]\\]>', 61 | relevance: 10 62 | }, 63 | { 64 | className: 'tag', 65 | begin: '', 66 | keywords: {'title': {'style': 1}}, 67 | contains: [TAG_INTERNALS], 68 | starts: { 69 | className: 'css', 70 | end: '', returnEnd: true, 71 | subLanguage: 'css' 72 | } 73 | }, 74 | { 75 | className: 'tag', 76 | begin: '', 77 | keywords: {'title': {'script': 1}}, 78 | contains: [TAG_INTERNALS], 79 | starts: { 80 | className: 'javascript', 81 | end: '', returnEnd: true, 82 | subLanguage: 'javascript' 83 | } 84 | }, 85 | { 86 | className: 'vbscript', 87 | begin: '<%', end: '%>', 88 | subLanguage: 'vbscript' 89 | }, 90 | { 91 | className: 'tag', 92 | begin: '', 93 | contains: [ 94 | { 95 | className: 'title', begin: '[^ />]+' 96 | }, 97 | TAG_INTERNALS 98 | ] 99 | } 100 | ] 101 | } 102 | }; 103 | }(); 104 | -------------------------------------------------------------------------------- /src/main/webapp/js/mediaChoserPlugin.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | // Define the hello button 3 | $.cleditor.buttons.media = { 4 | name: "media", 5 | image: "../../images/images2.png", 6 | title: "Choose an image from the media library", 7 | command: "inserthtml", 8 | popupName: "media", 9 | popupClass: "cleditorPrompt", 10 | popupContent: "Image URL:


", 11 | buttonClick: mediaClick 12 | }; 13 | 14 | // Add the button to the default controls before the bold button 15 | $.cleditor.defaultOptions.controls = $.cleditor.defaultOptions.controls 16 | .replace("image", "image media"); 17 | 18 | var page = 0; 19 | 20 | function addImgClickHandler() { 21 | $('#imgs img').click(function(img) { 22 | console.log(img.srcElement.getAttribute('fullsrc')); 23 | $('#imgToInsert').val(img.srcElement.getAttribute('fullsrc')); 24 | $('#submit').click(); 25 | }); 26 | } 27 | 28 | // Handle the hello button click event 29 | function mediaClick(e, data) { 30 | page = 0; 31 | $('#imgs').load('/admin/mediaSelector', addImgClickHandler); 32 | 33 | $(data.popup).children("#next").click(function(e) { 34 | $('#imgs').load('/admin/mediaSelector?page=' + ++page, addImgClickHandler); 35 | }); 36 | 37 | // Wire up the submit button click event 38 | $(data.popup).children("#submit") 39 | .unbind("click") 40 | .bind("click", function(e) { 41 | // Get the editor 42 | var editor = data.editor; 43 | 44 | // Get the full url of the image clicked 45 | var fullUrl = $(data.popup).find("#imgToInsert").val(); 46 | 47 | // Insert the img tag into the document 48 | var html = ""; 49 | editor.execCommand(data.command, html, null, data.button); 50 | 51 | // Hide the popup and set focus back to the editor 52 | editor.hidePopups(); 53 | editor.focus(); 54 | }); 55 | } 56 | })(jQuery); -------------------------------------------------------------------------------- /src/main/webapp/js/postEdit.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function() { 2 | var isExistingArticle = $('#titleInput').val().length > 0; 3 | 4 | $(".chzn-select").chosen(); 5 | 6 | var editor = $("#content").cleditor({ 7 | width: 600, 8 | height: 400, 9 | useCSS: true, 10 | docCSSFile: '/css/wysiwyg.css', 11 | styles: [ 12 | ["Paragraph", "

"], 13 | ["Header 1", "

"], 14 | ["Header 2", "

"], 15 | ["Header 3", "

"], 16 | ["Header 4","

"], 17 | ["Code sample", "
"],
 18 |             ["Quote", "
"] 19 | ] 20 | }); 21 | 22 | $('#titleInput').blur(function(evt) { 23 | var title = $(this).val(); 24 | if (title.length == 0) { 25 | $('#titleInputError').css('display', 'inline-block'); 26 | $('#submitButton').attr('disabled', 'true'); 27 | } else { 28 | if (!isExistingArticle) { 29 | $.ajax({ 30 | url: '/admin/titleExists', 31 | data: {'title': title}, 32 | success: function(msg) { 33 | if (msg == 'true') { 34 | $('#titleInputError').css('display', 'inline-block'); 35 | $('#submitButton').attr('disabled', 'true'); 36 | } else { 37 | $('#titleInputError').css('display', 'none'); 38 | } 39 | } 40 | }); 41 | } 42 | if ($('#createdInput').val().match('\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}')) { 43 | $('#submitButton').attr('disabled', false); 44 | } 45 | } 46 | }); 47 | 48 | $('#createdInput').blur(function(evt) { 49 | if (!$(this).val().match('\\d{4}/\\d{2}/\\d{2} \\d{2}:\\d{2}')) { 50 | $('#dateInputError').css('display', 'inline-block'); 51 | $('#submitButton').attr('disabled', 'true'); 52 | } else { 53 | $('#dateInputError').css('display', 'none'); 54 | if ($('#titleInput').val().length > 0) { 55 | $('#submitButton').attr('disabled', false); 56 | } 57 | } 58 | }).keydown(function(event) { 59 | // catch up / down arrows to increase / decrease date field values 60 | if (event.keyCode == 38 || event.keyCode == 40) { 61 | var direction = event.keyCode == 38 ? 1 : -1; 62 | var date = new Date(event.srcElement.value); 63 | var position = event.srcElement.selectionStart; 64 | switch (position) { 65 | case 0: 66 | case 1: 67 | case 2: 68 | case 3: 69 | case 4: 70 | date.setFullYear(date.getFullYear() + direction); 71 | break; 72 | case 5: 73 | case 6: 74 | case 7: 75 | date.setMonth(date.getMonth() + direction); 76 | break; 77 | case 8: 78 | case 9: 79 | case 10: 80 | date.setDate(date.getDate() + direction); 81 | break; 82 | case 11: 83 | case 12: 84 | case 13: 85 | date.setHours(date.getHours() + direction); 86 | break; 87 | case 14: 88 | case 15: 89 | case 16: 90 | date.setMinutes(date.getMinutes() + direction); 91 | break; 92 | } 93 | event.srcElement.value = '' + date.getFullYear() + '/' + 94 | (date.getMonth()+1 < 10 ? '0' + (date.getMonth()+1) : (date.getMonth()+1)) + '/' + 95 | (date.getDate() < 10 ? '0' + date.getDate() : date.getDate()) + ' ' + 96 | (date.getHours() < 10 ? '0' + date.getHours() : date.getHours()) + ':' + 97 | (date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes()); 98 | event.srcElement.selectionStart = position; 99 | event.srcElement.selectionEnd = position; 100 | } 101 | // allow left / right arrow to move to a different date field, as well as tab 102 | if (event.keyCode != 37 && event.keyCode != 39 && event.keyCode != 9) { 103 | event.preventDefault(); 104 | } 105 | }); 106 | 107 | $('#titleInput').focus(); 108 | }); -------------------------------------------------------------------------------- /src/main/webapp/robots.txt: -------------------------------------------------------------------------------- 1 | Sitemap: http://glaforge.appspot.com/sitemap.xml 2 | User-agent: * 3 | Disallow: /admin 4 | Disallow: /live 5 | -------------------------------------------------------------------------------- /src/test/groovy/RegisterSpec.groovy: -------------------------------------------------------------------------------- 1 | import spock.lang.* 2 | 3 | class RegisterSpec extends Specification { 4 | 5 | def "register with no parameters should return error"() { 6 | expect: 7 | 1 == 1 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/test/groovy/RoutesSpec.groovy: -------------------------------------------------------------------------------- 1 | import groovyx.gaelyk.spock.* 2 | 3 | class RoutesSpec extends GaelykRoutingSpec { 4 | 5 | def setup() { 6 | routing 'routes.groovy' 7 | } 8 | 9 | def "a get method may be routed"() { 10 | expect: 11 | get('/') 12 | } 13 | 14 | def "an incorrectly routed method will not match"() { 15 | expect: 16 | !get('/wrongurl') 17 | } 18 | 19 | def "a forward of a mapping may be configured"() { 20 | expect: 21 | with get('/gcm/register'), { 22 | matches 23 | destination == "/gcm/register.groovy" 24 | //redirectionType == 'FORWARD' 25 | } 26 | } 27 | } 28 | --------------------------------------------------------------------------------