* Introduce new widget helper function to evaluate variables.Functions are evaluated as parameterised filter strings, macros as text with textual substitution of parameters and variables, and procedures and widgets as plain text
* Refactor the function operator and unknown operator to use the new helper
* Use the new helper to evaluate variables within filter strings, thus fixing a bug whereby functions called in such a way were being returned as plain text instead of being evaluated
* Refactor the transclude widget to use the new helper
* Update tests
This first implementation concatenates the results of the filter (with no separator) and then wikifies the result.
The test in this commit is quite interesting...
Global variables access within attributes will automatically trigger a refresh if the attribute text changes, but that wasn't happening for transclusions.
The objective is to add a $depth attribute so that it is possible to reach up to retrieve the parameters of ancestor transclusions. However, doing so requires changing the encoding of parameter names so that it is not possible for a user parameter to clash with an attribute like $depth. So now we have to double up dollars on any attribute names seen by the parameters widget, just like with the transclude widget itself.
Can invoke any functions, not just those start with a period. And can pass zero parameters (in contrast when invoked as a custom filter operator there's no way to omit the first parameter).
So far it appears to be totally backwards compatible... In practice, I think maybe this and the conversion of the other macros should go into a separate subsequent PR.
The basic idea is that if we don't find a variable `foo` then we fallback to retrieving the value from the tiddler `$:/global/foo`, if it exists.
This allows us to replace the usual importvariables-based mechanism for global definitions, avoiding cluttering up the variable namespace with every macro.
In order to permit subprocedures to be overridden, we also introduce a mechanism for conditional definitions: preceding the word definition|procedure|function|widget with a + causes the definition only to occur if the specified variable doesn't already exist. In the next commit we'll apply this mechanism to the tabs macro
An experiment to try out using the new JSON operators for rendering the JSON parse tree that we get back from the wikify widget.
As usual with these experiments, this one is going to require quite a lot more work to finish up:
* The formatting is via direct styles rather than classes
* The formatting for attributes and properties is not yet completed
* The same thing needs to also be done to the widget tree preview
There are two big changes here:
Replace the previous "ts-wrapper" mechanism, which we had been using to redefine custom widgets inside their definitions to prevent recursive calls. Now we've got the genesis widget we can instead control recursion through a new "$remappable" attribute that allows the custom widget mechanism to be skipped.
We also extend the slot widget to allow a depth to be specified; it then reaches up by the indicated number of transclusion widgets to find the one from which it should retrieve the slot value.
Xememex is a multiuser TiddlyWiki from [[Federatial]]. It allows large groups of people to work together on intertwingled wikis that can share content. It is implemented as a serverless application on Amazon Web Services.
Xememex is a multiuser TiddlyWiki from [[Federatial]]. It allows large groups of people to work together on intertwingled wikis that can share content.
The largest customer implementation has hundreds of online wikis with thousands of users. See https://manuals.annafreud.org/
@@ -29,8 +29,6 @@ Each field can be specified as either a ''string'' or ''array'' value to be assi
** //extname// the extension of the filename of the file containing the tiddler
** //created// the creation date/time of the file containing the tiddler
** //modified// the modification date/time of the file containing the tiddler
** <<.from-version "5.3.0">> //filepath// the path of the file containing the tiddler, relative to the ''path'' property of the directory (only usable in ''directories'' declarations)
** <<.from-version "5.3.0">> //subdirectories// an array of the subdirectories in the file's path relative, to the ''path'' property of the directory (only usable in ''directories'' declarations)
* ''prefix'' - (optional) a string to be prepended to the value of the field
* ''suffix'' - (optional) a string to be appended to the value of the field
@@ -54,7 +52,7 @@ Directory specifications in the `directories` array may take the following forms
** ''filesRegExp'' - (optional) a [[regular expression|https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Regular_Expressions]] that matches the filenames of the files that should be processed within the directory
** ''isTiddlerFile'' - (required) if `true`, the file will be treated as a [[tiddler file|TiddlerFiles]] and deserialised to extract the tiddlers. Otherwise, the raw content of the file is assigned to the `text` field without any parsing
** ''isEditableFile'' - <<.from-version "5.1.23">> (optional) if `true`, changes to the tiddler be saved back to the original file. The tiddler will be saved back to the original filepath as long as it does not generate a result from the $:/config/FileSystemPath filters, which will override the final filepath generated if a result is returned from a filter.
** ''searchSubdirectories'' - <<.from-version "5.1.23">> (optional) if `true`, all subdirectories of the //path// are searched recursively for files that match the (optional) //filesRegExp//. If no //filesRegExp// is provided, all files in all subdirectories of the //path// are loaded. Tiddler titles generated via the //source// attribute //filename// (see above) will only include the filename, not any of the subdirectories of the path. If this results in multiple files with loaded with the same tiddler title, then only the last file loaded under that tiddler title will be in memory. In order to prevent this, you can use the //filepath// attribute instead of //filename//. Alternately, you can include multiple directory objects and customise the title field with a //prefix// or //suffix// alongside the //source// attribute.
** ''searchSubdirectories'' - <<.from-version "5.1.23">> (optional) if `true`, all subdirectories of the //path// are searched recursively for files that match the (optional) //filesRegExp//. If no //filesRegExp// is provided, all files in all subdirectories of the //path// are loaded. Tiddler titles generated via a //source// attribute (see above) will only include the filename, not any of the subdirectories of the path. If this results in multiple files with loaded with the same tiddler title, then only the last file loaded under that tiddler title will be in memory. In order to prevent this, you must have multiple directory objects listed and customise the title field with a //prefix// or //suffix// alongside the //source// attribute.
** ''fields'' - (required) an object containing values that override or customise the fields provided in the tiddler file (see above)
Fields can also be overridden for particular files by creating a file with the same name plus the suffix `.meta` -- see TiddlerFiles.
@@ -97,7 +95,6 @@ This example retrieves all the files with the extension `.pdf` from a folder spe
]
}
```
!! Importing a folder of text files
This example retrieves all the files with the extension `.txt` from a folder specified by a relative path. This folder is within the wiki's base directory, and the current config file is in a directory within the wiki's "tiddlers/" directory. So, in this case the path starts with "../../" to traverse upwards two directory levels, and then down into the "externalnotes/" directory. Each tiddler is set up with the following fields:
@@ -133,39 +130,4 @@ This will load all text files in the `../../externalnotes/` directory into the w
From the examples in [[Customising Tiddler File Naming]] we see that the final `[!tag[externalnote]addprefix[wiki/]]` filter in the $:/config/FileSystemPaths tiddler excludes all tiddlers tagged with `externalnotes` (that have not matched an earlier filter). These tiddlers have their filepath retrieved from the $:/config/OriginalTiddlerPaths generated upon boot startup.
Then, the `[tag[.txt]then[.txt]]` filter in the $:/config/FileSystemExtensions tiddler forces all these tiddlers to be saved back to disk as *.txt and accompanying *.txt.meta files (overriding the normal tiddler-type to file-type mapping). In this case, allowing the snippets of Tiddlywiki wikitext or markdown-text to be saved back to "text" *.txt files.
!! Importing and auto-tagging images
This example imports all the image files in the `files` directory and all its subdirectories as external-image tiddlers, and tags them based on their filepath. Each tiddler is set up with the following fields:
* ''title'' - set to the URI decoded base filename of the text file
* ''created'' - set to the creation date/time of the text file
* ''modified'' - set to the modification date/time of the text file
* ''type'' - set to `image/jpeg`. There is currently no way to infer the correct ContentType of the image tiddler from the file, but `image/jpeg` tiddlers should render correctly even with png or gif images. As an alternative, you could create separate definitions for jpg, png, and gif files with the `image/jpeg`, `image/png`, and `image/gif` types respectively.
* ''tags'' - generated based on the path of the image relative to the parent directory (`files` in this case). Eg, images in `files/photos` will be tagged with `photos`, those in `files/photos/family` will be tagged with both `photos` and `family`, and those in the root `files` directory will have no tags.
* ''text'' - set to an empty string
* ''_canonical_uri'' - set to the full filepath of the image relative to the wiki root
Then, the `[tag[.txt]then[.txt]]` filter in the $:/config/FileSystemExtensions tiddler forces all these tiddlers to be saved back to disk as *.txt and accompanying *.txt.meta files (overriding the normal tiddler-type to file-type mapping). In this case, allowing the snippets of Tiddlywiki wikitext or markdown-text to be saved back to "text" *.txt files.
<<.from-version "5.3.0">> The <<.def thisTiddler>> [[variable|Variables]] is set by the <<.wlink TranscludeWidget>> widget to contain the title of the tiddler that was transcluded. This means that within a tiddler <<.def thisTiddler>> will contain the title of that tiddler. It is not affected by macros, which means that within a macro <<.def thisTiddler>> will contain the title of the tiddler from which the macro was invoked. Intermediate, nested macro calls are ignored.
Compare <<.vlink storyTiddler>> and <<.vlink currentTiddler>>.
|! how declared|! how parameters are defined|! accessing parameter values in the body|
|\define|`()`|`$param$, <<__param__>>`|
|~|<<.wlink ParametersWidget>> or `\parameters`|`<<param>>`|
|<<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>|<<.wlink ParametersWidget>> or `\parameters`|`<<param>>`|
|\procedure, \widget|`()`, <<.wlink ParametersWidget>> or `\parameters`|`<<param>>`|
|\function|`()`|`<param>`|
|javascript macros|`exports.params` javascript property array|passed as normal javascript function parameter and so accessed as a normal javascript variable|
!!Examples
These examples are meant to provide insight into the various ways of defining and using parameters. In many cases they do not illustrate best practices.
!Behavior of invoked variables depends on how the variable was declared
|!how invoked|!how declared|!behavior|
|`<$transclude $variable=macro/>` or `<<macro>>` in normal wikitext context|\define|All wikitext and variable substitution and textual substitution takes place|
|~|\function|Invoking a function in this way (`<<macro>>`) is a synonym for `<$text text={{{[function[macro]]}}}/>`. As with any filtered transclusion (i.e. triple curly braces), all results except the first are discarded.|
||||
|widget attribute: `<div class=<<macro>>/>`|\define|Textual substitution of parameters is performed on the body text. No further processing takes place. The result after textual substitution is used as the attribute's value|
|~|<<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|Body text is retrieved as-is and used as the attribute's value.|
|~|\function|When a function is invoked as `<div class=<<macro>>/>`, it is a synonym for `<div class={{{[function[macro]]}}}/>`. As with any filtered transclusion (i.e. triple curly braces), all results except the first are discarded. That first result is used as the attribute's value. Note that functions are recursively processed even when invoked in this form. In other words a filter expression in a function can invoke another function and the processing will continue|
||||
|filter operator parameter: `[<macro>]`|\define|Textual substitution of parameters is performed on the body text. No further processing takes place. The result after textual substitution is used as the filter operator's parameter.|
|~|<<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|Body text is retrieved as-is and used as the filter operator's parameter.|
|~|\function|The body text of the function is treated as a filter expression and evaluated. The first result is passed to the operator as a parameter. The remaining results are discarded|
||||
|function call in a filter expression: `[function[macro]]`|\define, <<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget|Every function is a variable, but only variables defined using \function are invokable using the <<.olink function>> filter operator. Attempts to use a non-function variable is the same as if the function doesn't exist. The behavior in this case is like the identity function. All filter input is passed unchanged to the output.|
|~|\function|The body text of the function is treated as a filter expression and evaluated. This filter expression can itself contain a function call. Filter expressions can be factored out into functions arbitrarily deep.|
!! Examples
Below is an example macro, procedure and function definition. All three forms of parameter substitution `$a1$`, `<<__a1__>>`, and `<<a1>>` are included in each definition. The output helps illustrate when each form of substitution will or will not have affect.
*''tiddler titles'' - tiddlers are uniquely identified by their title. The namespace for tiddler titles and variable names are completely separate.
*''variables'' - \define, <<.wlink SetWidget>>, <<.wlink LetWidget>>, <<.wlink VarsWidget>>, \procedure, \widget, \function all create variables. If the same name is used, then later define will overwrite earlier defined
*''<<.op function>> filter operator parameter'' - only variables defined using \function can be called using the <<.olink function>> operator
*''filter operators'' - only the [[javascript defined filter operators|Filter Operators]] and variables defined using \function with name starting with a dot can be called
*''widgets'' - variables defined using \widget can be invoked using `<$widget/>` syntax ONLY if the name starts a dollar sign (to override existing javascript defined widgets) or double dollar sign (to define [[custom widgets|Custom Widgets]]). Without the dollar sign prefix, defining variables using \widget is no different than using \procedure.
This tiddler is also included in the "server-external-js" edition. Take care before editing or moving it.
-->
You can use a special template to externalise ~TiddlyWiki's core code into a separate file. This configuration allows the browser to cache the core for improved efficiency.
! Background
@@ -64,7 +60,7 @@ The "server-external-js" edition lets you save the snapshot from the command lin
tiddlywiki YOUR_WIKI_FOLDER --build index
```
The files `external-5-x-x.html` and `tiddlywikicore-5.x.x.js` will be saved in your wiki folder's `output` directory.
The files `index.html` and `tiddlywikicore-5.x.x.js` will be saved in your wiki folder's `output` directory.
@@ -25,7 +25,7 @@ The `<$dynannotate>` widget uses the selection tracker to support a popup that d
|popup |Popup state tiddler to be used to trigger a popup when an annotation is clicked |
|search |Search text to be highlighted within the widget |
|searchDisplay |"overlay" or "snippet" (see below) |
|searchMode |"literal" (default), "regexp", "whitespace", "words" or "some" (see below) |
|searchMode |"normal" (default), "regexp" or "whitespace" (see below) |
|searchMinLength |Optional minimum length of search string |
|searchCaseSensitive |"yes" (the default) for a case sensitive search, or "no" for a case insensitive search|
|searchClass |Optional CSS class to be added to search overlays |
@@ -46,10 +46,9 @@ The values supported by the `searchDisplay` attribute are:
The search modes supported by the `searchMode` attribute are:
* `literal` or `normal` - a literal string of plain text to match (default).
* `normal` - a literal string of plain text to match
* `regexp` - a JavaScript-style regular expression (without the quoting backslashes and flags)
* `whitespace` - a literal string to match while normalising runs of whitespace. Thus `A B` matches `A B`.
* `words` or `some` - treats the search string as a list of tokens separated by whitespace, and matches all tokens (regardless of ordering and whether there is other text in between)
* `whitespace` - a literal string to match while normalising runs of whitespace. This allows `a. b` to match `a. b`
When the selection popup is triggered, the currently selected text can be found in the tiddler named in the `selection` attribute, with the disambiguating prefix and suffix in the tiddlers named in the `selectionPrefix` and `selectionPopup` tiddlers. Note that the selection text will be an empty string if the selection popup was triggered in response to a click (ie zero width selection).
@@ -96,7 +95,7 @@ Note that using the `annotate-tiddler` field to associate an annotation with the
!! Selection Trackers
The selection trackers are enabled when the following configuration tiddlers are set to ''yes''.
The following configuration tiddlers can be used to control whether the selection trackers are enabled when the following configuration tiddlers are set to ''yes'' (the default).
* $:/config/Dynannotate/SelectionTracker/Enable for the main selection tracker
* $:/config/Dynannotate/LegacySelectionTracker/Enable for the legacy selection tracker
We use the `target*` attributes to specify a target string for the annotation and optionally a prefix and suffix for disambiguating multiple occurences.
We use the `target*` attributes to specify a target string for the annotation and optionally a prefix and suffix for disambiguating multiple occurances.
</div>
<<show-example """<$dynannotate
<<show-example """
<$dynannotate
target="the"
targetPrefix="Yet "
targetSuffix=" speed"
@@ -47,35 +30,55 @@ We use the `target*` attributes to specify a target string for the annotation an
<div class="tc-dynannotation-example-info">
!! Highlights with `search`
!! Plain text searching
We use the `search` attribute to specify a search string for highlighting.
The search type can be set with the `searchMode` and `searchCaseSensitive` attributes.
We can style the highlights with the `searchClass` attribute, which has some predefined values.
We use the `search` attribute to specify a search string for highlighting:
We use the `mode` attribute set to `whitespace` to search for a string with whitespace normalised (ie runs of whitespace are collapsed to a single space for matching purposes):
This example shows how to override the core view template with a custom template that includes dynannotate. It is disabled by default but can be enabled by clicking the corresponding button below. The example transcludes the [[Searching in TiddlyWiki|$:/plugins/tiddlywiki/dynannotate/searching-in-tiddlywiki]] tiddler for illustration purposes, but the chosen view template is applied to all open tiddlers.
This example shows how to override the core view template with a custom template that includes dynannotate. It is disabled by default but can be enabled by clicking the button below. (Clicking the button below copies the custom view template from $:/plugins/tiddlywiki/dynannotate/examples/viewtemplate/text to $:/core/ui/ViewTemplate/body).
Once enabled, this example demonstrates several features of Dynannotate:
Once enabled, this example demonstrates several features:
* Highlight text within tiddler bodies -- any text entered in the sidebar search input will be highlighted (in all tiddlers)
* Create annotations (on any tiddler) by selecting text and then clicking //Create annotation// in the resulting dropdown
(Clicking the buttons below either puts the custom body view template [[$:/plugins/tiddlywiki/dynannotate/examples/viewtemplate/text]] in front of the default in the [[View Template Body Cascade|https://tiddlywiki.com/#View%20Template%20Body%20Cascade]] or removes it from the cascade).
* Highlighting of search results within tiddler bodies
* Creating annotations on any tiddler by selecting text and then clicking a colour in the resulting dropdown
!! Using Dynannotate to highlight text on a per-tiddler basis
Using state tiddlers containing the text which is to be highlighted, Dynannotate highlights can be applied on a per-tiddler basis when used in the body view template. This can also be combined with the [[GenesisWidget]] to insert the Dynannotate widget into the DOM only when such a highlight is configured.
This example uses a transcluded tiddler, but Dynannotate could be added to the view template (to show highlights in all parts of a tiddler) or to the body view template (to show highlights only in the tiddler body) in the same way. Note how in this example, Dynannotate only affects the transcluded content.
When used in the view template, the state tiddler title could be derived from the current tiddler, e.g. `<$let dynannotateText={{{ [<currentTiddler>addprefix[$:/state/dynannotate/]get[text]] }}}>`, to configure highlights for each tiddler separately.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.