diff --git a/build.gradle b/build.gradle index 2439c1cc..67a98120 100644 --- a/build.gradle +++ b/build.gradle @@ -216,6 +216,10 @@ task docsZip(type: Zip, dependsOn: [':docs:asciidoctor', ':api', ':buildSamples' from(file('samples/rest-notes-spring-hateoas/build/asciidoc/html5')) { into 'samples/restful-notes' } + + from(file('samples/rest-notes-slate/build/docs')) { + into 'samples/slate' + } } configurations { diff --git a/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy b/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy index 5ddd17ab..c960ee1e 100644 --- a/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy +++ b/buildSrc/src/main/groovy/org/springframework/restdocs/build/SampleBuildConfigurer.groovy @@ -29,6 +29,8 @@ public class SampleBuildConfigurer { private String workingDir + private boolean verifyIncludes = true + SampleBuildConfigurer(String name) { this.name = name } @@ -39,24 +41,34 @@ public class SampleBuildConfigurer { Task createTask(Project project, Object... dependencies) { File sampleDir = new File(this.workingDir).absoluteFile - Task verifyIncludes + Task sampleBuild = project.tasks.create name + sampleBuild.description = "Builds the ${name} sample" + sampleBuild.group = "Build" if (new File(sampleDir, 'build.gradle').isFile()) { Task gradleBuild = createGradleBuild(project, dependencies) - verifyIncludes = createVerifyIncludes(project, new File(sampleDir, 'build/asciidoc')) - verifyIncludes.dependsOn gradleBuild + if (verifyIncludes) { + Task verifyIncludesTask = createVerifyIncludes(project, new File(sampleDir, 'build/asciidoc')) + verifyIncludesTask.dependsOn gradleBuild + sampleBuild.dependsOn verifyIncludesTask + } + else { + sampleBuild.dependsOn gradleBuild + } } else if (new File(sampleDir, 'pom.xml').isFile()) { Task mavenBuild = createMavenBuild(project, sampleDir, dependencies) - verifyIncludes = createVerifyIncludes(project, new File(sampleDir, 'target/generated-docs')) - verifyIncludes.dependsOn(mavenBuild) + if (verifyIncludes) { + Task verifyIncludesTask = createVerifyIncludes(project, new File(sampleDir, 'target/generated-docs')) + verifyIncludesTask.dependsOn(mavenBuild) + sampleBuild.dependsOn verifyIncludesTask + } + else { + sampleBuild.dependsOn mavenBuild + } } else { throw new IllegalStateException("No pom.xml or build.gradle was found in $sampleDir") } - Task sampleBuild = project.tasks.create name - sampleBuild.description = "Builds the ${name} sample" - sampleBuild.group = "Build" - sampleBuild.dependsOn verifyIncludes return sampleBuild } @@ -108,9 +120,9 @@ public class SampleBuildConfigurer { } private Task createVerifyIncludes(Project project, File buildDir) { - Task verifyIncludes = project.tasks.create("${name}VerifyIncludes") - verifyIncludes.description = "Verifies the includes in the ${name} sample" - verifyIncludes << { + Task verifyIncludesTask = project.tasks.create("${name}VerifyIncludes") + verifyIncludesTask.description = "Verifies the includes in the ${name} sample" + verifyIncludesTask << { Map unprocessedIncludes = [:] buildDir.eachFileRecurse { file -> if (file.name.endsWith('.html')) { @@ -132,6 +144,6 @@ public class SampleBuildConfigurer { throw new GradleException(message.toString()) } } - return verifyIncludes + return verifyIncludesTask } } \ No newline at end of file diff --git a/docs/src/docs/asciidoc/getting-started.adoc b/docs/src/docs/asciidoc/getting-started.adoc index 485dec89..67d7dc17 100644 --- a/docs/src/docs/asciidoc/getting-started.adoc +++ b/docs/src/docs/asciidoc/getting-started.adoc @@ -16,21 +16,26 @@ If you want to jump straight in, a number of sample applications are available: | {samples}/rest-assured[REST Assured] | Gradle -| Demonstrates the use of Spring REST Docs with REST Assured. +| Demonstrates the use of Spring REST Docs with http://rest-assured.io[REST Assured]. + +| {samples}/rest-notes-slate[Slate] +| Gradle +| Demonstrates the use of Spring REST Docs with Markdown and + http://github.com/tripit/slate[Slate]. | {samples}/rest-notes-spring-data-rest[Spring Data REST] | Maven | Demonstrates the creation of a getting started guide and an API guide for a service - implemented using Spring Data REST. + implemented using http://projects.spring.io/spring-data-rest/[Spring Data REST]. | {samples}/rest-notes-spring-hateoas[Spring HATEOAS] | Gradle | Demonstrates the creation of a getting started guide and an API guide for a service - implemented using Spring HATEOAS. + implemented using http://projects.spring.io/spring-hateoas/[Spring HATEOAS]. | {samples}/testng[TestNG] | Gradle -| Demonstrates the use of Spring REST Docs with TestNG. +| Demonstrates the use of Spring REST Docs with http://testng.org[TestNG]. |=== diff --git a/samples/rest-notes-slate/README.md b/samples/rest-notes-slate/README.md new file mode 100644 index 00000000..bb4de692 --- /dev/null +++ b/samples/rest-notes-slate/README.md @@ -0,0 +1,24 @@ +# REST Notes Slate + +This sample shows how to document a RESTful API using Spring REST Docs and [Slate][1]. +The sample can be built with Gradle, but requires Ruby and the `bundler` gem to +be installed. + +## Quickstart + +``` +./gradlew build +open build/docs/api-guide.html +``` + +## Details + +The bulk of the documentation is written in Markdown in the file named +[slate/api-guide.md.erb][2]. When the documentation is built, snippets generated by +Spring REST Docs in the [ApiDocumentation][3] tests are incorporated into this +documentation by [ERB][4]. The combined Markdown document is then turned into HTML. + +[1]: https://github.com/tripit/slate +[2]: slate/api-guide.md.erb +[3]: src/test/java/com/example/notes/ApiDocumentation.java +[4]: http://ruby-doc.org/stdlib-2.2.3/libdoc/erb/rdoc/ERB.html \ No newline at end of file diff --git a/samples/rest-notes-slate/build.gradle b/samples/rest-notes-slate/build.gradle new file mode 100644 index 00000000..79788c3d --- /dev/null +++ b/samples/rest-notes-slate/build.gradle @@ -0,0 +1,64 @@ +buildscript { + repositories { + mavenCentral() + } + dependencies { + classpath 'org.springframework.boot:spring-boot-gradle-plugin:1.2.7.RELEASE' + } +} + +apply plugin: 'java' +apply plugin: 'spring-boot' +apply plugin: 'eclipse' + +repositories { + mavenLocal() + maven { url 'https://repo.spring.io/libs-snapshot' } + mavenCentral() +} + +group = 'com.example' + +sourceCompatibility = 1.7 +targetCompatibility = 1.7 + +ext { + snippetsDir = file('build/generated-snippets') + springRestdocsVersion = '1.1.0.BUILD-SNAPSHOT' +} + +dependencies { + compile 'org.springframework.boot:spring-boot-starter-data-jpa' + compile 'org.springframework.boot:spring-boot-starter-data-rest' + + runtime 'com.h2database:h2' + runtime 'org.atteo:evo-inflector:1.2.1' + + testCompile 'com.jayway.jsonpath:json-path' + testCompile 'org.springframework.boot:spring-boot-starter-test' + testCompile "org.springframework.restdocs:spring-restdocs-mockmvc:$springRestdocsVersion" +} + +test { + outputs.dir snippetsDir +} + +task(bundleInstall, type: Exec) { + workingDir file('slate') + executable 'bundle' + args 'install' +} + +task(slate, type: Exec) { + dependsOn 'bundleInstall', 'test' + workingDir file('slate') + executable 'bundle' + args 'exec', 'middleman', 'build' +} + +build { + dependsOn 'slate' +} + +eclipseJdt.onlyIf { false } +cleanEclipseJdt.onlyIf { false } diff --git a/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.jar b/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 00000000..e8c6bf7b Binary files /dev/null and b/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.jar differ diff --git a/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.properties b/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..90a0f04c --- /dev/null +++ b/samples/rest-notes-slate/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Oct 15 14:25:16 BST 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.7-bin.zip diff --git a/samples/rest-notes-slate/gradlew b/samples/rest-notes-slate/gradlew new file mode 100755 index 00000000..97fac783 --- /dev/null +++ b/samples/rest-notes-slate/gradlew @@ -0,0 +1,160 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/samples/rest-notes-slate/gradlew.bat b/samples/rest-notes-slate/gradlew.bat new file mode 100644 index 00000000..8a0b282a --- /dev/null +++ b/samples/rest-notes-slate/gradlew.bat @@ -0,0 +1,90 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windowz variants + +if not "%OS%" == "Windows_NT" goto win9xME_args +if "%@eval[2+2]" == "4" goto 4NT_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* +goto execute + +:4NT_args +@rem Get arguments from the 4NT Shell from JP Software +set CMD_LINE_ARGS=%$ + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/samples/rest-notes-slate/slate/.gitignore b/samples/rest-notes-slate/slate/.gitignore new file mode 100644 index 00000000..f6fc8c00 --- /dev/null +++ b/samples/rest-notes-slate/slate/.gitignore @@ -0,0 +1,22 @@ +*.gem +*.rbc +.bundle +.config +coverage +InstalledFiles +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp +*.DS_STORE +build/ +.cache + +# YARD artifacts +.yardoc +_yardoc +doc/ +.idea/ \ No newline at end of file diff --git a/samples/rest-notes-slate/slate/CHANGELOG.md b/samples/rest-notes-slate/slate/CHANGELOG.md new file mode 100644 index 00000000..ee496db6 --- /dev/null +++ b/samples/rest-notes-slate/slate/CHANGELOG.md @@ -0,0 +1,49 @@ +# Changelog + +## Version 1.2 + +*June 20, 2015* + +**Fixes:** + +- Remove crash on invalid languages +- Update Tocify to scroll to the highlighted header in the Table of Contents +- Fix variable leak and update search algorithms +- Update Python examples to be valid Python +- Update gems +- More misc. bugfixes of Javascript errors +- Add Dockerfile +- Remove unused gems +- Optimize images, fonts, and generated asset files +- Add chinese font support +- Remove RedCarpet header ID patch +- Update language tabs to not disturb existing query strings + +## Version 1.1 + +*July 27th, 2014* + +**Fixes:** + +- Finally, a fix for the redcarpet upgrade bug + +## Version 1.0 + +*July 2, 2014* + +[View Issues](https://github.com/tripit/slate/issues?milestone=1&state=closed) + +**Features:** + +- Responsive designs for phones and tablets +- Started tagging versions + +**Fixes:** + +- Fixed 'unrecognized expression' error +- Fixed #undefined hash bug +- Fixed bug where the current language tab would be unselected +- Fixed bug where tocify wouldn't highlight the current section while searching +- Fixed bug where ids of header tags would have special characters that caused problems +- Updated layout so that pages with disabled search wouldn't load search.js +- Cleaned up Javascript diff --git a/samples/rest-notes-slate/slate/Gemfile b/samples/rest-notes-slate/slate/Gemfile new file mode 100644 index 00000000..0933b9d6 --- /dev/null +++ b/samples/rest-notes-slate/slate/Gemfile @@ -0,0 +1,12 @@ +source 'https://rubygems.org' + +# Middleman +gem 'middleman', '~>3.3.10' +gem 'middleman-gh-pages', '~> 0.0.3' +gem 'middleman-syntax', '~> 2.0.0' +gem 'middleman-autoprefixer', '~> 2.4.4' +gem 'rouge', '~> 1.9.0' +gem 'redcarpet', '~> 3.3.2' + +gem 'rake', '~> 10.4.2' +gem 'therubyracer', '~> 0.12.1', platforms: :ruby diff --git a/samples/rest-notes-slate/slate/Gemfile.lock b/samples/rest-notes-slate/slate/Gemfile.lock new file mode 100644 index 00000000..fff5ee10 --- /dev/null +++ b/samples/rest-notes-slate/slate/Gemfile.lock @@ -0,0 +1,140 @@ +GEM + remote: https://rubygems.org/ + specs: + activesupport (4.1.11) + i18n (~> 0.6, >= 0.6.9) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.1) + tzinfo (~> 1.1) + autoprefixer-rails (5.2.0.1) + execjs + json + celluloid (0.16.0) + timers (~> 4.0.0) + chunky_png (1.3.4) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.9.1.1) + compass (1.0.3) + chunky_png (~> 1.2) + compass-core (~> 1.0.2) + compass-import-once (~> 1.0.5) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + sass (>= 3.3.13, < 3.5) + compass-core (1.0.3) + multi_json (~> 1.0) + sass (>= 3.3.0, < 3.5) + compass-import-once (1.0.5) + sass (>= 3.2, < 3.5) + erubis (2.7.0) + execjs (2.5.2) + ffi (1.9.8) + haml (4.0.6) + tilt + hike (1.2.3) + hitimes (1.2.2) + hooks (0.4.0) + uber (~> 0.0.4) + i18n (0.7.0) + json (1.8.3) + kramdown (1.7.0) + libv8 (3.16.14.7) + listen (2.10.1) + celluloid (~> 0.16.0) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9) + middleman (3.3.12) + coffee-script (~> 2.2) + compass (>= 1.0.0, < 2.0.0) + compass-import-once (= 1.0.5) + execjs (~> 2.0) + haml (>= 4.0.5) + kramdown (~> 1.2) + middleman-core (= 3.3.12) + middleman-sprockets (>= 3.1.2) + sass (>= 3.4.0, < 4.0) + uglifier (~> 2.5) + middleman-autoprefixer (2.4.4) + autoprefixer-rails (~> 5.2.0) + middleman-core (>= 3.3.3) + middleman-core (3.3.12) + activesupport (~> 4.1.0) + bundler (~> 1.1) + erubis + hooks (~> 0.3) + i18n (~> 0.7.0) + listen (>= 2.7.9, < 3.0) + padrino-helpers (~> 0.12.3) + rack (>= 1.4.5, < 2.0) + rack-test (~> 0.6.2) + thor (>= 0.15.2, < 2.0) + tilt (~> 1.4.1, < 2.0) + middleman-gh-pages (0.0.3) + rake (> 0.9.3) + middleman-sprockets (3.4.2) + middleman-core (>= 3.3) + sprockets (~> 2.12.1) + sprockets-helpers (~> 1.1.0) + sprockets-sass (~> 1.3.0) + middleman-syntax (2.0.0) + middleman-core (~> 3.2) + rouge (~> 1.0) + minitest (5.7.0) + multi_json (1.11.1) + padrino-helpers (0.12.5) + i18n (~> 0.6, >= 0.6.7) + padrino-support (= 0.12.5) + tilt (~> 1.4.1) + padrino-support (0.12.5) + activesupport (>= 3.1) + rack (1.6.4) + rack-test (0.6.3) + rack (>= 1.0) + rake (10.4.2) + rb-fsevent (0.9.5) + rb-inotify (0.9.5) + ffi (>= 0.5.0) + redcarpet (3.3.2) + ref (1.0.5) + rouge (1.9.0) + sass (3.4.14) + sprockets (2.12.3) + hike (~> 1.2) + multi_json (~> 1.0) + rack (~> 1.0) + tilt (~> 1.1, != 1.3.0) + sprockets-helpers (1.1.0) + sprockets (~> 2.0) + sprockets-sass (1.3.1) + sprockets (~> 2.0) + tilt (~> 1.1) + therubyracer (0.12.2) + libv8 (~> 3.16.14.0) + ref + thor (0.19.1) + thread_safe (0.3.5) + tilt (1.4.1) + timers (4.0.1) + hitimes + tzinfo (1.2.2) + thread_safe (~> 0.1) + uber (0.0.13) + uglifier (2.7.1) + execjs (>= 0.3.0) + json (>= 1.8.0) + +PLATFORMS + ruby + +DEPENDENCIES + middleman (~> 3.3.10) + middleman-autoprefixer (~> 2.4.4) + middleman-gh-pages (~> 0.0.3) + middleman-syntax (~> 2.0.0) + rake (~> 10.4.2) + redcarpet (~> 3.3.2) + rouge (~> 1.9.0) + therubyracer (~> 0.12.1) diff --git a/samples/rest-notes-slate/slate/LICENSE b/samples/rest-notes-slate/slate/LICENSE new file mode 100644 index 00000000..5ceddf59 --- /dev/null +++ b/samples/rest-notes-slate/slate/LICENSE @@ -0,0 +1,13 @@ +Copyright 2008-2013 Concur Technologies, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain +a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. \ No newline at end of file diff --git a/samples/rest-notes-slate/slate/README.md b/samples/rest-notes-slate/slate/README.md new file mode 100644 index 00000000..2f042e7f --- /dev/null +++ b/samples/rest-notes-slate/slate/README.md @@ -0,0 +1,128 @@ +Slate +======== + +[![Build Status](https://travis-ci.org/tripit/slate.svg?branch=master)](https://travis-ci.org/tripit/slate) [![Dependency Status](https://gemnasium.com/tripit/slate.png)](https://gemnasium.com/tripit/slate) + +Slate helps you create beautiful API documentation. Think of it as an intelligent, responsive documentation template for your API. + +Screenshot of Example Documentation created with Slate + +*The example above was created with Slate. Check it out at [tripit.github.io/slate](http://tripit.github.io/slate).* + +Features +------------ + +* **Clean, intuitive design** — with Slate, the description of your API is on the left side of your documentation, and all the code examples are on the right side. Inspired by [Stripe's](https://stripe.com/docs/api) and [Paypal's](https://developer.paypal.com/webapps/developer/docs/api/) API docs. Slate is responsive, so it looks great on tablets, phones, and even print. + +* **Everything on a single page** — gone are the days where your users had to search through a million pages to find what they wanted. Slate puts the entire documentation on a single page. We haven't sacrificed linkability, though. As you scroll, your browser's hash will update to the nearest header, so linking to a particular point in the documentation is still natural and easy. + +* **Slate is just Markdown** — when you write docs with Slate, you're just writing Markdown, which makes it simple to edit and understand. Everything is written in Markdown — even the code samples are just Markdown code blocks! + +* **Write code samples in multiple languages** — if your API has bindings in multiple programming languages, you easily put in tabs to switch between them. In your document, you'll distinguish different languages by specifying the language name at the top of each code block, just like with Github Flavored Markdown! + +* **Out-of-the-box syntax highlighting** for [almost 60 languages](http://rouge.jayferd.us/demo), no configuration required. + +* **Automatic, smoothly scrolling table of contents** on the far left of the page. As you scroll, it displays your current position in the document. It's fast, too. We're using Slate at TripIt to build documentation for our new API, where our table of contents has over 180 entries. We've made sure that the performance remains excellent, even for larger documents. + +* **Let your users update your documentation for you** — by default, your Slate-generated documentation is hosted in a public Github repository. Not only does this mean you get free hosting for your docs with Github Pages, but it also makes it's simple for other developers to make pull requests to your docs if they find typos or other problems. Of course, if you don't want to, you're welcome to not use Github and host your docs elsewhere! + +Getting starting with Slate is super easy! Simply fork this repository, and then follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](http://tripit.github.io/slate). + + + +Getting Started with Slate +------------------------------ + +### Prerequisites + +You're going to need: + + - **Linux or OS X** — Windows may work, but is unsupported. + - **Ruby, version 1.9.3 or newer** + - **Bundler** — If Ruby is already installed, but the `bundle` command doesn't work, just run `gem install bundler` in a terminal. + +### Getting Set Up + + 1. Fork this repository on Github. + 2. Clone *your forked repository* (not our original one) to your hard drive with `git clone https://github.com/YOURUSERNAME/slate.git` + 3. `cd slate` + 4. Install all dependencies: `bundle install` + 5. Start the test server: `bundle exec middleman server` + +Or use the included Dockerfile! (must install Docker first) + +```shell +docker build -t slate . +docker run -d -p 4567:4567 --name slate -v $(pwd)/source:/app/source slate +``` + +You can now see the docs at . Whoa! That was fast! + +*Note: if you're using the Docker setup on OSX, the docs will be +availalable at the output of `boot2docker ip` instead of `localhost:4567`.* + +Now that Slate is all set up your machine, you'll probably want to learn more about [editing Slate markdown](https://github.com/tripit/slate/wiki/Markdown-Syntax), or [how to publish your docs](https://github.com/tripit/slate/wiki/Deploying-Slate). + +Examples of Slate in the Wild +--------------------------------- + +* [Travis-CI's API docs](http://docs.travis-ci.com/api/) +* [Mozilla's localForage docs](http://mozilla.github.io/localForage/) +* [Mozilla Recroom](http://mozilla.github.io/recroom/) +* [ChaiOne Gameplan API docs](http://chaione.github.io/gameplanb2b/#introduction) +* [Drcaban's Build a Quine tutorial](http://drcabana.github.io/build-a-quine/#introduction) +* [PricePlow API docs](https://www.priceplow.com/api/documentation) +* [Emerging Threats API docs](http://apidocs.emergingthreats.net/) +* [Appium docs](http://appium.io/slate/en/master) +* [Golazon Developer](http://developer.golazon.com) +* [Dwolla API docs](https://docs.dwolla.com/) +* [RozpisyZapasu API docs](http://www.rozpisyzapasu.cz/dev/api/) +* [Codestar Framework Docs](http://codestarframework.com/documentation/) +* [Buddycloud API](http://buddycloud.com/api) +* [Crafty Clicks API](https://craftyclicks.co.uk/api/) +* [Paracel API Reference](http://paracel.io/docs/api_reference.html) +* [Switch Payments Documentation](http://switchpayments.com/docs/) & [API](http://switchpayments.com/developers/) +* [Coinbase API Reference](https://developers.coinbase.com/api) +* [Whispir.io API](https://whispir.github.io/api) +* [NASA API](https://data.nasa.gov/developer/external/planetary/) +* [CardPay API](https://developers.cardpay.com/) +* [IBM Cloudant](https://docs-testb.cloudant.com/content-review/_design/couchapp/index.html) +* [Bitrix basis components](http://bbc.bitrix.expert/) +* [viagogo API Documentation](http://developer.viagogo.net/) +* [Fidor Bank API Documentation](http://docs.fidor.de/) +* [Market Prophit API Documentation](http://developer.marketprophit.com/) +* [OAuth.io API Documentation](http://docs.oauth.io/) +* [Aircall for Developers](http://developer.aircall.io/) +* [SupportKit API Docs](http://docs.supportkit.io/) +* [SocialRadar's LocationKit Docs](https://docs.locationkit.io/) +* [SafetyCulture API Documentation](https://developer.safetyculture.io/) +* [hosting.de API Documentation](https://www.hosting.de/docs/api/) + +(Feel free to add your site to this list in a pull request!) + +Need Help? Found a bug? +-------------------- + +Just [submit a issue](https://github.com/tripit/slate/issues) to the Slate Github if you need any help. And, of course, feel free to submit pull requests with bug fixes or changes. + + +Contributors +-------------------- + +Slate was built by [Robert Lord](https://lord.io) while at [TripIt](http://tripit.com). + +Thanks to the following people who have submitted major pull requests: + +- [@chrissrogers](https://github.com/chrissrogers) +- [@bootstraponline](https://github.com/bootstraponline) +- [@realityking](https://github.com/realityking) + +Also, thanks to [Sauce Labs](http://saucelabs.com) for helping sponsor the project. + +Special Thanks +-------------------- +- [Middleman](https://github.com/middleman/middleman) +- [jquery.tocify.js](https://github.com/gfranko/jquery.tocify.js) +- [middleman-syntax](https://github.com/middleman/middleman-syntax) +- [middleman-gh-pages](https://github.com/neo/middleman-gh-pages) +- [Font Awesome](http://fortawesome.github.io/Font-Awesome/) diff --git a/samples/rest-notes-slate/slate/Rakefile b/samples/rest-notes-slate/slate/Rakefile new file mode 100644 index 00000000..6a952e1e --- /dev/null +++ b/samples/rest-notes-slate/slate/Rakefile @@ -0,0 +1,6 @@ +require 'middleman-gh-pages' +require 'rake/clean' + +CLOBBER.include('build') + +task :default => [:build] diff --git a/samples/rest-notes-slate/slate/config.rb b/samples/rest-notes-slate/slate/config.rb new file mode 100644 index 00000000..fdcb21f3 --- /dev/null +++ b/samples/rest-notes-slate/slate/config.rb @@ -0,0 +1,41 @@ +# Markdown +set :markdown_engine, :redcarpet +set :markdown, + fenced_code_blocks: true, + smartypants: true, + disable_indented_code_blocks: true, + prettify: true, + tables: true, + with_toc_data: true, + no_intra_emphasis: true + +# Assets +set :css_dir, 'stylesheets' +set :js_dir, 'javascripts' +set :images_dir, 'images' +set :fonts_dir, 'fonts' + +# Activate the syntax highlighter +activate :syntax + +activate :autoprefixer do |config| + config.browsers = ['last 2 version', 'Firefox ESR'] + config.cascade = false + config.inline = true +end + +# Github pages require relative links +activate :relative_assets +set :relative_links, true + +# Build Configuration + +set :build_dir, '../build/docs' + +configure :build do + activate :minify_css + activate :minify_javascript + # activate :relative_assets + # activate :asset_hash + # activate :gzip +end diff --git a/samples/rest-notes-slate/slate/font-selection.json b/samples/rest-notes-slate/slate/font-selection.json new file mode 100755 index 00000000..5e78f5d8 --- /dev/null +++ b/samples/rest-notes-slate/slate/font-selection.json @@ -0,0 +1,148 @@ +{ + "IcoMoonType": "selection", + "icons": [ + { + "icon": { + "paths": [ + "M438.857 73.143q119.429 0 220.286 58.857t159.714 159.714 58.857 220.286-58.857 220.286-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857zM512 785.714v-108.571q0-8-5.143-13.429t-12.571-5.429h-109.714q-7.429 0-13.143 5.714t-5.714 13.143v108.571q0 7.429 5.714 13.143t13.143 5.714h109.714q7.429 0 12.571-5.429t5.143-13.429zM510.857 589.143l10.286-354.857q0-6.857-5.714-10.286-5.714-4.571-13.714-4.571h-125.714q-8 0-13.714 4.571-5.714 3.429-5.714 10.286l9.714 354.857q0 5.714 5.714 10t13.714 4.286h105.714q8 0 13.429-4.286t6-10z" + ], + "attrs": [], + "isMulticolor": false, + "tags": [ + "exclamation-circle" + ], + "defaultCode": 61546, + "grid": 14 + }, + "attrs": [], + "properties": { + "id": 100, + "order": 4, + "prevSize": 28, + "code": 58880, + "name": "exclamation-sign", + "ligatures": "" + }, + "setIdx": 0, + "iconIdx": 0 + }, + { + "icon": { + "paths": [ + "M585.143 786.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-54.857v-292.571q0-8-5.143-13.143t-13.143-5.143h-182.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h54.857v182.857h-54.857q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h256q8 0 13.143-5.143t5.143-13.143zM512 274.286v-91.429q0-8-5.143-13.143t-13.143-5.143h-109.714q-8 0-13.143 5.143t-5.143 13.143v91.429q0 8 5.143 13.143t13.143 5.143h109.714q8 0 13.143-5.143t5.143-13.143zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z" + ], + "attrs": [], + "isMulticolor": false, + "tags": [ + "info-circle" + ], + "defaultCode": 61530, + "grid": 14 + }, + "attrs": [], + "properties": { + "id": 85, + "order": 3, + "name": "info-sign", + "prevSize": 28, + "code": 58882 + }, + "setIdx": 0, + "iconIdx": 2 + }, + { + "icon": { + "paths": [ + "M733.714 419.429q0-16-10.286-26.286l-52-51.429q-10.857-10.857-25.714-10.857t-25.714 10.857l-233.143 232.571-129.143-129.143q-10.857-10.857-25.714-10.857t-25.714 10.857l-52 51.429q-10.286 10.286-10.286 26.286 0 15.429 10.286 25.714l206.857 206.857q10.857 10.857 25.714 10.857 15.429 0 26.286-10.857l310.286-310.286q10.286-10.286 10.286-25.714zM877.714 512q0 119.429-58.857 220.286t-159.714 159.714-220.286 58.857-220.286-58.857-159.714-159.714-58.857-220.286 58.857-220.286 159.714-159.714 220.286-58.857 220.286 58.857 159.714 159.714 58.857 220.286z" + ], + "attrs": [], + "isMulticolor": false, + "tags": [ + "check-circle" + ], + "defaultCode": 61528, + "grid": 14 + }, + "attrs": [], + "properties": { + "id": 83, + "order": 9, + "prevSize": 28, + "code": 58886, + "name": "ok-sign" + }, + "setIdx": 0, + "iconIdx": 6 + }, + { + "icon": { + "paths": [ + "M658.286 475.429q0-105.714-75.143-180.857t-180.857-75.143-180.857 75.143-75.143 180.857 75.143 180.857 180.857 75.143 180.857-75.143 75.143-180.857zM950.857 950.857q0 29.714-21.714 51.429t-51.429 21.714q-30.857 0-51.429-21.714l-196-195.429q-102.286 70.857-228 70.857-81.714 0-156.286-31.714t-128.571-85.714-85.714-128.571-31.714-156.286 31.714-156.286 85.714-128.571 128.571-85.714 156.286-31.714 156.286 31.714 128.571 85.714 85.714 128.571 31.714 156.286q0 125.714-70.857 228l196 196q21.143 21.143 21.143 51.429z" + ], + "width": 951, + "attrs": [], + "isMulticolor": false, + "tags": [ + "search" + ], + "defaultCode": 61442, + "grid": 14 + }, + "attrs": [], + "properties": { + "id": 2, + "order": 1, + "prevSize": 28, + "code": 58887, + "name": "icon-search" + }, + "setIdx": 0, + "iconIdx": 7 + } + ], + "height": 1024, + "metadata": { + "name": "slate", + "license": "SIL OFL 1.1" + }, + "preferences": { + "showGlyphs": true, + "showQuickUse": true, + "showQuickUse2": true, + "showSVGs": true, + "fontPref": { + "prefix": "icon-", + "metadata": { + "fontFamily": "slate", + "majorVersion": 1, + "minorVersion": 0, + "description": "Based on FontAwesome", + "license": "SIL OFL 1.1" + }, + "metrics": { + "emSize": 1024, + "baseline": 6.25, + "whitespace": 50 + }, + "resetPoint": 58880, + "showSelector": false, + "selector": "class", + "classSelector": ".icon", + "showMetrics": false, + "showMetadata": true, + "showVersion": true, + "ie7": false + }, + "imagePref": { + "prefix": "icon-", + "png": true, + "useClassSelector": true, + "color": 4473924, + "bgColor": 16777215 + }, + "historySize": 100, + "showCodes": true, + "gridSize": 16, + "showLiga": false + } +} diff --git a/samples/rest-notes-slate/slate/source/api-guide.md.erb b/samples/rest-notes-slate/slate/source/api-guide.md.erb new file mode 100644 index 00000000..11248a3e --- /dev/null +++ b/samples/rest-notes-slate/slate/source/api-guide.md.erb @@ -0,0 +1,206 @@ +--- +title: REST Notes API Guide + +language_tabs: + - shell + - http + +search: true +--- + +# Overview + + +## HTTP verbs + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP verbs. + + +Verb | Usage +-------- | ----- +`GET` | Used to retrieve a resource +`POST` | Used to create a new resource +`PATCH` | Used to update an existing resource, including partial updates +`DELETE` | Used to delete an existing resource + +## HTTP status codes + +RESTful notes tries to adhere as closely as possible to standard HTTP and REST conventions in its +use of HTTP status codes. + +Status code | Usage +----------------- | ----- +`200 OK` | The request completed successfully +`201 Created` | A new resource has been created successfully. The resource's URI is available from the response's `Location` header +`204 No Content` | An update to an existing resource has been applied successfully +`400 Bad Request` | The request was malformed. The response body will include an error providing further information +`404 Not Found` | The requested resource did not exist + +## Errors + +<%= ERB.new(File.read("../build/generated-snippets/error-example/http-response.md")).result(binding) %> + +Whenever an error response (status code >= 400) is returned, the body will contain a JSON object +that describes the problem. The error object has the following structure: + +<%= ERB.new(File.read("../build/generated-snippets/error-example/response-fields.md")).result(binding) %> + +## Hypermedia + +RESTful Notes uses hypermedia and resources include links to other resources in their +responses. Responses are in [Hypertext Application Language (HAL)](http://stateless.co/hal_specification.html format). +Links can be found beneath the `_links` key. Users of the API should not create URIs +themselves, instead they should use the above-described links to navigate + + + +# Resources + + + +## Index + +<%= ERB.new(File.read("../build/generated-snippets/index-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/index-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/index-example/http-response.md")).result(binding) %> + +The index provides the entry point into the service. A `GET` request is used to access the index. + +### Response structure + +<%= ERB.new(File.read("../build/generated-snippets/index-example/response-fields.md")).result(binding) %> + +### Links + +<%= ERB.new(File.read("../build/generated-snippets/index-example/links.md")).result(binding) %> + + + +## Notes + +The Notes resources is used to create and list notes + +### Listing notes + +<%= ERB.new(File.read("../build/generated-snippets/notes-list-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/notes-list-example/http-response.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/notes-list-example/curl-request.md")).result(binding) %> + +A `GET` request will list all of the service's notes. + +#### Response structure + +<%= ERB.new(File.read("../build/generated-snippets/notes-list-example/response-fields.md")).result(binding) %> + +### Creating a note + +<%= ERB.new(File.read("../build/generated-snippets/notes-create-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/notes-create-example/http-response.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/notes-create-example/curl-request.md")).result(binding) %> + +A `POST` request is used to create a note + +#### Request structure + +<%= ERB.new(File.read("../build/generated-snippets/notes-create-example/request-fields.md")).result(binding) %> + + + +## Tags + +The Tags resource is used to create and list tags. + +### Listing tags + +<%= ERB.new(File.read("../build/generated-snippets/tags-list-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tags-list-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tags-list-example/http-response.md")).result(binding) %> + +A `GET` request will list all of the service's tags. + +#### Response structure + +<%= ERB.new(File.read("../build/generated-snippets/tags-list-example/response-fields.md")).result(binding) %> + + +### Creating a tag + +<%= ERB.new(File.read("../build/generated-snippets/tags-create-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tags-create-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/notes-create-example/http-response.md")).result(binding) %> + +A `POST` request is used to create a tag + +#### Request structure + +<%= ERB.new(File.read("../build/generated-snippets/tags-create-example/request-fields.md")).result(binding) %> + + + +## Note + +The Note resource is used to retrieve, update, and delete individual notes + +### Retrieve a note + +<%= ERB.new(File.read("../build/generated-snippets/note-get-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/note-get-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/note-get-example/http-response.md")).result(binding) %> + +A `GET` request will retrieve the details of a note + +<%= ERB.new(File.read("../build/generated-snippets/note-get-example/response-fields.md")).result(binding) %> + +#### Links + +<%= ERB.new(File.read("../build/generated-snippets/note-get-example/links.md")).result(binding) %> + +### Update a note + +<%= ERB.new(File.read("../build/generated-snippets/note-update-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/note-update-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/note-update-example/http-response.md")).result(binding) %> + +A `PATCH` request is used to update a note + +#### Request structure + +<%= ERB.new(File.read("../build/generated-snippets/note-update-example/request-fields.md")).result(binding) %> + +To leave an attribute of a note unchanged, any of the above may be omitted from the +request. + + + +## Tag + +The Tag resource is used to retrieve, update, and delete individual tags + +### Retrieve a tag + +<%= ERB.new(File.read("../build/generated-snippets/tag-get-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tag-get-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tag-get-example/http-response.md")).result(binding) %> + +A `GET` request will retrieve the details of a tag + +#### Response structure + +<%= ERB.new(File.read("../build/generated-snippets/tag-get-example/response-fields.md")).result(binding) %> + +#### Links + +<%= ERB.new(File.read("../build/generated-snippets/tag-get-example/links.md")).result(binding) %> + +### Update a tag + +<%= ERB.new(File.read("../build/generated-snippets/tag-update-example/curl-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tag-update-example/http-request.md")).result(binding) %> +<%= ERB.new(File.read("../build/generated-snippets/tag-update-example/http-response.md")).result(binding) %> + +A `PATCH` request is used to update a tag + +#### Request structure + +<%= ERB.new(File.read("../build/generated-snippets/tag-update-example/request-fields.md")).result(binding) %> \ No newline at end of file diff --git a/samples/rest-notes-slate/slate/source/fonts/slate.eot b/samples/rest-notes-slate/slate/source/fonts/slate.eot new file mode 100755 index 00000000..13c4839a Binary files /dev/null and b/samples/rest-notes-slate/slate/source/fonts/slate.eot differ diff --git a/samples/rest-notes-slate/slate/source/fonts/slate.svg b/samples/rest-notes-slate/slate/source/fonts/slate.svg new file mode 100755 index 00000000..5f349823 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/fonts/slate.svg @@ -0,0 +1,14 @@ + + + +Generated by IcoMoon + + + + + + + + + + diff --git a/samples/rest-notes-slate/slate/source/fonts/slate.ttf b/samples/rest-notes-slate/slate/source/fonts/slate.ttf new file mode 100755 index 00000000..ace9a46a Binary files /dev/null and b/samples/rest-notes-slate/slate/source/fonts/slate.ttf differ diff --git a/samples/rest-notes-slate/slate/source/fonts/slate.woff b/samples/rest-notes-slate/slate/source/fonts/slate.woff new file mode 100755 index 00000000..1e72e0ee Binary files /dev/null and b/samples/rest-notes-slate/slate/source/fonts/slate.woff differ diff --git a/samples/rest-notes-slate/slate/source/fonts/slate.woff2 b/samples/rest-notes-slate/slate/source/fonts/slate.woff2 new file mode 100755 index 00000000..7c585a72 Binary files /dev/null and b/samples/rest-notes-slate/slate/source/fonts/slate.woff2 differ diff --git a/samples/rest-notes-slate/slate/source/images/logo.png b/samples/rest-notes-slate/slate/source/images/logo.png new file mode 100644 index 00000000..fa1f13da Binary files /dev/null and b/samples/rest-notes-slate/slate/source/images/logo.png differ diff --git a/samples/rest-notes-slate/slate/source/images/navbar.png b/samples/rest-notes-slate/slate/source/images/navbar.png new file mode 100644 index 00000000..df38e90d Binary files /dev/null and b/samples/rest-notes-slate/slate/source/images/navbar.png differ diff --git a/samples/rest-notes-slate/slate/source/javascripts/all.js b/samples/rest-notes-slate/slate/source/javascripts/all.js new file mode 100644 index 00000000..ffaa9b01 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/all.js @@ -0,0 +1,4 @@ +//= require ./lib/_energize +//= require ./app/_lang +//= require ./app/_search +//= require ./app/_toc diff --git a/samples/rest-notes-slate/slate/source/javascripts/all_nosearch.js b/samples/rest-notes-slate/slate/source/javascripts/all_nosearch.js new file mode 100644 index 00000000..818bc4e5 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/all_nosearch.js @@ -0,0 +1,3 @@ +//= require ./lib/_energize +//= require ./app/_lang +//= require ./app/_toc diff --git a/samples/rest-notes-slate/slate/source/javascripts/app/_lang.js b/samples/rest-notes-slate/slate/source/javascripts/app/_lang.js new file mode 100644 index 00000000..1a124bb6 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/app/_lang.js @@ -0,0 +1,162 @@ +/* +Copyright 2008-2013 Concur Technologies, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); you may +not use this file except in compliance with the License. You may obtain +a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +License for the specific language governing permissions and limitations +under the License. +*/ +(function (global) { + 'use strict'; + + var languages = []; + + global.setupLanguages = setupLanguages; + global.activateLanguage = activateLanguage; + + function activateLanguage(language) { + if (!language) return; + if (language === "") return; + + $(".lang-selector a").removeClass('active'); + $(".lang-selector a[data-language-name='" + language + "']").addClass('active'); + for (var i=0; i < languages.length; i++) { + $(".highlight." + languages[i]).hide(); + } + $(".highlight." + language).show(); + + global.toc.calculateHeights(); + + // scroll to the new location of the position + if ($(window.location.hash).get(0)) { + $(window.location.hash).get(0).scrollIntoView(true); + } + } + + // parseURL and stringifyURL are from https://github.com/sindresorhus/query-string + // MIT licensed + // https://github.com/sindresorhus/query-string/blob/7bee64c16f2da1a326579e96977b9227bf6da9e6/license + function parseURL(str) { + if (typeof str !== 'string') { + return {}; + } + + str = str.trim().replace(/^(\?|#|&)/, ''); + + if (!str) { + return {}; + } + + return str.split('&').reduce(function (ret, param) { + var parts = param.replace(/\+/g, ' ').split('='); + var key = parts[0]; + var val = parts[1]; + + key = decodeURIComponent(key); + // missing `=` should be `null`: + // http://w3.org/TR/2012/WD-url-20120524/#collect-url-parameters + val = val === undefined ? null : decodeURIComponent(val); + + if (!ret.hasOwnProperty(key)) { + ret[key] = val; + } else if (Array.isArray(ret[key])) { + ret[key].push(val); + } else { + ret[key] = [ret[key], val]; + } + + return ret; + }, {}); + }; + + function stringifyURL(obj) { + return obj ? Object.keys(obj).sort().map(function (key) { + var val = obj[key]; + + if (Array.isArray(val)) { + return val.sort().map(function (val2) { + return encodeURIComponent(key) + '=' + encodeURIComponent(val2); + }).join('&'); + } + + return encodeURIComponent(key) + '=' + encodeURIComponent(val); + }).join('&') : ''; + }; + + // gets the language set in the query string + function getLanguageFromQueryString() { + if (location.search.length >= 1) { + var language = parseURL(location.search).language + if (language) { + return language; + } else if (jQuery.inArray(location.search.substr(1), languages) != -1) { + return location.search.substr(1); + } + } + + return false; + } + + // returns a new query string with the new language in it + function generateNewQueryString(language) { + var url = parseURL(location.search); + if (url.language) { + url.language = language; + return stringifyURL(url); + } + return language; + } + + // if a button is clicked, add the state to the history + function pushURL(language) { + if (!history) { return; } + var hash = window.location.hash; + if (hash) { + hash = hash.replace(/^#+/, ''); + } + history.pushState({}, '', '?' + generateNewQueryString(language) + '#' + hash); + + // save language as next default + localStorage.setItem("language", language); + } + + function setupLanguages(l) { + var defaultLanguage = localStorage.getItem("language"); + + languages = l; + + var presetLanguage = getLanguageFromQueryString(); + if (presetLanguage) { + // the language is in the URL, so use that language! + activateLanguage(presetLanguage); + + localStorage.setItem("language", presetLanguage); + } else if ((defaultLanguage !== null) && (jQuery.inArray(defaultLanguage, languages) != -1)) { + // the language was the last selected one saved in localstorage, so use that language! + activateLanguage(defaultLanguage); + } else { + // no language selected, so use the default + activateLanguage(languages[0]); + } + } + + // if we click on a language tab, activate that language + $(function() { + $(".lang-selector a").on("click", function() { + var language = $(this).data("language-name"); + pushURL(language); + activateLanguage(language); + return false; + }); + window.onpopstate = function() { + activateLanguage(getLanguageFromQueryString()); + }; + }); +})(window); diff --git a/samples/rest-notes-slate/slate/source/javascripts/app/_search.js b/samples/rest-notes-slate/slate/source/javascripts/app/_search.js new file mode 100644 index 00000000..91f38a04 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/app/_search.js @@ -0,0 +1,74 @@ +//= require ../lib/_lunr +//= require ../lib/_jquery.highlight +(function () { + 'use strict'; + + var content, searchResults; + var highlightOpts = { element: 'span', className: 'search-highlight' }; + + var index = new lunr.Index(); + + index.ref('id'); + index.field('title', { boost: 10 }); + index.field('body'); + index.pipeline.add(lunr.trimmer, lunr.stopWordFilter); + + $(populate); + $(bind); + + function populate() { + $('h1, h2').each(function() { + var title = $(this); + var body = title.nextUntil('h1, h2'); + index.add({ + id: title.prop('id'), + title: title.text(), + body: body.text() + }); + }); + } + + function bind() { + content = $('.content'); + searchResults = $('.search-results'); + + $('#input-search').on('keyup', search); + } + + function search(event) { + unhighlight(); + searchResults.addClass('visible'); + + // ESC clears the field + if (event.keyCode === 27) this.value = ''; + + if (this.value) { + var results = index.search(this.value).filter(function(r) { + return r.score > 0.0001; + }); + + if (results.length) { + searchResults.empty(); + $.each(results, function (index, result) { + var elem = document.getElementById(result.ref); + searchResults.append("
  • " + $(elem).text() + "
  • "); + }); + highlight.call(this); + } else { + searchResults.html('
  • '); + $('.search-results li').text('No Results Found for "' + this.value + '"'); + } + } else { + unhighlight(); + searchResults.removeClass('visible'); + } + } + + function highlight() { + if (this.value) content.highlight(this.value, highlightOpts); + } + + function unhighlight() { + content.unhighlight(highlightOpts); + } +})(); diff --git a/samples/rest-notes-slate/slate/source/javascripts/app/_toc.js b/samples/rest-notes-slate/slate/source/javascripts/app/_toc.js new file mode 100644 index 00000000..bc2aa3e1 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/app/_toc.js @@ -0,0 +1,55 @@ +//= require ../lib/_jquery_ui +//= require ../lib/_jquery.tocify +//= require ../lib/_imagesloaded.min +(function (global) { + 'use strict'; + + var closeToc = function() { + $(".tocify-wrapper").removeClass('open'); + $("#nav-button").removeClass('open'); + }; + + var makeToc = function() { + global.toc = $("#toc").tocify({ + selectors: 'h1, h2', + extendPage: false, + theme: 'none', + smoothScroll: false, + showEffectSpeed: 0, + hideEffectSpeed: 180, + ignoreSelector: '.toc-ignore', + highlightOffset: 60, + scrollTo: -1, + scrollHistory: true, + hashGenerator: function (text, element) { + return element.prop('id'); + } + }).data('toc-tocify'); + + $("#nav-button").click(function() { + $(".tocify-wrapper").toggleClass('open'); + $("#nav-button").toggleClass('open'); + return false; + }); + + $(".page-wrapper").click(closeToc); + $(".tocify-item").click(closeToc); + }; + + // Hack to make already open sections to start opened, + // instead of displaying an ugly animation + function animate() { + setTimeout(function() { + toc.setOption('showEffectSpeed', 180); + }, 50); + } + + $(function() { + makeToc(); + animate(); + $('.content').imagesLoaded( function() { + global.toc.calculateHeights(); + }); + }); +})(window); + diff --git a/samples/rest-notes-slate/slate/source/javascripts/lib/_energize.js b/samples/rest-notes-slate/slate/source/javascripts/lib/_energize.js new file mode 100644 index 00000000..6798f3c0 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/lib/_energize.js @@ -0,0 +1,169 @@ +/** + * energize.js v0.1.0 + * + * Speeds up click events on mobile devices. + * https://github.com/davidcalhoun/energize.js + */ + +(function() { // Sandbox + /** + * Don't add to non-touch devices, which don't need to be sped up + */ + if(!('ontouchstart' in window)) return; + + var lastClick = {}, + isThresholdReached, touchstart, touchmove, touchend, + click, closest; + + /** + * isThresholdReached + * + * Compare touchstart with touchend xy coordinates, + * and only fire simulated click event if the coordinates + * are nearby. (don't want clicking to be confused with a swipe) + */ + isThresholdReached = function(startXY, xy) { + return Math.abs(startXY[0] - xy[0]) > 5 || Math.abs(startXY[1] - xy[1]) > 5; + }; + + /** + * touchstart + * + * Save xy coordinates when the user starts touching the screen + */ + touchstart = function(e) { + this.startXY = [e.touches[0].clientX, e.touches[0].clientY]; + this.threshold = false; + }; + + /** + * touchmove + * + * Check if the user is scrolling past the threshold. + * Have to check here because touchend will not always fire + * on some tested devices (Kindle Fire?) + */ + touchmove = function(e) { + // NOOP if the threshold has already been reached + if(this.threshold) return false; + + this.threshold = isThresholdReached(this.startXY, [e.touches[0].clientX, e.touches[0].clientY]); + }; + + /** + * touchend + * + * If the user didn't scroll past the threshold between + * touchstart and touchend, fire a simulated click. + * + * (This will fire before a native click) + */ + touchend = function(e) { + // Don't fire a click if the user scrolled past the threshold + if(this.threshold || isThresholdReached(this.startXY, [e.changedTouches[0].clientX, e.changedTouches[0].clientY])) { + return; + } + + /** + * Create and fire a click event on the target element + * https://developer.mozilla.org/en/DOM/event.initMouseEvent + */ + var touch = e.changedTouches[0], + evt = document.createEvent('MouseEvents'); + evt.initMouseEvent('click', true, true, window, 0, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null); + evt.simulated = true; // distinguish from a normal (nonsimulated) click + e.target.dispatchEvent(evt); + }; + + /** + * click + * + * Because we've already fired a click event in touchend, + * we need to listed for all native click events here + * and suppress them as necessary. + */ + click = function(e) { + /** + * Prevent ghost clicks by only allowing clicks we created + * in the click event we fired (look for e.simulated) + */ + var time = Date.now(), + timeDiff = time - lastClick.time, + x = e.clientX, + y = e.clientY, + xyDiff = [Math.abs(lastClick.x - x), Math.abs(lastClick.y - y)], + target = closest(e.target, 'A') || e.target, // needed for standalone apps + nodeName = target.nodeName, + isLink = nodeName === 'A', + standAlone = window.navigator.standalone && isLink && e.target.getAttribute("href"); + + lastClick.time = time; + lastClick.x = x; + lastClick.y = y; + + /** + * Unfortunately Android sometimes fires click events without touch events (seen on Kindle Fire), + * so we have to add more logic to determine the time of the last click. Not perfect... + * + * Older, simpler check: if((!e.simulated) || standAlone) + */ + if((!e.simulated && (timeDiff < 500 || (timeDiff < 1500 && xyDiff[0] < 50 && xyDiff[1] < 50))) || standAlone) { + e.preventDefault(); + e.stopPropagation(); + if(!standAlone) return false; + } + + /** + * Special logic for standalone web apps + * See http://stackoverflow.com/questions/2898740/iphone-safari-web-app-opens-links-in-new-window + */ + if(standAlone) { + window.location = target.getAttribute("href"); + } + + /** + * Add an energize-focus class to the targeted link (mimics :focus behavior) + * TODO: test and/or remove? Does this work? + */ + if(!target || !target.classList) return; + target.classList.add("energize-focus"); + window.setTimeout(function(){ + target.classList.remove("energize-focus"); + }, 150); + }; + + /** + * closest + * @param {HTMLElement} node current node to start searching from. + * @param {string} tagName the (uppercase) name of the tag you're looking for. + * + * Find the closest ancestor tag of a given node. + * + * Starts at node and goes up the DOM tree looking for a + * matching nodeName, continuing until hitting document.body + */ + closest = function(node, tagName){ + var curNode = node; + + while(curNode !== document.body) { // go up the dom until we find the tag we're after + if(!curNode || curNode.nodeName === tagName) { return curNode; } // found + curNode = curNode.parentNode; // not found, so keep going up + } + + return null; // not found + }; + + /** + * Add all delegated event listeners + * + * All the events we care about bubble up to document, + * so we can take advantage of event delegation. + * + * Note: no need to wait for DOMContentLoaded here + */ + document.addEventListener('touchstart', touchstart, false); + document.addEventListener('touchmove', touchmove, false); + document.addEventListener('touchend', touchend, false); + document.addEventListener('click', click, true); // TODO: why does this use capture? + +})(); \ No newline at end of file diff --git a/samples/rest-notes-slate/slate/source/javascripts/lib/_imagesloaded.min.js b/samples/rest-notes-slate/slate/source/javascripts/lib/_imagesloaded.min.js new file mode 100644 index 00000000..d66f6589 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/lib/_imagesloaded.min.js @@ -0,0 +1,7 @@ +/*! + * imagesLoaded PACKAGED v3.1.8 + * JavaScript is all like "You images are done yet or what?" + * MIT License + */ + +(function(){function e(){}function t(e,t){for(var n=e.length;n--;)if(e[n].listener===t)return n;return-1}function n(e){return function(){return this[e].apply(this,arguments)}}var i=e.prototype,r=this,o=r.EventEmitter;i.getListeners=function(e){var t,n,i=this._getEvents();if("object"==typeof e){t={};for(n in i)i.hasOwnProperty(n)&&e.test(n)&&(t[n]=i[n])}else t=i[e]||(i[e]=[]);return t},i.flattenListeners=function(e){var t,n=[];for(t=0;e.length>t;t+=1)n.push(e[t].listener);return n},i.getListenersAsObject=function(e){var t,n=this.getListeners(e);return n instanceof Array&&(t={},t[e]=n),t||n},i.addListener=function(e,n){var i,r=this.getListenersAsObject(e),o="object"==typeof n;for(i in r)r.hasOwnProperty(i)&&-1===t(r[i],n)&&r[i].push(o?n:{listener:n,once:!1});return this},i.on=n("addListener"),i.addOnceListener=function(e,t){return this.addListener(e,{listener:t,once:!0})},i.once=n("addOnceListener"),i.defineEvent=function(e){return this.getListeners(e),this},i.defineEvents=function(e){for(var t=0;e.length>t;t+=1)this.defineEvent(e[t]);return this},i.removeListener=function(e,n){var i,r,o=this.getListenersAsObject(e);for(r in o)o.hasOwnProperty(r)&&(i=t(o[r],n),-1!==i&&o[r].splice(i,1));return this},i.off=n("removeListener"),i.addListeners=function(e,t){return this.manipulateListeners(!1,e,t)},i.removeListeners=function(e,t){return this.manipulateListeners(!0,e,t)},i.manipulateListeners=function(e,t,n){var i,r,o=e?this.removeListener:this.addListener,s=e?this.removeListeners:this.addListeners;if("object"!=typeof t||t instanceof RegExp)for(i=n.length;i--;)o.call(this,t,n[i]);else for(i in t)t.hasOwnProperty(i)&&(r=t[i])&&("function"==typeof r?o.call(this,i,r):s.call(this,i,r));return this},i.removeEvent=function(e){var t,n=typeof e,i=this._getEvents();if("string"===n)delete i[e];else if("object"===n)for(t in i)i.hasOwnProperty(t)&&e.test(t)&&delete i[t];else delete this._events;return this},i.removeAllListeners=n("removeEvent"),i.emitEvent=function(e,t){var n,i,r,o,s=this.getListenersAsObject(e);for(r in s)if(s.hasOwnProperty(r))for(i=s[r].length;i--;)n=s[r][i],n.once===!0&&this.removeListener(e,n.listener),o=n.listener.apply(this,t||[]),o===this._getOnceReturnValue()&&this.removeListener(e,n.listener);return this},i.trigger=n("emitEvent"),i.emit=function(e){var t=Array.prototype.slice.call(arguments,1);return this.emitEvent(e,t)},i.setOnceReturnValue=function(e){return this._onceReturnValue=e,this},i._getOnceReturnValue=function(){return this.hasOwnProperty("_onceReturnValue")?this._onceReturnValue:!0},i._getEvents=function(){return this._events||(this._events={})},e.noConflict=function(){return r.EventEmitter=o,e},"function"==typeof define&&define.amd?define("eventEmitter/EventEmitter",[],function(){return e}):"object"==typeof module&&module.exports?module.exports=e:this.EventEmitter=e}).call(this),function(e){function t(t){var n=e.event;return n.target=n.target||n.srcElement||t,n}var n=document.documentElement,i=function(){};n.addEventListener?i=function(e,t,n){e.addEventListener(t,n,!1)}:n.attachEvent&&(i=function(e,n,i){e[n+i]=i.handleEvent?function(){var n=t(e);i.handleEvent.call(i,n)}:function(){var n=t(e);i.call(e,n)},e.attachEvent("on"+n,e[n+i])});var r=function(){};n.removeEventListener?r=function(e,t,n){e.removeEventListener(t,n,!1)}:n.detachEvent&&(r=function(e,t,n){e.detachEvent("on"+t,e[t+n]);try{delete e[t+n]}catch(i){e[t+n]=void 0}});var o={bind:i,unbind:r};"function"==typeof define&&define.amd?define("eventie/eventie",o):e.eventie=o}(this),function(e,t){"function"==typeof define&&define.amd?define(["eventEmitter/EventEmitter","eventie/eventie"],function(n,i){return t(e,n,i)}):"object"==typeof exports?module.exports=t(e,require("wolfy87-eventemitter"),require("eventie")):e.imagesLoaded=t(e,e.EventEmitter,e.eventie)}(window,function(e,t,n){function i(e,t){for(var n in t)e[n]=t[n];return e}function r(e){return"[object Array]"===d.call(e)}function o(e){var t=[];if(r(e))t=e;else if("number"==typeof e.length)for(var n=0,i=e.length;i>n;n++)t.push(e[n]);else t.push(e);return t}function s(e,t,n){if(!(this instanceof s))return new s(e,t);"string"==typeof e&&(e=document.querySelectorAll(e)),this.elements=o(e),this.options=i({},this.options),"function"==typeof t?n=t:i(this.options,t),n&&this.on("always",n),this.getImages(),a&&(this.jqDeferred=new a.Deferred);var r=this;setTimeout(function(){r.check()})}function f(e){this.img=e}function c(e){this.src=e,v[e]=this}var a=e.jQuery,u=e.console,h=u!==void 0,d=Object.prototype.toString;s.prototype=new t,s.prototype.options={},s.prototype.getImages=function(){this.images=[];for(var e=0,t=this.elements.length;t>e;e++){var n=this.elements[e];"IMG"===n.nodeName&&this.addImage(n);var i=n.nodeType;if(i&&(1===i||9===i||11===i))for(var r=n.querySelectorAll("img"),o=0,s=r.length;s>o;o++){var f=r[o];this.addImage(f)}}},s.prototype.addImage=function(e){var t=new f(e);this.images.push(t)},s.prototype.check=function(){function e(e,r){return t.options.debug&&h&&u.log("confirm",e,r),t.progress(e),n++,n===i&&t.complete(),!0}var t=this,n=0,i=this.images.length;if(this.hasAnyBroken=!1,!i)return this.complete(),void 0;for(var r=0;i>r;r++){var o=this.images[r];o.on("confirm",e),o.check()}},s.prototype.progress=function(e){this.hasAnyBroken=this.hasAnyBroken||!e.isLoaded;var t=this;setTimeout(function(){t.emit("progress",t,e),t.jqDeferred&&t.jqDeferred.notify&&t.jqDeferred.notify(t,e)})},s.prototype.complete=function(){var e=this.hasAnyBroken?"fail":"done";this.isComplete=!0;var t=this;setTimeout(function(){if(t.emit(e,t),t.emit("always",t),t.jqDeferred){var n=t.hasAnyBroken?"reject":"resolve";t.jqDeferred[n](t)}})},a&&(a.fn.imagesLoaded=function(e,t){var n=new s(this,e,t);return n.jqDeferred.promise(a(this))}),f.prototype=new t,f.prototype.check=function(){var e=v[this.img.src]||new c(this.img.src);if(e.isConfirmed)return this.confirm(e.isLoaded,"cached was confirmed"),void 0;if(this.img.complete&&void 0!==this.img.naturalWidth)return this.confirm(0!==this.img.naturalWidth,"naturalWidth"),void 0;var t=this;e.on("confirm",function(e,n){return t.confirm(e.isLoaded,n),!0}),e.check()},f.prototype.confirm=function(e,t){this.isLoaded=e,this.emit("confirm",this,t)};var v={};return c.prototype=new t,c.prototype.check=function(){if(!this.isChecked){var e=new Image;n.bind(e,"load",this),n.bind(e,"error",this),e.src=this.src,this.isChecked=!0}},c.prototype.handleEvent=function(e){var t="on"+e.type;this[t]&&this[t](e)},c.prototype.onload=function(e){this.confirm(!0,"onload"),this.unbindProxyEvents(e)},c.prototype.onerror=function(e){this.confirm(!1,"onerror"),this.unbindProxyEvents(e)},c.prototype.confirm=function(e,t){this.isConfirmed=!0,this.isLoaded=e,this.emit("confirm",this,t)},c.prototype.unbindProxyEvents=function(e){n.unbind(e.target,"load",this),n.unbind(e.target,"error",this)},s}); \ No newline at end of file diff --git a/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.highlight.js b/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.highlight.js new file mode 100644 index 00000000..9dcf3c7a --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.highlight.js @@ -0,0 +1,108 @@ +/* + * jQuery Highlight plugin + * + * Based on highlight v3 by Johann Burkard + * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html + * + * Code a little bit refactored and cleaned (in my humble opinion). + * Most important changes: + * - has an option to highlight only entire words (wordsOnly - false by default), + * - has an option to be case sensitive (caseSensitive - false by default) + * - highlight element tag and class names can be specified in options + * + * Usage: + * // wrap every occurrance of text 'lorem' in content + * // with (default options) + * $('#content').highlight('lorem'); + * + * // search for and highlight more terms at once + * // so you can save some time on traversing DOM + * $('#content').highlight(['lorem', 'ipsum']); + * $('#content').highlight('lorem ipsum'); + * + * // search only for entire word 'lorem' + * $('#content').highlight('lorem', { wordsOnly: true }); + * + * // don't ignore case during search of term 'lorem' + * $('#content').highlight('lorem', { caseSensitive: true }); + * + * // wrap every occurrance of term 'ipsum' in content + * // with + * $('#content').highlight('ipsum', { element: 'em', className: 'important' }); + * + * // remove default highlight + * $('#content').unhighlight(); + * + * // remove custom highlight + * $('#content').unhighlight({ element: 'em', className: 'important' }); + * + * + * Copyright (c) 2009 Bartek Szopka + * + * Licensed under MIT license. + * + */ + +jQuery.extend({ + highlight: function (node, re, nodeName, className) { + if (node.nodeType === 3) { + var match = node.data.match(re); + if (match) { + var highlight = document.createElement(nodeName || 'span'); + highlight.className = className || 'highlight'; + var wordNode = node.splitText(match.index); + wordNode.splitText(match[0].length); + var wordClone = wordNode.cloneNode(true); + highlight.appendChild(wordClone); + wordNode.parentNode.replaceChild(highlight, wordNode); + return 1; //skip added node in parent + } + } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children + !/(script|style)/i.test(node.tagName) && // ignore script and style nodes + !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted + for (var i = 0; i < node.childNodes.length; i++) { + i += jQuery.highlight(node.childNodes[i], re, nodeName, className); + } + } + return 0; + } +}); + +jQuery.fn.unhighlight = function (options) { + var settings = { className: 'highlight', element: 'span' }; + jQuery.extend(settings, options); + + return this.find(settings.element + "." + settings.className).each(function () { + var parent = this.parentNode; + parent.replaceChild(this.firstChild, this); + parent.normalize(); + }).end(); +}; + +jQuery.fn.highlight = function (words, options) { + var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false }; + jQuery.extend(settings, options); + + if (words.constructor === String) { + words = [words]; + } + words = jQuery.grep(words, function(word, i){ + return word != ''; + }); + words = jQuery.map(words, function(word, i) { + return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + }); + if (words.length == 0) { return this; }; + + var flag = settings.caseSensitive ? "" : "i"; + var pattern = "(" + words.join("|") + ")"; + if (settings.wordsOnly) { + pattern = "\\b" + pattern + "\\b"; + } + var re = new RegExp(pattern, flag); + + return this.each(function () { + jQuery.highlight(this, re, settings.element, settings.className); + }); +}; + diff --git a/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.tocify.js b/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.tocify.js new file mode 100644 index 00000000..91cf6379 --- /dev/null +++ b/samples/rest-notes-slate/slate/source/javascripts/lib/_jquery.tocify.js @@ -0,0 +1,1042 @@ +/* jquery Tocify - v1.8.0 - 2013-09-16 +* http://www.gregfranko.com/jquery.tocify.js/ +* Copyright (c) 2013 Greg Franko; Licensed MIT +* Modified lightly by Robert Lord to fix a bug I found, +* and also so it adds ids to headers +* also because I want height caching, since the +* height lookup for h1s and h2s was causing serious +* lag spikes below 30 fps */ + +// Immediately-Invoked Function Expression (IIFE) [Ben Alman Blog Post](http://benalman.com/news/2010/11/immediately-invoked-function-expression/) that calls another IIFE that contains all of the plugin logic. I used this pattern so that anyone viewing this code would not have to scroll to the bottom of the page to view the local parameters that were passed to the main IIFE. +(function(tocify) { + + // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) + "use strict"; + + // Calls the second IIFE and locally passes in the global jQuery, window, and document objects + tocify(window.jQuery, window, document); + +} + +// Locally passes in `jQuery`, the `window` object, the `document` object, and an `undefined` variable. The `jQuery`, `window` and `document` objects are passed in locally, to improve performance, since javascript first searches for a variable match within the local variables set before searching the global variables set. All of the global variables are also passed in locally to be minifier friendly. `undefined` can be passed in locally, because it is not a reserved word in JavaScript. +(function($, window, document, undefined) { + + // ECMAScript 5 Strict Mode: [John Resig Blog Post](http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/) + "use strict"; + + var tocClassName = "tocify", + tocClass = "." + tocClassName, + tocFocusClassName = "tocify-focus", + tocHoverClassName = "tocify-hover", + hideTocClassName = "tocify-hide", + hideTocClass = "." + hideTocClassName, + headerClassName = "tocify-header", + headerClass = "." + headerClassName, + subheaderClassName = "tocify-subheader", + subheaderClass = "." + subheaderClassName, + itemClassName = "tocify-item", + itemClass = "." + itemClassName, + extendPageClassName = "tocify-extend-page", + extendPageClass = "." + extendPageClassName; + + // Calling the jQueryUI Widget Factory Method + $.widget("toc.tocify", { + + //Plugin version + version: "1.8.0", + + // These options will be used as defaults + options: { + + // **context**: Accepts String: Any jQuery selector + // The container element that holds all of the elements used to generate the table of contents + context: "body", + + // **ignoreSelector**: Accepts String: Any jQuery selector + // A selector to any element that would be matched by selectors that you wish to be ignored + ignoreSelector: null, + + // **selectors**: Accepts an Array of Strings: Any jQuery selectors + // The element's used to generate the table of contents. The order is very important since it will determine the table of content's nesting structure + selectors: "h1, h2, h3", + + // **showAndHide**: Accepts a boolean: true or false + // Used to determine if elements should be shown and hidden + showAndHide: true, + + // **showEffect**: Accepts String: "none", "fadeIn", "show", or "slideDown" + // Used to display any of the table of contents nested items + showEffect: "slideDown", + + // **showEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" + // The time duration of the show animation + showEffectSpeed: "medium", + + // **hideEffect**: Accepts String: "none", "fadeOut", "hide", or "slideUp" + // Used to hide any of the table of contents nested items + hideEffect: "slideUp", + + // **hideEffectSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" + // The time duration of the hide animation + hideEffectSpeed: "medium", + + // **smoothScroll**: Accepts a boolean: true or false + // Determines if a jQuery animation should be used to scroll to specific table of contents items on the page + smoothScroll: true, + + // **smoothScrollSpeed**: Accepts Number (milliseconds) or String: "slow", "medium", or "fast" + // The time duration of the smoothScroll animation + smoothScrollSpeed: "medium", + + // **scrollTo**: Accepts Number (pixels) + // The amount of space between the top of page and the selected table of contents item after the page has been scrolled + scrollTo: 0, + + // **showAndHideOnScroll**: Accepts a boolean: true or false + // Determines if table of contents nested items should be shown and hidden while scrolling + showAndHideOnScroll: true, + + // **highlightOnScroll**: Accepts a boolean: true or false + // Determines if table of contents nested items should be highlighted (set to a different color) while scrolling + highlightOnScroll: true, + + // **highlightOffset**: Accepts a number + // The offset distance in pixels to trigger the next active table of contents item + highlightOffset: 40, + + // **theme**: Accepts a string: "bootstrap", "jqueryui", or "none" + // Determines if Twitter Bootstrap, jQueryUI, or Tocify classes should be added to the table of contents + theme: "bootstrap", + + // **extendPage**: Accepts a boolean: true or false + // If a user scrolls to the bottom of the page and the page is not tall enough to scroll to the last table of contents item, then the page height is increased + extendPage: true, + + // **extendPageOffset**: Accepts a number: pixels + // How close to the bottom of the page a user must scroll before the page is extended + extendPageOffset: 100, + + // **history**: Accepts a boolean: true or false + // Adds a hash to the page url to maintain history + history: true, + + // **scrollHistory**: Accepts a boolean: true or false + // Adds a hash to the page url, to maintain history, when scrolling to a TOC item + scrollHistory: false, + + // **hashGenerator**: How the hash value (the anchor segment of the URL, following the + // # character) will be generated. + // + // "compact" (default) - #CompressesEverythingTogether + // "pretty" - #looks-like-a-nice-url-and-is-easily-readable + // function(text, element){} - Your own hash generation function that accepts the text as an + // argument, and returns the hash value. + hashGenerator: "compact", + + // **highlightDefault**: Accepts a boolean: true or false + // Set's the first TOC item as active if no other TOC item is active. + highlightDefault: true + + }, + + // _Create + // ------- + // Constructs the plugin. Only called once. + _create: function() { + + var self = this; + + self.tocifyWrapper = $('.tocify-wrapper'); + self.extendPageScroll = true; + + // Internal array that keeps track of all TOC items (Helps to recognize if there are duplicate TOC item strings) + self.items = []; + + // Generates the HTML for the dynamic table of contents + self._generateToc(); + + // Caches heights and anchors + self.cachedHeights = [], + self.cachedAnchors = []; + + // Adds CSS classes to the newly generated table of contents HTML + self._addCSSClasses(); + + self.webkit = (function() { + + for(var prop in window) { + + if(prop) { + + if(prop.toLowerCase().indexOf("webkit") !== -1) { + + return true; + + } + + } + + } + + return false; + + }()); + + // Adds jQuery event handlers to the newly generated table of contents + self._setEventHandlers(); + + // Binding to the Window load event to make sure the correct scrollTop is calculated + $(window).load(function() { + + // Sets the active TOC item + self._setActiveElement(true); + + // Once all animations on the page are complete, this callback function will be called + $("html, body").promise().done(function() { + + setTimeout(function() { + + self.extendPageScroll = false; + + },0); + + }); + + }); + + }, + + // _generateToc + // ------------ + // Generates the HTML for the dynamic table of contents + _generateToc: function() { + + // _Local variables_ + + // Stores the plugin context in the self variable + var self = this, + + // All of the HTML tags found within the context provided (i.e. body) that match the top level jQuery selector above + firstElem, + + // Instantiated variable that will store the top level newly created unordered list DOM element + ul, + ignoreSelector = self.options.ignoreSelector; + + // If the selectors option has a comma within the string + if(this.options.selectors.indexOf(",") !== -1) { + + // Grabs the first selector from the string + firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"").substr(0, this.options.selectors.indexOf(","))); + + } + + // If the selectors option does not have a comman within the string + else { + + // Grabs the first selector from the string and makes sure there are no spaces + firstElem = $(this.options.context).find(this.options.selectors.replace(/ /g,"")); + + } + + if(!firstElem.length) { + + self.element.addClass(hideTocClassName); + + return; + + } + + self.element.addClass(tocClassName); + + // Loops through each top level selector + firstElem.each(function(index) { + + //If the element matches the ignoreSelector then we skip it + if($(this).is(ignoreSelector)) { + return; + } + + // Creates an unordered list HTML element and adds a dynamic ID and standard class name + ul = $("