Add RESTful Notes Slate sample
This commit is contained in:
7
restful-notes-slate/.gitignore
vendored
Normal file
7
restful-notes-slate/.gitignore
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
.classpath
|
||||
.gradle/
|
||||
.project
|
||||
.settings/
|
||||
bin/
|
||||
build/
|
||||
out/
|
||||
22
restful-notes-slate/README.md
Normal file
22
restful-notes-slate/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# RESTful Notes Slate Sample
|
||||
|
||||
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/source/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/slatedocs/slate
|
||||
[2]: slate/source/api-guide.html.md.erb
|
||||
[3]: src/test/java/com/example/notes/ApiDocumentation.java
|
||||
[4]: https://ruby-doc.org/stdlib-2.7.1/libdoc/erb/rdoc/ERB.html
|
||||
52
restful-notes-slate/build.gradle
Normal file
52
restful-notes-slate/build.gradle
Normal file
@@ -0,0 +1,52 @@
|
||||
plugins {
|
||||
id "java"
|
||||
id "org.springframework.boot" version "3.0.0-M4"
|
||||
}
|
||||
|
||||
apply plugin: 'io.spring.dependency-management'
|
||||
|
||||
repositories {
|
||||
maven { url 'https://repo.spring.io/milestone' }
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
group = 'com.example'
|
||||
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
|
||||
ext {
|
||||
snippetsDir = file('build/generated-snippets')
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
|
||||
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
runtimeOnly 'org.atteo:evo-inflector:1.3'
|
||||
|
||||
testImplementation 'org.springframework.boot:spring-boot-starter-test'
|
||||
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
BIN
restful-notes-slate/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
restful-notes-slate/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
restful-notes-slate/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
restful-notes-slate/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-bin.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
240
restful-notes-slate/gradlew
vendored
Executable file
240
restful-notes-slate/gradlew
vendored
Executable file
@@ -0,0 +1,240 @@
|
||||
#!/bin/sh
|
||||
|
||||
#
|
||||
# Copyright © 2015-2021 the original authors.
|
||||
#
|
||||
# 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
|
||||
#
|
||||
# https://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.
|
||||
#
|
||||
|
||||
##############################################################################
|
||||
#
|
||||
# Gradle start up script for POSIX generated by Gradle.
|
||||
#
|
||||
# Important for running:
|
||||
#
|
||||
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
|
||||
# noncompliant, but you have some other compliant shell such as ksh or
|
||||
# bash, then to run this script, type that shell name before the whole
|
||||
# command line, like:
|
||||
#
|
||||
# ksh Gradle
|
||||
#
|
||||
# Busybox and similar reduced shells will NOT work, because this script
|
||||
# requires all of these POSIX shell features:
|
||||
# * functions;
|
||||
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
|
||||
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
|
||||
# * compound commands having a testable exit status, especially «case»;
|
||||
# * various built-in commands including «command», «set», and «ulimit».
|
||||
#
|
||||
# Important for patching:
|
||||
#
|
||||
# (2) This script targets any POSIX shell, so it avoids extensions provided
|
||||
# by Bash, Ksh, etc; in particular arrays are avoided.
|
||||
#
|
||||
# The "traditional" practice of packing multiple parameters into a
|
||||
# space-separated string is a well documented source of bugs and security
|
||||
# problems, so this is (mostly) avoided, by progressively accumulating
|
||||
# options in "$@", and eventually passing that to Java.
|
||||
#
|
||||
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
|
||||
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
|
||||
# see the in-line comments for details.
|
||||
#
|
||||
# There are tweaks for specific operating systems such as AIX, CygWin,
|
||||
# Darwin, MinGW, and NonStop.
|
||||
#
|
||||
# (3) This script is generated from the Groovy template
|
||||
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
|
||||
# within the Gradle project.
|
||||
#
|
||||
# You can find Gradle at https://github.com/gradle/gradle/.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
# Attempt to set APP_HOME
|
||||
|
||||
# Resolve links: $0 may be a link
|
||||
app_path=$0
|
||||
|
||||
# Need this for daisy-chained symlinks.
|
||||
while
|
||||
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
|
||||
[ -h "$app_path" ]
|
||||
do
|
||||
ls=$( ls -ld "$app_path" )
|
||||
link=${ls#*' -> '}
|
||||
case $link in #(
|
||||
/*) app_path=$link ;; #(
|
||||
*) app_path=$APP_HOME$link ;;
|
||||
esac
|
||||
done
|
||||
|
||||
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
|
||||
|
||||
APP_NAME="Gradle"
|
||||
APP_BASE_NAME=${0##*/}
|
||||
|
||||
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
warn () {
|
||||
echo "$*"
|
||||
} >&2
|
||||
|
||||
die () {
|
||||
echo
|
||||
echo "$*"
|
||||
echo
|
||||
exit 1
|
||||
} >&2
|
||||
|
||||
# OS specific support (must be 'true' or 'false').
|
||||
cygwin=false
|
||||
msys=false
|
||||
darwin=false
|
||||
nonstop=false
|
||||
case "$( uname )" in #(
|
||||
CYGWIN* ) cygwin=true ;; #(
|
||||
Darwin* ) darwin=true ;; #(
|
||||
MSYS* | MINGW* ) msys=true ;; #(
|
||||
NONSTOP* ) nonstop=true ;;
|
||||
esac
|
||||
|
||||
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" && ! "$darwin" && ! "$nonstop" ; then
|
||||
case $MAX_FD in #(
|
||||
max*)
|
||||
MAX_FD=$( ulimit -H -n ) ||
|
||||
warn "Could not query maximum file descriptor limit"
|
||||
esac
|
||||
case $MAX_FD in #(
|
||||
'' | soft) :;; #(
|
||||
*)
|
||||
ulimit -n "$MAX_FD" ||
|
||||
warn "Could not set maximum file descriptor limit to $MAX_FD"
|
||||
esac
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command, stacking in reverse order:
|
||||
# * args from the command line
|
||||
# * the main class name
|
||||
# * -classpath
|
||||
# * -D...appname settings
|
||||
# * --module-path (only if needed)
|
||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
|
||||
|
||||
# For Cygwin or MSYS, switch paths to Windows format before running java
|
||||
if "$cygwin" || "$msys" ; then
|
||||
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
|
||||
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
|
||||
|
||||
JAVACMD=$( cygpath --unix "$JAVACMD" )
|
||||
|
||||
# Now convert the arguments - kludge to limit ourselves to /bin/sh
|
||||
for arg do
|
||||
if
|
||||
case $arg in #(
|
||||
-*) false ;; # don't mess with options #(
|
||||
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
|
||||
[ -e "$t" ] ;; #(
|
||||
*) false ;;
|
||||
esac
|
||||
then
|
||||
arg=$( cygpath --path --ignore --mixed "$arg" )
|
||||
fi
|
||||
# Roll the args list around exactly as many times as the number of
|
||||
# args, so each arg winds up back in the position where it started, but
|
||||
# possibly modified.
|
||||
#
|
||||
# NB: a `for` loop captures its iteration list before it begins, so
|
||||
# changing the positional parameters here affects neither the number of
|
||||
# iterations, nor the values presented in `arg`.
|
||||
shift # remove old arg
|
||||
set -- "$@" "$arg" # push replacement arg
|
||||
done
|
||||
fi
|
||||
|
||||
# Collect all arguments for the java command;
|
||||
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
|
||||
# shell script including quotes and variable substitutions, so put them in
|
||||
# double quotes to make sure that they get re-expanded; and
|
||||
# * put everything else in single quotes, so that it's not re-expanded.
|
||||
|
||||
set -- \
|
||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||
-classpath "$CLASSPATH" \
|
||||
org.gradle.wrapper.GradleWrapperMain \
|
||||
"$@"
|
||||
|
||||
# Stop when "xargs" is not available.
|
||||
if ! command -v xargs >/dev/null 2>&1
|
||||
then
|
||||
die "xargs is not available"
|
||||
fi
|
||||
|
||||
# Use "xargs" to parse quoted args.
|
||||
#
|
||||
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
|
||||
#
|
||||
# In Bash we could simply go:
|
||||
#
|
||||
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
|
||||
# set -- "${ARGS[@]}" "$@"
|
||||
#
|
||||
# but POSIX shell has neither arrays nor command substitution, so instead we
|
||||
# post-process each arg (as a line of input to sed) to backslash-escape any
|
||||
# character that might be a shell metacharacter, then use eval to reverse
|
||||
# that process (while maintaining the separation between arguments), and wrap
|
||||
# the whole thing up as a single "set" statement.
|
||||
#
|
||||
# This will of course break if any of these variables contains a newline or
|
||||
# an unmatched quote.
|
||||
#
|
||||
|
||||
eval "set -- $(
|
||||
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
|
||||
xargs -n1 |
|
||||
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
|
||||
tr '\n' ' '
|
||||
)" '"$@"'
|
||||
|
||||
exec "$JAVACMD" "$@"
|
||||
91
restful-notes-slate/gradlew.bat
vendored
Normal file
91
restful-notes-slate/gradlew.bat
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
@rem
|
||||
@rem Copyright 2015 the original author or authors.
|
||||
@rem
|
||||
@rem Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@rem you may not use this file except in compliance with the License.
|
||||
@rem You may obtain a copy of the License at
|
||||
@rem
|
||||
@rem https://www.apache.org/licenses/LICENSE-2.0
|
||||
@rem
|
||||
@rem Unless required by applicable law or agreed to in writing, software
|
||||
@rem distributed under the License is distributed on an "AS IS" BASIS,
|
||||
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@rem See the License for the specific language governing permissions and
|
||||
@rem limitations under the License.
|
||||
@rem
|
||||
|
||||
@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
|
||||
|
||||
set DIRNAME=%~dp0
|
||||
if "%DIRNAME%"=="" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@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="-Xmx64m" "-Xms64m"
|
||||
|
||||
@rem Find java.exe
|
||||
if defined JAVA_HOME goto findJavaFromJavaHome
|
||||
|
||||
set JAVA_EXE=java.exe
|
||||
%JAVA_EXE% -version >NUL 2>&1
|
||||
if %ERRORLEVEL% equ 0 goto execute
|
||||
|
||||
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 execute
|
||||
|
||||
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
|
||||
|
||||
: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 %*
|
||||
|
||||
:end
|
||||
@rem End local scope for the variables with windows NT shell
|
||||
if %ERRORLEVEL% equ 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!
|
||||
set EXIT_CODE=%ERRORLEVEL%
|
||||
if %EXIT_CODE% equ 0 set EXIT_CODE=1
|
||||
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
|
||||
exit /b %EXIT_CODE%
|
||||
|
||||
:mainEnd
|
||||
if "%OS%"=="Windows_NT" endlocal
|
||||
|
||||
:omega
|
||||
6
restful-notes-slate/settings.gradle
Normal file
6
restful-notes-slate/settings.gradle
Normal file
@@ -0,0 +1,6 @@
|
||||
pluginManagement {
|
||||
repositories {
|
||||
gradlePluginPortal()
|
||||
maven { url "https://repo.spring.io/milestone" }
|
||||
}
|
||||
}
|
||||
12
restful-notes-slate/slate/.dockerignore
Normal file
12
restful-notes-slate/slate/.dockerignore
Normal file
@@ -0,0 +1,12 @@
|
||||
.git/
|
||||
.github/
|
||||
build/
|
||||
.editorconfig
|
||||
.gitattributes
|
||||
.gitignore
|
||||
CHANGELOG.md
|
||||
CODE_OF_CONDUCT.md
|
||||
deploy.sh
|
||||
font-selection.json
|
||||
README.md
|
||||
Vagrantfile
|
||||
27
restful-notes-slate/slate/.gitignore
vendored
Normal file
27
restful-notes-slate/slate/.gitignore
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
*.gem
|
||||
*.rbc
|
||||
.bundle
|
||||
.config
|
||||
coverage
|
||||
InstalledFiles
|
||||
lib/bundler/man
|
||||
pkg
|
||||
rdoc
|
||||
spec/reports
|
||||
test/tmp
|
||||
test/version_tmp
|
||||
tmp
|
||||
*.DS_STORE
|
||||
build/
|
||||
.cache
|
||||
.vagrant
|
||||
.sass-cache
|
||||
|
||||
# YARD artifacts
|
||||
.yardoc
|
||||
_yardoc
|
||||
doc/
|
||||
.idea/
|
||||
|
||||
# Vagrant artifacts
|
||||
ubuntu-*-console.log
|
||||
307
restful-notes-slate/slate/CHANGELOG.md
Normal file
307
restful-notes-slate/slate/CHANGELOG.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# Changelog
|
||||
|
||||
## Version 2.12.0
|
||||
|
||||
*November 04, 2021*
|
||||
|
||||
* Bump nokogiri from 1.12.3 to 1.12.5
|
||||
* Bump ffi from 1.15.0 to 1.15.4
|
||||
* Bump rouge from 3.26.0 to 3.26.1
|
||||
* Bump middleman from 4.4.0 to 4.4.2
|
||||
* Remove unnecessary files from docker images
|
||||
|
||||
## Version 2.11.0
|
||||
|
||||
*August 12, 2021*
|
||||
|
||||
* __[Security]__ Bump addressable transitive dependency from 2.7.0 to 2.8.0
|
||||
* Support specifying custom meta tags in YAML front-matter
|
||||
* Bump nokogiri from 1.11.3 to 1.12.3 (minimum supported version is 1.11.4)
|
||||
* Bump middleman-autoprefixer from 2.10.1 to 3.0.0
|
||||
* Bump jquery from 3.5.1 to 3.6.0
|
||||
* Bump middleman from [`d180ca3`](https://github.com/middleman/middleman/commit/d180ca337202873f2601310c74ba2b6b4cf063ec) to 4.4.0
|
||||
|
||||
## Version 2.10.0
|
||||
|
||||
*April 13, 2021*
|
||||
|
||||
* Add support for Ruby 3.0 (thanks @shaun-scale)
|
||||
* Add requirement for Git on installing dependencies
|
||||
* Bump nokogiri from 1.11.2 to 1.11.3
|
||||
* Bump middleman from 4.3.11 to [`d180ca3`](https://github.com/middleman/middleman/commit/d180ca337202873f2601310c74ba2b6b4cf063ec)
|
||||
|
||||
## Version 2.9.2
|
||||
|
||||
*March 30, 2021*
|
||||
|
||||
* __[Security]__ Bump kramdown from 2.3.0 to 2.3.1
|
||||
* Bump nokogiri from 1.11.1 to 1.11.2
|
||||
|
||||
## Version 2.9.1
|
||||
|
||||
*February 27, 2021*
|
||||
|
||||
* Fix Slate language tabs not working if localStorage is disabled
|
||||
|
||||
## Version 2.9.0
|
||||
|
||||
*January 19, 2021*
|
||||
|
||||
* __Drop support for Ruby 2.3 and 2.4__
|
||||
* __[Security]__ Bump nokogiri from 1.10.10 to 1.11.1
|
||||
* __[Security]__ Bump redcarpet from 3.5.0 to 3.5.1
|
||||
* Specify slate is not supported on Ruby 3.x
|
||||
* Bump rouge from 3.24.0 to 3.26.0
|
||||
|
||||
## Version 2.8.0
|
||||
|
||||
*October 27, 2020*
|
||||
|
||||
* Remove last trailing newline when using the copy code button
|
||||
* Rework docker image and make available at slatedocs/slate
|
||||
* Improve Dockerfile layout to improve caching (thanks @micvbang)
|
||||
* Bump rouge from 3.20 to 3.24
|
||||
* Bump nokogiri from 1.10.9 to 1.10.10
|
||||
* Bump middleman from 4.3.8 to 4.3.11
|
||||
* Bump lunr.js from 2.3.8 to 2.3.9
|
||||
|
||||
## Version 2.7.1
|
||||
|
||||
*August 13, 2020*
|
||||
|
||||
* __[security]__ Bumped middleman from 4.3.7 to 4.3.8
|
||||
|
||||
_Note_: Slate uses redcarpet, not kramdown, for rendering markdown to HTML, and so was unaffected by the security vulnerability in middleman.
|
||||
If you have changed slate to use kramdown, and with GFM, you may need to install the `kramdown-parser-gfm` gem.
|
||||
|
||||
## Version 2.7.0
|
||||
|
||||
*June 21, 2020*
|
||||
|
||||
* __[security]__ Bumped rack in Gemfile.lock from 2.2.2 to 2.2.3
|
||||
* Bumped bundled jQuery from 3.2.1 to 3.5.1
|
||||
* Bumped bundled lunr from 0.5.7 to 2.3.8
|
||||
* Bumped imagesloaded from 3.1.8 to 4.1.4
|
||||
* Bumped rouge from 3.17.0 to 3.20.0
|
||||
* Bumped redcarpet from 3.4.0 to 3.5.0
|
||||
* Fix color of highlighted code being unreadable when printing page
|
||||
* Add clipboard icon for "Copy to Clipboard" functionality to code boxes (see note below)
|
||||
* Fix handling of ToC selectors that contain punctutation (thanks @gruis)
|
||||
* Fix language bar truncating languages that overflow screen width
|
||||
* Strip HTML tags from ToC title before displaying it in title bar in JS (backup to stripping done in Ruby code) (thanks @atic)
|
||||
|
||||
To enable the new clipboard icon, you need to add `code_clipboard: true` to the frontmatter of source/index.html.md.
|
||||
See [this line](https://github.com/slatedocs/slate/blame/main/source/index.html.md#L19) for an example of usage.
|
||||
|
||||
## Version 2.6.1
|
||||
|
||||
*May 30, 2020*
|
||||
|
||||
* __[security]__ update child dependency activesupport in Gemfile.lock to 5.4.2.3
|
||||
* Update Middleman in Gemfile.lock to 4.3.7
|
||||
* Replace Travis-CI with GitHub actions for continuous integration
|
||||
* Replace Spectrum with GitHub discussions
|
||||
|
||||
## Version 2.6.0
|
||||
|
||||
*May 18, 2020*
|
||||
|
||||
__Note__: 2.5.0 was "pulled" due to a breaking bug discovered after release. It is recommended to skip it, and move straight to 2.6.0.
|
||||
|
||||
* Fix large whitespace gap in middle column for sections with codeblocks
|
||||
* Fix highlighted code elements having a different background than rest of code block
|
||||
* Change JSON keys to have a different font color than their values
|
||||
* Disable asset hashing for woff and woff2 elements due to middleman bug breaking woff2 asset hashing in general
|
||||
* Move Dockerfile to Debian from Alpine
|
||||
* Converted repo to a [GitHub template](https://help.github.com/en/github/creating-cloning-and-archiving-repositories/creating-a-template-repository)
|
||||
* Update sassc to 2.3.0 in Gemfile.lock
|
||||
|
||||
## Version 2.5.0
|
||||
|
||||
*May 8, 2020*
|
||||
|
||||
* __[security]__ update nokogiri to ~> 1.10.8
|
||||
* Update links in example docs to https://github.com/slatedocs/slate from https://github.com/lord/slate
|
||||
* Update LICENSE to include full Apache 2.0 text
|
||||
* Test slate against Ruby 2.5 and 2.6 on Travis-CI
|
||||
* Update Vagrantfile to use Ubuntu 18.04 (thanks @bradthurber)
|
||||
* Parse arguments and flags for deploy.sh on script start, instead of potentially after building source files
|
||||
* Install nodejs inside Vagrantfile (thanks @fernandoaguilar)
|
||||
* Add Dockerfile for running slate (thanks @redhatxl)
|
||||
* update middleman-syntax and rouge to ~>3.2
|
||||
* update middleman to 4.3.6
|
||||
|
||||
## Version 2.4.0
|
||||
|
||||
*October 19, 2019*
|
||||
|
||||
- Move repository from lord/slate to slatedocs/slate
|
||||
- Fix documentation to point at new repo link, thanks to [Arun](https://github.com/slash-arun), [Gustavo Gawryszewski](https://github.com/gawry), and [Daniel Korbit](https://github.com/danielkorbit)
|
||||
- Update `nokogiri` to 1.10.4
|
||||
- Update `ffi` in `Gemfile.lock` to fix security warnings, thanks to [Grey Baker](https://github.com/greysteil) and [jakemack](https://github.com/jakemack)
|
||||
- Update `rack` to 2.0.7 in `Gemfile.lock` to fix security warnings, thanks to [Grey Baker](https://github.com/greysteil) and [jakemack](https://github.com/jakemack)
|
||||
- Update middleman to `4.3` and relax constraints on middleman related gems, thanks to [jakemack](https://github.com/jakemack)
|
||||
- Add sass gem, thanks to [jakemack](https://github.com/jakemack)
|
||||
- Activate `asset_cache` in middleman to improve cacheability of static files, thanks to [Sam Gilman](https://github.com/thenengah)
|
||||
- Update to using bundler 2 for `Gemfile.lock`, thanks to [jakemack](https://github.com/jakemack)
|
||||
|
||||
## Version 2.3.1
|
||||
|
||||
*July 5, 2018*
|
||||
|
||||
- Update `sprockets` in `Gemfile.lock` to fix security warnings
|
||||
|
||||
## Version 2.3
|
||||
|
||||
*July 5, 2018*
|
||||
|
||||
- Allows strikethrough in markdown by default.
|
||||
- Upgrades jQuery to 3.2.1, thanks to [Tomi Takussaari](https://github.com/TomiTakussaari)
|
||||
- Fixes invalid HTML in `layout.erb`, thanks to [Eric Scouten](https://github.com/scouten) for pointing out
|
||||
- Hopefully fixes Vagrant memory issues, thanks to [Petter Blomberg](https://github.com/p-blomberg) for the suggestion
|
||||
- Cleans HTML in headers before setting `document.title`, thanks to [Dan Levy](https://github.com/justsml)
|
||||
- Allows trailing whitespace in markdown files, thanks to [Samuel Cousin](https://github.com/kuzyn)
|
||||
- Fixes pushState/replaceState problems with scrolling not changing the document hash, thanks to [Andrey Fedorov](https://github.com/anfedorov)
|
||||
- Removes some outdated examples, thanks [@al-tr](https://github.com/al-tr), [Jerome Dahdah](https://github.com/jdahdah), and [Ricardo Castro](https://github.com/mccricardo)
|
||||
- Fixes `nav-padding` bug, thanks [Jerome Dahdah](https://github.com/jdahdah)
|
||||
- Code style fixes thanks to [Sebastian Zaremba](https://github.com/vassyz)
|
||||
- Nokogiri version bump thanks to [Grey Baker](https://github.com/greysteil)
|
||||
- Fix to default `index.md` text thanks to [Nick Busey](https://github.com/NickBusey)
|
||||
|
||||
Thanks to everyone who contributed to this release!
|
||||
|
||||
## Version 2.2
|
||||
|
||||
*January 19, 2018*
|
||||
|
||||
- Fixes bugs with some non-roman languages not generating unique headers
|
||||
- Adds editorconfig, thanks to [Jay Thomas](https://github.com/jaythomas)
|
||||
- Adds optional `NestingUniqueHeadCounter`, thanks to [Vladimir Morozov](https://github.com/greenhost87)
|
||||
- Small fixes to typos and language, thx [Emir Ribić](https://github.com/ribice), [Gregor Martynus](https://github.com/gr2m), and [Martius](https://github.com/martiuslim)!
|
||||
- Adds links to Spectrum chat for questions in README and ISSUE_TEMPLATE
|
||||
|
||||
## Version 2.1
|
||||
|
||||
*October 30, 2017*
|
||||
|
||||
- Right-to-left text stylesheet option, thanks to [Mohammad Hossein Rabiee](https://github.com/mhrabiee)
|
||||
- Fix for HTML5 history state bug, thanks to [Zach Toolson](https://github.com/ztoolson)
|
||||
- Small styling changes, typo fixes, small bug fixes from [Marian Friedmann](https://github.com/rnarian), [Ben Wilhelm](https://github.com/benwilhelm), [Fouad Matin](https://github.com/fouad), [Nicolas Bonduel](https://github.com/NicolasBonduel), [Christian Oliff](https://github.com/coliff)
|
||||
|
||||
Thanks to everyone who submitted PRs for this version!
|
||||
|
||||
## Version 2.0
|
||||
|
||||
*July 17, 2017*
|
||||
|
||||
- All-new statically generated table of contents
|
||||
- Should be much faster loading and scrolling for large pages
|
||||
- Smaller Javascript file sizes
|
||||
- Avoids the problem with the last link in the ToC not ever highlighting if the section was shorter than the page
|
||||
- Fixes control-click not opening in a new page
|
||||
- Automatically updates the HTML title as you scroll
|
||||
- Updated design
|
||||
- New default colors!
|
||||
- New spacings and sizes!
|
||||
- System-default typefaces, just like GitHub
|
||||
- Added search input delay on large corpuses to reduce lag
|
||||
- We even bumped the major version cause hey, why not?
|
||||
- Various small bug fixes
|
||||
|
||||
Thanks to everyone who helped debug or wrote code for this version! It was a serious community effort, and I couldn't have done it alone.
|
||||
|
||||
## Version 1.5
|
||||
|
||||
*February 23, 2017*
|
||||
|
||||
- Add [multiple tabs per programming language](https://github.com/lord/slate/wiki/Multiple-language-tabs-per-programming-language) feature
|
||||
- Upgrade Middleman to add Ruby 1.4.0 compatibility
|
||||
- Switch default code highlighting color scheme to better highlight JSON
|
||||
- Various small typo and bug fixes
|
||||
|
||||
## Version 1.4
|
||||
|
||||
*November 24, 2016*
|
||||
|
||||
- Upgrade Middleman and Rouge gems, should hopefully solve a number of bugs
|
||||
- Update some links in README
|
||||
- Fix broken Vagrant startup script
|
||||
- Fix some problems with deploy.sh help message
|
||||
- Fix bug with language tabs not hiding properly if no error
|
||||
- Add `!default` to SASS variables
|
||||
- Fix bug with logo margin
|
||||
- Bump tested Ruby versions in .travis.yml
|
||||
|
||||
## Version 1.3.3
|
||||
|
||||
*June 11, 2016*
|
||||
|
||||
Documentation and example changes.
|
||||
|
||||
## Version 1.3.2
|
||||
|
||||
*February 3, 2016*
|
||||
|
||||
A small bugfix for slightly incorrect background colors on code samples in some cases.
|
||||
|
||||
## Version 1.3.1
|
||||
|
||||
*January 31, 2016*
|
||||
|
||||
A small bugfix for incorrect whitespace in code blocks.
|
||||
|
||||
## Version 1.3
|
||||
|
||||
*January 27, 2016*
|
||||
|
||||
We've upgraded Middleman and a number of other dependencies, which should fix quite a few bugs.
|
||||
|
||||
Instead of `rake build` and `rake deploy`, you should now run `bundle exec middleman build --clean` to build your server, and `./deploy.sh` to deploy it to Github Pages.
|
||||
|
||||
## 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 27, 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
|
||||
29
restful-notes-slate/slate/Dockerfile
Normal file
29
restful-notes-slate/slate/Dockerfile
Normal file
@@ -0,0 +1,29 @@
|
||||
FROM ruby:2.6-slim
|
||||
|
||||
WORKDIR /srv/slate
|
||||
|
||||
VOLUME /srv/slate/build
|
||||
VOLUME /srv/slate/source
|
||||
|
||||
EXPOSE 4567
|
||||
|
||||
COPY Gemfile .
|
||||
COPY Gemfile.lock .
|
||||
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
git \
|
||||
nodejs \
|
||||
&& gem install bundler \
|
||||
&& bundle install \
|
||||
&& apt-get remove -y build-essential git \
|
||||
&& apt-get autoremove -y \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY . /srv/slate
|
||||
|
||||
RUN chmod +x /srv/slate/slate.sh
|
||||
|
||||
ENTRYPOINT ["/srv/slate/slate.sh"]
|
||||
CMD ["build"]
|
||||
13
restful-notes-slate/slate/Gemfile
Normal file
13
restful-notes-slate/slate/Gemfile
Normal file
@@ -0,0 +1,13 @@
|
||||
ruby '>= 2.5'
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Middleman
|
||||
gem 'middleman', '~> 4.4'
|
||||
gem 'middleman-syntax', '~> 3.2'
|
||||
gem 'middleman-autoprefixer', '~> 3.0'
|
||||
gem 'middleman-sprockets', '~> 4.1'
|
||||
gem 'rouge', '~> 3.21'
|
||||
gem 'redcarpet', '~> 3.5.0'
|
||||
gem 'nokogiri', '~> 1.12.1'
|
||||
gem 'sass'
|
||||
gem 'webrick'
|
||||
145
restful-notes-slate/slate/Gemfile.lock
Normal file
145
restful-notes-slate/slate/Gemfile.lock
Normal file
@@ -0,0 +1,145 @@
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activesupport (6.1.4.1)
|
||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||
i18n (>= 1.6, < 2)
|
||||
minitest (>= 5.1)
|
||||
tzinfo (~> 2.0)
|
||||
zeitwerk (~> 2.3)
|
||||
addressable (2.8.0)
|
||||
public_suffix (>= 2.0.2, < 5.0)
|
||||
autoprefixer-rails (10.2.5.0)
|
||||
execjs (< 2.8.0)
|
||||
backports (3.21.0)
|
||||
coffee-script (2.4.1)
|
||||
coffee-script-source
|
||||
execjs
|
||||
coffee-script-source (1.12.2)
|
||||
concurrent-ruby (1.1.9)
|
||||
contracts (0.13.0)
|
||||
dotenv (2.7.6)
|
||||
erubis (2.7.0)
|
||||
execjs (2.7.0)
|
||||
fast_blank (1.0.1)
|
||||
fastimage (2.2.5)
|
||||
ffi (1.15.4)
|
||||
haml (5.2.2)
|
||||
temple (>= 0.8.0)
|
||||
tilt
|
||||
hamster (3.0.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
hashie (3.6.0)
|
||||
i18n (1.6.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
kramdown (2.3.1)
|
||||
rexml
|
||||
listen (3.0.8)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
memoist (0.16.2)
|
||||
middleman (4.4.2)
|
||||
coffee-script (~> 2.2)
|
||||
haml (>= 4.0.5)
|
||||
kramdown (>= 2.3.0)
|
||||
middleman-cli (= 4.4.2)
|
||||
middleman-core (= 4.4.2)
|
||||
middleman-autoprefixer (3.0.0)
|
||||
autoprefixer-rails (~> 10.0)
|
||||
middleman-core (>= 4.0.0)
|
||||
middleman-cli (4.4.2)
|
||||
thor (>= 0.17.0, < 2.0)
|
||||
middleman-core (4.4.2)
|
||||
activesupport (>= 6.1, < 7.0)
|
||||
addressable (~> 2.4)
|
||||
backports (~> 3.6)
|
||||
bundler (~> 2.0)
|
||||
contracts (~> 0.13.0)
|
||||
dotenv
|
||||
erubis
|
||||
execjs (~> 2.0)
|
||||
fast_blank
|
||||
fastimage (~> 2.0)
|
||||
hamster (~> 3.0)
|
||||
hashie (~> 3.4)
|
||||
i18n (~> 1.6.0)
|
||||
listen (~> 3.0.0)
|
||||
memoist (~> 0.14)
|
||||
padrino-helpers (~> 0.15.0)
|
||||
parallel
|
||||
rack (>= 1.4.5, < 3)
|
||||
sassc (~> 2.0)
|
||||
servolux
|
||||
tilt (~> 2.0.9)
|
||||
toml
|
||||
uglifier (~> 3.0)
|
||||
webrick
|
||||
middleman-sprockets (4.1.1)
|
||||
middleman-core (~> 4.0)
|
||||
sprockets (>= 3.0)
|
||||
middleman-syntax (3.2.0)
|
||||
middleman-core (>= 3.2)
|
||||
rouge (~> 3.2)
|
||||
mini_portile2 (2.6.1)
|
||||
minitest (5.14.4)
|
||||
nokogiri (1.12.5)
|
||||
mini_portile2 (~> 2.6.1)
|
||||
racc (~> 1.4)
|
||||
padrino-helpers (0.15.1)
|
||||
i18n (>= 0.6.7, < 2)
|
||||
padrino-support (= 0.15.1)
|
||||
tilt (>= 1.4.1, < 3)
|
||||
padrino-support (0.15.1)
|
||||
parallel (1.21.0)
|
||||
parslet (2.0.0)
|
||||
public_suffix (4.0.6)
|
||||
racc (1.5.2)
|
||||
rack (2.2.3)
|
||||
rb-fsevent (0.11.0)
|
||||
rb-inotify (0.10.1)
|
||||
ffi (~> 1.0)
|
||||
redcarpet (3.5.1)
|
||||
rexml (3.2.5)
|
||||
rouge (3.26.1)
|
||||
sass (3.7.4)
|
||||
sass-listen (~> 4.0.0)
|
||||
sass-listen (4.0.0)
|
||||
rb-fsevent (~> 0.9, >= 0.9.4)
|
||||
rb-inotify (~> 0.9, >= 0.9.7)
|
||||
sassc (2.4.0)
|
||||
ffi (~> 1.9)
|
||||
servolux (0.13.0)
|
||||
sprockets (3.7.2)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
temple (0.8.2)
|
||||
thor (1.1.0)
|
||||
tilt (2.0.10)
|
||||
toml (0.3.0)
|
||||
parslet (>= 1.8.0, < 3.0.0)
|
||||
tzinfo (2.0.4)
|
||||
concurrent-ruby (~> 1.0)
|
||||
uglifier (3.2.0)
|
||||
execjs (>= 0.3.0, < 3)
|
||||
webrick (1.7.0)
|
||||
zeitwerk (2.5.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
middleman (~> 4.4)
|
||||
middleman-autoprefixer (~> 3.0)
|
||||
middleman-sprockets (~> 4.1)
|
||||
middleman-syntax (~> 3.2)
|
||||
nokogiri (~> 1.12.1)
|
||||
redcarpet (~> 3.5.0)
|
||||
rouge (~> 3.21)
|
||||
sass
|
||||
webrick
|
||||
|
||||
RUBY VERSION
|
||||
ruby 2.7.2p137
|
||||
|
||||
BUNDLED WITH
|
||||
2.2.22
|
||||
201
restful-notes-slate/slate/LICENSE
Normal file
201
restful-notes-slate/slate/LICENSE
Normal file
@@ -0,0 +1,201 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
82
restful-notes-slate/slate/README.md
Normal file
82
restful-notes-slate/slate/README.md
Normal file
@@ -0,0 +1,82 @@
|
||||
<p align="center">
|
||||
<img src="https://raw.githubusercontent.com/slatedocs/img/main/logo-slate.png" alt="Slate: API Documentation Generator" width="226">
|
||||
<br>
|
||||
<a href="https://github.com/slatedocs/slate/actions?query=workflow%3ABuild+branch%3Amain"><img src="https://github.com/slatedocs/slate/workflows/Build/badge.svg?branch=main" alt="Build Status"></a>
|
||||
<a href="https://hub.docker.com/r/slatedocs/slate"><img src="https://img.shields.io/docker/v/slatedocs/slate?sort=semver" alt="Docker Version" /></a>
|
||||
</p>
|
||||
|
||||
<p align="center">Slate helps you create beautiful, intelligent, responsive API documentation.</p>
|
||||
|
||||
<p align="center"><img src="https://raw.githubusercontent.com/slatedocs/img/main/screenshot-slate.png" width=700 alt="Screenshot of Example Documentation created with Slate"></p>
|
||||
|
||||
<p align="center"><em>The example above was created with Slate. Check it out at <a href="https://slatedocs.github.io/slate">slatedocs.github.io/slate</a>.</em></p>
|
||||
|
||||
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 in print.
|
||||
|
||||
* **Everything on a single page** — Gone are the days when 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 can 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 [over 100 languages](https://github.com/rouge-ruby/rouge/wiki/List-of-supported-languages-and-lexers), 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 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 use GitHub, you're also welcome to host your docs elsewhere.
|
||||
|
||||
* **RTL Support** Full right-to-left layout for RTL languages such as Arabic, Persian (Farsi), Hebrew etc.
|
||||
|
||||
Getting started with Slate is super easy! Simply press the green "use this template" button above and follow the instructions below. Or, if you'd like to check out what Slate is capable of, take a look at the [sample docs](https://slatedocs.github.io/slate/).
|
||||
|
||||
Getting Started with Slate
|
||||
------------------------------
|
||||
|
||||
To get started with Slate, please check out the [Getting Started](https://github.com/slatedocs/slate/wiki#getting-started)
|
||||
section in our [wiki](https://github.com/slatedocs/slate/wiki).
|
||||
|
||||
We support running Slate in three different ways:
|
||||
* [Natively](https://github.com/slatedocs/slate/wiki/Using-Slate-Natively)
|
||||
* [Using Vagrant](https://github.com/slatedocs/slate/wiki/Using-Slate-in-Vagrant)
|
||||
* [Using Docker](https://github.com/slatedocs/slate/wiki/Using-Slate-in-Docker)
|
||||
|
||||
Companies Using Slate
|
||||
---------------------------------
|
||||
|
||||
* [NASA](https://api.nasa.gov)
|
||||
* [Sony](http://developers.cimediacloud.com)
|
||||
* [Best Buy](https://bestbuyapis.github.io/api-documentation/)
|
||||
* [Travis-CI](https://docs.travis-ci.com/api/)
|
||||
* [Greenhouse](https://developers.greenhouse.io/harvest.html)
|
||||
* [WooCommerce](http://woocommerce.github.io/woocommerce-rest-api-docs/)
|
||||
* [Dwolla](https://docs.dwolla.com/)
|
||||
* [Clearbit](https://clearbit.com/docs)
|
||||
* [Coinbase](https://developers.coinbase.com/api)
|
||||
* [Parrot Drones](http://developer.parrot.com/docs/bebop/)
|
||||
* [CoinAPI](https://docs.coinapi.io/)
|
||||
|
||||
You can view more in [the list on the wiki](https://github.com/slatedocs/slate/wiki/Slate-in-the-Wild).
|
||||
|
||||
Questions? Need Help? Found a bug?
|
||||
--------------------
|
||||
|
||||
If you've got questions about setup, deploying, special feature implementation in your fork, or just want to chat with the developer, please feel free to [start a thread in our Discussions tab](https://github.com/slatedocs/slate/discussions)!
|
||||
|
||||
Found a bug with upstream Slate? Go ahead and [submit an issue](https://github.com/slatedocs/slate/issues). And, of course, feel free to submit pull requests with bug fixes or changes to the `dev` branch.
|
||||
|
||||
Contributors
|
||||
--------------------
|
||||
|
||||
Slate was built by [Robert Lord](https://lord.io) while at [TripIt](https://www.tripit.com/). The project is now maintained by [Matthew Peveler](https://github.com/MasterOdin) and [Mike Ralphson](https://github.com/MikeRalphson).
|
||||
|
||||
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)
|
||||
- [@cvkef](https://github.com/cvkef)
|
||||
|
||||
Also, thanks to [Sauce Labs](http://saucelabs.com) for sponsoring the development of the responsive styles.
|
||||
47
restful-notes-slate/slate/Vagrantfile
vendored
Normal file
47
restful-notes-slate/slate/Vagrantfile
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
Vagrant.configure(2) do |config|
|
||||
config.vm.box = "ubuntu/bionic64"
|
||||
config.vm.network :forwarded_port, guest: 4567, host: 4567
|
||||
config.vm.provider "virtualbox" do |vb|
|
||||
vb.memory = "2048"
|
||||
end
|
||||
|
||||
config.vm.provision "bootstrap",
|
||||
type: "shell",
|
||||
inline: <<-SHELL
|
||||
# add nodejs v12 repository
|
||||
curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
|
||||
|
||||
sudo apt-get update
|
||||
sudo apt-get install -yq ruby ruby-dev
|
||||
sudo apt-get install -yq pkg-config build-essential nodejs git libxml2-dev libxslt-dev
|
||||
sudo apt-get autoremove -yq
|
||||
gem install --no-ri --no-rdoc bundler
|
||||
SHELL
|
||||
|
||||
# add the local user git config to the vm
|
||||
config.vm.provision "file", source: "~/.gitconfig", destination: ".gitconfig"
|
||||
|
||||
config.vm.provision "install",
|
||||
type: "shell",
|
||||
privileged: false,
|
||||
inline: <<-SHELL
|
||||
echo "=============================================="
|
||||
echo "Installing app dependencies"
|
||||
cd /vagrant
|
||||
sudo gem install bundler -v "$(grep -A 1 "BUNDLED WITH" Gemfile.lock | tail -n 1)"
|
||||
bundle config build.nokogiri --use-system-libraries
|
||||
bundle install
|
||||
SHELL
|
||||
|
||||
config.vm.provision "run",
|
||||
type: "shell",
|
||||
privileged: false,
|
||||
run: "always",
|
||||
inline: <<-SHELL
|
||||
echo "=============================================="
|
||||
echo "Starting up middleman at http://localhost:4567"
|
||||
echo "If it does not come up, check the ~/middleman.log file for any error messages"
|
||||
cd /vagrant
|
||||
bundle exec middleman server --watcher-force-polling --watcher-latency=1 &> ~/middleman.log &
|
||||
SHELL
|
||||
end
|
||||
63
restful-notes-slate/slate/config.rb
Normal file
63
restful-notes-slate/slate/config.rb
Normal file
@@ -0,0 +1,63 @@
|
||||
# Unique header generation
|
||||
require './lib/unique_head.rb'
|
||||
|
||||
# Markdown
|
||||
set :markdown_engine, :redcarpet
|
||||
set :markdown,
|
||||
fenced_code_blocks: true,
|
||||
smartypants: true,
|
||||
disable_indented_code_blocks: true,
|
||||
prettify: true,
|
||||
strikethrough: true,
|
||||
tables: true,
|
||||
with_toc_data: true,
|
||||
no_intra_emphasis: true,
|
||||
renderer: UniqueHeadCounter
|
||||
|
||||
# Assets
|
||||
set :css_dir, 'stylesheets'
|
||||
set :js_dir, 'javascripts'
|
||||
set :images_dir, 'images'
|
||||
set :fonts_dir, 'fonts'
|
||||
|
||||
# Activate the syntax highlighter
|
||||
activate :syntax
|
||||
ready do
|
||||
require './lib/monokai_sublime_slate.rb'
|
||||
require './lib/multilang.rb'
|
||||
end
|
||||
|
||||
activate :sprockets
|
||||
|
||||
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
|
||||
configure :build do
|
||||
# We do want to hash woff and woff2 as there's a bug where woff2 will use
|
||||
# woff asset hash which breaks things. Trying to use a combination of ignore and
|
||||
# rewrite_ignore does not work as it conflicts weirdly with relative_assets. Disabling
|
||||
# the .woff2 extension only does not work as .woff will still activate it so have to
|
||||
# have both. See https://github.com/slatedocs/slate/issues/1171 for more details.
|
||||
activate :asset_hash, :exts => app.config[:asset_extensions] - %w[.woff .woff2]
|
||||
# If you're having trouble with Middleman hanging, commenting
|
||||
# out the following two lines has been known to help
|
||||
activate :minify_css
|
||||
activate :minify_javascript
|
||||
# activate :gzip
|
||||
end
|
||||
|
||||
# Deploy Configuration
|
||||
# If you want Middleman to listen on a different port, you can set that below
|
||||
set :port, 4567
|
||||
|
||||
helpers do
|
||||
require './lib/toc_data.rb'
|
||||
end
|
||||
226
restful-notes-slate/slate/deploy.sh
Executable file
226
restful-notes-slate/slate/deploy.sh
Executable file
@@ -0,0 +1,226 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit #abort if any command fails
|
||||
me=$(basename "$0")
|
||||
|
||||
help_message="\
|
||||
Usage: $me [-c FILE] [<options>]
|
||||
Deploy generated files to a git branch.
|
||||
|
||||
Options:
|
||||
|
||||
-h, --help Show this help information.
|
||||
-v, --verbose Increase verbosity. Useful for debugging.
|
||||
-e, --allow-empty Allow deployment of an empty directory.
|
||||
-m, --message MESSAGE Specify the message used when committing on the
|
||||
deploy branch.
|
||||
-n, --no-hash Don't append the source commit's hash to the deploy
|
||||
commit's message.
|
||||
--source-only Only build but not push
|
||||
--push-only Only push but not build
|
||||
"
|
||||
|
||||
|
||||
run_build() {
|
||||
bundle exec middleman build --clean
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# Set args from a local environment file.
|
||||
if [ -e ".env" ]; then
|
||||
source .env
|
||||
fi
|
||||
|
||||
# Parse arg flags
|
||||
# If something is exposed as an environment variable, set/overwrite it
|
||||
# here. Otherwise, set/overwrite the internal variable instead.
|
||||
while : ; do
|
||||
if [[ $1 = "-h" || $1 = "--help" ]]; then
|
||||
echo "$help_message"
|
||||
exit 0
|
||||
elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
|
||||
verbose=true
|
||||
shift
|
||||
elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
|
||||
allow_empty=true
|
||||
shift
|
||||
elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
|
||||
commit_message=$2
|
||||
shift 2
|
||||
elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
|
||||
GIT_DEPLOY_APPEND_HASH=false
|
||||
shift
|
||||
elif [[ $1 = "--source-only" ]]; then
|
||||
source_only=true
|
||||
shift
|
||||
elif [[ $1 = "--push-only" ]]; then
|
||||
push_only=true
|
||||
shift
|
||||
else
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${source_only} ] && [ ${push_only} ]; then
|
||||
>&2 echo "You can only specify one of --source-only or --push-only"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set internal option vars from the environment and arg flags. All internal
|
||||
# vars should be declared here, with sane defaults if applicable.
|
||||
|
||||
# Source directory & target branch.
|
||||
deploy_directory=build
|
||||
deploy_branch=gh-pages
|
||||
|
||||
#if no user identity is already set in the current git environment, use this:
|
||||
default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
|
||||
default_email=${GIT_DEPLOY_EMAIL:-}
|
||||
|
||||
#repository to deploy to. must be readable and writable.
|
||||
repo=origin
|
||||
|
||||
#append commit hash to the end of message by default
|
||||
append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
|
||||
}
|
||||
|
||||
main() {
|
||||
enable_expanded_output
|
||||
|
||||
if ! git diff --exit-code --quiet --cached; then
|
||||
echo Aborting due to uncommitted changes in the index >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
commit_title=`git log -n 1 --format="%s" HEAD`
|
||||
commit_hash=` git log -n 1 --format="%H" HEAD`
|
||||
|
||||
#default commit message uses last title if a custom one is not supplied
|
||||
if [[ -z $commit_message ]]; then
|
||||
commit_message="publish: $commit_title"
|
||||
fi
|
||||
|
||||
#append hash to commit message unless no hash flag was found
|
||||
if [ $append_hash = true ]; then
|
||||
commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
|
||||
fi
|
||||
|
||||
previous_branch=`git rev-parse --abbrev-ref HEAD`
|
||||
|
||||
if [ ! -d "$deploy_directory" ]; then
|
||||
echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# must use short form of flag in ls for compatibility with macOS and BSD
|
||||
if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
|
||||
echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
|
||||
# deploy_branch exists in $repo; make sure we have the latest version
|
||||
|
||||
disable_expanded_output
|
||||
git fetch --force $repo $deploy_branch:$deploy_branch
|
||||
enable_expanded_output
|
||||
fi
|
||||
|
||||
# check if deploy_branch exists locally
|
||||
if git show-ref --verify --quiet "refs/heads/$deploy_branch"
|
||||
then incremental_deploy
|
||||
else initial_deploy
|
||||
fi
|
||||
|
||||
restore_head
|
||||
}
|
||||
|
||||
initial_deploy() {
|
||||
git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
|
||||
git --work-tree "$deploy_directory" add --all
|
||||
commit+push
|
||||
}
|
||||
|
||||
incremental_deploy() {
|
||||
#make deploy_branch the current branch
|
||||
git symbolic-ref HEAD refs/heads/$deploy_branch
|
||||
#put the previously committed contents of deploy_branch into the index
|
||||
git --work-tree "$deploy_directory" reset --mixed --quiet
|
||||
git --work-tree "$deploy_directory" add --all
|
||||
|
||||
set +o errexit
|
||||
diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
|
||||
set -o errexit
|
||||
case $diff in
|
||||
0) echo No changes to files in $deploy_directory. Skipping commit.;;
|
||||
1) commit+push;;
|
||||
*)
|
||||
echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to main, use: git symbolic-ref HEAD refs/heads/main && git reset --mixed >&2
|
||||
return $diff
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
commit+push() {
|
||||
set_user_id
|
||||
git --work-tree "$deploy_directory" commit -m "$commit_message"
|
||||
|
||||
disable_expanded_output
|
||||
#--quiet is important here to avoid outputting the repo URL, which may contain a secret token
|
||||
git push --quiet $repo $deploy_branch
|
||||
enable_expanded_output
|
||||
}
|
||||
|
||||
#echo expanded commands as they are executed (for debugging)
|
||||
enable_expanded_output() {
|
||||
if [ $verbose ]; then
|
||||
set -o xtrace
|
||||
set +o verbose
|
||||
fi
|
||||
}
|
||||
|
||||
#this is used to avoid outputting the repo URL, which may contain a secret token
|
||||
disable_expanded_output() {
|
||||
if [ $verbose ]; then
|
||||
set +o xtrace
|
||||
set -o verbose
|
||||
fi
|
||||
}
|
||||
|
||||
set_user_id() {
|
||||
if [[ -z `git config user.name` ]]; then
|
||||
git config user.name "$default_username"
|
||||
fi
|
||||
if [[ -z `git config user.email` ]]; then
|
||||
git config user.email "$default_email"
|
||||
fi
|
||||
}
|
||||
|
||||
restore_head() {
|
||||
if [[ $previous_branch = "HEAD" ]]; then
|
||||
#we weren't on any branch before, so just set HEAD back to the commit it was on
|
||||
git update-ref --no-deref HEAD $commit_hash $deploy_branch
|
||||
else
|
||||
git symbolic-ref HEAD refs/heads/$previous_branch
|
||||
fi
|
||||
|
||||
git reset --mixed
|
||||
}
|
||||
|
||||
filter() {
|
||||
sed -e "s|$repo|\$repo|g"
|
||||
}
|
||||
|
||||
sanitize() {
|
||||
"$@" 2> >(filter 1>&2) | filter
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
if [[ ${source_only} ]]; then
|
||||
run_build
|
||||
elif [[ ${push_only} ]]; then
|
||||
main "$@"
|
||||
else
|
||||
run_build
|
||||
main "$@"
|
||||
fi
|
||||
148
restful-notes-slate/slate/font-selection.json
Executable file
148
restful-notes-slate/slate/font-selection.json
Executable file
@@ -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
|
||||
}
|
||||
}
|
||||
95
restful-notes-slate/slate/lib/monokai_sublime_slate.rb
Normal file
95
restful-notes-slate/slate/lib/monokai_sublime_slate.rb
Normal file
@@ -0,0 +1,95 @@
|
||||
# -*- coding: utf-8 -*- #
|
||||
# frozen_string_literal: true
|
||||
|
||||
# this is based on https://github.com/rouge-ruby/rouge/blob/master/lib/rouge/themes/monokai_sublime.rb
|
||||
# but without the added background, and changed styling for JSON keys to be soft_yellow instead of white
|
||||
|
||||
module Rouge
|
||||
module Themes
|
||||
class MonokaiSublimeSlate < CSSTheme
|
||||
name 'monokai.sublime.slate'
|
||||
|
||||
palette :black => '#000000'
|
||||
palette :bright_green => '#a6e22e'
|
||||
palette :bright_pink => '#f92672'
|
||||
palette :carmine => '#960050'
|
||||
palette :dark => '#49483e'
|
||||
palette :dark_grey => '#888888'
|
||||
palette :dark_red => '#aa0000'
|
||||
palette :dimgrey => '#75715e'
|
||||
palette :emperor => '#555555'
|
||||
palette :grey => '#999999'
|
||||
palette :light_grey => '#aaaaaa'
|
||||
palette :light_violet => '#ae81ff'
|
||||
palette :soft_cyan => '#66d9ef'
|
||||
palette :soft_yellow => '#e6db74'
|
||||
palette :very_dark => '#1e0010'
|
||||
palette :whitish => '#f8f8f2'
|
||||
palette :orange => '#f6aa11'
|
||||
palette :white => '#ffffff'
|
||||
|
||||
style Generic::Heading, :fg => :grey
|
||||
style Literal::String::Regex, :fg => :orange
|
||||
style Generic::Output, :fg => :dark_grey
|
||||
style Generic::Prompt, :fg => :emperor
|
||||
style Generic::Strong, :bold => false
|
||||
style Generic::Subheading, :fg => :light_grey
|
||||
style Name::Builtin, :fg => :orange
|
||||
style Comment::Multiline,
|
||||
Comment::Preproc,
|
||||
Comment::Single,
|
||||
Comment::Special,
|
||||
Comment, :fg => :dimgrey
|
||||
style Error,
|
||||
Generic::Error,
|
||||
Generic::Traceback, :fg => :carmine
|
||||
style Generic::Deleted,
|
||||
Generic::Inserted,
|
||||
Generic::Emph, :fg => :dark
|
||||
style Keyword::Constant,
|
||||
Keyword::Declaration,
|
||||
Keyword::Reserved,
|
||||
Name::Constant,
|
||||
Keyword::Type, :fg => :soft_cyan
|
||||
style Literal::Number::Float,
|
||||
Literal::Number::Hex,
|
||||
Literal::Number::Integer::Long,
|
||||
Literal::Number::Integer,
|
||||
Literal::Number::Oct,
|
||||
Literal::Number,
|
||||
Literal::String::Char,
|
||||
Literal::String::Escape,
|
||||
Literal::String::Symbol, :fg => :light_violet
|
||||
style Literal::String::Doc,
|
||||
Literal::String::Double,
|
||||
Literal::String::Backtick,
|
||||
Literal::String::Heredoc,
|
||||
Literal::String::Interpol,
|
||||
Literal::String::Other,
|
||||
Literal::String::Single,
|
||||
Literal::String, :fg => :soft_yellow
|
||||
style Name::Attribute,
|
||||
Name::Class,
|
||||
Name::Decorator,
|
||||
Name::Exception,
|
||||
Name::Function, :fg => :bright_green
|
||||
style Name::Variable::Class,
|
||||
Name::Namespace,
|
||||
Name::Entity,
|
||||
Name::Builtin::Pseudo,
|
||||
Name::Variable::Global,
|
||||
Name::Variable::Instance,
|
||||
Name::Variable,
|
||||
Text::Whitespace,
|
||||
Text,
|
||||
Name, :fg => :white
|
||||
style Name::Label, :fg => :bright_pink
|
||||
style Operator::Word,
|
||||
Name::Tag,
|
||||
Keyword,
|
||||
Keyword::Namespace,
|
||||
Keyword::Pseudo,
|
||||
Operator, :fg => :bright_pink
|
||||
end
|
||||
end
|
||||
end
|
||||
16
restful-notes-slate/slate/lib/multilang.rb
Normal file
16
restful-notes-slate/slate/lib/multilang.rb
Normal file
@@ -0,0 +1,16 @@
|
||||
module Multilang
|
||||
def block_code(code, full_lang_name)
|
||||
if full_lang_name
|
||||
parts = full_lang_name.split('--')
|
||||
rouge_lang_name = (parts) ? parts[0] : "" # just parts[0] here causes null ref exception when no language specified
|
||||
super(code, rouge_lang_name).sub("highlight #{rouge_lang_name}") do |match|
|
||||
match + " tab-" + full_lang_name
|
||||
end
|
||||
else
|
||||
super(code, full_lang_name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
require 'middleman-core/renderers/redcarpet'
|
||||
Middleman::Renderers::MiddlemanRedcarpetHTML.send :include, Multilang
|
||||
22
restful-notes-slate/slate/lib/nesting_unique_head.rb
Normal file
22
restful-notes-slate/slate/lib/nesting_unique_head.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
# Nested unique header generation
|
||||
require 'middleman-core/renderers/redcarpet'
|
||||
|
||||
class NestingUniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
|
||||
def initialize
|
||||
super
|
||||
@@headers_history = {} if !defined?(@@headers_history)
|
||||
end
|
||||
|
||||
def header(text, header_level)
|
||||
friendly_text = text.gsub(/<[^>]*>/,"").parameterize
|
||||
@@headers_history[header_level] = text.parameterize
|
||||
|
||||
if header_level > 1
|
||||
for i in (header_level - 1).downto(1)
|
||||
friendly_text.prepend("#{@@headers_history[i]}-") if @@headers_history.key?(i)
|
||||
end
|
||||
end
|
||||
|
||||
return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
|
||||
end
|
||||
end
|
||||
31
restful-notes-slate/slate/lib/toc_data.rb
Normal file
31
restful-notes-slate/slate/lib/toc_data.rb
Normal file
@@ -0,0 +1,31 @@
|
||||
require 'nokogiri'
|
||||
|
||||
def toc_data(page_content)
|
||||
html_doc = Nokogiri::HTML::DocumentFragment.parse(page_content)
|
||||
|
||||
# get a flat list of headers
|
||||
headers = []
|
||||
html_doc.css('h1, h2, h3').each do |header|
|
||||
headers.push({
|
||||
id: header.attribute('id').to_s,
|
||||
content: header.children,
|
||||
title: header.children.to_s.gsub(/<[^>]*>/, ''),
|
||||
level: header.name[1].to_i,
|
||||
children: []
|
||||
})
|
||||
end
|
||||
|
||||
[3,2].each do |header_level|
|
||||
header_to_nest = nil
|
||||
headers = headers.reject do |header|
|
||||
if header[:level] == header_level
|
||||
header_to_nest[:children].push header if header_to_nest
|
||||
true
|
||||
else
|
||||
header_to_nest = header if header[:level] < header_level
|
||||
false
|
||||
end
|
||||
end
|
||||
end
|
||||
headers
|
||||
end
|
||||
24
restful-notes-slate/slate/lib/unique_head.rb
Normal file
24
restful-notes-slate/slate/lib/unique_head.rb
Normal file
@@ -0,0 +1,24 @@
|
||||
# Unique header generation
|
||||
require 'middleman-core/renderers/redcarpet'
|
||||
require 'digest'
|
||||
class UniqueHeadCounter < Middleman::Renderers::MiddlemanRedcarpetHTML
|
||||
def initialize
|
||||
super
|
||||
@head_count = {}
|
||||
end
|
||||
def header(text, header_level)
|
||||
friendly_text = text.gsub(/<[^>]*>/,"").parameterize
|
||||
if friendly_text.strip.length == 0
|
||||
# Looks like parameterize removed the whole thing! It removes many unicode
|
||||
# characters like Chinese and Russian. To get a unique URL, let's just
|
||||
# URI escape the whole header
|
||||
friendly_text = Digest::SHA1.hexdigest(text)[0,10]
|
||||
end
|
||||
@head_count[friendly_text] ||= 0
|
||||
@head_count[friendly_text] += 1
|
||||
if @head_count[friendly_text] > 1
|
||||
friendly_text += "-#{@head_count[friendly_text]}"
|
||||
end
|
||||
return "<h#{header_level} id='#{friendly_text}'>#{text}</h#{header_level}>"
|
||||
end
|
||||
end
|
||||
248
restful-notes-slate/slate/slate.sh
Executable file
248
restful-notes-slate/slate/slate.sh
Executable file
@@ -0,0 +1,248 @@
|
||||
#!/usr/bin/env bash
|
||||
set -o errexit #abort if any command fails
|
||||
|
||||
me=$(basename "$0")
|
||||
|
||||
help_message="\
|
||||
Usage: $me [<options>] <command> [<command-options>]
|
||||
Run commands related to the slate process.
|
||||
|
||||
Commands:
|
||||
|
||||
serve Run the middleman server process, useful for
|
||||
development.
|
||||
build Run the build process.
|
||||
deploy Will build and deploy files to branch. Use
|
||||
--no-build to only deploy.
|
||||
|
||||
Global Options:
|
||||
|
||||
-h, --help Show this help information.
|
||||
-v, --verbose Increase verbosity. Useful for debugging.
|
||||
|
||||
Deploy options:
|
||||
-e, --allow-empty Allow deployment of an empty directory.
|
||||
-m, --message MESSAGE Specify the message used when committing on the
|
||||
deploy branch.
|
||||
-n, --no-hash Don't append the source commit's hash to the deploy
|
||||
commit's message.
|
||||
--no-build Do not build the source files.
|
||||
"
|
||||
|
||||
|
||||
run_serve() {
|
||||
exec bundle exec middleman serve --watcher-force-polling
|
||||
}
|
||||
|
||||
run_build() {
|
||||
bundle exec middleman build --clean
|
||||
}
|
||||
|
||||
parse_args() {
|
||||
# Set args from a local environment file.
|
||||
if [ -e ".env" ]; then
|
||||
source .env
|
||||
fi
|
||||
|
||||
command=
|
||||
|
||||
# Parse arg flags
|
||||
# If something is exposed as an environment variable, set/overwrite it
|
||||
# here. Otherwise, set/overwrite the internal variable instead.
|
||||
while : ; do
|
||||
if [[ $1 = "-h" || $1 = "--help" ]]; then
|
||||
echo "$help_message"
|
||||
exit 0
|
||||
elif [[ $1 = "-v" || $1 = "--verbose" ]]; then
|
||||
verbose=true
|
||||
shift
|
||||
elif [[ $1 = "-e" || $1 = "--allow-empty" ]]; then
|
||||
allow_empty=true
|
||||
shift
|
||||
elif [[ ( $1 = "-m" || $1 = "--message" ) && -n $2 ]]; then
|
||||
commit_message=$2
|
||||
shift 2
|
||||
elif [[ $1 = "-n" || $1 = "--no-hash" ]]; then
|
||||
GIT_DEPLOY_APPEND_HASH=false
|
||||
shift
|
||||
elif [[ $1 = "--no-build" ]]; then
|
||||
no_build=true
|
||||
shift
|
||||
elif [[ $1 = "serve" || $1 = "build" || $1 = "deploy" ]]; then
|
||||
if [ ! -z "${command}" ]; then
|
||||
>&2 echo "You can only specify one command."
|
||||
exit 1
|
||||
fi
|
||||
command=$1
|
||||
shift
|
||||
elif [ -z $1 ]; then
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "${command}" ]; then
|
||||
>&2 echo "Command not specified."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set internal option vars from the environment and arg flags. All internal
|
||||
# vars should be declared here, with sane defaults if applicable.
|
||||
|
||||
# Source directory & target branch.
|
||||
deploy_directory=build
|
||||
deploy_branch=gh-pages
|
||||
|
||||
#if no user identity is already set in the current git environment, use this:
|
||||
default_username=${GIT_DEPLOY_USERNAME:-deploy.sh}
|
||||
default_email=${GIT_DEPLOY_EMAIL:-}
|
||||
|
||||
#repository to deploy to. must be readable and writable.
|
||||
repo=origin
|
||||
|
||||
#append commit hash to the end of message by default
|
||||
append_hash=${GIT_DEPLOY_APPEND_HASH:-true}
|
||||
}
|
||||
|
||||
main() {
|
||||
enable_expanded_output
|
||||
|
||||
if ! git diff --exit-code --quiet --cached; then
|
||||
echo Aborting due to uncommitted changes in the index >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
commit_title=`git log -n 1 --format="%s" HEAD`
|
||||
commit_hash=` git log -n 1 --format="%H" HEAD`
|
||||
|
||||
#default commit message uses last title if a custom one is not supplied
|
||||
if [[ -z $commit_message ]]; then
|
||||
commit_message="publish: $commit_title"
|
||||
fi
|
||||
|
||||
#append hash to commit message unless no hash flag was found
|
||||
if [ $append_hash = true ]; then
|
||||
commit_message="$commit_message"$'\n\n'"generated from commit $commit_hash"
|
||||
fi
|
||||
|
||||
previous_branch=`git rev-parse --abbrev-ref HEAD`
|
||||
|
||||
if [ ! -d "$deploy_directory" ]; then
|
||||
echo "Deploy directory '$deploy_directory' does not exist. Aborting." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# must use short form of flag in ls for compatibility with macOS and BSD
|
||||
if [[ -z `ls -A "$deploy_directory" 2> /dev/null` && -z $allow_empty ]]; then
|
||||
echo "Deploy directory '$deploy_directory' is empty. Aborting. If you're sure you want to deploy an empty tree, use the --allow-empty / -e flag." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
if git ls-remote --exit-code $repo "refs/heads/$deploy_branch" ; then
|
||||
# deploy_branch exists in $repo; make sure we have the latest version
|
||||
|
||||
disable_expanded_output
|
||||
git fetch --force $repo $deploy_branch:$deploy_branch
|
||||
enable_expanded_output
|
||||
fi
|
||||
|
||||
# check if deploy_branch exists locally
|
||||
if git show-ref --verify --quiet "refs/heads/$deploy_branch"
|
||||
then incremental_deploy
|
||||
else initial_deploy
|
||||
fi
|
||||
|
||||
restore_head
|
||||
}
|
||||
|
||||
initial_deploy() {
|
||||
git --work-tree "$deploy_directory" checkout --orphan $deploy_branch
|
||||
git --work-tree "$deploy_directory" add --all
|
||||
commit+push
|
||||
}
|
||||
|
||||
incremental_deploy() {
|
||||
#make deploy_branch the current branch
|
||||
git symbolic-ref HEAD refs/heads/$deploy_branch
|
||||
#put the previously committed contents of deploy_branch into the index
|
||||
git --work-tree "$deploy_directory" reset --mixed --quiet
|
||||
git --work-tree "$deploy_directory" add --all
|
||||
|
||||
set +o errexit
|
||||
diff=$(git --work-tree "$deploy_directory" diff --exit-code --quiet HEAD --)$?
|
||||
set -o errexit
|
||||
case $diff in
|
||||
0) echo No changes to files in $deploy_directory. Skipping commit.;;
|
||||
1) commit+push;;
|
||||
*)
|
||||
echo git diff exited with code $diff. Aborting. Staying on branch $deploy_branch so you can debug. To switch back to main, use: git symbolic-ref HEAD refs/heads/main && git reset --mixed >&2
|
||||
return $diff
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
commit+push() {
|
||||
set_user_id
|
||||
git --work-tree "$deploy_directory" commit -m "$commit_message"
|
||||
|
||||
disable_expanded_output
|
||||
#--quiet is important here to avoid outputting the repo URL, which may contain a secret token
|
||||
git push --quiet $repo $deploy_branch
|
||||
enable_expanded_output
|
||||
}
|
||||
|
||||
#echo expanded commands as they are executed (for debugging)
|
||||
enable_expanded_output() {
|
||||
if [ $verbose ]; then
|
||||
set -o xtrace
|
||||
set +o verbose
|
||||
fi
|
||||
}
|
||||
|
||||
#this is used to avoid outputting the repo URL, which may contain a secret token
|
||||
disable_expanded_output() {
|
||||
if [ $verbose ]; then
|
||||
set +o xtrace
|
||||
set -o verbose
|
||||
fi
|
||||
}
|
||||
|
||||
set_user_id() {
|
||||
if [[ -z `git config user.name` ]]; then
|
||||
git config user.name "$default_username"
|
||||
fi
|
||||
if [[ -z `git config user.email` ]]; then
|
||||
git config user.email "$default_email"
|
||||
fi
|
||||
}
|
||||
|
||||
restore_head() {
|
||||
if [[ $previous_branch = "HEAD" ]]; then
|
||||
#we weren't on any branch before, so just set HEAD back to the commit it was on
|
||||
git update-ref --no-deref HEAD $commit_hash $deploy_branch
|
||||
else
|
||||
git symbolic-ref HEAD refs/heads/$previous_branch
|
||||
fi
|
||||
|
||||
git reset --mixed
|
||||
}
|
||||
|
||||
filter() {
|
||||
sed -e "s|$repo|\$repo|g"
|
||||
}
|
||||
|
||||
sanitize() {
|
||||
"$@" 2> >(filter 1>&2) | filter
|
||||
}
|
||||
|
||||
parse_args "$@"
|
||||
|
||||
if [ "${command}" = "serve" ]; then
|
||||
run_serve
|
||||
elif [[ "${command}" = "build" ]]; then
|
||||
run_build
|
||||
elif [[ ${command} = "deploy" ]]; then
|
||||
if [[ ${no_build} != true ]]; then
|
||||
run_build
|
||||
fi
|
||||
main "$@"
|
||||
fi
|
||||
206
restful-notes-slate/slate/source/api-guide.html.md.erb
Normal file
206
restful-notes-slate/slate/source/api-guide.html.md.erb
Normal file
@@ -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)](https://github.com/mikekelly/hal_specification)
|
||||
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) %>
|
||||
BIN
restful-notes-slate/slate/source/fonts/slate.eot
Normal file
BIN
restful-notes-slate/slate/source/fonts/slate.eot
Normal file
Binary file not shown.
14
restful-notes-slate/slate/source/fonts/slate.svg
Normal file
14
restful-notes-slate/slate/source/fonts/slate.svg
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<metadata>Generated by IcoMoon</metadata>
|
||||
<defs>
|
||||
<font id="slate" horiz-adv-x="1024">
|
||||
<font-face units-per-em="1024" ascent="960" descent="-64" />
|
||||
<missing-glyph horiz-adv-x="1024" />
|
||||
<glyph unicode=" " d="" horiz-adv-x="512" />
|
||||
<glyph unicode="" d="M438.857 877.714q119.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 165.143v108.571q0 8-5.143 13.429t-12.571 5.429h-109.714q-7.429 0-13.143-5.714t-5.714-13.143v-108.571q0-7.429 5.714-13.143t13.143-5.714h109.714q7.429 0 12.571 5.429t5.143 13.429zM510.857 361.714l10.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" />
|
||||
<glyph unicode="" d="M585.143 164.571v91.429q0 8-5.143 13.143t-13.143 5.143h-54.857v292.571q0 8-5.143 13.143t-13.143 5.143h-182.857q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h54.857v-182.857h-54.857q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h256q8 0 13.143 5.143t5.143 13.143zM512 676.571v91.429q0 8-5.143 13.143t-13.143 5.143h-109.714q-8 0-13.143-5.143t-5.143-13.143v-91.429q0-8 5.143-13.143t13.143-5.143h109.714q8 0 13.143 5.143t5.143 13.143zM877.714 438.857q0-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" />
|
||||
<glyph unicode="" d="M733.714 531.428q0 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 438.857q0-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" />
|
||||
<glyph unicode="" d="M658.286 475.428q0 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 0q0-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" horiz-adv-x="951" />
|
||||
</font></defs></svg>
|
||||
|
After Width: | Height: | Size: 2.9 KiB |
BIN
restful-notes-slate/slate/source/fonts/slate.ttf
Normal file
BIN
restful-notes-slate/slate/source/fonts/slate.ttf
Normal file
Binary file not shown.
BIN
restful-notes-slate/slate/source/fonts/slate.woff
Normal file
BIN
restful-notes-slate/slate/source/fonts/slate.woff
Normal file
Binary file not shown.
BIN
restful-notes-slate/slate/source/fonts/slate.woff2
Normal file
BIN
restful-notes-slate/slate/source/fonts/slate.woff2
Normal file
Binary file not shown.
BIN
restful-notes-slate/slate/source/images/logo.png
Normal file
BIN
restful-notes-slate/slate/source/images/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
BIN
restful-notes-slate/slate/source/images/navbar.png
Normal file
BIN
restful-notes-slate/slate/source/images/navbar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 B |
22
restful-notes-slate/slate/source/includes/_errors.md
Normal file
22
restful-notes-slate/slate/source/includes/_errors.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Errors
|
||||
|
||||
<aside class="notice">
|
||||
This error section is stored in a separate file in <code>includes/_errors.md</code>. Slate allows you to optionally separate out your docs into many files...just save them to the <code>includes</code> folder and add them to the top of your <code>index.md</code>'s frontmatter. Files are included in the order listed.
|
||||
</aside>
|
||||
|
||||
The Kittn API uses the following error codes:
|
||||
|
||||
|
||||
Error Code | Meaning
|
||||
---------- | -------
|
||||
400 | Bad Request -- Your request is invalid.
|
||||
401 | Unauthorized -- Your API key is wrong.
|
||||
403 | Forbidden -- The kitten requested is hidden for administrators only.
|
||||
404 | Not Found -- The specified kitten could not be found.
|
||||
405 | Method Not Allowed -- You tried to access a kitten with an invalid method.
|
||||
406 | Not Acceptable -- You requested a format that isn't json.
|
||||
410 | Gone -- The kitten requested has been removed from our servers.
|
||||
418 | I'm a teapot.
|
||||
429 | Too Many Requests -- You're requesting too many kittens! Slow down!
|
||||
500 | Internal Server Error -- We had a problem with our server. Try again later.
|
||||
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later.
|
||||
245
restful-notes-slate/slate/source/index.html.md
Normal file
245
restful-notes-slate/slate/source/index.html.md
Normal file
@@ -0,0 +1,245 @@
|
||||
---
|
||||
title: API Reference
|
||||
|
||||
language_tabs: # must be one of https://git.io/vQNgJ
|
||||
- shell
|
||||
- ruby
|
||||
- python
|
||||
- javascript
|
||||
|
||||
toc_footers:
|
||||
- <a href='#'>Sign Up for a Developer Key</a>
|
||||
- <a href='https://github.com/slatedocs/slate'>Documentation Powered by Slate</a>
|
||||
|
||||
includes:
|
||||
- errors
|
||||
|
||||
search: true
|
||||
|
||||
code_clipboard: true
|
||||
|
||||
meta:
|
||||
- name: description
|
||||
content: Documentation for the Kittn API
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
||||
Welcome to the Kittn API! You can use our API to access Kittn API endpoints, which can get information on various cats, kittens, and breeds in our database.
|
||||
|
||||
We have language bindings in Shell, Ruby, Python, and JavaScript! You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
|
||||
|
||||
This example API documentation page was created with [Slate](https://github.com/slatedocs/slate). Feel free to edit it and use it as a base for your own API's documentation.
|
||||
|
||||
# Authentication
|
||||
|
||||
> To authorize, use this code:
|
||||
|
||||
```ruby
|
||||
require 'kittn'
|
||||
|
||||
api = Kittn::APIClient.authorize!('meowmeowmeow')
|
||||
```
|
||||
|
||||
```python
|
||||
import kittn
|
||||
|
||||
api = kittn.authorize('meowmeowmeow')
|
||||
```
|
||||
|
||||
```shell
|
||||
# With shell, you can just pass the correct header with each request
|
||||
curl "api_endpoint_here" \
|
||||
-H "Authorization: meowmeowmeow"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const kittn = require('kittn');
|
||||
|
||||
let api = kittn.authorize('meowmeowmeow');
|
||||
```
|
||||
|
||||
> Make sure to replace `meowmeowmeow` with your API key.
|
||||
|
||||
Kittn uses API keys to allow access to the API. You can register a new Kittn API key at our [developer portal](http://example.com/developers).
|
||||
|
||||
Kittn expects for the API key to be included in all API requests to the server in a header that looks like the following:
|
||||
|
||||
`Authorization: meowmeowmeow`
|
||||
|
||||
<aside class="notice">
|
||||
You must replace <code>meowmeowmeow</code> with your personal API key.
|
||||
</aside>
|
||||
|
||||
# Kittens
|
||||
|
||||
## Get All Kittens
|
||||
|
||||
```ruby
|
||||
require 'kittn'
|
||||
|
||||
api = Kittn::APIClient.authorize!('meowmeowmeow')
|
||||
api.kittens.get
|
||||
```
|
||||
|
||||
```python
|
||||
import kittn
|
||||
|
||||
api = kittn.authorize('meowmeowmeow')
|
||||
api.kittens.get()
|
||||
```
|
||||
|
||||
```shell
|
||||
curl "http://example.com/api/kittens" \
|
||||
-H "Authorization: meowmeowmeow"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const kittn = require('kittn');
|
||||
|
||||
let api = kittn.authorize('meowmeowmeow');
|
||||
let kittens = api.kittens.get();
|
||||
```
|
||||
|
||||
> The above command returns JSON structured like this:
|
||||
|
||||
```json
|
||||
[
|
||||
{
|
||||
"id": 1,
|
||||
"name": "Fluffums",
|
||||
"breed": "calico",
|
||||
"fluffiness": 6,
|
||||
"cuteness": 7
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Max",
|
||||
"breed": "unknown",
|
||||
"fluffiness": 5,
|
||||
"cuteness": 10
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
This endpoint retrieves all kittens.
|
||||
|
||||
### HTTP Request
|
||||
|
||||
`GET http://example.com/api/kittens`
|
||||
|
||||
### Query Parameters
|
||||
|
||||
Parameter | Default | Description
|
||||
--------- | ------- | -----------
|
||||
include_cats | false | If set to true, the result will also include cats.
|
||||
available | true | If set to false, the result will include kittens that have already been adopted.
|
||||
|
||||
<aside class="success">
|
||||
Remember — a happy kitten is an authenticated kitten!
|
||||
</aside>
|
||||
|
||||
## Get a Specific Kitten
|
||||
|
||||
```ruby
|
||||
require 'kittn'
|
||||
|
||||
api = Kittn::APIClient.authorize!('meowmeowmeow')
|
||||
api.kittens.get(2)
|
||||
```
|
||||
|
||||
```python
|
||||
import kittn
|
||||
|
||||
api = kittn.authorize('meowmeowmeow')
|
||||
api.kittens.get(2)
|
||||
```
|
||||
|
||||
```shell
|
||||
curl "http://example.com/api/kittens/2" \
|
||||
-H "Authorization: meowmeowmeow"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const kittn = require('kittn');
|
||||
|
||||
let api = kittn.authorize('meowmeowmeow');
|
||||
let max = api.kittens.get(2);
|
||||
```
|
||||
|
||||
> The above command returns JSON structured like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"name": "Max",
|
||||
"breed": "unknown",
|
||||
"fluffiness": 5,
|
||||
"cuteness": 10
|
||||
}
|
||||
```
|
||||
|
||||
This endpoint retrieves a specific kitten.
|
||||
|
||||
<aside class="warning">Inside HTML code blocks like this one, you can't use Markdown, so use <code><code></code> blocks to denote code.</aside>
|
||||
|
||||
### HTTP Request
|
||||
|
||||
`GET http://example.com/kittens/<ID>`
|
||||
|
||||
### URL Parameters
|
||||
|
||||
Parameter | Description
|
||||
--------- | -----------
|
||||
ID | The ID of the kitten to retrieve
|
||||
|
||||
## Delete a Specific Kitten
|
||||
|
||||
```ruby
|
||||
require 'kittn'
|
||||
|
||||
api = Kittn::APIClient.authorize!('meowmeowmeow')
|
||||
api.kittens.delete(2)
|
||||
```
|
||||
|
||||
```python
|
||||
import kittn
|
||||
|
||||
api = kittn.authorize('meowmeowmeow')
|
||||
api.kittens.delete(2)
|
||||
```
|
||||
|
||||
```shell
|
||||
curl "http://example.com/api/kittens/2" \
|
||||
-X DELETE \
|
||||
-H "Authorization: meowmeowmeow"
|
||||
```
|
||||
|
||||
```javascript
|
||||
const kittn = require('kittn');
|
||||
|
||||
let api = kittn.authorize('meowmeowmeow');
|
||||
let max = api.kittens.delete(2);
|
||||
```
|
||||
|
||||
> The above command returns JSON structured like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": 2,
|
||||
"deleted" : ":("
|
||||
}
|
||||
```
|
||||
|
||||
This endpoint deletes a specific kitten.
|
||||
|
||||
### HTTP Request
|
||||
|
||||
`DELETE http://example.com/kittens/<ID>`
|
||||
|
||||
### URL Parameters
|
||||
|
||||
Parameter | Description
|
||||
--------- | -----------
|
||||
ID | The ID of the kitten to delete
|
||||
|
||||
2
restful-notes-slate/slate/source/javascripts/all.js
Normal file
2
restful-notes-slate/slate/source/javascripts/all.js
Normal file
@@ -0,0 +1,2 @@
|
||||
//= require ./all_nosearch
|
||||
//= require ./app/_search
|
||||
27
restful-notes-slate/slate/source/javascripts/all_nosearch.js
Normal file
27
restful-notes-slate/slate/source/javascripts/all_nosearch.js
Normal file
@@ -0,0 +1,27 @@
|
||||
//= require ./lib/_energize
|
||||
//= require ./app/_copy
|
||||
//= require ./app/_toc
|
||||
//= require ./app/_lang
|
||||
|
||||
function adjustLanguageSelectorWidth() {
|
||||
const elem = $('.dark-box > .lang-selector');
|
||||
elem.width(elem.parent().width());
|
||||
}
|
||||
|
||||
$(function() {
|
||||
loadToc($('#toc'), '.toc-link', '.toc-list-h2', 10);
|
||||
setupLanguages($('body').data('languages'));
|
||||
$('.content').imagesLoaded( function() {
|
||||
window.recacheHeights();
|
||||
window.refreshToc();
|
||||
});
|
||||
|
||||
$(window).resize(function() {
|
||||
adjustLanguageSelectorWidth();
|
||||
});
|
||||
adjustLanguageSelectorWidth();
|
||||
});
|
||||
|
||||
window.onpopstate = function() {
|
||||
activateLanguage(getLanguageFromQueryString());
|
||||
};
|
||||
15
restful-notes-slate/slate/source/javascripts/app/_copy.js
Normal file
15
restful-notes-slate/slate/source/javascripts/app/_copy.js
Normal file
@@ -0,0 +1,15 @@
|
||||
function copyToClipboard(container) {
|
||||
const el = document.createElement('textarea');
|
||||
el.value = container.textContent.replace(/\n$/, '');
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(el);
|
||||
}
|
||||
|
||||
function setupCodeCopy() {
|
||||
$('pre.highlight').prepend('<div class="copy-clipboard"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><title>Copy to Clipboard</title><path d="M18 6v-6h-18v18h6v6h18v-18h-6zm-12 10h-4v-14h14v4h-10v10zm16 6h-14v-14h14v14z"></path></svg></div>');
|
||||
$('.copy-clipboard').on('click', function() {
|
||||
copyToClipboard(this.parentNode.children[1]);
|
||||
});
|
||||
}
|
||||
171
restful-notes-slate/slate/source/javascripts/app/_lang.js
Normal file
171
restful-notes-slate/slate/source/javascripts/app/_lang.js
Normal file
@@ -0,0 +1,171 @@
|
||||
//= require ../lib/_jquery
|
||||
|
||||
/*
|
||||
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 () {
|
||||
'use strict';
|
||||
|
||||
var languages = [];
|
||||
|
||||
window.setupLanguages = setupLanguages;
|
||||
window.activateLanguage = activateLanguage;
|
||||
window.getLanguageFromQueryString = getLanguageFromQueryString;
|
||||
|
||||
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.tab-" + languages[i]).hide();
|
||||
$(".lang-specific." + languages[i]).hide();
|
||||
}
|
||||
$(".highlight.tab-" + language).show();
|
||||
$(".lang-specific." + language).show();
|
||||
|
||||
window.recacheHeights();
|
||||
|
||||
// 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
|
||||
if (localStorage) {
|
||||
localStorage.setItem("language", language);
|
||||
}
|
||||
}
|
||||
|
||||
function setupLanguages(l) {
|
||||
var defaultLanguage = null;
|
||||
if (localStorage) {
|
||||
defaultLanguage = localStorage.getItem("language");
|
||||
}
|
||||
|
||||
languages = l;
|
||||
|
||||
var presetLanguage = getLanguageFromQueryString();
|
||||
if (presetLanguage) {
|
||||
// the language is in the URL, so use that language!
|
||||
activateLanguage(presetLanguage);
|
||||
|
||||
if (localStorage) {
|
||||
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;
|
||||
});
|
||||
});
|
||||
})();
|
||||
102
restful-notes-slate/slate/source/javascripts/app/_search.js
Normal file
102
restful-notes-slate/slate/source/javascripts/app/_search.js
Normal file
@@ -0,0 +1,102 @@
|
||||
//= require ../lib/_lunr
|
||||
//= require ../lib/_jquery
|
||||
//= require ../lib/_jquery.highlight
|
||||
;(function () {
|
||||
'use strict';
|
||||
|
||||
var content, searchResults;
|
||||
var highlightOpts = { element: 'span', className: 'search-highlight' };
|
||||
var searchDelay = 0;
|
||||
var timeoutHandle = 0;
|
||||
var index;
|
||||
|
||||
function populate() {
|
||||
index = lunr(function(){
|
||||
|
||||
this.ref('id');
|
||||
this.field('title', { boost: 10 });
|
||||
this.field('body');
|
||||
this.pipeline.add(lunr.trimmer, lunr.stopWordFilter);
|
||||
var lunrConfig = this;
|
||||
|
||||
$('h1, h2').each(function() {
|
||||
var title = $(this);
|
||||
var body = title.nextUntil('h1, h2');
|
||||
lunrConfig.add({
|
||||
id: title.prop('id'),
|
||||
title: title.text(),
|
||||
body: body.text()
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
determineSearchDelay();
|
||||
}
|
||||
|
||||
$(populate);
|
||||
$(bind);
|
||||
|
||||
function determineSearchDelay() {
|
||||
if (index.tokenSet.toArray().length>5000) {
|
||||
searchDelay = 300;
|
||||
}
|
||||
}
|
||||
|
||||
function bind() {
|
||||
content = $('.content');
|
||||
searchResults = $('.search-results');
|
||||
|
||||
$('#input-search').on('keyup',function(e) {
|
||||
var wait = function() {
|
||||
return function(executingFunction, waitTime){
|
||||
clearTimeout(timeoutHandle);
|
||||
timeoutHandle = setTimeout(executingFunction, waitTime);
|
||||
};
|
||||
}();
|
||||
wait(function(){
|
||||
search(e);
|
||||
}, searchDelay);
|
||||
});
|
||||
}
|
||||
|
||||
function search(event) {
|
||||
|
||||
var searchInput = $('#input-search')[0];
|
||||
|
||||
unhighlight();
|
||||
searchResults.addClass('visible');
|
||||
|
||||
// ESC clears the field
|
||||
if (event.keyCode === 27) searchInput.value = '';
|
||||
|
||||
if (searchInput.value) {
|
||||
var results = index.search(searchInput.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("<li><a href='#" + result.ref + "'>" + $(elem).text() + "</a></li>");
|
||||
});
|
||||
highlight.call(searchInput);
|
||||
} else {
|
||||
searchResults.html('<li></li>');
|
||||
$('.search-results li').text('No Results Found for "' + searchInput.value + '"');
|
||||
}
|
||||
} else {
|
||||
unhighlight();
|
||||
searchResults.removeClass('visible');
|
||||
}
|
||||
}
|
||||
|
||||
function highlight() {
|
||||
if (this.value) content.highlight(this.value, highlightOpts);
|
||||
}
|
||||
|
||||
function unhighlight() {
|
||||
content.unhighlight(highlightOpts);
|
||||
}
|
||||
})();
|
||||
|
||||
122
restful-notes-slate/slate/source/javascripts/app/_toc.js
Normal file
122
restful-notes-slate/slate/source/javascripts/app/_toc.js
Normal file
@@ -0,0 +1,122 @@
|
||||
//= require ../lib/_jquery
|
||||
//= require ../lib/_imagesloaded.min
|
||||
;(function () {
|
||||
'use strict';
|
||||
|
||||
var htmlPattern = /<[^>]*>/g;
|
||||
var loaded = false;
|
||||
|
||||
var debounce = function(func, waitTime) {
|
||||
var timeout = false;
|
||||
return function() {
|
||||
if (timeout === false) {
|
||||
setTimeout(function() {
|
||||
func();
|
||||
timeout = false;
|
||||
}, waitTime);
|
||||
timeout = true;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var closeToc = function() {
|
||||
$(".toc-wrapper").removeClass('open');
|
||||
$("#nav-button").removeClass('open');
|
||||
};
|
||||
|
||||
function loadToc($toc, tocLinkSelector, tocListSelector, scrollOffset) {
|
||||
var headerHeights = {};
|
||||
var pageHeight = 0;
|
||||
var windowHeight = 0;
|
||||
var originalTitle = document.title;
|
||||
|
||||
var recacheHeights = function() {
|
||||
headerHeights = {};
|
||||
pageHeight = $(document).height();
|
||||
windowHeight = $(window).height();
|
||||
|
||||
$toc.find(tocLinkSelector).each(function() {
|
||||
var targetId = $(this).attr('href');
|
||||
if (targetId[0] === "#") {
|
||||
headerHeights[targetId] = $("#" + $.escapeSelector(targetId.substring(1))).offset().top;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var refreshToc = function() {
|
||||
var currentTop = $(document).scrollTop() + scrollOffset;
|
||||
|
||||
if (currentTop + windowHeight >= pageHeight) {
|
||||
// at bottom of page, so just select last header by making currentTop very large
|
||||
// this fixes the problem where the last header won't ever show as active if its content
|
||||
// is shorter than the window height
|
||||
currentTop = pageHeight + 1000;
|
||||
}
|
||||
|
||||
var best = null;
|
||||
for (var name in headerHeights) {
|
||||
if ((headerHeights[name] < currentTop && headerHeights[name] > headerHeights[best]) || best === null) {
|
||||
best = name;
|
||||
}
|
||||
}
|
||||
|
||||
// Catch the initial load case
|
||||
if (currentTop == scrollOffset && !loaded) {
|
||||
best = window.location.hash;
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
var $best = $toc.find("[href='" + best + "']").first();
|
||||
if (!$best.hasClass("active")) {
|
||||
// .active is applied to the ToC link we're currently on, and its parent <ul>s selected by tocListSelector
|
||||
// .active-expanded is applied to the ToC links that are parents of this one
|
||||
$toc.find(".active").removeClass("active");
|
||||
$toc.find(".active-parent").removeClass("active-parent");
|
||||
$best.addClass("active");
|
||||
$best.parents(tocListSelector).addClass("active").siblings(tocLinkSelector).addClass('active-parent');
|
||||
$best.siblings(tocListSelector).addClass("active");
|
||||
$toc.find(tocListSelector).filter(":not(.active)").slideUp(150);
|
||||
$toc.find(tocListSelector).filter(".active").slideDown(150);
|
||||
if (window.history.replaceState) {
|
||||
window.history.replaceState(null, "", best);
|
||||
}
|
||||
var thisTitle = $best.data("title");
|
||||
if (thisTitle !== undefined && thisTitle.length > 0) {
|
||||
document.title = thisTitle.replace(htmlPattern, "") + " – " + originalTitle;
|
||||
} else {
|
||||
document.title = originalTitle;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var makeToc = function() {
|
||||
recacheHeights();
|
||||
refreshToc();
|
||||
|
||||
$("#nav-button").click(function() {
|
||||
$(".toc-wrapper").toggleClass('open');
|
||||
$("#nav-button").toggleClass('open');
|
||||
return false;
|
||||
});
|
||||
$(".page-wrapper").click(closeToc);
|
||||
$(".toc-link").click(closeToc);
|
||||
|
||||
// reload immediately after scrolling on toc click
|
||||
$toc.find(tocLinkSelector).click(function() {
|
||||
setTimeout(function() {
|
||||
refreshToc();
|
||||
}, 0);
|
||||
});
|
||||
|
||||
$(window).scroll(debounce(refreshToc, 200));
|
||||
$(window).resize(debounce(recacheHeights, 200));
|
||||
};
|
||||
|
||||
makeToc();
|
||||
|
||||
window.recacheHeights = recacheHeights;
|
||||
window.refreshToc = refreshToc;
|
||||
}
|
||||
|
||||
window.loadToc = loadToc;
|
||||
})();
|
||||
169
restful-notes-slate/slate/source/javascripts/lib/_energize.js
Normal file
169
restful-notes-slate/slate/source/javascripts/lib/_energize.js
Normal file
@@ -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?
|
||||
|
||||
})();
|
||||
7
restful-notes-slate/slate/source/javascripts/lib/_imagesloaded.min.js
vendored
Normal file
7
restful-notes-slate/slate/source/javascripts/lib/_imagesloaded.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -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 <span class='highlight'> (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 <em class='important'>
|
||||
* $('#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);
|
||||
});
|
||||
};
|
||||
|
||||
10881
restful-notes-slate/slate/source/javascripts/lib/_jquery.js
Normal file
10881
restful-notes-slate/slate/source/javascripts/lib/_jquery.js
Normal file
File diff suppressed because it is too large
Load Diff
3475
restful-notes-slate/slate/source/javascripts/lib/_lunr.js
Normal file
3475
restful-notes-slate/slate/source/javascripts/lib/_lunr.js
Normal file
File diff suppressed because it is too large
Load Diff
137
restful-notes-slate/slate/source/layouts/layout.erb
Normal file
137
restful-notes-slate/slate/source/layouts/layout.erb
Normal file
@@ -0,0 +1,137 @@
|
||||
<%#
|
||||
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.
|
||||
%>
|
||||
<% language_tabs = current_page.data.language_tabs || [] %>
|
||||
<% page_content = yield %>
|
||||
<%
|
||||
if current_page.data.includes
|
||||
current_page.data.includes.each do |include|
|
||||
page_content += partial("includes/#{include}")
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<% if current_page.data.key?('meta') %>
|
||||
<% current_page.data.meta.each do |meta| %>
|
||||
<meta
|
||||
<% meta.each do |key, value| %>
|
||||
<%= "#{key}=\"#{value}\"" %>
|
||||
<% end %>
|
||||
>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<title><%= current_page.data.title || "API Documentation" %></title>
|
||||
|
||||
<style media="screen">
|
||||
<%= Rouge::Themes::MonokaiSublimeSlate.render(:scope => '.highlight') %>
|
||||
</style>
|
||||
<style media="print">
|
||||
* {
|
||||
transition:none!important;
|
||||
}
|
||||
<%= Rouge::Themes::Base16::Solarized.render(:scope => '.highlight') %>
|
||||
</style>
|
||||
<%= stylesheet_link_tag :screen, media: :screen %>
|
||||
<%= stylesheet_link_tag :print, media: :print %>
|
||||
<% if current_page.data.search %>
|
||||
<%= javascript_include_tag "all" %>
|
||||
<% else %>
|
||||
<%= javascript_include_tag "all_nosearch" %>
|
||||
<% end %>
|
||||
|
||||
<% if current_page.data.code_clipboard %>
|
||||
<script>
|
||||
$(function() { setupCodeCopy(); });
|
||||
</script>
|
||||
<% end %>
|
||||
</head>
|
||||
|
||||
<body class="<%= page_classes %>" data-languages="<%=h language_tabs.map{ |lang| lang.is_a?(Hash) ? lang.keys.first : lang }.to_json %>">
|
||||
<a href="#" id="nav-button">
|
||||
<span>
|
||||
NAV
|
||||
<%= image_tag('navbar.png') %>
|
||||
</span>
|
||||
</a>
|
||||
<div class="toc-wrapper">
|
||||
<%= image_tag "logo.png", class: 'logo' %>
|
||||
<% if language_tabs.any? %>
|
||||
<div class="lang-selector">
|
||||
<% language_tabs.each do |lang| %>
|
||||
<% if lang.is_a? Hash %>
|
||||
<a href="#" data-language-name="<%= lang.keys.first %>"><%= lang.values.first %></a>
|
||||
<% else %>
|
||||
<a href="#" data-language-name="<%= lang %>"><%= lang %></a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
<% if current_page.data.search %>
|
||||
<div class="search">
|
||||
<input type="text" class="search" id="input-search" placeholder="Search">
|
||||
</div>
|
||||
<ul class="search-results"></ul>
|
||||
<% end %>
|
||||
<ul id="toc" class="toc-list-h1">
|
||||
<% toc_data(page_content).each do |h1| %>
|
||||
<li>
|
||||
<a href="#<%= h1[:id] %>" class="toc-h1 toc-link" data-title="<%= h1[:title] %>"><%= h1[:content] %></a>
|
||||
<% if h1[:children].length > 0 %>
|
||||
<ul class="toc-list-h2">
|
||||
<% h1[:children].each do |h2| %>
|
||||
<li>
|
||||
<a href="#<%= h2[:id] %>" class="toc-h2 toc-link" data-title="<%= h2[:title] %>"><%= h2[:content] %></a>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% if current_page.data.toc_footers %>
|
||||
<ul class="toc-footer">
|
||||
<% current_page.data.toc_footers.each do |footer| %>
|
||||
<li><%= footer %></li>
|
||||
<% end %>
|
||||
</ul>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="page-wrapper">
|
||||
<div class="dark-box"></div>
|
||||
<div class="content">
|
||||
<%= page_content %>
|
||||
</div>
|
||||
<div class="dark-box">
|
||||
<% if language_tabs.any? %>
|
||||
<div class="lang-selector">
|
||||
<% language_tabs.each do |lang| %>
|
||||
<% if lang.is_a? Hash %>
|
||||
<a href="#" data-language-name="<%= lang.keys.first %>"><%= lang.values.first %></a>
|
||||
<% else %>
|
||||
<a href="#" data-language-name="<%= lang %>"><%= lang %></a>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
38
restful-notes-slate/slate/source/stylesheets/_icon-font.scss
Normal file
38
restful-notes-slate/slate/source/stylesheets/_icon-font.scss
Normal file
@@ -0,0 +1,38 @@
|
||||
@font-face {
|
||||
font-family: 'slate';
|
||||
src:font-url('slate.eot?-syv14m');
|
||||
src:font-url('slate.eot?#iefix-syv14m') format('embedded-opentype'),
|
||||
font-url('slate.woff2?-syv14m') format('woff2'),
|
||||
font-url('slate.woff?-syv14m') format('woff'),
|
||||
font-url('slate.ttf?-syv14m') format('truetype'),
|
||||
font-url('slate.svg?-syv14m#slate') format('svg');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
%icon {
|
||||
font-family: 'slate';
|
||||
speak: none;
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
font-variant: normal;
|
||||
text-transform: none;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
%icon-exclamation-sign {
|
||||
@extend %icon;
|
||||
content: "\e600";
|
||||
}
|
||||
%icon-info-sign {
|
||||
@extend %icon;
|
||||
content: "\e602";
|
||||
}
|
||||
%icon-ok-sign {
|
||||
@extend %icon;
|
||||
content: "\e606";
|
||||
}
|
||||
%icon-search {
|
||||
@extend %icon;
|
||||
content: "\e607";
|
||||
}
|
||||
427
restful-notes-slate/slate/source/stylesheets/_normalize.scss
Normal file
427
restful-notes-slate/slate/source/stylesheets/_normalize.scss
Normal file
@@ -0,0 +1,427 @@
|
||||
/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
|
||||
|
||||
/**
|
||||
* 1. Set default font family to sans-serif.
|
||||
* 2. Prevent iOS text size adjust after orientation change, without disabling
|
||||
* user zoom.
|
||||
*/
|
||||
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default margin.
|
||||
*/
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Correct `block` display not defined for any HTML5 element in IE 8/9.
|
||||
* Correct `block` display not defined for `details` or `summary` in IE 10/11
|
||||
* and Firefox.
|
||||
* Correct `block` display not defined for `main` in IE 11.
|
||||
*/
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `inline-block` display not defined in IE 8/9.
|
||||
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
|
||||
*/
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent modern browsers from displaying `audio` without controls.
|
||||
* Remove excess height in iOS 5 devices.
|
||||
*/
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `[hidden]` styling not present in IE 8/9/10.
|
||||
* Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
|
||||
*/
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove the gray background color from active links in IE 10.
|
||||
*/
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Improve readability when focused and also mouse hovered in all browsers.
|
||||
*/
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in Safari and Chrome.
|
||||
*/
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address variable `h1` font-size and margin within `section` and `article`
|
||||
* contexts in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address styling not present in IE 8/9.
|
||||
*/
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent and variable font size in all browsers.
|
||||
*/
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
||||
*/
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove border when inside `a` element in IE 8/9/10.
|
||||
*/
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct overflow not hidden in IE 9/10/11.
|
||||
*/
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Address margin not present in IE 8/9 and Safari.
|
||||
*/
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address differences between Firefox and other browsers.
|
||||
*/
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Contain overflow in all browsers.
|
||||
*/
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address odd `em`-unit font size rendering in all browsers.
|
||||
*/
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
/* Forms
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Known limitation: by default, Chrome and Safari on OS X allow very limited
|
||||
* styling of `select`, unless a `border` property is set.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 1. Correct color not being inherited.
|
||||
* Known issue: affects color of disabled elements.
|
||||
* 2. Correct font properties not being inherited.
|
||||
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
|
||||
*/
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Address `overflow` set to `hidden` in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address inconsistent `text-transform` inheritance for `button` and `select`.
|
||||
* All other form control elements do not inherit `text-transform` values.
|
||||
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
|
||||
* Correct `select` style inheritance in Firefox.
|
||||
*/
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
|
||||
* and `video` controls.
|
||||
* 2. Correct inability to style clickable `input` types in iOS.
|
||||
* 3. Improve usability and consistency of cursor style between image-type
|
||||
* `input` and others.
|
||||
*/
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Re-set default cursor for disabled elements.
|
||||
*/
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and border in Firefox 4+.
|
||||
*/
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
|
||||
* the UA stylesheet.
|
||||
*/
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
/**
|
||||
* It's recommended that you don't attempt to style these elements.
|
||||
* Firefox's implementation doesn't respect box-sizing, padding, or width.
|
||||
*
|
||||
* 1. Address box sizing set to `content-box` in IE 8/9/10.
|
||||
* 2. Remove excess padding in IE 8/9/10.
|
||||
*/
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
|
||||
* `font-size` values of the `input`, it causes the cursor style of the
|
||||
* decrement button to change from `default` to `text`.
|
||||
*/
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
|
||||
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome
|
||||
* (include `-moz` to future-proof).
|
||||
*/
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
|
||||
* Safari (but not Chrome) clips the cancel button when the search input has
|
||||
* padding (and `textfield` appearance).
|
||||
*/
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define consistent border, margin, and padding.
|
||||
*/
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove default vertical scrollbar in IE 8/9/10/11.
|
||||
*/
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
|
||||
/**
|
||||
* Remove most spacing between table cells.
|
||||
*/
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
140
restful-notes-slate/slate/source/stylesheets/_rtl.scss
Normal file
140
restful-notes-slate/slate/source/stylesheets/_rtl.scss
Normal file
@@ -0,0 +1,140 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// RTL Styles Variables
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
$default: auto;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TABLE OF CONTENTS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#toc>ul>li>a>span {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.toc-wrapper {
|
||||
transition: right 0.3s ease-in-out !important;
|
||||
left: $default !important;
|
||||
#{right}: 0;
|
||||
}
|
||||
|
||||
.toc-h2 {
|
||||
padding-#{right}: $nav-padding + $nav-indent;
|
||||
}
|
||||
|
||||
#nav-button {
|
||||
#{right}: 0;
|
||||
transition: right 0.3s ease-in-out;
|
||||
&.open {
|
||||
right: $nav-width
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PAGE LAYOUT AND CODE SAMPLE BACKGROUND
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
.page-wrapper {
|
||||
margin-#{left}: $default !important;
|
||||
margin-#{right}: $nav-width;
|
||||
.dark-box {
|
||||
#{right}: $default;
|
||||
#{left}: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.lang-selector {
|
||||
width: $default !important;
|
||||
a {
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CODE SAMPLE STYLES
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
.content {
|
||||
&>h1,
|
||||
&>h2,
|
||||
&>h3,
|
||||
&>h4,
|
||||
&>h5,
|
||||
&>h6,
|
||||
&>p,
|
||||
&>table,
|
||||
&>ul,
|
||||
&>ol,
|
||||
&>aside,
|
||||
&>dl {
|
||||
margin-#{left}: $examples-width;
|
||||
margin-#{right}: $default !important;
|
||||
}
|
||||
&>ul,
|
||||
&>ol {
|
||||
padding-#{right}: $main-padding + 15px;
|
||||
}
|
||||
table {
|
||||
th,
|
||||
td {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
dd {
|
||||
margin-#{right}: 15px;
|
||||
}
|
||||
aside {
|
||||
aside:before {
|
||||
padding-#{left}: 0.5em;
|
||||
}
|
||||
.search-highlight {
|
||||
background: linear-gradient(to top right, #F7E633 0%, #F1D32F 100%);
|
||||
}
|
||||
}
|
||||
pre,
|
||||
blockquote {
|
||||
float: left !important;
|
||||
clear: left !important;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TYPOGRAPHY
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6,
|
||||
p,
|
||||
aside {
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.toc-wrapper {
|
||||
text-align: right;
|
||||
direction: rtl;
|
||||
font-weight: 100 !important;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// RESPONSIVE DESIGN
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@media (max-width: $tablet-width) {
|
||||
.toc-wrapper {
|
||||
#{right}: -$nav-width;
|
||||
&.open {
|
||||
#{right}: 0;
|
||||
}
|
||||
}
|
||||
.page-wrapper {
|
||||
margin-#{right}: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $phone-width) {
|
||||
%left-col {
|
||||
margin-#{left}: 0;
|
||||
}
|
||||
}
|
||||
103
restful-notes-slate/slate/source/stylesheets/_variables.scss
Normal file
103
restful-notes-slate/slate/source/stylesheets/_variables.scss
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CUSTOMIZE SLATE
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Use these settings to help adjust the appearance of Slate
|
||||
|
||||
|
||||
// BACKGROUND COLORS
|
||||
////////////////////
|
||||
$nav-bg: #2E3336 !default;
|
||||
$examples-bg: #2E3336 !default;
|
||||
$code-bg: #1E2224 !default;
|
||||
$code-annotation-bg: #191D1F !default;
|
||||
$nav-subitem-bg: #1E2224 !default;
|
||||
$nav-active-bg: #0F75D4 !default;
|
||||
$nav-active-parent-bg: #1E2224 !default; // parent links of the current section
|
||||
$lang-select-border: #000 !default;
|
||||
$lang-select-bg: #1E2224 !default;
|
||||
$lang-select-active-bg: $examples-bg !default; // feel free to change this to blue or something
|
||||
$lang-select-pressed-bg: #111 !default; // color of language tab bg when mouse is pressed
|
||||
$main-bg: #F3F7F9 !default;
|
||||
$aside-notice-bg: #8fbcd4 !default;
|
||||
$aside-warning-bg: #c97a7e !default;
|
||||
$aside-success-bg: #6ac174 !default;
|
||||
$search-notice-bg: #c97a7e !default;
|
||||
|
||||
|
||||
// TEXT COLORS
|
||||
////////////////////
|
||||
$main-text: #333 !default; // main content text color
|
||||
$nav-text: #fff !default;
|
||||
$nav-active-text: #fff !default;
|
||||
$nav-active-parent-text: #fff !default; // parent links of the current section
|
||||
$lang-select-text: #fff !default; // color of unselected language tab text
|
||||
$lang-select-active-text: #fff !default; // color of selected language tab text
|
||||
$lang-select-pressed-text: #fff !default; // color of language tab text when mouse is pressed
|
||||
|
||||
|
||||
// SIZES
|
||||
////////////////////
|
||||
$nav-width: 230px !default; // width of the navbar
|
||||
$examples-width: 50% !default; // portion of the screen taken up by code examples
|
||||
$logo-margin: 0px !default; // margin below logo
|
||||
$main-padding: 28px !default; // padding to left and right of content & examples
|
||||
$nav-padding: 15px !default; // padding to left and right of navbar
|
||||
$nav-v-padding: 10px !default; // padding used vertically around search boxes and results
|
||||
$nav-indent: 10px !default; // extra padding for ToC subitems
|
||||
$code-annotation-padding: 13px !default; // padding inside code annotations
|
||||
$h1-margin-bottom: 21px !default; // padding under the largest header tags
|
||||
$tablet-width: 930px !default; // min width before reverting to tablet size
|
||||
$phone-width: $tablet-width - $nav-width !default; // min width before reverting to mobile size
|
||||
|
||||
|
||||
// FONTS
|
||||
////////////////////
|
||||
%default-font {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
%header-font {
|
||||
@extend %default-font;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
%code-font {
|
||||
font-family: Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
|
||||
// OTHER
|
||||
////////////////////
|
||||
$nav-footer-border-color: #666 !default;
|
||||
$search-box-border-color: #666 !default;
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// INTERNAL
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// These settings are probably best left alone.
|
||||
|
||||
%break-words {
|
||||
word-break: break-all;
|
||||
hyphens: auto;
|
||||
}
|
||||
153
restful-notes-slate/slate/source/stylesheets/print.css.scss
Normal file
153
restful-notes-slate/slate/source/stylesheets/print.css.scss
Normal file
@@ -0,0 +1,153 @@
|
||||
@charset "utf-8";
|
||||
@import 'normalize';
|
||||
@import 'variables';
|
||||
@import 'icon-font';
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
$print-color: #999;
|
||||
$print-color-light: #ccc;
|
||||
$print-font-size: 12px;
|
||||
|
||||
body {
|
||||
@extend %default-font;
|
||||
}
|
||||
|
||||
.tocify, .toc-footer, .lang-selector, .search, #nav-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tocify-wrapper>img {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.content {
|
||||
font-size: 12px;
|
||||
|
||||
pre, code {
|
||||
@extend %code-font;
|
||||
@extend %break-words;
|
||||
border: 1px solid $print-color;
|
||||
border-radius: 5px;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
pre {
|
||||
code {
|
||||
border: 0;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 1.3em;
|
||||
}
|
||||
|
||||
code {
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
table {
|
||||
border: 1px solid $print-color;
|
||||
tr {
|
||||
border-bottom: 1px solid $print-color;
|
||||
}
|
||||
td,th {
|
||||
padding: 0.7em;
|
||||
}
|
||||
}
|
||||
|
||||
p {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
a {
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@extend %header-font;
|
||||
font-size: 2.5em;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
margin-top: 1em;
|
||||
margin-bottom: $h1-margin-bottom;
|
||||
border: 2px solid $print-color-light;
|
||||
border-width: 2px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@extend %header-font;
|
||||
font-size: 1.8em;
|
||||
margin-top: 2em;
|
||||
border-top: 2px solid $print-color-light;
|
||||
padding-top: 0.8em;
|
||||
}
|
||||
|
||||
h1+h2, h1+div+h2 {
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h3, h4 {
|
||||
@extend %header-font;
|
||||
font-size: 0.8em;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 0.8em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
h5, h6 {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
aside {
|
||||
padding: 1em;
|
||||
border: 1px solid $print-color-light;
|
||||
border-radius: 5px;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
aside:before {
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5em;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
aside.notice:before {
|
||||
@extend %icon-info-sign;
|
||||
}
|
||||
|
||||
aside.warning:before {
|
||||
@extend %icon-exclamation-sign;
|
||||
}
|
||||
|
||||
aside.success:before {
|
||||
@extend %icon-ok-sign;
|
||||
}
|
||||
}
|
||||
|
||||
.copy-clipboard {
|
||||
@media print {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
633
restful-notes-slate/slate/source/stylesheets/screen.css.scss
Normal file
633
restful-notes-slate/slate/source/stylesheets/screen.css.scss
Normal file
@@ -0,0 +1,633 @@
|
||||
@charset "utf-8";
|
||||
@import 'normalize';
|
||||
@import 'variables';
|
||||
@import 'icon-font';
|
||||
// @import 'rtl'; // uncomment to switch to RTL format
|
||||
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// GENERAL STUFF
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
html, body {
|
||||
color: $main-text;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
@extend %default-font;
|
||||
background-color: $main-bg;
|
||||
height: 100%;
|
||||
-webkit-text-size-adjust: none; /* Never autoresize text */
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// TABLE OF CONTENTS
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#toc > ul > li > a > span {
|
||||
float: right;
|
||||
background-color: #2484FF;
|
||||
border-radius: 40px;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.toc-wrapper {
|
||||
transition: left 0.3s ease-in-out;
|
||||
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
position: fixed;
|
||||
z-index: 30;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
width: $nav-width;
|
||||
background-color: $nav-bg;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
|
||||
// language selector for mobile devices
|
||||
.lang-selector {
|
||||
display: none;
|
||||
a {
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
|
||||
// This is the logo at the top of the ToC
|
||||
.logo {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
margin-bottom: $logo-margin;
|
||||
}
|
||||
|
||||
&>.search {
|
||||
position: relative;
|
||||
|
||||
input {
|
||||
background: $nav-bg;
|
||||
border-width: 0 0 1px 0;
|
||||
border-color: $search-box-border-color;
|
||||
padding: 6px 0 6px 20px;
|
||||
box-sizing: border-box;
|
||||
margin: $nav-v-padding $nav-padding;
|
||||
width: $nav-width - ($nav-padding*2);
|
||||
outline: none;
|
||||
color: $nav-text;
|
||||
border-radius: 0; /* ios has a default border radius */
|
||||
}
|
||||
|
||||
&:before {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
left: $nav-padding;
|
||||
color: $nav-text;
|
||||
@extend %icon-search;
|
||||
}
|
||||
}
|
||||
|
||||
.search-results {
|
||||
margin-top: 0;
|
||||
box-sizing: border-box;
|
||||
height: 0;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
transition-property: height, margin;
|
||||
transition-duration: 180ms;
|
||||
transition-timing-function: ease-in-out;
|
||||
background: $nav-subitem-bg;
|
||||
&.visible {
|
||||
height: 30%;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin: 1em $nav-padding;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
a {
|
||||
color: $nav-text;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The Table of Contents is composed of multiple nested
|
||||
// unordered lists. These styles remove the default
|
||||
// styling of an unordered list because it is ugly.
|
||||
ul, li {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
li {
|
||||
color: $nav-text;
|
||||
transition-property: background;
|
||||
transition-timing-function: linear;
|
||||
transition-duration: 200ms;
|
||||
}
|
||||
|
||||
// This is the currently selected ToC entry
|
||||
.toc-link.active {
|
||||
background-color: $nav-active-bg;
|
||||
color: $nav-active-text;
|
||||
}
|
||||
|
||||
// this is parent links of the currently selected ToC entry
|
||||
.toc-link.active-parent {
|
||||
background-color: $nav-active-parent-bg;
|
||||
color: $nav-active-parent-text;
|
||||
}
|
||||
|
||||
.toc-list-h2 {
|
||||
display: none;
|
||||
background-color: $nav-subitem-bg;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.toc-h2 {
|
||||
padding-left: $nav-padding + $nav-indent;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.toc-footer {
|
||||
padding: 1em 0;
|
||||
margin-top: 1em;
|
||||
border-top: 1px dashed $nav-footer-border-color;
|
||||
|
||||
li,a {
|
||||
color: $nav-text;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 0.8em;
|
||||
line-height: 1.7;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toc-link, .toc-footer li {
|
||||
padding: 0 $nav-padding 0 $nav-padding;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
text-decoration: none;
|
||||
color: $nav-text;
|
||||
transition-property: background;
|
||||
transition-timing-function: linear;
|
||||
transition-duration: 130ms;
|
||||
}
|
||||
|
||||
// button to show navigation on mobile devices
|
||||
#nav-button {
|
||||
span {
|
||||
display: block;
|
||||
$side-pad: $main-padding / 2 - 8px;
|
||||
padding: $side-pad $side-pad $side-pad;
|
||||
background-color: rgba($main-bg, 0.7);
|
||||
transform-origin: 0 0;
|
||||
transform: rotate(-90deg) translate(-100%, 0);
|
||||
border-radius: 0 0 0 5px;
|
||||
}
|
||||
padding: 0 1.5em 5em 0; // increase touch size area
|
||||
display: none;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
color: #000;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
opacity: 0.7;
|
||||
line-height: 16px;
|
||||
img {
|
||||
height: 16px;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
transition: left 0.3s ease-in-out;
|
||||
|
||||
&:hover { opacity: 1; }
|
||||
&.open {left: $nav-width}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// PAGE LAYOUT AND CODE SAMPLE BACKGROUND
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
.page-wrapper {
|
||||
margin-left: $nav-width;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
background-color: $main-bg;
|
||||
min-height: 100%;
|
||||
|
||||
padding-bottom: 1px; // prevent margin overflow
|
||||
|
||||
// The dark box is what gives the code samples their dark background.
|
||||
// It sits essentially under the actual content block, which has a
|
||||
// transparent background.
|
||||
// I know, it's hackish, but it's the simplist way to make the left
|
||||
// half of the content always this background color.
|
||||
.dark-box {
|
||||
width: $examples-width;
|
||||
background-color: $examples-bg;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.lang-selector {
|
||||
position: fixed;
|
||||
z-index: 50;
|
||||
border-bottom: 5px solid $lang-select-active-bg;
|
||||
}
|
||||
}
|
||||
|
||||
.lang-selector {
|
||||
display: flex;
|
||||
background-color: $lang-select-bg;
|
||||
width: 100%;
|
||||
font-weight: bold;
|
||||
overflow-x: auto;
|
||||
a {
|
||||
display: inline;
|
||||
color: $lang-select-text;
|
||||
text-decoration: none;
|
||||
padding: 0 10px;
|
||||
line-height: 30px;
|
||||
outline: 0;
|
||||
|
||||
&:active, &:focus {
|
||||
background-color: $lang-select-pressed-bg;
|
||||
color: $lang-select-pressed-text;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: $lang-select-active-bg;
|
||||
color: $lang-select-active-text;
|
||||
}
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
clear: both;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CONTENT STYLES
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This is all the stuff with the light background in the left half of the page
|
||||
|
||||
.content {
|
||||
// fixes webkit rendering bug for some: see #538
|
||||
-webkit-transform: translateZ(0);
|
||||
// to place content above the dark box
|
||||
position: relative;
|
||||
z-index: 30;
|
||||
|
||||
&:after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
&>h1, &>h2, &>h3, &>h4, &>h5, &>h6, &>p, &>table, &>ul, &>ol, &>aside, &>dl {
|
||||
margin-right: $examples-width;
|
||||
padding: 0 $main-padding;
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
|
||||
@extend %left-col;
|
||||
}
|
||||
|
||||
&>ul, &>ol {
|
||||
padding-left: $main-padding + 15px;
|
||||
}
|
||||
|
||||
// the div is the tocify hidden div for placeholding stuff
|
||||
&>h1, &>h2, &>div {
|
||||
clear:both;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@extend %header-font;
|
||||
font-size: 25px;
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
margin-bottom: $h1-margin-bottom;
|
||||
margin-top: 2em;
|
||||
border-top: 1px solid #ccc;
|
||||
border-bottom: 1px solid #ccc;
|
||||
background-color: #fdfdfd;
|
||||
}
|
||||
|
||||
h1:first-child, div:first-child + h1 {
|
||||
border-top-width: 0;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@extend %header-font;
|
||||
font-size: 19px;
|
||||
margin-top: 4em;
|
||||
margin-bottom: 0;
|
||||
border-top: 1px solid #ccc;
|
||||
padding-top: 1.2em;
|
||||
padding-bottom: 1.2em;
|
||||
background-image: linear-gradient(to bottom, rgba(#fff, 0.2), rgba(#fff, 0));
|
||||
}
|
||||
|
||||
// h2s right after h1s should bump right up
|
||||
// against the h1s.
|
||||
h1 + h2, h1 + div + h2 {
|
||||
margin-top: $h1-margin-bottom * -1;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
h3, h4, h5, h6 {
|
||||
@extend %header-font;
|
||||
font-size: 15px;
|
||||
margin-top: 2.5em;
|
||||
margin-bottom: 0.8em;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
hr {
|
||||
margin: 2em 0;
|
||||
border-top: 2px solid $examples-bg;
|
||||
border-bottom: 2px solid $main-bg;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-bottom: 1em;
|
||||
overflow: auto;
|
||||
th,td {
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
line-height: 1.6;
|
||||
code {
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
th {
|
||||
padding: 5px 10px;
|
||||
border-bottom: 1px solid #ccc;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
tr:last-child {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
|
||||
tr:nth-child(odd)>td {
|
||||
background-color: lighten($main-bg,4.2%);
|
||||
}
|
||||
|
||||
tr:nth-child(even)>td {
|
||||
background-color: lighten($main-bg,2.4%);
|
||||
}
|
||||
}
|
||||
|
||||
dt {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dd {
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
p, li, dt, dd {
|
||||
line-height: 1.6;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: rgba(0,0,0,0.05);
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
@extend %break-words;
|
||||
@extend %code-font;
|
||||
}
|
||||
|
||||
pre>code {
|
||||
background-color: transparent;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
aside {
|
||||
padding-top: 1em;
|
||||
padding-bottom: 1em;
|
||||
margin-top: 1.5em;
|
||||
margin-bottom: 1.5em;
|
||||
background: $aside-notice-bg;
|
||||
line-height: 1.6;
|
||||
|
||||
&.warning {
|
||||
background-color: $aside-warning-bg;
|
||||
}
|
||||
|
||||
&.success {
|
||||
background-color: $aside-success-bg;
|
||||
}
|
||||
}
|
||||
|
||||
aside:before {
|
||||
vertical-align: middle;
|
||||
padding-right: 0.5em;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
aside.notice:before {
|
||||
@extend %icon-info-sign;
|
||||
}
|
||||
|
||||
aside.warning:before {
|
||||
@extend %icon-exclamation-sign;
|
||||
}
|
||||
|
||||
aside.success:before {
|
||||
@extend %icon-ok-sign;
|
||||
}
|
||||
|
||||
.search-highlight {
|
||||
padding: 2px;
|
||||
margin: -3px;
|
||||
border-radius: 4px;
|
||||
border: 1px solid #F7E633;
|
||||
background: linear-gradient(to top left, #F7E633 0%, #F1D32F 100%);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// CODE SAMPLE STYLES
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// This is all the stuff that appears in the right half of the page
|
||||
|
||||
.content {
|
||||
&>div.highlight {
|
||||
clear:none;
|
||||
}
|
||||
|
||||
pre, blockquote {
|
||||
background-color: $code-bg;
|
||||
color: #fff;
|
||||
|
||||
margin: 0;
|
||||
width: $examples-width;
|
||||
|
||||
float:right;
|
||||
clear:right;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
@extend %right-col;
|
||||
|
||||
&>p { margin: 0; }
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
text-decoration: none;
|
||||
border-bottom: dashed 1px #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
@extend %code-font;
|
||||
padding-top: 2em;
|
||||
padding-bottom: 2em;
|
||||
padding: 2em $main-padding;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
&>p {
|
||||
background-color: $code-annotation-bg;
|
||||
padding: $code-annotation-padding 2em;
|
||||
color: #eee;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// RESPONSIVE DESIGN
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// These are the styles for phones and tablets
|
||||
// There are also a couple styles disperesed
|
||||
|
||||
@media (max-width: $tablet-width) {
|
||||
.toc-wrapper {
|
||||
left: -$nav-width;
|
||||
|
||||
&.open {
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.page-wrapper {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#nav-button {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.toc-link {
|
||||
padding-top: 0.3em;
|
||||
padding-bottom: 0.3em;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: $phone-width) {
|
||||
.dark-box {
|
||||
display: none;
|
||||
}
|
||||
|
||||
%left-col {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.toc-wrapper .lang-selector {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.page-wrapper .lang-selector {
|
||||
display: none;
|
||||
}
|
||||
|
||||
%right-col {
|
||||
width: auto;
|
||||
float: none;
|
||||
}
|
||||
|
||||
%right-col + %left-col {
|
||||
margin-top: $main-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.highlight .c, .highlight .cm, .highlight .c1, .highlight .cs {
|
||||
color: #909090;
|
||||
}
|
||||
|
||||
.highlight, .highlight .w {
|
||||
background-color: $code-bg;
|
||||
}
|
||||
|
||||
.copy-clipboard {
|
||||
float: right;
|
||||
fill: #9DAAB6;
|
||||
cursor: pointer;
|
||||
opacity: 0.4;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
}
|
||||
|
||||
.copy-clipboard:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
228
restful-notes-slate/src/main/asciidoc/api-guide.adoc
Normal file
228
restful-notes-slate/src/main/asciidoc/api-guide.adoc
Normal file
@@ -0,0 +1,228 @@
|
||||
= RESTful Notes API Guide
|
||||
Andy Wilkinson;
|
||||
:doctype: book
|
||||
:icons: font
|
||||
:source-highlighter: highlightjs
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:sectlinks:
|
||||
:operation-curl-request-title: Example request
|
||||
:operation-http-response-title: Example response
|
||||
|
||||
[[overview]]
|
||||
= Overview
|
||||
|
||||
[[overview_http_verbs]]
|
||||
== 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
|
||||
|===
|
||||
|
||||
[[overview_http_status_codes]]
|
||||
== 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
|
||||
|===
|
||||
|
||||
[[overview_errors]]
|
||||
== Errors
|
||||
|
||||
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:
|
||||
|
||||
include::{snippets}/error-example/response-fields.adoc[]
|
||||
|
||||
For example, a request that attempts to apply a non-existent tag to a note will produce a
|
||||
`400 Bad Request` response:
|
||||
|
||||
include::{snippets}/error-example/http-response.adoc[]
|
||||
|
||||
[[overview_hypermedia]]
|
||||
== Hypermedia
|
||||
|
||||
RESTful Notes uses hypermedia and resources include links to other resources in their
|
||||
responses. Responses are in https://github.com/mikekelly/hal_specification[Hypertext
|
||||
Application Language (HAL)] 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 from resource to resource.
|
||||
|
||||
[[resources]]
|
||||
= Resources
|
||||
|
||||
|
||||
|
||||
[[resources_index]]
|
||||
== Index
|
||||
|
||||
The index provides the entry point into the service.
|
||||
|
||||
|
||||
|
||||
[[resources_index_access]]
|
||||
=== Accessing the index
|
||||
|
||||
A `GET` request is used to access the index
|
||||
|
||||
operation::index-example[snippets='response-fields,http-response,links']
|
||||
|
||||
|
||||
|
||||
[[resources_notes]]
|
||||
== Notes
|
||||
|
||||
The Notes resources is used to create and list notes
|
||||
|
||||
|
||||
|
||||
[[resources_notes_list]]
|
||||
=== Listing notes
|
||||
|
||||
A `GET` request will list all of the service's notes.
|
||||
|
||||
operation::notes-list-example[snippets='response-fields,curl-request,http-response,links']
|
||||
|
||||
|
||||
|
||||
[[resources_notes_create]]
|
||||
=== Creating a note
|
||||
|
||||
A `POST` request is used to create a note.
|
||||
|
||||
operation::notes-create-example[snippets='request-fields,curl-request,http-response']
|
||||
|
||||
|
||||
|
||||
[[resources_tags]]
|
||||
== Tags
|
||||
|
||||
The Tags resource is used to create and list tags.
|
||||
|
||||
|
||||
|
||||
[[resources_tags_list]]
|
||||
=== Listing tags
|
||||
|
||||
A `GET` request will list all of the service's tags.
|
||||
|
||||
operation::tags-list-example[snippets='response-fields,curl-request,http-response,links']
|
||||
|
||||
|
||||
|
||||
[[resources_tags_create]]
|
||||
=== Creating a tag
|
||||
|
||||
A `POST` request is used to create a note
|
||||
|
||||
operation::tags-create-example[snippets='request-fields,curl-request,http-response']
|
||||
|
||||
|
||||
|
||||
[[resources_note]]
|
||||
== Note
|
||||
|
||||
The Note resource is used to retrieve, update, and delete individual notes
|
||||
|
||||
|
||||
|
||||
[[resources_note_links]]
|
||||
=== Links
|
||||
|
||||
include::{snippets}/note-get-example/links.adoc[]
|
||||
|
||||
|
||||
|
||||
[[resources_note_retrieve]]
|
||||
=== Retrieve a note
|
||||
|
||||
A `GET` request will retrieve the details of a note
|
||||
|
||||
operation::note-get-example[snippets='response-fields,curl-request,http-response']
|
||||
|
||||
|
||||
|
||||
[[resources_note_update]]
|
||||
=== Update a note
|
||||
|
||||
A `PATCH` request is used to update a note
|
||||
|
||||
==== Request structure
|
||||
|
||||
include::{snippets}/note-update-example/request-fields.adoc[]
|
||||
|
||||
To leave an attribute of a note unchanged, any of the above may be omitted from the request.
|
||||
|
||||
==== Example request
|
||||
|
||||
include::{snippets}/note-update-example/curl-request.adoc[]
|
||||
|
||||
==== Example response
|
||||
|
||||
include::{snippets}/note-update-example/http-response.adoc[]
|
||||
|
||||
|
||||
|
||||
[[resources_tag]]
|
||||
== Tag
|
||||
|
||||
The Tag resource is used to retrieve, update, and delete individual tags
|
||||
|
||||
|
||||
|
||||
[[resources_tag_links]]
|
||||
=== Links
|
||||
|
||||
include::{snippets}/tag-get-example/links.adoc[]
|
||||
|
||||
|
||||
|
||||
[[resources_tag_retrieve]]
|
||||
=== Retrieve a tag
|
||||
|
||||
A `GET` request will retrieve the details of a tag
|
||||
|
||||
operation::tag-get-example[snippets='response-fields,curl-request,http-response']
|
||||
|
||||
|
||||
|
||||
[[resources_tag_update]]
|
||||
=== Update a tag
|
||||
|
||||
A `PATCH` request is used to update a tag
|
||||
|
||||
operation::tag-update-example[snippets='request-fields,curl-request,http-response']
|
||||
175
restful-notes-slate/src/main/asciidoc/getting-started-guide.adoc
Normal file
175
restful-notes-slate/src/main/asciidoc/getting-started-guide.adoc
Normal file
@@ -0,0 +1,175 @@
|
||||
= RESTful Notes Getting Started Guide
|
||||
Andy Wilkinson;
|
||||
:doctype: book
|
||||
:icons: font
|
||||
:source-highlighter: highlightjs
|
||||
:toc: left
|
||||
:toclevels: 4
|
||||
:sectlinks:
|
||||
|
||||
[[introduction]]
|
||||
= Introduction
|
||||
|
||||
RESTful Notes is a RESTful web service for creating and storing notes. It uses hypermedia
|
||||
to describe the relationships between resources and to allow navigation between them.
|
||||
|
||||
|
||||
|
||||
[[getting_started_running_the_service]]
|
||||
== Running the service
|
||||
RESTful Notes is written using https://projects.spring.io/spring-boot[Spring Boot] which
|
||||
makes it easy to get it up and running so that you can start exploring the REST API.
|
||||
|
||||
The first step is to clone the Git repository:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ git clone https://github.com/spring-projects/spring-restdocs-samples
|
||||
----
|
||||
|
||||
Once the clone is complete, you're ready to get the service up and running:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ cd restful-notes-spring-data-rest
|
||||
$ ./mvnw clean package
|
||||
$ java -jar target/*.jar
|
||||
----
|
||||
|
||||
You can check that the service is up and running by executing a simple request using
|
||||
cURL:
|
||||
|
||||
include::{snippets}/index/1/curl-request.adoc[]
|
||||
|
||||
This request should yield the following response in the
|
||||
https://github.com/mikekelly/hal_specification[Hypertext Application Language (HAL)]
|
||||
format:
|
||||
|
||||
include::{snippets}/index/1/http-response.adoc[]
|
||||
|
||||
Note the `_links` in the JSON response. They are key to navigating the API.
|
||||
|
||||
|
||||
|
||||
[[getting_started_creating_a_note]]
|
||||
== Creating a note
|
||||
Now that you've started the service and verified that it works, the next step is to use
|
||||
it to create a new note. As you saw above, the URI for working with notes is included as
|
||||
a link when you perform a `GET` request against the root of the service:
|
||||
|
||||
include::{snippets}/index/1/http-response.adoc[]
|
||||
|
||||
To create a note, you need to execute a `POST` request to this URI including a JSON
|
||||
payload containing the title and body of the note:
|
||||
|
||||
include::{snippets}/creating-a-note/1/curl-request.adoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created note:
|
||||
|
||||
include::{snippets}/creating-a-note/1/http-response.adoc[]
|
||||
|
||||
To work with the newly created note you use the URI in the `Location` header. For example,
|
||||
you can access the note's details by performing a `GET` request:
|
||||
|
||||
include::{snippets}/creating-a-note/2/curl-request.adoc[]
|
||||
|
||||
This request will produce a response with the note's details in its body:
|
||||
|
||||
include::{snippets}/creating-a-note/2/http-response.adoc[]
|
||||
|
||||
Note the `tags` link which we'll make use of later.
|
||||
|
||||
|
||||
|
||||
[[getting_started_creating_a_tag]]
|
||||
== Creating a tag
|
||||
To make a note easier to find, it can be associated with any number of tags. To be able
|
||||
to tag a note, you must first create the tag.
|
||||
|
||||
Referring back to the response for the service's index, the URI for working with tags is
|
||||
include as a link:
|
||||
|
||||
include::{snippets}/index/1/http-response.adoc[]
|
||||
|
||||
To create a tag you need to execute a `POST` request to this URI, including a JSON
|
||||
payload containing the name of the tag:
|
||||
|
||||
include::{snippets}/creating-a-note/3/curl-request.adoc[]
|
||||
|
||||
The response from this request should have a status code of `201 Created` and contain a
|
||||
`Location` header whose value is the URI of the newly created tag:
|
||||
|
||||
include::{snippets}/creating-a-note/3/http-response.adoc[]
|
||||
|
||||
To work with the newly created tag you use the URI in the `Location` header. For example
|
||||
you can access the tag's details by performing a `GET` request:
|
||||
|
||||
include::{snippets}/creating-a-note/4/curl-request.adoc[]
|
||||
|
||||
This request will produce a response with the tag's details in its body:
|
||||
|
||||
include::{snippets}/creating-a-note/4/http-response.adoc[]
|
||||
|
||||
|
||||
|
||||
[[getting_started_tagging_a_note]]
|
||||
== Tagging a note
|
||||
A tag isn't particularly useful until it's been associated with one or more notes. There
|
||||
are two ways to tag a note: when the note is first created or by updating an existing
|
||||
note. We'll look at both of these in turn.
|
||||
|
||||
|
||||
|
||||
[[getting_started_tagging_a_note_creating]]
|
||||
=== Creating a tagged note
|
||||
The process is largely the same as we saw before, but this time, in addition to providing
|
||||
a title and body for the note, we'll also provide the tag that we want to be associated
|
||||
with it.
|
||||
|
||||
Once again we execute a `POST` request. However, this time, in an array named tags, we
|
||||
include the URI of the tag we just created:
|
||||
|
||||
include::{snippets}/creating-a-note/5/curl-request.adoc[]
|
||||
|
||||
Once again, the response's `Location` header tells us the URI of the newly created note:
|
||||
|
||||
include::{snippets}/creating-a-note/5/http-response.adoc[]
|
||||
|
||||
As before, a `GET` request executed against this URI will retrieve the note's details:
|
||||
|
||||
include::{snippets}/creating-a-note/6/curl-request.adoc[]
|
||||
include::{snippets}/creating-a-note/6/http-response.adoc[]
|
||||
|
||||
To verify that the tag has been associated with the note, we can perform a `GET` request
|
||||
against the URI from the `tags` link:
|
||||
|
||||
include::{snippets}/creating-a-note/7/curl-request.adoc[]
|
||||
|
||||
The response embeds information about the tag that we've just associated with the note:
|
||||
|
||||
include::{snippets}/creating-a-note/7/http-response.adoc[]
|
||||
|
||||
|
||||
|
||||
[[getting_started_tagging_a_note_existing]]
|
||||
=== Tagging an existing note
|
||||
An existing note can be tagged by executing a `PATCH` request against the note's URI with
|
||||
a body that contains the array of tags to be associated with the note. We'll used the
|
||||
URI of the untagged note that we created earlier:
|
||||
|
||||
include::{snippets}/creating-a-note/8/curl-request.adoc[]
|
||||
|
||||
This request should produce a `204 No Content` response:
|
||||
|
||||
include::{snippets}/creating-a-note/8/http-response.adoc[]
|
||||
|
||||
When we first created this note, we noted the tags link included in its details:
|
||||
|
||||
include::{snippets}/creating-a-note/2/http-response.adoc[]
|
||||
|
||||
We can use that link now and execute a `GET` request to see that the note now has a
|
||||
single tag:
|
||||
|
||||
include::{snippets}/creating-a-note/9/curl-request.adoc[]
|
||||
include::{snippets}/creating-a-note/9/http-response.adoc[]
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
@Entity
|
||||
public class Note {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
|
||||
private String title;
|
||||
|
||||
private String body;
|
||||
|
||||
@ManyToMany
|
||||
private List<Tag> tags;
|
||||
|
||||
@JsonIgnore
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getBody() {
|
||||
return body;
|
||||
}
|
||||
|
||||
public void setBody(String body) {
|
||||
this.body = body;
|
||||
}
|
||||
|
||||
public List<Tag> getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(List<Tag> tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface NoteRepository extends CrudRepository<Note, Long> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class RestNotesSpringDataRest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RestNotesSpringDataRest.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
65
restful-notes-slate/src/main/java/com/example/notes/Tag.java
Normal file
65
restful-notes-slate/src/main/java/com/example/notes/Tag.java
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.GenerationType;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToMany;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
|
||||
@Entity
|
||||
public class Tag {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.AUTO)
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
|
||||
@ManyToMany(mappedBy = "tags")
|
||||
private List<Note> notes;
|
||||
|
||||
@JsonIgnore
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public List<Note> getNotes() {
|
||||
return notes;
|
||||
}
|
||||
|
||||
public void setNotes(List<Note> notes) {
|
||||
this.notes = notes;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import org.springframework.data.repository.CrudRepository;
|
||||
|
||||
public interface TagRepository extends CrudRepository<Tag, Long> {
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
spring.jackson.serialization.indent_output: true
|
||||
@@ -0,0 +1,347 @@
|
||||
/*
|
||||
* Copyright 2014-2022 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.
|
||||
*/
|
||||
|
||||
package com.example.notes;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.linkWithRel;
|
||||
import static org.springframework.restdocs.hypermedia.HypermediaDocumentation.links;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.document;
|
||||
import static org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.documentationConfiguration;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.get;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.patch;
|
||||
import static org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders.post;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.fieldWithPath;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.requestFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.responseFields;
|
||||
import static org.springframework.restdocs.payload.PayloadDocumentation.subsectionWithPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.hateoas.MediaTypes;
|
||||
import org.springframework.restdocs.RestDocumentationContextProvider;
|
||||
import org.springframework.restdocs.RestDocumentationExtension;
|
||||
import org.springframework.restdocs.payload.JsonFieldType;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import jakarta.servlet.RequestDispatcher;
|
||||
|
||||
@SpringBootTest
|
||||
@ExtendWith(RestDocumentationExtension.class)
|
||||
class ApiDocumentation {
|
||||
|
||||
@Autowired
|
||||
private NoteRepository noteRepository;
|
||||
|
||||
@Autowired
|
||||
private TagRepository tagRepository;
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Autowired
|
||||
private WebApplicationContext context;
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(RestDocumentationContextProvider restDocumentation) {
|
||||
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.context)
|
||||
.apply(documentationConfiguration(restDocumentation)).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorExample() throws Exception {
|
||||
this.mockMvc
|
||||
.perform(get("/error")
|
||||
.requestAttr(RequestDispatcher.ERROR_STATUS_CODE, 400)
|
||||
.requestAttr(RequestDispatcher.ERROR_REQUEST_URI,
|
||||
"/notes")
|
||||
.requestAttr(RequestDispatcher.ERROR_MESSAGE,
|
||||
"The tag 'http://localhost:8080/tags/123' does not exist"))
|
||||
.andDo(print()).andExpect(status().isBadRequest())
|
||||
.andExpect(jsonPath("error", is("Bad Request")))
|
||||
.andExpect(jsonPath("timestamp", is(notNullValue())))
|
||||
.andExpect(jsonPath("status", is(400)))
|
||||
.andExpect(jsonPath("path", is(notNullValue())))
|
||||
.andDo(document("error-example",
|
||||
responseFields(
|
||||
fieldWithPath("error").description("The HTTP error that occurred, e.g. `Bad Request`"),
|
||||
fieldWithPath("path").description("The path to which the request was made"),
|
||||
fieldWithPath("status").description("The HTTP status code, e.g. `400`"),
|
||||
fieldWithPath("timestamp").description("The time, in milliseconds, at which the error occurred"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void indexExample() throws Exception {
|
||||
this.mockMvc.perform(get("/"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("index-example",
|
||||
links(
|
||||
linkWithRel("notes").description("The <<resources_notes,Notes resource>>"),
|
||||
linkWithRel("tags").description("The <<resources_tags,Tags resource>>"),
|
||||
linkWithRel("profile").description("The ALPS profile for the service")),
|
||||
responseFields(
|
||||
subsectionWithPath("_links").description("<<resources_index_access_links,Links>> to other resources"))));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void notesListExample() throws Exception {
|
||||
this.noteRepository.deleteAll();
|
||||
|
||||
createNote("REST maturity model",
|
||||
"https://martinfowler.com/articles/richardsonMaturityModel.html");
|
||||
createNote("Hypertext Application Language (HAL)",
|
||||
"https://github.com/mikekelly/hal_specification");
|
||||
createNote("Application-Level Profile Semantics (ALPS)", "https://github.com/alps-io/spec");
|
||||
|
||||
this.mockMvc.perform(get("/notes"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("notes-list-example",
|
||||
links(
|
||||
linkWithRel("self").description("Canonical link for this resource"),
|
||||
linkWithRel("profile").description("The ALPS profile for this resource")),
|
||||
responseFields(
|
||||
subsectionWithPath("_embedded.notes").description("An array of <<resources_note, Note resources>>"),
|
||||
subsectionWithPath("_links").description("<<resources_tags_list_links, Links>> to other resources"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void notesCreateExample() throws Exception {
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
String tagLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
Map<String, Object> note = new HashMap<String, Object>();
|
||||
note.put("title", "REST maturity model");
|
||||
note.put("body", "https://martinfowler.com/articles/richardsonMaturityModel.html");
|
||||
note.put("tags", Arrays.asList(tagLocation));
|
||||
|
||||
this.mockMvc.perform(
|
||||
post("/notes").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(note))).andExpect(
|
||||
status().isCreated())
|
||||
.andDo(document("notes-create-example",
|
||||
requestFields(
|
||||
fieldWithPath("title").description("The title of the note"),
|
||||
fieldWithPath("body").description("The body of the note"),
|
||||
fieldWithPath("tags").description("An array of tag resource URIs"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void noteGetExample() throws Exception {
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
String tagLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
Map<String, Object> note = new HashMap<String, Object>();
|
||||
note.put("title", "REST maturity model");
|
||||
note.put("body", "https://martinfowler.com/articles/richardsonMaturityModel.html");
|
||||
note.put("tags", Arrays.asList(tagLocation));
|
||||
|
||||
String noteLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/notes").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(note)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
this.mockMvc.perform(get(noteLocation))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("title", is(note.get("title"))))
|
||||
.andExpect(jsonPath("body", is(note.get("body"))))
|
||||
.andExpect(jsonPath("_links.self.href", is(noteLocation)))
|
||||
.andExpect(jsonPath("_links.tags", is(notNullValue())))
|
||||
.andDo(print())
|
||||
.andDo(document("note-get-example",
|
||||
links(
|
||||
linkWithRel("self").description("Canonical link for this <<resources_note,note>>"),
|
||||
linkWithRel("note").description("This <<resources_note,note>>"),
|
||||
linkWithRel("tags").description("This note's tags")),
|
||||
responseFields(
|
||||
fieldWithPath("title").description("The title of the note"),
|
||||
fieldWithPath("body").description("The body of the note"),
|
||||
subsectionWithPath("_links").description("<<resources_note_links,Links>> to other resources"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagsListExample() throws Exception {
|
||||
this.noteRepository.deleteAll();
|
||||
this.tagRepository.deleteAll();
|
||||
|
||||
createTag("REST");
|
||||
createTag("Hypermedia");
|
||||
createTag("HTTP");
|
||||
|
||||
this.mockMvc.perform(get("/tags"))
|
||||
.andExpect(status().isOk())
|
||||
.andDo(document("tags-list-example",
|
||||
links(
|
||||
linkWithRel("self").description("Canonical link for this resource"),
|
||||
linkWithRel("profile").description("The ALPS profile for this resource")),
|
||||
responseFields(
|
||||
subsectionWithPath("_embedded.tags").description("An array of <<resources_tag,Tag resources>>"),
|
||||
subsectionWithPath("_links").description("<<resources_tags_list_links, Links>> to other resources"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagsCreateExample() throws Exception {
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
this.mockMvc.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated())
|
||||
.andDo(document("tags-create-example",
|
||||
requestFields(
|
||||
fieldWithPath("name").description("The name of the tag"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void noteUpdateExample() throws Exception {
|
||||
Map<String, Object> note = new HashMap<String, Object>();
|
||||
note.put("title", "REST maturity model");
|
||||
note.put("body", "https://martinfowler.com/articles/richardsonMaturityModel.html");
|
||||
|
||||
String noteLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/notes").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(note)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
this.mockMvc.perform(get(noteLocation)).andExpect(status().isOk())
|
||||
.andExpect(jsonPath("title", is(note.get("title"))))
|
||||
.andExpect(jsonPath("body", is(note.get("body"))))
|
||||
.andExpect(jsonPath("_links.self.href", is(noteLocation)))
|
||||
.andExpect(jsonPath("_links.tags", is(notNullValue())));
|
||||
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
String tagLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
Map<String, Object> noteUpdate = new HashMap<String, Object>();
|
||||
noteUpdate.put("tags", Arrays.asList(tagLocation));
|
||||
|
||||
this.mockMvc.perform(
|
||||
patch(noteLocation).contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(noteUpdate)))
|
||||
.andExpect(status().isNoContent())
|
||||
.andDo(document("note-update-example",
|
||||
requestFields(
|
||||
fieldWithPath("title").description("The title of the note").type(JsonFieldType.STRING).optional(),
|
||||
fieldWithPath("body").description("The body of the note").type(JsonFieldType.STRING).optional(),
|
||||
fieldWithPath("tags").description("An array of tag resource URIs").optional())));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagGetExample() throws Exception {
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
String tagLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
this.mockMvc.perform(get(tagLocation))
|
||||
.andExpect(status().isOk())
|
||||
.andExpect(jsonPath("name", is(tag.get("name"))))
|
||||
.andDo(document("tag-get-example",
|
||||
links(
|
||||
linkWithRel("self").description("Canonical link for this <<resources_tag,tag>>"),
|
||||
linkWithRel("tag").description("This <<resources_tag,tag>>"),
|
||||
linkWithRel("notes").description("The notes that have this tag")),
|
||||
responseFields(
|
||||
fieldWithPath("name").description("The name of the tag"),
|
||||
subsectionWithPath("_links").description("<<resources_tag_links,Links>> to other resources"))));
|
||||
}
|
||||
|
||||
@Test
|
||||
void tagUpdateExample() throws Exception {
|
||||
Map<String, String> tag = new HashMap<String, String>();
|
||||
tag.put("name", "REST");
|
||||
|
||||
String tagLocation = this.mockMvc
|
||||
.perform(
|
||||
post("/tags").contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tag)))
|
||||
.andExpect(status().isCreated()).andReturn().getResponse()
|
||||
.getHeader("Location");
|
||||
|
||||
Map<String, Object> tagUpdate = new HashMap<String, Object>();
|
||||
tagUpdate.put("name", "RESTful");
|
||||
|
||||
this.mockMvc.perform(
|
||||
patch(tagLocation).contentType(MediaTypes.HAL_JSON).content(
|
||||
this.objectMapper.writeValueAsString(tagUpdate)))
|
||||
.andExpect(status().isNoContent())
|
||||
.andDo(document("tag-update-example",
|
||||
requestFields(
|
||||
fieldWithPath("name").description("The name of the tag"))));
|
||||
}
|
||||
|
||||
private void createNote(String title, String body) {
|
||||
Note note = new Note();
|
||||
note.setTitle(title);
|
||||
note.setBody(body);
|
||||
|
||||
this.noteRepository.save(note);
|
||||
}
|
||||
|
||||
private void createTag(String name) {
|
||||
Tag tag = new Tag();
|
||||
tag.setName(name);
|
||||
this.tagRepository.save(tag);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user