docs+client/users: document user filtering

This commit is contained in:
rr- 2016-04-14 19:37:05 +02:00
parent f34e83b325
commit 286df9faf3
10 changed files with 526 additions and 403 deletions

398
API.md
View File

@ -77,260 +77,268 @@ data.
## Listing users ## Listing users
**Request** - **Request**
`GET /users/?page=<page>&pageSize=<page-size>&query=<query>` `GET /users/?page=<page>&pageSize=<page-size>&query=<query>`
**Output** - **Output**
```json5 ```json5
{ {
"query": "rr-", "query": "rr-",
"users": [ "users": [
<user>, <user>,
<user>, <user>,
<user>, <user>,
<user>, <user>,
<user> <user>
], ],
"page": 1, "page": 1,
"pageSize": 5, "pageSize": 5,
"total": 7 "total": 7
} }
``` ```
...where `<user>` is an [user resource](#user) and `query` contains standard ...where `<user>` is an [user resource](#user) and `query` contains standard
[search query](#search). [search query](#search).
**Errors** - **Errors**
- privileges are too low - privileges are too low
**Description** - **Description**
Searches for users. Searches for users.
Available search named tokens: **Anonymous tokens**
| name | ranged? | array? | Same as `name` token.
| ----------------- | ------- | ------ |
| (anonymous) | | ✓ |
| `name` | | ✓ |
| `creation-date` | ✓ | ✓ |
| `creation-time` | ✓ | ✓ |
| `last-login-date` | ✓ | ✓ |
| `last-login-time` | ✓ | ✓ |
| `login-date` | ✓ | ✓ |
| `login-time` | ✓ | ✓ |
Anonymous search tokens are equivalent to `name` token. **Named tokens**
Available search orders: | `<value>` | Description |
| ----------------- | ------------------------------------------------ |
| `name` | having given name (doesn't accept wildcards yet) |
| `creation-date` | registered at given date |
| `creation-time` | alias of `creation-date` |
| `last-login-date` | whose most recent login date matches given date |
| `last-login-time` | alias of `last-login-date` |
| `login-date` | alias of `last-login-date` |
| `login-time` | alias of `last-login-date` |
- `random` **Order tokens**
- `name`
- `creation-date`
- `creation-time`
- `last-login-date`
- `last-login-time`
- `login-date`
- `login-time`
| `<value>` | Description |
| ----------------- | -------------------------- |
| `random` | as random as it can get |
| `name` | A to Z |
| `creation-date` | newest to oldest |
| `creation-time` | alias of `creation-date` |
| `last-login-date` | recently active first |
| `last-login-time` | alias of `last-login-date` |
| `login-date` | alias of `last-login-date` |
| `login-time` | alias of `last-login-date` |
**Special tokens**
None.
## Creating user ## Creating user
**Request** - **Request**
`POST /users` `POST /users`
**Input** - **Input**
```json5 ```json5
{ {
"name": <user-name>, "name": <user-name>,
"password": <user-password>, "password": <user-password>,
"email": <email> "email": <email>
} }
``` ```
**Output** - **Output**
```json5 ```json5
{ {
"user": <user> "user": <user>
} }
``` ```
...where `<user>` is an [user resource](#user). ...where `<user>` is an [user resource](#user).
**Errors** - **Errors**
- such user already exists (names are case insensitive) - such user already exists (names are case insensitive)
- either user name, password or email are invalid - either user name, password or email are invalid
- privileges are too low - privileges are too low
**Description** - **Description**
Creates a new user using specified parameters. Names and passwords must match Creates a new user using specified parameters. Names and passwords must
`user_name_regex` and `password_regex` from server's configuration, match `user_name_regex` and `password_regex` from server's configuration,
respectively. Email address is optional. If the user happens to be the first respectively. Email address is optional. If the user happens to be the
user ever created, they're granted highest available rank, becoming an first user ever created, they're granted highest available rank, becoming
administrator. Subsequent users will be given the rank indicated by an administrator. Subsequent users will be given the rank indicated by
`default_rank` in the server's configuration. `default_rank` in the server's configuration.
## Updating user ## Updating user
**Request** - **Request**
`PUT /user/<name>` `PUT /user/<name>`
**Input** - **Input**
```json5 ```json5
{ {
"name": <user-name>, "name": <user-name>,
"password": <user-password>, "password": <user-password>,
"email": <email>, "email": <email>,
"rank": <rank>, "rank": <rank>,
"avatarStyle": <avatar-style> "avatarStyle": <avatar-style>
} }
``` ```
**Files** - **Files**
- `avatar` - the content of the new avatar. - `avatar` - the content of the new avatar.
**Output** - **Output**
```json5 ```json5
{ {
"user": <user> "user": <user>
} }
``` ```
...where `<user>` is an [user resource](#user). ...where `<user>` is an [user resource](#user).
**Errors** - **Errors**
- the user does not exist - the user does not exist
- the user with new name already exists (names are case insensitive) - the user with new name already exists (names are case insensitive)
- either user name, password, email or rank are invalid - either user name, password, email or rank are invalid
- the user is trying to update their or someone else's rank to higher than - the user is trying to update their or someone else's rank to higher than
their own their own
- privileges are too low - privileges are too low
- avatar is missing for manual avatar style - avatar is missing for manual avatar style
**Description** - **Description**
Updates an existing user using specified parameters. Names and passwords must Updates an existing user using specified parameters. Names and passwords
match `user_name_regex` and `password_regex` from server's configuration, must match `user_name_regex` and `password_regex` from server's
respectively. All fields are optional - update concerns only provided fields. configuration, respectively. All fields are optional - update concerns only
To update last login time, see [authentication](#authentication). Avatar style provided fields. To update last login time, see
can be either `gravatar` or `manual`. `manual` avatar style requires client to [authentication](#authentication). Avatar style can be either `gravatar` or
pass also `avatar` file - see [file uploads](#file-uploads) for details. `manual`. `manual` avatar style requires client to pass also `avatar`
file - see [file uploads](#file-uploads) for details.
## Getting user ## Getting user
**Request** - **Request**
`GET /user/<name>` `GET /user/<name>`
**Output** - **Output**
```json5 ```json5
{ {
"user": <user> "user": <user>
} }
``` ```
...where `<user>` is an [user resource](#user). ...where `<user>` is an [user resource](#user).
**Errors** - **Errors**
- the user does not exist - the user does not exist
- privileges are too low - privileges are too low
**Description** - **Description**
Retrieves information about an existing user. Retrieves information about an existing user.
## Removing user ## Removing user
**Request** - **Request**
`DELETE /user/<name>` `DELETE /user/<name>`
**Output** - **Output**
```json5 ```json5
{} {}
``` ```
**Errors** - **Errors**
- the user does not exist - the user does not exist
- privileges are too low - privileges are too low
**Description** - **Description**
Deletes existing user. Deletes existing user.
## Password reset - step 1: mail request ## Password reset - step 1: mail request
**Request** - **Request**
`GET /password-reset/<email-or-name>` `GET /password-reset/<email-or-name>`
**Output** - **Output**
``` ```
{} {}
``` ```
**Errors** - **Errors**
- the user does not exist - the user does not exist
- the user hasn't provided an email address - the user hasn't provided an email address
**Description** - **Description**
Sends a confirmation email to given user. The email contains link containing a Sends a confirmation email to given user. The email contains link
token. The token cannot be guessed, thus using such link proves that the person containing a token. The token cannot be guessed, thus using such link
who requested to reset the password also owns the mailbox, which is a strong proves that the person who requested to reset the password also owns the
indication they are the rightful owner of the account. mailbox, which is a strong indication they are the rightful owner of the
account.
## Password reset - step 2: confirmation ## Password reset - step 2: confirmation
**Request** - **Request**
`POST /password-reset/<email-or-name>` `POST /password-reset/<email-or-name>`
**Input** - **Input**
```json5 ```json5
{ {
"token": <token-from-email> "token": <token-from-email>
} }
``` ```
**Output** - **Output**
```json5 ```json5
{ {
"password": <new-password> "password": <new-password>
} }
``` ```
**Errors** - **Errors**
- the token is missing - the token is missing
- the token is invalid - the token is invalid
- the user does not exist - the user does not exist
**Description** - **Description**
Generates a new password for given user. Password is sent as plain-text, so it Generates a new password for given user. Password is sent as plain-text, so
is recommended to connect through HTTPS. it is recommended to connect through HTTPS.
@ -354,29 +362,39 @@ is recommended to connect through HTTPS.
# Search # Search
Nomenclature: Search queries are built of tokens that are separated by spaces. Each token can
be of following form:
- Tokens - search terms inside a query, separated by white space. | Syntax | Token type | Description |
- Anonymous tokens - tokens of form `<value>`, used to filter the search | ----------------- | ----------------- | ------------------------------------------ |
results. | `<value>` | anonymous tokens | basic filters |
- Named tokens - tokens of form `<key>:<value>`, used to filter the search | `<key>:<value>` | named tokens | advanced filters |
results. | `order:<style>` | order tokens | sort results |
- Special tokens - tokens of form `special:<value>`, used to filter the search | `special:<value>` | special tokens | filters usually tied to the logged in user |
results.
- Order tokens - tokens of form `order:<value>`, used to sort the search
results.
Features: Most of anonymous and named tokens support ranged and composite values that
take following form:
- Most tokens can be negated like so: `-token`. Used with order tokens, it | `<value>` | Description |
flips the sort direction. | --------- | ----------------------------------------------------- |
- Some tokens support multiple values like so: `3,4,5`. | `a,b,c` | will show things that satisfy either `a`, `b` or `c`. |
- Some tokens support ranges like so: `100..`, `..200`, `100..200`. | `1..` | will show things that are equal to or greater than 1. |
- Date token values can contain following values: `today`, `yesterday`, | `..4` | will show things that are equal to at most 4. |
`<year>`, `<year>-<month>`, `<year>-<month>-<day>`. | `1..4` | will show things that are equal to 1, 2, 3 or 4. |
- Order token values can be appended with `,asc` and `,desc` suffixes, which
control the sort direction.
Example how it works: Date/time values can be of following form:
haruhi -kyon fav-count:3.. order:fav-count,desc -special:liked - `today`
- `yesterday`
- `<year>`
- `<year>-<month>`
- `<year>-<month>-<day>`
**Example**
Searching for posts with following query:
sea -fav-count:8.. type:swf uploader:Pirate
will show flash files tagged as sea, that were liked by seven people at most,
uploaded by user Pirate.

View File

@ -17,6 +17,10 @@ form
margin-bottom: 1em margin-bottom: 1em
.buttons .buttons
margin-top: 1em margin-top: 1em
a
margin-left: 1em
.fa-question-circle-o
font-size: 120%
.input li:first-child label:not(.radio):not(.checkbox):not(.file-dropper), .input li:first-child label:not(.radio):not(.checkbox):not(.file-dropper),
.input li:first-child .input li:first-child
padding-top: 0 padding-top: 0

View File

@ -1,11 +1,17 @@
@import colors
#help #help
width: 40em width: 40em
nav nav
margin-bottom: 1.5em margin-bottom: 1.5em
td, th
td padding: 0 0.5em
padding-right: 1em &:first-child
white-space: pre
.section .section
margin-top: 2em margin-top: 2em
h1
margin-top: 2.5em
font-size: 1.6em
&:first-child
margin-top: 0

View File

@ -12,6 +12,9 @@ h1, h2, h3
font-weight: normal font-weight: normal
margin-bottom: 1em margin-bottom: 1em
th
font-weight: normal
a a
color: $main-color color: $main-color
text-decoration: none text-decoration: none

View File

@ -24,11 +24,6 @@
margin: 0 0 0.5em 0 margin: 0 0 0.5em 0
#login
.buttons a
margin-left: 1em
#user #user
width: 30em width: 30em
.text-nav .text-nav
@ -99,6 +94,6 @@
.user-list-header .user-list-header
text-align: left text-align: left
form form
max-width: auto width: auto
input[name=search-text] input[name=search-text]
max-width: 15em max-width: 15em

View File

@ -1,265 +1,345 @@
<h1>General search syntax</h1>
<p>Search queries are built of tokens that are separated by spaces. Each token
can be of following form:</p>
<table> <table>
<thead> <thead>
<tr> <tr>
<th>Command</th> <th>Syntax</th>
<th>Token type</th>
<th>Description</th> <th>Description</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr> <tr>
<td><a href='/posts/query=Haruhi'><code>Haruhi</code></a></td> <td><code>&lt;value&gt;</code></td>
<td>containing tag “Haruhi”</td> <td>anonymous tokens</td>
<td>basic filters</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=-Kyon'><code>-Kyon</code></a></td> <td><code>&lt;key&gt;:&lt;value&gt;</code></td>
<td>not containing tag “Kyon”</td> <td>named tokens</td>
<td>advanced filters</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=uploader:David'><code>uploader:David</code></a></td> <td><code>order:&lt;style&gt;</code></td>
<td>uploaded by user David</td> <td>order tokens</td>
<td>sort results</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=comment:David'><code>comment:David</code></a></td> <td><code>special:&lt;value&gt;</code></td>
<td>commented by David</td> <td>special tokens</td>
<td>filters usually tied to the logged in user</td>
</tr>
</tbody>
</table>
<p>Most of anonymous and named tokens support ranged and composite values that
take following form:</p>
<table>
<tbody>
<tr>
<td><code>a,b,c</code></td>
<td>will show things that satisfy either <code>a</code>,
<code>b</code> or <code>c</code>.</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=fav:David'><code>fav:David</code></a></td> <td><code>1..</code></td>
<td>favorited by David</td> <td>will show things that are equal to or greater than 1.</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=fav-count:4'><code>fav-count:4</code></a></td> <td><code>..4</code></td>
<td>favorited by exactly four users</td> <td>will show things that are equal to at most 4.</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=fav-count:4,5'><code>fav-count:4,5</code></a></td> <td><code>1..4</code></td>
<td>favorited by four or five users</td> <td>will show things that are equal to 1, 2, 3 or 4.</td>
</tr> </tr>
</tbody>
</table>
<p>Date/time values can be of following form:</p>
<ul>
<li><code>today</code></li>
<li><code>yesterday</code></li>
<li><code>&lt;year&gt;</code></li>
<li><code>&lt;year&gt;-&lt;month&gt;</code></li>
<li><code>&lt;year&gt;-&lt;month&gt;-&lt;day&gt;</code></li>
</ul>
<p>All tokens can be negated by prepending them with <code>-</code>.</p>
<p>Order token values can be appended with <code>,asc</code> or
<code>,desc</code> to control the sort direction, which can be also controlled
by negating the whole token.</p>
<h1>Example</h1>
<p>Searching for posts with following query:</p>
<pre><code>sea -fav-count:8.. type:swf uploader:Pirate</code></pre>
<p>will show flash files tagged as sea, that were liked by seven people at
most, uploaded by user Pirate.</p>
<h1 id='post-search-help'>Post search tokens</h1>
<p><strong>Anonymous tokens</strong></p>
<p>Filter posts tagged with given <code>&lt;value&gt;</code>.</p>
<p><strong>Named tokens</strong></p>
<table>
<tbody>
<tr> <tr>
<td><a href='/posts/query=fav-count:4..'><code>fav-count:4..</code></a></td> <td><code>id</code></td>
<td>favorited by at least four users</td>
</tr>
<tr>
<td><a href='/posts/query=fav-count:..4'><code>fav-count:..4</code></a></td>
<td>favorited by at most four users</td>
</tr>
<tr>
<td><a href='/posts/query=fav-count:4..6'><code>fav-count:4..6</code></a></td>
<td>favorited by at least four, but no more than six users</td>
</tr>
<tr>
<td><a href='/posts/query=comment-count:3'><code>comment-count:3</code></a></td>
<td>having exactly three comments</td>
</tr>
<tr>
<td><a href='/posts/query=score:4'><code>score:4</code></a></td>
<td>having score of 4</td>
</tr>
<tr>
<td><a href='/posts/query=tag-count:7'><code>tag-count:7</code></a></td>
<td>tagged with exactly seven tags</td>
</tr>
<tr>
<td><a href='/posts/query=note-count:1..'><code>note-count:1..</code></a></td>
<td>having at least one post note</td>
</tr>
<tr>
<td><a href='/posts/query=feature-count:1..'><code>feature-count:1..</code></a></td>
<td>having been featured at least once</td>
</tr>
<tr>
<td><a href='/posts/query=date:today'><code>date:today</code></a></td>
<td>posted today</td>
</tr>
<tr>
<td><a href='/posts/query=date:yesterday'><code>date:yesterday</code></a></td>
<td>posted yesterday</td>
</tr>
<tr>
<td><a href='/posts/query=date:2000'><code>date:2000</code></a></td>
<td>posted in year 2000</td>
</tr>
<tr>
<td><a href='/posts/query=date:2000-01'><code>date:2000-01</code></a></td>
<td>posted in January, 2000</td>
</tr>
<tr>
<td><a href='/posts/query=date:2000-01-01'><code>date:2000-01-01</code></a></td>
<td>posted on January 1st, 2000</td>
</tr>
<tr>
<td><a href='/posts/query=id:1'><code>id:1</code></a></td>
<td>having specific post ID</td> <td>having specific post ID</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=name:hash'><code>name:<em>hash</em></code></a></td> <td><code>score</code></td>
<td>having specific post name (hash in full URLs)</td> <td>having given score</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=file-size:100..'><code>file-size:100..</code></a></td> <td><code>uploader</code></td>
<td>having at least 100 bytes</td> <td>uploaded by given user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=image-width:100..'><code>image-width:100..</code></a></td> <td><code>comment</code></td>
<td>being at least 100 pixels wide</td> <td>commented by given user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=image-height:100..'><code>image-height:100..</code></a></td> <td><code>fav</code></td>
<td>being at least 100 pixels tall</td> <td>favorited by given user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=image-area:10000..'><code>image-area:10000..</code></a></td> <td><code>fav-count</code></td>
<td>having at least 10000 pixels</td> <td>favorited by given number of users</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=type:image'><code>type:image</code></a></td> <td><code>comment-count</code></td>
<td>only image posts</td> <td>having given number of comments</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=type:flash'><code>type:flash</code></a></td> <td><code>tag-count</code></td>
<td>only Flash posts</td> <td>having given number of tags</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=type:youtube'><code>type:youtube</code></a></td> <td><code>note-count</code></td>
<td>only Youtube posts</td> <td>having given number of annotations</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=type:video'><code>type:video</code></a></td> <td><code>feature-count</code></td>
<td>only video posts</td> <td>having been featured given number of times</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=special:liked'><code>special:liked</code></a></td> <td><code>date</code></td>
<td>posted at given date</td>
</tr>
<tr>
<td><code>file-size</code></td>
<td>having given file size (in bytes)</td>
</tr>
<tr>
<td><code>image-width</code></td>
<td>having given image width (where applicable)</td>
</tr>
<tr>
<td><code>image-height</code></td>
<td>having given image height (where applicable)</td>
</tr>
<tr>
<td><code>image-area</code></td>
<td>having given number of pixels (image width * image height)</td>
</tr>
<tr>
<td><code>type</code></td>
<td>given type of posts (<code>&lt;value&gt;</code> can be either <code>image</code>, <code>flash</code>/<code>swf</code>, <code>youtube</code>/<code>yt</code>, <code>video</code> or <code>animation</code>)</td>
</tr>
</tbody>
</table>
<p><strong>Order tokens</strong></p>
<table>
<tbody>
<tr>
<td><code>random</code></td>
<td>as random as it can get</td>
</tr>
<tr>
<td><code>id</code></td>
<td>highest to lowest post ID</td>
</tr>
<tr>
<td><code>score</code></td>
<td>highest scored</td>
</tr>
<tr>
<td><code>fav-count</code></td>
<td>loved by most</td>
</tr>
<tr>
<td><code>comment-count</code></td>
<td>most commented first</td>
</tr>
<tr>
<td><code>tag-count</code></td>
<td>with most tags</td>
</tr>
<tr>
<td><code>note-count</code></td>
<td>with most annotations</td>
</tr>
<tr>
<td><code>file-size</code></td>
<td>largest files first</td>
</tr>
<tr>
<td><code>image-width</code></td>
<td>widest images first</td>
</tr>
<tr>
<td><code>image-height</code></td>
<td>tallest images first</td>
</tr>
<tr>
<td><code>image-area</code></td>
<td>largest images first</td>
</tr>
<tr>
<td><code>creation-date</code></td>
<td>newest to oldest (pretty much same as <code>id</code>)</td>
</tr>
<tr>
<td><code>edit-date</code></td>
<td>like <code>creation-date</code>, only looks at last edit time</td>
</tr>
<tr>
<td><code>fav-date</code></td>
<td>recently added to favorites by anyone</td>
</tr>
<tr>
<td><code>comment-date</code></td>
<td>recently commented by anyone</td>
</tr>
<tr>
<td><code>feature-date</code></td>
<td>recently featured</td>
</tr>
<tr>
<td><code>feature-count</code></td>
<td>most often featured</td>
</tr>
</tbody>
</table>
<p><strong>Special tokens</strong></p>
<table>
<tbody>
<tr>
<td><code>liked</code></td>
<td>posts liked by currently logged in user</td> <td>posts liked by currently logged in user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=special:disliked'><code>special:disliked</code></a></td> <td><code>disliked</code></td>
<td>posts disliked by currently logged in user</td> <td>posts disliked by currently logged in user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=special:fav'><code>special:fav</code></a></td> <td><code>fav</code></td>
<td>posts added to favorites by currently logged in user</td> <td>posts added to favorites by currently logged in user</td>
</tr> </tr>
<tr> <tr>
<td><a href='/posts/query=special:tumbleweed'><code>special:tumbleweed</code></a></td> <td><code>tumbleweed</code></td>
<td>posts with score of 0, without comments and without favorites</td> <td>posts with score of 0, without comments and without favorites</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<p>Most of the commands support ranged and composites values, e.g. <h1 id='user-search-help'>User search tokens</h1>
<code>id:<em>number</em></code> operator supports respectively
<a href='/posts/query=id:5..7'><code>id:5..7</code></a> and
<a href='/posts/query=id:5,10,15'><code>id:5,10,15</code></a>.
You can combine tags and negate any of them for interesting results.
<a href='/posts/query=sea -fav-count:..8 type:flash uploader:Pirate'><code>sea -fav-count:8.. type:swf uploader:Pirate</code></a>
will show you flash files tagged as sea, that were liked by seven people at
most, uploaded by user Pirate.</p>
<p>All of the above can be sorted using additional tag in form of <p><strong>Anonymous tokens</strong></p>
<code>order:<em>keyword</em></code>:</p>
<p>Same as <code>name</code> token.</p>
<p><strong>Named tokens</strong></p>
<table> <table>
<thead>
<tr>
<th>Command</th>
<th>Description</th>
</tr>
</thead>
<tbody> <tbody>
<tr> <tr>
<td><a href='/posts/query=order:random'><code>order:random</code></a></td> <td><code>name</code></td>
<td>as random as it can get</td> <td>having given name (doesn't accept wildcards yet)</td>
</tr> </tr>
<tr>
<tr> <td><code>creation-date</code></td>
<td><a href='/posts/query=order:id'><code>order:id</code></a></td> <td>registered at given date</td>
<td>highest to lowest post ID (default browse view)</td> </tr>
</tr> <tr>
<td><code>creation-time</code></td>
<tr> <td>alias of <code>creation-date</code></td>
<td><a href='/posts/query=order:creation-date'><code>order:creation-date</code></a></td> </tr>
<td>newest to oldest (pretty much same as above)</td> <tr>
</tr> <td><code>last-login-date</code>
<td>whose most recent login date matches given date</td>
<tr> </tr>
<td><a href='/posts/query=-order:creation-date'><code>-order:creation-date</code></a></td> <tr>
<td>oldest to newest</td> <td><code>last-login-time</code>
</tr> <td>alias of <code>last-login-date</code>
</tr>
<tr> <tr>
<td><a href='/posts/query=order:creation-date,asc'><code>order:creation-date,asc</code></a></td> <td><code>login-date</code>
<td>oldest to newest (ascending order, default = descending)</td> <td>alias of <code>last-login-date</code>
</tr> </tr>
<tr>
<tr> <td><code>login-time</code></td>
<td><a href='/posts/query=order:edit-date'><code>order:edit-date</code></a></td> <td>alias of <code>last-login-date</code>
<td>like <code>creation-date</code>, only looks at last edit time</td> </tr>
</tr>
<tr>
<td><a href='/posts/query=order:score'><code>order:score</code></a></td>
<td>highest scored</td>
</tr>
<tr>
<td><a href='/posts/query=order:file-size'><code>order:file-size</code></a></td>
<td>largest files first</td>
</tr>
<tr>
<td><a href='/posts/query=order:image-width'><code>order:image-width</code></a></td>
<td>widest images first</td>
</tr>
<tr>
<td><a href='/posts/query=order:image-height'><code>order:image-height</code></a></td>
<td>tallest images first</td>
</tr>
<tr>
<td><a href='/posts/query=order:image-area'><code>order:image-area</code></a></td>
<td>largest images first</td>
</tr>
<tr>
<td><a href='/posts/query=order:tag-count'><code>order:tag-count</code></a></td>
<td>with most tags</td>
</tr>
<tr>
<td><a href='/posts/query=order:fav-count'><code>order:fav-count</code></a></td>
<td>loved by most</td>
</tr>
<tr>
<td><a href='/posts/query=order:comment-count'><code>order:comment-count</code></a></td>
<td>most commented first</td>
</tr>
<tr>
<td><a href='/posts/query=order:fav-date'><code>order:fav-date</code></a></td>
<td>recently added to favorites</td>
</tr>
<tr>
<td><a href='/posts/query=order:comment-date'><code>order:comment-date</code></a></td>
<td>recently commented</td>
</tr>
<tr>
<td><a href='/posts/query=order:feature-date'><code>order:feature-date</code></a></td>
<td>recently featured</td>
</tr>
<tr>
<td><a href='/posts/query=order:feature-count'><code>order:feature-count</code></a></td>
<td>most often featured</td>
</tr>
</tbody> </tbody>
</table> </table>
<p>As shown with <a <p><strong>Order tokens</strong></p>
href='/posts/query=-order:creation-date'><code>-order:creation-date</code></a>,
any of them can be reversed in the same way as negating other tags: by placing <table>
a dash before the tag.</p> <tbody>
<tr>
<td><code>random</code></td>
<td>as random as it can get</td>
</tr>
<tr>
<td><code>name</code></td>
<td>A to Z</td>
</tr>
<tr>
<td><code>creation-date</code></td>
<td>newest to oldest</td>
</tr>
<tr>
<td><code>creation-time</code></td>
<td>alias of <code>creation-date</code></td>
</tr>
<tr>
<td><code>last-login-date</code></td>
<td>recently active first</td>
</tr>
<tr>
<td><code>last-login-time</code></td>
<td>alias of <code>last-login-date</code></td>
</tr>
<tr>
<td><code>login-date</code></td>
<td>alias of <code>last-login-date</code></td>
</tr>
<tr>
<td><code>login-time</code></td>
<td>alias of <code>last-login-date</code></td>
</tr>
</tbody>
</table>
<p><strong>Special tokens</strong></p>
<p>None.</p>

View File

@ -5,7 +5,7 @@
<meta name='viewport' content='width=device-width, initial-scale=1.0'> <meta name='viewport' content='width=device-width, initial-scale=1.0'>
<title><!-- confiured in config file --></title> <title><!-- confiured in config file --></title>
<link href='/bundle.min.css' rel='stylesheet' type='text/css'/> <link href='/bundle.min.css' rel='stylesheet' type='text/css'/>
<link href='//maxcdn.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css' rel='stylesheet' type='text/css'/> <link href='//maxcdn.bootstrapcdn.com/font-awesome/4.6.0/css/font-awesome.min.css' rel='stylesheet' type='text/css'/>
<link href='//fonts.googleapis.com/css?family=Droid+Sans' rel='stylesheet' type='text/css'/> <link href='//fonts.googleapis.com/css?family=Droid+Sans' rel='stylesheet' type='text/css'/>
<link rel='shortcut icon' type='image/png' href='/favicon.png'/> <link rel='shortcut icon' type='image/png' href='/favicon.png'/>
</head> </head>

View File

@ -9,6 +9,7 @@
</div> </div>
<div class='buttons'> <div class='buttons'>
<input type='submit' value='Search'/> <input type='submit' value='Search'/>
<a href='/help/search#user-search-help'><i class='fa fa-question-circle-o'></i></a>
</div> </div>
</form> </form>
</div> </div>

View File

@ -126,6 +126,19 @@ function showView(target, source) {
} }
} }
function scrollToHash() {
window.setTimeout(() => {
if (!window.location.hash) {
return;
}
const el = document.getElementById(
window.location.hash.replace(/#/, ''));
if (el) {
el.scrollIntoView();
}
}, 10);
}
module.exports = { module.exports = {
htmlToDom: htmlToDom, htmlToDom: htmlToDom,
getTemplate: getTemplate, getTemplate: getTemplate,
@ -137,4 +150,5 @@ module.exports = {
decorateValidator: decorateValidator, decorateValidator: decorateValidator,
makeVoidElement: makeVoidElement, makeVoidElement: makeVoidElement,
makeNonVoidElement: makeNonVoidElement, makeNonVoidElement: makeNonVoidElement,
scrollToHash: scrollToHash,
}; };

View File

@ -38,6 +38,8 @@ class HelpView {
views.listenToMessages(target); views.listenToMessages(target);
views.showView(target, source); views.showView(target, source);
views.scrollToHash();
} }
} }