Skip to content

Commit

Permalink
Merge branch 'master' into fix-metadata-docs
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael "Tres" Brenan authored Mar 20, 2024
2 parents e3bbb96 + 692198b commit e808323
Show file tree
Hide file tree
Showing 19 changed files with 304 additions and 87 deletions.
10 changes: 6 additions & 4 deletions docs/docs/annotation/metadata-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ Just like pages, you can also add **fields** on list item and task level to bind
- [X] I finished this on [completion:: 2021-08-15].
```

Tasks and list items are the same data wise, so all your bullet points have all the information described here available, too.
Tasks and list items are the same data wise, so all your bullet points have all the information described here available, too.

## Field Shorthands

For supporting "common use cases", Dataview understands a few shorthands for some fields you may want to annotate task
with:
The [Tasks](https://publish.obsidian.md/tasks/Introduction) plugin introduced a different [notation by using Emoji](https://publish.obsidian.md/tasks/Reference/Task+Formats/Tasks+Emoji+Format) to configure the different dates related to a task. In the context of Dataview, this notation is called `Field Shorthands`. The current version of Dataview only support the dates shorthands as shown below. The priorities and recurrence shorthands are not supported.

=== "Example"


=== "Example"
- [ ] Due this Saturday 🗓️2021-08-29
Expand Down Expand Up @@ -62,7 +64,7 @@ As with pages, Dataview adds a number of implicit fields to each task or list it
| `completed` | Boolean | Whether or not this *specific* task has been completed; this does not consider the completion or non-completion of any child tasks. A task is explicitly considered "completed" if it has been marked with an `"x"`. If you use a custom status, e.g. `[-]`, `checked` will be true, whereas `completed` will be false. |
| `fullyCompleted` | Boolean | Whether or not this task and **all** of its subtasks are completed. |
| `text` | Text | The plain text of this task, including any metadata field annotations. |
| `visual` | Text | The text of this task, which is rendered by Dataview. It can be modified to render arbitrary text. |
| `visual` | Text | The text of this task, which is rendered by Dataview. This field can be overriden in DataviewJS to allow for different task text to be rendered than the regular task text, while still allowing the task to be checked (since Dataview validation logic normally checks the text against the text in-file). |
| `line` | Number | The line of the file this task shows up on. |
| `lineCount` | Number | The number of Markdown lines that this task takes up. |
| `path` | Text | The full path of the file this task is in. Equals to `file.path` for [pages](./metadata-pages.md). |
Expand Down
8 changes: 6 additions & 2 deletions docs/docs/api/code-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,8 +190,9 @@ dv.list(dv.pages("#book").where(p => p.rating > 7)) => list of all books with ra

### `dv.taskList(tasks, groupByFile)`

Render a dataview list of `Task` objects, as obtained by `page.file.tasks`. Only the first argument is required; if the
second argument `groupByFile` is provided (and is true), then tasks will be grouped by the file they come from automatically.
Render a dataview list of `Task` objects, as obtained by `page.file.tasks`. By default, this view will automatically
group the tasks by their origin file. If you provide `false` as a second argument explicitly, it will instead render them
as a single unified list.

```js
// List all tasks from pages marked '#project'
Expand All @@ -204,6 +205,9 @@ dv.taskList(dv.pages("#project").file.tasks
// List all tasks tagged with '#tag' from pages marked #project
dv.taskList(dv.pages("#project").file.tasks
.where(t => t.text.includes("#tag")))

// List all tasks from pages marked '#project', without grouping.
dv.taskList(dv.pages("#project").file.tasks, false)
```

### `dv.table(headers, elements)`
Expand Down
67 changes: 62 additions & 5 deletions docs/docs/reference/functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ object("a", 4, "c", "yes") => object which maps a to 4, and c to "yes"

### `list(value1, value2, ...)`

Creates a new list with the given values in it.
Creates a new list with the given values in it. `array` can be used an alias for `list`.

```js
list() => empty list
list(1, 2, 3) => list with 1, 2, and 3
list("a", "b", "c") => list with "a", "b", and "c"
array("a", "b", "c") => list with "a", "b", and "c"
```

### `date(any)`
Expand Down Expand Up @@ -158,7 +158,7 @@ Round a number to a given number of digits. If the second argument is not specif
otherwise, rounds to the given number of digits.

```js
round(16.555555) = 7
round(16.555555) = 17
round(16.555555, 2) = 16.56
```

Expand Down Expand Up @@ -238,6 +238,20 @@ product([]) = null
product(nonnull([null, 1, 2, 4])) = 8
```

### `reduce(array, operand)`

A generic function to reduce a list into a single value, valid operands are `"+"`, `"-"`, `"*"`, `"/"` and the boolean operands `"&"` and `"|"`. Note that using `"+"` and `"*"` equals the `sum()` and `product()` functions, and using `"&"` and `"|"` matches `all()` and `any()`.

```js
reduce([100, 20, 3], "-") = 77
reduce([200, 10, 2], "/") = 10
reduce(values, "*") = Multiplies every element of values, same as product(values)
reduce(values, this.operand) = Applies the local field operand to each of the values
reduce(["", 3], "*") = "⭐⭐⭐", same as "" * 3

reduce([1]), "+") = 1, has the side effect of reducing the list into a single element
```

### `average(array)`

Computes the numeric average of numeric values. If you have null values in your average, you can eliminate them via the
Expand Down Expand Up @@ -519,6 +533,18 @@ flat(list(1, list(21, 22), list(list (311, 312, 313))), 4) => list(1, 21, 22, 31
flat(rows.file.outlinks)) => All the file outlinks at first level in output
```

### `slice(array, [start, [end]])`

Returns a shallow copy of a portion of an array into a new array object selected from `start`
to `end` (`end` not included) where `start` and `end` represents the index of items in that array.

```js
slice([1, 2, 3, 4, 5], 3) = [4, 5] => All items from given position, 0 as first
slice(["ant", "bison", "camel", "duck", "elephant"], 0, 2) = ["ant", "bison"] => First two items
slice([1, 2, 3, 4, 5], -2) = [4, 5] => counts from the end, last two items
slice(someArray) => a copy of someArray
```

---

## String Operations
Expand Down Expand Up @@ -688,6 +714,25 @@ choice(false, "yes", "no") = "no"
choice(x > 4, y, z) = y if x > 4, else z
```

### `hash(seed, [text], [variant])`

Generate a hash based on the `seed`, and the optional extra `text` or a variant `number`. The function
generates a fixed number based on the combination of these parameters, which can be used to randomise
the sort order of files or lists/tasks. If you choose a `seed` based on a date, i.e. "2024-03-17",
or another timestamp, i.e. "2024-03-17 19:13", you can make the "randomness" be fixed
related to that timestamp. `variant` is a number, which in some cases is needed to make the combination of
`text` and `variant` become unique.

```js
hash(dateformat(date(today), "YYYY-MM-DD"), file.name) = ... A unique value for a given date in time
hash(dateformat(date(today), "YYYY-MM-DD"), file.name, position.start.line) = ... A unique "random" value in a TASK query
```

This function can be used in a `SORT` statement to randomise the order. If you're using a `TASK` query,
since the file name could be the same for multiple tasks, you can add some number like the starting line
number (as shown above) to make it a unique combination. If using something like `FLATTEN file.lists as item`,
the similar addition would be to do `item.position.start.line` as the last parameter.

### `striptime(date)`

Strip the time component of a date, leaving only the year, month, and day. Good for date comparisons if you don't care
Expand All @@ -700,8 +745,7 @@ striptime(file.mtime) = file.mday

### `dateformat(date|datetime, string)`

Format a Dataview date using a formatting string.
Uses [Luxon tokens](https://moment.github.io/luxon/#/formatting?id=table-of-tokens).
Format a Dataview date using a formatting string. Uses [Luxon tokens](https://moment.github.io/luxon/#/formatting?id=table-of-tokens).

```js
dateformat(file.ctime,"yyyy-MM-dd") = "2022-01-05"
Expand All @@ -710,6 +754,8 @@ dateformat(date(now),"x") = "1407287224054"
dateformat(file.mtime,"ffff") = "Wednesday, August 6, 2014, 1:07 PM Eastern Daylight Time"
```

**Note:** `dateformat()` returns a string, not a date, so you can't compare it against the result from a call to `date()` or a variable like `file.day` which already is a date. To make those comparisons you can format both arguments.

### `durationformat(duration, string)`

Format a Dataview duration using a formatting string.
Expand All @@ -734,6 +780,17 @@ durationformat(dur("2000 years"), "M months") = "24000 months"
durationformat(dur("14d"), "s 'seconds'") = "1209600 seconds"
```

### `currencyformat(number, [currency])`

Presents the number depending on your current locale, according to the `currency` code, from [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217#List_of_ISO_4217_currency_codes).

```
number = 123456.789
currencyformat(number, "EUR") = €123,456.79 in locale: en_US)
currencyformat(number, "EUR") = 123.456,79 € in locale: de_DE)
currencyformat(number, "EUR") = € 123 456,79 in locale: nb)
```

### `localtime(date)`

Converts a date in a fixed timezone to a date in the current timezone.
Expand Down
6 changes: 6 additions & 0 deletions docs/docs/resources/develop-against-dataview.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@ simply use:
npm install -D obsidian-dataview
```

To verify that it is the correct version installed, do `npm list obsidian-dataview`. If that fails to report the latest version, which currently is 0.5.64, you can do:

```bash
npm install obsidian-dataview@0.5.64
```

**Note**: If [Git](http://git-scm.com/) is not already installed on your local system, you will need to install it first. You may need to restart your device to complete the Git installation before you can install the Dataview API.

##### Accessing the Dataview API
Expand Down
38 changes: 37 additions & 1 deletion docs/docs/resources/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,40 @@ This will give you back the example page, even though the result doesn't fulfill

### How can I hide the result count on TABLE Queries?

With Dataview 0.5.52, you can hide the result count on TABLE and TASK Queries via a setting. Go to Dataview's settings -> Display result count.
With Dataview 0.5.52, you can hide the result count on TABLE and TASK Queries via a setting. Go to Dataview's settings -> Display result count.
### How can I style my queries?
You can use [CSS Snippets](https://help.obsidian.md/Extending+Obsidian/CSS+snippets) to define custom styling in general for Obsidian. So if you define `cssclasses: myTable` as a property, and enable the snippet below you could set the background color of a table from dataview. Similar to target the outer <ul> of a `TASK` or `LIST` query, you could use the `ul.contains-task-list` or `ul.list-view-ul` respectively.
```css
.myTable dataview.table {
background-color: green
}
```
In general there are no unique ID's given to a specific table on a page, so the mentioned targetting applies to any note having that `cssclasses` defined and **all** tables on that page. Currently you can't target a specific table using an ordinary query, but if you're using javascript, you can add the class `clsname` directly to your query result by doing:

```js
dv.container.className += ' clsname'
```

However, there is a trick to target any table within Obsidian using tags like in the example below, and that would apply to any table having that tag tag within it. This would apply to both manually and dataview generated tables. To make the snippet below work add the tag `#myId` _anywhere_ within your table output.

```css
[href="#myId"] {
display: none; /* Hides the tag from the table view */
}
table:has([href="#myId"]) {
/* Style your table as you like */
background-color: #262626;
& tr:nth-child(even) td:first-child{
background-color: #3f3f3f;
}
}
```

Which would end up having a grey background on the entire table, and the first cell in every even row a different variant of grey. **Disclaimer:** We're not style gurus, so this is just an example to show some of the syntax needed for styling different parts of a table.
Furthermore, in [Style dataview table columns](https://s-blu.github.io/obsidian_dataview_example_vault/20%20Dataview%20Queries/Style%20dataview%20table%20columns/) @s-blu describes an alternate trick using `<span>` to style various parts of table cells (and columns).
27 changes: 14 additions & 13 deletions src/api/inline-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export class DataviewInlineApi {
}

let _el = container.createEl(el, options);
renderValue(wrapped.value, _el, this.currentFilePath, this.component, this.settings, true);
renderValue(this.app, wrapped.value, _el, this.currentFilePath, this.component, this.settings, true);
return _el;
}

Expand Down Expand Up @@ -319,6 +319,7 @@ export class DataviewInlineApi {
const simpleViewPath = `${viewName}.js`;
const complexViewPath = `${viewName}/view.js`;
let checkForCss = false;
let cssElement = undefined;
let viewFile = this.app.metadataCache.getFirstLinkpathDest(simpleViewPath, this.currentFilePath);
if (!viewFile) {
viewFile = this.app.metadataCache.getFirstLinkpathDest(complexViewPath, this.currentFilePath);
Expand All @@ -333,6 +334,16 @@ export class DataviewInlineApi {
return;
}

if (checkForCss) {
// Check for optional CSS.
let cssFile = this.app.metadataCache.getFirstLinkpathDest(`${viewName}/view.css`, this.currentFilePath);
if (cssFile) {
let cssContents = await this.app.vault.read(cssFile);
cssContents += `\n/*# sourceURL=${location.origin}/${cssFile.path} */`;
cssElement = this.container.createEl("style", { text: cssContents, attr: { scope: " " } });
}
}

let contents = await this.app.vault.read(viewFile);
if (contents.contains("await")) contents = "(async () => { " + contents + " })()";
contents += `\n//# sourceURL=${viewFile.path}`;
Expand All @@ -343,6 +354,7 @@ export class DataviewInlineApi {
let result = await Promise.resolve(func(this, input));
if (result)
await renderValue(
this.app,
result as any,
this.container,
this.currentFilePath,
Expand All @@ -351,20 +363,9 @@ export class DataviewInlineApi {
true
);
} catch (ex) {
if (cssElement) this.container.removeChild(cssElement);
renderErrorPre(this.container, `Dataview: Failed to execute view '${viewFile.path}'.\n\n${ex}`);
}

if (!checkForCss) {
return;
}

// Check for optional CSS.
let cssFile = this.app.metadataCache.getFirstLinkpathDest(`${viewName}/view.css`, this.currentFilePath);
if (!cssFile) return;

let cssContents = await this.app.vault.read(cssFile);
cssContents += `\n/*# sourceURL=${location.origin}/${cssFile.path} */`;
this.container.createEl("style", { text: cssContents, attr: { scope: " " } });
}

/** Render a dataview list of the given values. */
Expand Down
2 changes: 1 addition & 1 deletion src/api/plugin-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,7 @@ export class DataviewApi {
filePath: string,
inline: boolean = false
) {
return renderValue(value as Literal, container, filePath, component, this.settings, inline);
return renderValue(this.app, value as Literal, container, filePath, component, this.settings, inline);
}

/////////////////
Expand Down
6 changes: 3 additions & 3 deletions src/data-model/value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -554,9 +554,9 @@ export class Link {

/** Convert the inner part of the link to something that Obsidian can open / understand. */
public obsidianLink(): string {
const escaped = this.path.replace("|", "\\|");
if (this.type == "header") return escaped + "#" + this.subpath?.replace("|", "\\|");
if (this.type == "block") return escaped + "#^" + this.subpath?.replace("|", "\\|");
const escaped = this.path.replaceAll("|", "\\|");
if (this.type == "header") return escaped + "#" + this.subpath?.replaceAll("|", "\\|");
if (this.type == "block") return escaped + "#^" + this.subpath?.replaceAll("|", "\\|");
else return escaped;
}

Expand Down
Loading

0 comments on commit e808323

Please sign in to comment.